diff --git a/.eslintrc.js b/.eslintrc.js index 827b373949..9d68942228 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -63,6 +63,11 @@ module.exports = { "@typescript-eslint/ban-ts-comment": "off", }, }], + settings: { + react: { + version: "detect", + } + } }; function buildRestrictedPropertiesOptions(properties, message) { diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 0ae59da09a..4f9826391a 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -10,6 +10,8 @@ on: jobs: end-to-end: runs-on: ubuntu-latest + env: + PR_NUMBER: ${{github.event.number}} container: vectorim/element-web-ci-e2etests-env:latest steps: - name: Checkout code diff --git a/.github/workflows/typecheck.yaml b/.github/workflows/typecheck.yaml new file mode 100644 index 0000000000..2e08418cf6 --- /dev/null +++ b/.github/workflows/typecheck.yaml @@ -0,0 +1,24 @@ +name: Type Check +on: + pull_request: + branches: [develop] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: c-hive/gha-yarn-cache@v2 + - name: Install Deps + run: "./scripts/ci/install-deps.sh --ignore-scripts" + - name: Typecheck + run: "yarn run lint:types" + - name: Switch js-sdk to release mode + run: | + scripts/ci/js-sdk-to-release.js + cd node_modules/matrix-js-sdk + yarn install + yarn run build:compile + yarn run build:types + - name: Typecheck (release mode) + run: "yarn run lint:types" + diff --git a/.stylelintrc.js b/.stylelintrc.js index 0e6de7000f..c044b19a63 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -17,6 +17,7 @@ module.exports = { "selector-list-comma-newline-after": null, "at-rule-no-unknown": null, "no-descending-specificity": null, + "no-empty-first-line": true, "scss/at-rule-no-unknown": [true, { // https://github.com/vector-im/element-web/issues/10544 "ignoreAtRules": ["define-mixin"], diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f71c1414c..9a445a4041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,114 @@ +Changes in [3.30.0](https://github.com/vector-im/element-desktop/releases/tag/v3.30.0) (2021-09-14) +=================================================================================================== + +## ✨ Features + * Add bubble highlight styling ([\#6582](https://github.com/matrix-org/matrix-react-sdk/pull/6582)). Fixes vector-im/element-web#18295 and vector-im/element-web#18295. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * [Release] Add config option to turn on in-room event sending timing metrics ([\#6773](https://github.com/matrix-org/matrix-react-sdk/pull/6773)). + * Create narrow mode for Composer ([\#6682](https://github.com/matrix-org/matrix-react-sdk/pull/6682)). Fixes vector-im/element-web#18533 and vector-im/element-web#18533. + * Prefer matrix.to alias links over room id in spaces & share ([\#6745](https://github.com/matrix-org/matrix-react-sdk/pull/6745)). Fixes vector-im/element-web#18796 and vector-im/element-web#18796. + * Stop automatic playback of voice messages if a non-voice message is encountered ([\#6728](https://github.com/matrix-org/matrix-react-sdk/pull/6728)). Fixes vector-im/element-web#18850 and vector-im/element-web#18850. + * Show call length during a call ([\#6700](https://github.com/matrix-org/matrix-react-sdk/pull/6700)). Fixes vector-im/element-web#18566 and vector-im/element-web#18566. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Serialize and retry mass-leave when leaving space ([\#6737](https://github.com/matrix-org/matrix-react-sdk/pull/6737)). Fixes vector-im/element-web#18789 and vector-im/element-web#18789. + * Improve form handling in and around space creation ([\#6739](https://github.com/matrix-org/matrix-react-sdk/pull/6739)). Fixes vector-im/element-web#18775 and vector-im/element-web#18775. + * Split autoplay GIFs and videos into different settings ([\#6726](https://github.com/matrix-org/matrix-react-sdk/pull/6726)). Fixes vector-im/element-web#5771 and vector-im/element-web#5771. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Add autoplay for voice messages ([\#6710](https://github.com/matrix-org/matrix-react-sdk/pull/6710)). Fixes vector-im/element-web#18804, vector-im/element-web#18715, vector-im/element-web#18714 vector-im/element-web#17961 and vector-im/element-web#18804. + * Allow to use basic html to format invite messages ([\#6703](https://github.com/matrix-org/matrix-react-sdk/pull/6703)). Fixes vector-im/element-web#15738 and vector-im/element-web#15738. Contributed by [skolmer](https://github.com/skolmer). + * Allow widgets, when eligible, to interact with more rooms as per MSC2762 ([\#6684](https://github.com/matrix-org/matrix-react-sdk/pull/6684)). + * Remove arbitrary limits from send/receive events for widgets ([\#6719](https://github.com/matrix-org/matrix-react-sdk/pull/6719)). Fixes vector-im/element-web#17994 and vector-im/element-web#17994. + * Reload suggested rooms if we see the state change down /sync ([\#6715](https://github.com/matrix-org/matrix-react-sdk/pull/6715)). Fixes vector-im/element-web#18761 and vector-im/element-web#18761. + * When creating private spaces, make the initial rooms restricted if supported ([\#6721](https://github.com/matrix-org/matrix-react-sdk/pull/6721)). Fixes vector-im/element-web#18722 and vector-im/element-web#18722. + * Threading exploration work ([\#6658](https://github.com/matrix-org/matrix-react-sdk/pull/6658)). Fixes vector-im/element-web#18532 and vector-im/element-web#18532. + * Default to `Don't leave any` when leaving a space ([\#6697](https://github.com/matrix-org/matrix-react-sdk/pull/6697)). Fixes vector-im/element-web#18592 and vector-im/element-web#18592. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Special case redaction event sending from widgets per MSC2762 ([\#6686](https://github.com/matrix-org/matrix-react-sdk/pull/6686)). Fixes vector-im/element-web#18573 and vector-im/element-web#18573. + * Add active speaker indicators ([\#6639](https://github.com/matrix-org/matrix-react-sdk/pull/6639)). Fixes vector-im/element-web#17627 and vector-im/element-web#17627. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Increase general app performance by optimizing layers ([\#6644](https://github.com/matrix-org/matrix-react-sdk/pull/6644)). Fixes vector-im/element-web#18730 and vector-im/element-web#18730. Contributed by [Palid](https://github.com/Palid). + +## 🐛 Bug Fixes + * Fix autocomplete not having y-scroll ([\#6802](https://github.com/matrix-org/matrix-react-sdk/pull/6802)). + * Fix emoji picker and stickerpicker not appearing correctly when opened ([\#6801](https://github.com/matrix-org/matrix-react-sdk/pull/6801)). + * Debounce read marker update on scroll ([\#6774](https://github.com/matrix-org/matrix-react-sdk/pull/6774)). + * Fix Space creation wizard go to my first room button behaviour ([\#6748](https://github.com/matrix-org/matrix-react-sdk/pull/6748)). Fixes vector-im/element-web#18764 and vector-im/element-web#18764. + * Fix scroll being stuck at bottom ([\#6751](https://github.com/matrix-org/matrix-react-sdk/pull/6751)). Fixes vector-im/element-web#18903 and vector-im/element-web#18903. + * Fix widgets not remembering identity verification when asked to. ([\#6742](https://github.com/matrix-org/matrix-react-sdk/pull/6742)). Fixes vector-im/element-web#15631 and vector-im/element-web#15631. + * Add missing pluralisation i18n strings for Spaces ([\#6738](https://github.com/matrix-org/matrix-react-sdk/pull/6738)). Fixes vector-im/element-web#18780 and vector-im/element-web#18780. + * Make ForgotPassword UX slightly more user friendly ([\#6636](https://github.com/matrix-org/matrix-react-sdk/pull/6636)). Fixes vector-im/element-web#11531 and vector-im/element-web#11531. Contributed by [Palid](https://github.com/Palid). + * Don't context switch room on SpaceStore ready as it can break permalinks ([\#6730](https://github.com/matrix-org/matrix-react-sdk/pull/6730)). Fixes vector-im/element-web#17974 and vector-im/element-web#17974. + * Fix explore rooms button not working during space creation wizard ([\#6729](https://github.com/matrix-org/matrix-react-sdk/pull/6729)). Fixes vector-im/element-web#18762 and vector-im/element-web#18762. + * Fix bug where one party's media would sometimes not be shown ([\#6731](https://github.com/matrix-org/matrix-react-sdk/pull/6731)). + * Only make the initial space rooms suggested by default ([\#6714](https://github.com/matrix-org/matrix-react-sdk/pull/6714)). Fixes vector-im/element-web#18760 and vector-im/element-web#18760. + * Replace fake username in EventTilePreview with a proper loading state ([\#6702](https://github.com/matrix-org/matrix-react-sdk/pull/6702)). Fixes vector-im/element-web#15897 and vector-im/element-web#15897. Contributed by [skolmer](https://github.com/skolmer). + * Don't send prehistorical events to widgets during decryption at startup ([\#6695](https://github.com/matrix-org/matrix-react-sdk/pull/6695)). Fixes vector-im/element-web#18060 and vector-im/element-web#18060. + * When creating subspaces properly set restricted join rule ([\#6725](https://github.com/matrix-org/matrix-react-sdk/pull/6725)). Fixes vector-im/element-web#18797 and vector-im/element-web#18797. + * Fix the Image View not openning for some pinned messages ([\#6723](https://github.com/matrix-org/matrix-react-sdk/pull/6723)). Fixes vector-im/element-web#18422 and vector-im/element-web#18422. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Show autocomplete sections vertically ([\#6722](https://github.com/matrix-org/matrix-react-sdk/pull/6722)). Fixes vector-im/element-web#18860 and vector-im/element-web#18860. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix EmojiPicker filtering to lower case emojibase data strings ([\#6717](https://github.com/matrix-org/matrix-react-sdk/pull/6717)). Fixes vector-im/element-web#18686 and vector-im/element-web#18686. + * Clear currentRoomId when viewing home page, fixing document title ([\#6716](https://github.com/matrix-org/matrix-react-sdk/pull/6716)). Fixes vector-im/element-web#18668 and vector-im/element-web#18668. + * Fix membership updates to Spaces not applying in real-time ([\#6713](https://github.com/matrix-org/matrix-react-sdk/pull/6713)). Fixes vector-im/element-web#18737 and vector-im/element-web#18737. + * Don't show a double stacked invite modals when inviting to Spaces ([\#6698](https://github.com/matrix-org/matrix-react-sdk/pull/6698)). Fixes vector-im/element-web#18745 and vector-im/element-web#18745. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Remove non-functional DuckDuckGo Autocomplete Provider ([\#6712](https://github.com/matrix-org/matrix-react-sdk/pull/6712)). Fixes vector-im/element-web#18778 and vector-im/element-web#18778. + * Filter members on `MemberList` load ([\#6708](https://github.com/matrix-org/matrix-react-sdk/pull/6708)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix improper voice messages being produced in Firefox and sometimes other browsers. ([\#6696](https://github.com/matrix-org/matrix-react-sdk/pull/6696)). Fixes vector-im/element-web#18587 and vector-im/element-web#18587. + * Fix client forgetting which capabilities a widget was approved for ([\#6685](https://github.com/matrix-org/matrix-react-sdk/pull/6685)). Fixes vector-im/element-web#18786 and vector-im/element-web#18786. + * Fix left panel widgets not remembering collapsed state ([\#6687](https://github.com/matrix-org/matrix-react-sdk/pull/6687)). Fixes vector-im/element-web#17803 and vector-im/element-web#17803. + * Fix changelog link colour back to blue ([\#6692](https://github.com/matrix-org/matrix-react-sdk/pull/6692)). Fixes vector-im/element-web#18726 and vector-im/element-web#18726. + * Soften codeblock border color ([\#6564](https://github.com/matrix-org/matrix-react-sdk/pull/6564)). Fixes vector-im/element-web#18367 and vector-im/element-web#18367. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Pause ringing more aggressively ([\#6691](https://github.com/matrix-org/matrix-react-sdk/pull/6691)). Fixes vector-im/element-web#18588 and vector-im/element-web#18588. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix command autocomplete ([\#6680](https://github.com/matrix-org/matrix-react-sdk/pull/6680)). Fixes vector-im/element-web#18670 and vector-im/element-web#18670. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Don't re-sort the room-list based on profile/status changes ([\#6595](https://github.com/matrix-org/matrix-react-sdk/pull/6595)). Fixes vector-im/element-web#110 and vector-im/element-web#110. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix codeblock formatting with syntax highlighting on ([\#6681](https://github.com/matrix-org/matrix-react-sdk/pull/6681)). Fixes vector-im/element-web#18739 vector-im/element-web#18365 and vector-im/element-web#18739. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Add padding to the Add button in the notification settings ([\#6665](https://github.com/matrix-org/matrix-react-sdk/pull/6665)). Fixes vector-im/element-web#18706 and vector-im/element-web#18706. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + +Changes in [3.29.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.29.1) (2021-09-13) +=================================================================================================== + +## 🔒 SECURITY FIXES + * Fix a security issue with message key sharing. See https://matrix.org/blog/2021/09/13/vulnerability-disclosure-key-sharing + for details. + +Changes in [3.29.0](https://github.com/vector-im/element-desktop/releases/tag/v3.29.0) (2021-08-31) +=================================================================================================== + +## ✨ Features + * [Release]Increase general app performance by optimizing layers ([\#6672](https://github.com/matrix-org/matrix-react-sdk/pull/6672)). Fixes vector-im/element-web#18730 and vector-im/element-web#18730. Contributed by [Palid](https://github.com/Palid). + * Add a warning on E2EE rooms if you try to make them public ([\#5698](https://github.com/matrix-org/matrix-react-sdk/pull/5698)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Allow pagination of the space hierarchy and use new APIs ([\#6507](https://github.com/matrix-org/matrix-react-sdk/pull/6507)). Fixes vector-im/element-web#18089 and vector-im/element-web#18427. + * Improve emoji in composer ([\#6650](https://github.com/matrix-org/matrix-react-sdk/pull/6650)). Fixes vector-im/element-web#18593 and vector-im/element-web#18593. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Allow playback of replied-to voice message ([\#6629](https://github.com/matrix-org/matrix-react-sdk/pull/6629)). Fixes vector-im/element-web#18599 and vector-im/element-web#18599. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Format autocomplete suggestions vertically ([\#6620](https://github.com/matrix-org/matrix-react-sdk/pull/6620)). Fixes vector-im/element-web#17574 and vector-im/element-web#17574. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Remember last `MemberList` search query per-room ([\#6640](https://github.com/matrix-org/matrix-react-sdk/pull/6640)). Fixes vector-im/element-web#18613 and vector-im/element-web#18613. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Sentry rageshakes ([\#6597](https://github.com/matrix-org/matrix-react-sdk/pull/6597)). Fixes vector-im/element-web#11111 and vector-im/element-web#11111. Contributed by [novocaine](https://github.com/novocaine). + * Autocomplete has been updated to match modern accessibility standards. Navigate via up/down arrows rather than Tab. Enter or Tab to confirm a suggestion. This should be familiar to Slack & Discord users. You can now use Tab to navigate around the application and do more without touching your mouse. No more accidentally sending half of people's names because the completion didn't fire on Enter! ([\#5659](https://github.com/matrix-org/matrix-react-sdk/pull/5659)). Fixes vector-im/element-web#4872, vector-im/element-web#11071, vector-im/element-web#17171, vector-im/element-web#15646 vector-im/element-web#4872 and vector-im/element-web#4872. + * Add new call tile states ([\#6610](https://github.com/matrix-org/matrix-react-sdk/pull/6610)). Fixes vector-im/element-web#18521 and vector-im/element-web#18521. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Left align call tiles ([\#6609](https://github.com/matrix-org/matrix-react-sdk/pull/6609)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Make loading encrypted images look snappier ([\#6590](https://github.com/matrix-org/matrix-react-sdk/pull/6590)). Fixes vector-im/element-web#17878 and vector-im/element-web#17862. Contributed by [Palid](https://github.com/Palid). + * Offer a way to create a space based on existing community ([\#6543](https://github.com/matrix-org/matrix-react-sdk/pull/6543)). Fixes vector-im/element-web#18092. + * Accessibility improvements in and around Spaces ([\#6569](https://github.com/matrix-org/matrix-react-sdk/pull/6569)). Fixes vector-im/element-web#18094 and vector-im/element-web#18094. + +## 🐛 Bug Fixes + * [Release] Fix commit edit history ([\#6690](https://github.com/matrix-org/matrix-react-sdk/pull/6690)). Fixes vector-im/element-web#18742 and vector-im/element-web#18742. Contributed by [Palid](https://github.com/Palid). + * Fix images not rendering when sent from other clients. ([\#6661](https://github.com/matrix-org/matrix-react-sdk/pull/6661)). Fixes vector-im/element-web#18702 and vector-im/element-web#18702. + * Fix autocomplete scrollbar and make the autocomplete a little smaller ([\#6655](https://github.com/matrix-org/matrix-react-sdk/pull/6655)). Fixes vector-im/element-web#18682 and vector-im/element-web#18682. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix replies on the bubble layout ([\#6451](https://github.com/matrix-org/matrix-react-sdk/pull/6451)). Fixes vector-im/element-web#18184. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Show "Enable encryption in settings" only when the user can do that ([\#6646](https://github.com/matrix-org/matrix-react-sdk/pull/6646)). Fixes vector-im/element-web#18646 and vector-im/element-web#18646. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix cross signing setup from settings screen ([\#6633](https://github.com/matrix-org/matrix-react-sdk/pull/6633)). Fixes vector-im/element-web#17761 and vector-im/element-web#17761. + * Fix call tiles on the bubble layout ([\#6647](https://github.com/matrix-org/matrix-react-sdk/pull/6647)). Fixes vector-im/element-web#18648 and vector-im/element-web#18648. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix error on accessing encrypted media without encryption keys ([\#6625](https://github.com/matrix-org/matrix-react-sdk/pull/6625)). Contributed by [Palid](https://github.com/Palid). + * Fix jitsi widget sometimes being permanently stuck in the bottom-right corner ([\#6632](https://github.com/matrix-org/matrix-react-sdk/pull/6632)). Fixes vector-im/element-web#17226 and vector-im/element-web#17226. Contributed by [Palid](https://github.com/Palid). + * Fix FilePanel pagination in E2EE rooms ([\#6630](https://github.com/matrix-org/matrix-react-sdk/pull/6630)). Fixes vector-im/element-web#18415 and vector-im/element-web#18415. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix call tile buttons ([\#6624](https://github.com/matrix-org/matrix-react-sdk/pull/6624)). Fixes vector-im/element-web#18565 and vector-im/element-web#18565. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix vertical call tile spacing issues ([\#6621](https://github.com/matrix-org/matrix-react-sdk/pull/6621)). Fixes vector-im/element-web#18558 and vector-im/element-web#18558. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix long display names in call tiles ([\#6618](https://github.com/matrix-org/matrix-react-sdk/pull/6618)). Fixes vector-im/element-web#18562 and vector-im/element-web#18562. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Avoid access token overflow ([\#6616](https://github.com/matrix-org/matrix-react-sdk/pull/6616)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Properly handle media errors ([\#6615](https://github.com/matrix-org/matrix-react-sdk/pull/6615)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix glare related regressions ([\#6614](https://github.com/matrix-org/matrix-react-sdk/pull/6614)). Fixes vector-im/element-web#18538 and vector-im/element-web#18538. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix long display names in call toasts ([\#6617](https://github.com/matrix-org/matrix-react-sdk/pull/6617)). Fixes vector-im/element-web#18557 and vector-im/element-web#18557. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix PiP of held calls ([\#6611](https://github.com/matrix-org/matrix-react-sdk/pull/6611)). Fixes vector-im/element-web#18539 and vector-im/element-web#18539. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix call tile behaviour on narrow layouts ([\#6556](https://github.com/matrix-org/matrix-react-sdk/pull/6556)). Fixes vector-im/element-web#18398. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Fix video call persisting when widget removed ([\#6608](https://github.com/matrix-org/matrix-react-sdk/pull/6608)). Fixes vector-im/element-web#15703 and vector-im/element-web#15703. + * Fix toast colors ([\#6606](https://github.com/matrix-org/matrix-react-sdk/pull/6606)). Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Remove tiny scrollbar dot from code blocks ([\#6596](https://github.com/matrix-org/matrix-react-sdk/pull/6596)). Fixes vector-im/element-web#18474. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + * Improve handling of pills in the composer ([\#6353](https://github.com/matrix-org/matrix-react-sdk/pull/6353)). Fixes vector-im/element-web#10134 vector-im/element-web#10896 and vector-im/element-web#15037. Contributed by [SimonBrandner](https://github.com/SimonBrandner). + Changes in [3.28.1](https://github.com/vector-im/element-desktop/releases/tag/v3.28.1) (2021-08-17) =================================================================================================== diff --git a/package.json b/package.json index e0883f5556..532e4218d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "3.28.1", + "version": "3.30.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { @@ -83,7 +83,7 @@ "linkifyjs": "^2.1.9", "lodash": "^4.17.20", "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", - "matrix-widget-api": "^0.1.0-beta.15", + "matrix-widget-api": "^0.1.0-beta.16", "minimist": "^1.2.5", "opus-recorder": "^8.0.3", "pako": "^2.0.3", @@ -151,7 +151,7 @@ "@typescript-eslint/eslint-plugin": "^4.17.0", "@typescript-eslint/parser": "^4.17.0", "@wojtekmaj/enzyme-adapter-react-17": "^0.6.1", - "allchange": "^1.0.0", + "allchange": "^1.0.3", "babel-jest": "^26.6.3", "chokidar": "^3.5.1", "concurrently": "^5.3.0", diff --git a/res/css/_common.scss b/res/css/_common.scss index fa925eba5b..a16e7d4d8f 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -53,8 +53,8 @@ html { body { font-family: $font-family; font-size: $font-15px; - background-color: $primary-bg-color; - color: $primary-fg-color; + background-color: $background; + color: $primary-content; border: 0px; margin: 0px; @@ -89,7 +89,7 @@ b { } h2 { - color: $primary-fg-color; + color: $primary-content; font-weight: 400; font-size: $font-18px; margin-top: 16px; @@ -142,12 +142,12 @@ textarea::placeholder { input[type=text], input[type=password], textarea { background-color: transparent; - color: $primary-fg-color; + color: $primary-content; } /* Required by Firefox */ textarea { - color: $primary-fg-color; + color: $primary-content; } input[type=text]:focus, input[type=password]:focus, textarea:focus { @@ -168,12 +168,12 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { // it has the appearance of a text box so the controls // appear to be part of the input -.mx_Dialog, .mx_MatrixChat { +.mx_Dialog, .mx_MatrixChat_wrapper { .mx_textinput > input[type=text], .mx_textinput > input[type=search] { border: none; flex: 1; - color: $primary-fg-color; + color: $primary-content; } :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=text], @@ -184,7 +184,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { background-color: transparent; color: $input-darker-fg-color; border-radius: 4px; - border: 1px solid rgba($primary-fg-color, .1); + border: 1px solid rgba($primary-content, .1); // these things should probably not be defined globally margin: 9px; } @@ -209,7 +209,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { :not(.mx_textinput):not(.mx_Field):not(.mx_no_textinput) > input[type=search], .mx_textinput { color: $input-darker-fg-color; - background-color: $primary-bg-color; + background-color: $background; border: none; } } @@ -271,7 +271,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { } .mx_Dialog { - background-color: $primary-bg-color; + background-color: $background; color: $light-fg-color; z-index: 4012; font-weight: 300; @@ -379,7 +379,7 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { .mx_Dialog_content { margin: 24px 0 68px; font-size: $font-14px; - color: $primary-fg-color; + color: $primary-content; word-wrap: break-word; } @@ -488,8 +488,8 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { border-radius: 3px; border: 1px solid $input-border-color; padding: 9px; - color: $primary-fg-color; - background-color: $primary-bg-color; + color: $primary-content; + background-color: $background; } .mx_textButton { diff --git a/res/css/_components.scss b/res/css/_components.scss index 035caec36a..ffaec43b68 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -17,6 +17,7 @@ @import "./structures/_LeftPanelWidget.scss"; @import "./structures/_MainSplit.scss"; @import "./structures/_MatrixChat.scss"; +@import "./structures/_BackdropPanel.scss"; @import "./structures/_MyGroups.scss"; @import "./structures/_NonUrgentToastContainer.scss"; @import "./structures/_NotificationPanel.scss"; @@ -27,8 +28,8 @@ @import "./structures/_RoomView.scss"; @import "./structures/_ScrollPanel.scss"; @import "./structures/_SearchBox.scss"; +@import "./structures/_SpaceHierarchy.scss"; @import "./structures/_SpacePanel.scss"; -@import "./structures/_SpaceRoomDirectory.scss"; @import "./structures/_SpaceRoomView.scss"; @import "./structures/_TabbedView.scss"; @import "./structures/_ToastContainer.scss"; @@ -131,6 +132,7 @@ @import "./views/elements/_EditableItemList.scss"; @import "./views/elements/_ErrorBoundary.scss"; @import "./views/elements/_EventListSummary.scss"; +@import "./views/elements/_EventTilePreview.scss"; @import "./views/elements/_FacePile.scss"; @import "./views/elements/_Field.scss"; @import "./views/elements/_ImageView.scss"; diff --git a/res/css/structures/_BackdropPanel.scss b/res/css/structures/_BackdropPanel.scss new file mode 100644 index 0000000000..482507cb15 --- /dev/null +++ b/res/css/structures/_BackdropPanel.scss @@ -0,0 +1,37 @@ +/* +Copyright 2021 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_BackdropPanel { + position: absolute; + left: 0; + top: 0; + height: 100vh; + width: 100%; + overflow: hidden; + filter: blur(var(--lp-background-blur)); + // Force a new layer for the backdropPanel so it's better hardware supported + transform: translateZ(0); +} + +.mx_BackdropPanel--image { + position: absolute; + top: 0; + left: 0; + min-height: 100%; + z-index: 0; + pointer-events: none; + overflow: hidden; +} diff --git a/res/css/structures/_ContextualMenu.scss b/res/css/structures/_ContextualMenu.scss index d7f2cb76e8..9f2b9e24b8 100644 --- a/res/css/structures/_ContextualMenu.scss +++ b/res/css/structures/_ContextualMenu.scss @@ -34,7 +34,7 @@ limitations under the License. border-radius: 8px; box-shadow: 4px 4px 12px 0 $menu-box-shadow-color; background-color: $menu-bg-color; - color: $primary-fg-color; + color: $primary-content; position: absolute; font-size: $font-14px; z-index: 5001; diff --git a/res/css/structures/_CreateRoom.scss b/res/css/structures/_CreateRoom.scss index e859beb20e..3d23ccc4b2 100644 --- a/res/css/structures/_CreateRoom.scss +++ b/res/css/structures/_CreateRoom.scss @@ -18,7 +18,7 @@ limitations under the License. width: 960px; margin-left: auto; margin-right: auto; - color: $primary-fg-color; + color: $primary-content; } .mx_CreateRoom input, diff --git a/res/css/structures/_GroupFilterPanel.scss b/res/css/structures/_GroupFilterPanel.scss index 444435dd57..cc0e760031 100644 --- a/res/css/structures/_GroupFilterPanel.scss +++ b/res/css/structures/_GroupFilterPanel.scss @@ -14,10 +14,27 @@ See the License for the specific language governing permissions and limitations under the License. */ +$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations + +.mx_GroupFilterPanelContainer { + flex-grow: 0; + flex-shrink: 0; + width: $groupFilterPanelWidth; + height: 100%; + + // Create another flexbox so the GroupFilterPanel fills the container + display: flex; + flex-direction: column; + + // GroupFilterPanel handles its own CSS +} + .mx_GroupFilterPanel { - flex: 1; + z-index: 1; background-color: $groupFilterPanel-bg-color; + flex: 1; cursor: pointer; + position: relative; display: flex; flex-direction: column; @@ -75,13 +92,13 @@ limitations under the License. } .mx_GroupFilterPanel .mx_TagTile.mx_TagTile_selected_prototype { - background-color: $primary-bg-color; + background-color: $background; border-radius: 6px; } .mx_TagTile_selected_prototype { .mx_TagTile_homeIcon::before { - background-color: $primary-fg-color; // dark-on-light + background-color: $primary-content; // dark-on-light } } diff --git a/res/css/structures/_GroupView.scss b/res/css/structures/_GroupView.scss index fb660f4194..5e224b1f38 100644 --- a/res/css/structures/_GroupView.scss +++ b/res/css/structures/_GroupView.scss @@ -132,7 +132,7 @@ limitations under the License. width: 100%; height: 31px; overflow: hidden; - color: $primary-fg-color; + color: $primary-content; font-weight: bold; font-size: $font-22px; padding-left: 19px; @@ -397,7 +397,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); - background-color: $secondary-fg-color; + background-color: $secondary-content; } .mx_AccessibleButton_kind_link { @@ -422,7 +422,7 @@ limitations under the License. mask-position: center; mask-size: 8px; mask-image: url('$(res)/img/image-view/close.svg'); - background-color: $secondary-fg-color; + background-color: $secondary-content; } } } diff --git a/res/css/structures/_LeftPanel.scss b/res/css/structures/_LeftPanel.scss index f254ca3226..5ddea244f3 100644 --- a/res/css/structures/_LeftPanel.scss +++ b/res/css/structures/_LeftPanel.scss @@ -14,31 +14,47 @@ See the License for the specific language governing permissions and limitations under the License. */ -$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations $roomListCollapsedWidth: 68px; +.mx_MatrixChat--with-avatar { + .mx_LeftPanel, + .mx_LeftPanel .mx_LeftPanel_roomListContainer { + background-color: transparent; + } +} + +.mx_LeftPanel_wrapper { + display: flex; + max-width: 50%; + position: relative; + + // Contain the amount of layers rendered by constraining what actually needs re-layering via css + contain: layout paint; + + .mx_LeftPanel_wrapper--user { + background-color: $roomlist-bg-color; + display: flex; + overflow: hidden; + position: relative; + + &[data-collapsed] { + max-width: $roomListCollapsedWidth; + } + } +} + + + .mx_LeftPanel { background-color: $roomlist-bg-color; // TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel - min-width: 206px; - max-width: 50%; // Create a row-based flexbox for the GroupFilterPanel and the room list display: flex; contain: content; - - .mx_LeftPanel_GroupFilterPanelContainer { - flex-grow: 0; - flex-shrink: 0; - flex-basis: $groupFilterPanelWidth; - height: 100%; - - // Create another flexbox so the GroupFilterPanel fills the container - display: flex; - flex-direction: column; - - // GroupFilterPanel handles its own CSS - } + position: relative; + flex-grow: 1; + overflow: hidden; // Note: The 'room list' in this context is actually everything that isn't the tag // panel, such as the menu options, breadcrumbs, filtering, etc @@ -130,7 +146,7 @@ $roomListCollapsedWidth: 68px; mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $secondary-fg-color; + background: $secondary-content; } } @@ -153,7 +169,7 @@ $roomListCollapsedWidth: 68px; mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $secondary-fg-color; + background: $secondary-content; } &.mx_LeftPanel_exploreButton_space::before { @@ -171,6 +187,8 @@ $roomListCollapsedWidth: 68px; } .mx_LeftPanel_roomListWrapper { + // Make the y-scrollbar more responsive + padding-right: 2px; overflow: hidden; margin-top: 10px; // so we're not up against the search/filter flex: 1 0 0; // needed in Safari to properly set flex-basis @@ -192,6 +210,7 @@ $roomListCollapsedWidth: 68px; // These styles override the defaults for the minimized (66px) layout &.mx_LeftPanel_minimized { + flex-grow: 0; min-width: unset; width: unset !important; diff --git a/res/css/structures/_LeftPanelWidget.scss b/res/css/structures/_LeftPanelWidget.scss index 6e2d99bb37..93c2898395 100644 --- a/res/css/structures/_LeftPanelWidget.scss +++ b/res/css/structures/_LeftPanelWidget.scss @@ -113,7 +113,7 @@ limitations under the License. &:hover .mx_LeftPanelWidget_resizerHandle { opacity: 0.8; - background-color: $primary-fg-color; + background-color: $primary-content; } .mx_LeftPanelWidget_maximizeButton { diff --git a/res/css/structures/_MainSplit.scss b/res/css/structures/_MainSplit.scss index 8199121420..407a1c270c 100644 --- a/res/css/structures/_MainSplit.scss +++ b/res/css/structures/_MainSplit.scss @@ -38,7 +38,7 @@ limitations under the License. width: 4px !important; border-radius: 4px !important; - background-color: $primary-fg-color; + background-color: $primary-content; opacity: 0.8; } } diff --git a/res/css/structures/_MatrixChat.scss b/res/css/structures/_MatrixChat.scss index a220c5d505..fdf5cb1a03 100644 --- a/res/css/structures/_MatrixChat.scss +++ b/res/css/structures/_MatrixChat.scss @@ -29,8 +29,6 @@ limitations under the License. .mx_MatrixChat_wrapper { display: flex; - flex-direction: column; - width: 100%; height: 100%; } @@ -42,13 +40,12 @@ limitations under the License. } .mx_MatrixChat { + position: relative; width: 100%; height: 100%; display: flex; - order: 2; - flex: 1; min-height: 0; } @@ -66,8 +63,8 @@ limitations under the License. } /* not the left panel, and not the resize handle, so the roomview/groupview/... */ -.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle) { - background-color: $primary-bg-color; +.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle):not(.mx_LeftPanel_wrapper) { + background-color: $background; flex: 1 1 0; min-width: 0; @@ -94,7 +91,7 @@ limitations under the License. content: ' '; - background-color: $primary-fg-color; + background-color: $primary-content; opacity: 0.8; } } diff --git a/res/css/structures/_NotificationPanel.scss b/res/css/structures/_NotificationPanel.scss index d271cd2bcc..68e1dd6a9a 100644 --- a/res/css/structures/_NotificationPanel.scss +++ b/res/css/structures/_NotificationPanel.scss @@ -49,7 +49,7 @@ limitations under the License. bottom: 0; left: 0; right: 0; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; height: 1px; opacity: 0.4; content: ''; @@ -70,7 +70,7 @@ limitations under the License. } .mx_NotificationPanel .mx_EventTile_roomName a { - color: $primary-fg-color; + color: $primary-content; } .mx_NotificationPanel .mx_EventTile_avatar { @@ -79,7 +79,7 @@ limitations under the License. .mx_NotificationPanel .mx_EventTile .mx_SenderProfile, .mx_NotificationPanel .mx_EventTile .mx_MessageTimestamp { - color: $primary-fg-color; + color: $primary-content; font-size: $font-12px; display: inline; } @@ -118,7 +118,7 @@ limitations under the License. } .mx_NotificationPanel .mx_EventTile:hover .mx_EventTile_line { - background-color: $primary-bg-color; + background-color: $background; } .mx_NotificationPanel .mx_EventTile_content { diff --git a/res/css/structures/_RightPanel.scss b/res/css/structures/_RightPanel.scss index 3222fe936c..5316cba61d 100644 --- a/res/css/structures/_RightPanel.scss +++ b/res/css/structures/_RightPanel.scss @@ -43,7 +43,7 @@ limitations under the License. .mx_RightPanel_headerButtonGroup { height: 100%; display: flex; - background-color: $primary-bg-color; + background-color: $background; padding: 0 9px; align-items: center; } diff --git a/res/css/structures/_RoomDirectory.scss b/res/css/structures/_RoomDirectory.scss index ec07500af5..fb0f7d10e1 100644 --- a/res/css/structures/_RoomDirectory.scss +++ b/res/css/structures/_RoomDirectory.scss @@ -28,7 +28,7 @@ limitations under the License. .mx_RoomDirectory { margin-bottom: 12px; - color: $primary-fg-color; + color: $primary-content; word-break: break-word; display: flex; flex-direction: column; @@ -71,14 +71,14 @@ limitations under the License. font-weight: $font-semi-bold; font-size: $font-15px; line-height: $font-18px; - color: $primary-fg-color; + color: $primary-content; } > p { margin: 40px auto 60px; font-size: $font-14px; line-height: $font-20px; - color: $secondary-fg-color; + color: $secondary-content; max-width: 464px; // easier reading } @@ -97,7 +97,7 @@ limitations under the License. } .mx_RoomDirectory_table { - color: $primary-fg-color; + color: $primary-content; display: grid; font-size: $font-12px; grid-template-columns: max-content auto max-content max-content max-content; diff --git a/res/css/structures/_RoomSearch.scss b/res/css/structures/_RoomSearch.scss index 7fdafab5a6..bbd60a5ff3 100644 --- a/res/css/structures/_RoomSearch.scss +++ b/res/css/structures/_RoomSearch.scss @@ -33,14 +33,14 @@ limitations under the License. height: 16px; mask: url('$(res)/img/element-icons/roomlist/search.svg'); mask-repeat: no-repeat; - background-color: $secondary-fg-color; + background-color: $secondary-content; margin-left: 7px; } .mx_RoomSearch_input { border: none !important; // !important to override default app-wide styles flex: 1 !important; // !important to override default app-wide styles - color: $primary-fg-color !important; // !important to override default app-wide styles + color: $primary-content !important; // !important to override default app-wide styles padding: 0; height: 100%; width: 100%; @@ -48,12 +48,12 @@ limitations under the License. line-height: $font-16px; &:not(.mx_RoomSearch_inputExpanded)::placeholder { - color: $tertiary-fg-color !important; // !important to override default app-wide styles + color: $tertiary-content !important; // !important to override default app-wide styles } } &.mx_RoomSearch_hasQuery { - border-color: $secondary-fg-color; + border-color: $secondary-content; } &.mx_RoomSearch_focused { @@ -62,7 +62,7 @@ limitations under the License. } &.mx_RoomSearch_focused, &.mx_RoomSearch_hasQuery { - background-color: $roomlist-filter-active-bg-color; + background-color: $background; .mx_RoomSearch_clearButton { width: 16px; @@ -71,7 +71,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background-color: $secondary-fg-color; + background-color: $secondary-content; margin-right: 8px; } } diff --git a/res/css/structures/_RoomStatusBar.scss b/res/css/structures/_RoomStatusBar.scss index de9e049165..bdfbca1afa 100644 --- a/res/css/structures/_RoomStatusBar.scss +++ b/res/css/structures/_RoomStatusBar.scss @@ -27,7 +27,7 @@ limitations under the License. .mx_RoomStatusBar_typingIndicatorAvatars .mx_BaseAvatar_image { margin-right: -12px; - border: 1px solid $primary-bg-color; + border: 1px solid $background; } .mx_RoomStatusBar_typingIndicatorAvatars .mx_BaseAvatar_initial { @@ -39,7 +39,7 @@ limitations under the License. display: inline-block; color: #acacac; background-color: #ddd; - border: 1px solid $primary-bg-color; + border: 1px solid $background; border-radius: 40px; width: 24px; height: 24px; @@ -171,14 +171,14 @@ limitations under the License. } .mx_RoomStatusBar_connectionLostBar_desc { - color: $primary-fg-color; + color: $primary-content; font-size: $font-13px; opacity: 0.5; padding-bottom: 20px; } .mx_RoomStatusBar_resend_link { - color: $primary-fg-color !important; + color: $primary-content !important; text-decoration: underline !important; cursor: pointer; } @@ -187,7 +187,7 @@ limitations under the License. height: 50px; line-height: $font-50px; - color: $primary-fg-color; + color: $primary-content; opacity: 0.5; overflow-y: hidden; display: block; diff --git a/res/css/structures/_RoomView.scss b/res/css/structures/_RoomView.scss index 831f186ed4..86c2efeb4a 100644 --- a/res/css/structures/_RoomView.scss +++ b/res/css/structures/_RoomView.scss @@ -14,10 +14,22 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_RoomView_wrapper { + display: flex; + flex-direction: column; + flex: 1; + position: relative; + justify-content: center; + // Contain the amount of layers rendered by constraining what actually needs re-layering via css + contain: strict; +} + .mx_RoomView { word-wrap: break-word; display: flex; flex-direction: column; + flex: 1; + position: relative; } @@ -40,7 +52,7 @@ limitations under the License. pointer-events: none; - background-color: $primary-bg-color; + background-color: $background; opacity: 0.95; position: absolute; @@ -87,7 +99,7 @@ limitations under the License. left: 0; right: 0; z-index: 3000; - background-color: $primary-bg-color; + background-color: $background; } .mx_RoomView_auxPanel_hiddenHighlights { @@ -153,7 +165,6 @@ limitations under the License. flex: 1; display: flex; flex-direction: column; - contain: content; } .mx_RoomView_statusArea { @@ -161,7 +172,7 @@ limitations under the License. flex: 0 0 auto; max-height: 0px; - background-color: $primary-bg-color; + background-color: $background; z-index: 1000; overflow: hidden; @@ -246,7 +257,7 @@ hr.mx_RoomView_myReadMarker { } .mx_RoomView_callStatusBar .mx_UploadBar_uploadProgressInner { - background-color: $primary-bg-color; + background-color: $background; } .mx_RoomView_callStatusBar .mx_UploadBar_uploadFilename { diff --git a/res/css/structures/_ScrollPanel.scss b/res/css/structures/_ScrollPanel.scss index 7b75c69e86..a668594bba 100644 --- a/res/css/structures/_ScrollPanel.scss +++ b/res/css/structures/_ScrollPanel.scss @@ -15,7 +15,6 @@ limitations under the License. */ .mx_ScrollPanel { - .mx_RoomView_MessageList { position: relative; display: flex; diff --git a/res/css/structures/_SpaceRoomDirectory.scss b/res/css/structures/_SpaceHierarchy.scss similarity index 80% rename from res/css/structures/_SpaceRoomDirectory.scss rename to res/css/structures/_SpaceHierarchy.scss index 88e6a3f494..a5d589f9c2 100644 --- a/res/css/structures/_SpaceRoomDirectory.scss +++ b/res/css/structures/_SpaceHierarchy.scss @@ -14,21 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_SpaceRoomDirectory_dialogWrapper > .mx_Dialog { - max-width: 960px; - height: 100%; -} - -.mx_SpaceRoomDirectory { - height: 100%; - margin-bottom: 12px; - color: $primary-fg-color; - word-break: break-word; - display: flex; - flex-direction: column; -} - -.mx_SpaceRoomDirectory, .mx_SpaceRoomView_landing { .mx_Dialog_title { display: flex; @@ -52,7 +37,7 @@ limitations under the License. > div { font-weight: 400; - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-15px; line-height: $font-24px; } @@ -68,23 +53,29 @@ limitations under the License. margin: 24px 0 16px; } - .mx_SpaceRoomDirectory_noResults { + .mx_SpaceHierarchy_noResults { text-align: center; > div { font-size: $font-15px; line-height: $font-24px; - color: $secondary-fg-color; + color: $secondary-content; } } - .mx_SpaceRoomDirectory_listHeader { + .mx_SpaceHierarchy_listHeader { display: flex; min-height: 32px; align-items: center; font-size: $font-15px; line-height: $font-24px; - color: $primary-fg-color; + color: $primary-content; + margin-bottom: 12px; + + > h4 { + font-weight: $font-semi-bold; + margin: 0; + } .mx_AccessibleButton { padding: 4px 12px; @@ -105,7 +96,7 @@ limitations under the License. } } - .mx_SpaceRoomDirectory_error { + .mx_SpaceHierarchy_error { position: relative; font-weight: $font-semi-bold; color: $notice-primary-color; @@ -124,43 +115,44 @@ limitations under the License. background-image: url("$(res)/img/element-icons/warning-badge.svg"); } } -} -.mx_SpaceRoomDirectory_list { - margin-top: 16px; - padding-bottom: 40px; + .mx_SpaceHierarchy_list { + list-style: none; + padding: 0; + margin: 0; + } - .mx_SpaceRoomDirectory_roomCount { + .mx_SpaceHierarchy_roomCount { > h3 { display: inline; font-weight: $font-semi-bold; font-size: $font-18px; line-height: $font-22px; - color: $primary-fg-color; + color: $primary-content; } > span { margin-left: 8px; font-size: $font-15px; line-height: $font-24px; - color: $secondary-fg-color; + color: $secondary-content; } } - .mx_SpaceRoomDirectory_subspace { + .mx_SpaceHierarchy_subspace { .mx_BaseAvatar_image { border-radius: 8px; } } - .mx_SpaceRoomDirectory_subspace_toggle { + .mx_SpaceHierarchy_subspace_toggle { position: absolute; left: -1px; top: 10px; height: 16px; width: 16px; border-radius: 4px; - background-color: $primary-bg-color; + background-color: $background; &::before { content: ''; @@ -171,23 +163,23 @@ limitations under the License. width: 16px; mask-repeat: no-repeat; mask-position: center; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; mask-size: 16px; transform: rotate(270deg); mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); } - &.mx_SpaceRoomDirectory_subspace_toggle_shown::before { + &.mx_SpaceHierarchy_subspace_toggle_shown::before { transform: rotate(0deg); } } - .mx_SpaceRoomDirectory_subspace_children { + .mx_SpaceHierarchy_subspace_children { position: relative; padding-left: 12px; } - .mx_SpaceRoomDirectory_roomTile { + .mx_SpaceHierarchy_roomTile { position: relative; padding: 8px 16px; border-radius: 8px; @@ -204,7 +196,7 @@ limitations under the License. grid-column: 1; } - .mx_SpaceRoomDirectory_roomTile_name { + .mx_SpaceHierarchy_roomTile_name { font-weight: $font-semi-bold; font-size: $font-15px; line-height: $font-18px; @@ -214,7 +206,7 @@ limitations under the License. .mx_InfoTooltip { display: inline; margin-left: 12px; - color: $tertiary-fg-color; + color: $tertiary-content; font-size: $font-12px; line-height: $font-15px; @@ -232,10 +224,10 @@ limitations under the License. } } - .mx_SpaceRoomDirectory_roomTile_info { + .mx_SpaceHierarchy_roomTile_info { font-size: $font-14px; line-height: $font-18px; - color: $secondary-fg-color; + color: $secondary-content; grid-row: 2; grid-column: 1/3; display: -webkit-box; @@ -244,7 +236,7 @@ limitations under the License. overflow: hidden; } - .mx_SpaceRoomDirectory_actions { + .mx_SpaceHierarchy_actions { text-align: right; margin-left: 20px; grid-column: 3; @@ -278,12 +270,12 @@ limitations under the License. } } - li.mx_SpaceRoomDirectory_roomTileWrapper { + li.mx_SpaceHierarchy_roomTileWrapper { list-style: none; } - .mx_SpaceRoomDirectory_roomTile, - .mx_SpaceRoomDirectory_subspace_children { + .mx_SpaceHierarchy_roomTile, + .mx_SpaceHierarchy_subspace_children { &::before { content: ""; position: absolute; @@ -295,12 +287,12 @@ limitations under the License. } } - .mx_SpaceRoomDirectory_actions { - .mx_SpaceRoomDirectory_actionsText { + .mx_SpaceHierarchy_actions { + .mx_SpaceHierarchy_actionsText { font-weight: normal; font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; } } @@ -311,7 +303,7 @@ limitations under the License. margin: 20px 0; } - .mx_SpaceRoomDirectory_createRoom { + .mx_SpaceHierarchy_createRoom { display: block; margin: 16px auto 0; width: max-content; diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss index 1dea6332f5..29c8c0c36d 100644 --- a/res/css/structures/_SpacePanel.scss +++ b/res/css/structures/_SpacePanel.scss @@ -20,13 +20,16 @@ $gutterSize: 16px; $activeBorderTransparentGap: 1px; $activeBackgroundColor: $roomtile-selected-bg-color; -$activeBorderColor: $secondary-fg-color; +$activeBorderColor: $secondary-content; .mx_SpacePanel { - flex: 0 0 auto; background-color: $groupFilterPanel-bg-color; + flex: 0 0 auto; padding: 0; margin: 0; + position: relative; + // Fix for the blurred avatar-background + z-index: 1; // Create another flexbox so the Panel fills the container display: flex; @@ -111,6 +114,7 @@ $activeBorderColor: $secondary-fg-color; align-items: center; padding: 4px 4px 4px 0; width: 100%; + cursor: pointer; &.mx_SpaceButton_active { &:not(.mx_SpaceButton_narrow) .mx_SpaceButton_selectionWrapper { @@ -135,7 +139,6 @@ $activeBorderColor: $secondary-fg-color; &:not(.mx_SpaceButton_narrow) { .mx_SpaceButton_selectionWrapper { width: 100%; - padding-right: 16px; overflow: hidden; } } @@ -147,7 +150,6 @@ $activeBorderColor: $secondary-fg-color; display: block; text-overflow: ellipsis; overflow: hidden; - padding-right: 8px; font-size: $font-14px; line-height: $font-18px; } @@ -221,8 +223,7 @@ $activeBorderColor: $secondary-fg-color; margin-top: auto; margin-bottom: auto; display: none; - position: absolute; - right: 4px; + position: relative; &::before { top: 2px; @@ -235,14 +236,12 @@ $activeBorderColor: $secondary-fg-color; mask-size: contain; mask-repeat: no-repeat; mask-image: url('$(res)/img/element-icons/context-menu.svg'); - background: $primary-fg-color; + background: $primary-content; } } } .mx_SpacePanel_badgeContainer { - position: absolute; - // Create a flexbox to make aligning dot badges easier display: flex; align-items: center; @@ -260,6 +259,7 @@ $activeBorderColor: $secondary-fg-color; &.collapsed { .mx_SpaceButton { .mx_SpacePanel_badgeContainer { + position: absolute; right: 0; top: 0; @@ -289,19 +289,12 @@ $activeBorderColor: $secondary-fg-color; } &:not(.collapsed) { - .mx_SpacePanel_badgeContainer { - position: absolute; - right: 4px; - } - .mx_SpaceButton:hover, .mx_SpaceButton:focus-within, .mx_SpaceButton_hasMenuOpen { &:not(.mx_SpaceButton_invite) { // Hide the badge container on hover because it'll be a menu button .mx_SpacePanel_badgeContainer { - width: 0; - height: 0; display: none; } diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss index 945de01eba..39eabe2e07 100644 --- a/res/css/structures/_SpaceRoomView.scss +++ b/res/css/structures/_SpaceRoomView.scss @@ -32,7 +32,7 @@ $SpaceRoomViewInnerWidth: 428px; } > span { - color: $secondary-fg-color; + color: $secondary-content; } &::before { @@ -45,7 +45,7 @@ $SpaceRoomViewInnerWidth: 428px; mask-position: center; mask-repeat: no-repeat; mask-size: 24px; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; } &:hover { @@ -56,12 +56,15 @@ $SpaceRoomViewInnerWidth: 428px; } > span { - color: $primary-fg-color; + color: $primary-content; } } } .mx_SpaceRoomView { + overflow-y: auto; + flex: 1; + .mx_MainSplit > div:first-child { padding: 80px 60px; flex-grow: 1; @@ -72,13 +75,13 @@ $SpaceRoomViewInnerWidth: 428px; margin: 0; font-size: $font-24px; font-weight: $font-semi-bold; - color: $primary-fg-color; + color: $primary-content; width: max-content; } .mx_SpaceRoomView_description { font-size: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; margin-top: 12px; margin-bottom: 24px; max-width: $SpaceRoomViewInnerWidth; @@ -154,7 +157,7 @@ $SpaceRoomViewInnerWidth: 428px; font-weight: $font-semi-bold; font-size: $font-14px; line-height: $font-24px; - color: $primary-fg-color; + color: $primary-content; margin-top: 24px; position: relative; padding-left: 24px; @@ -176,7 +179,7 @@ $SpaceRoomViewInnerWidth: 428px; mask-position: center; mask-size: contain; mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); - background-color: $secondary-fg-color; + background-color: $secondary-content; } } @@ -207,7 +210,7 @@ $SpaceRoomViewInnerWidth: 428px; .mx_SpaceRoomView_preview_inviter_mxid { line-height: $font-24px; - color: $secondary-fg-color; + color: $secondary-content; } } } @@ -224,7 +227,7 @@ $SpaceRoomViewInnerWidth: 428px; .mx_SpaceRoomView_preview_topic { font-size: $font-14px; line-height: $font-22px; - color: $secondary-fg-color; + color: $secondary-content; margin: 20px 0; max-height: 160px; overflow-y: auto; @@ -248,6 +251,7 @@ $SpaceRoomViewInnerWidth: 428px; .mx_SpaceRoomView_landing { display: flex; flex-direction: column; + min-width: 0; > .mx_BaseAvatar_image, > .mx_BaseAvatar > .mx_BaseAvatar_image { @@ -257,7 +261,7 @@ $SpaceRoomViewInnerWidth: 428px; .mx_SpaceRoomView_landing_name { margin: 24px 0 16px; font-size: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; > span { display: inline-block; @@ -330,7 +334,7 @@ $SpaceRoomViewInnerWidth: 428px; top: 0; height: 24px; width: 24px; - background: $tertiary-fg-color; + background: $tertiary-content; mask-position: center; mask-size: contain; mask-repeat: no-repeat; @@ -354,16 +358,11 @@ $SpaceRoomViewInnerWidth: 428px; .mx_SpaceFeedbackPrompt { padding: 7px; // 8px - 1px border - border: 1px solid rgba($primary-fg-color, .1); + border: 1px solid rgba($primary-content, .1); border-radius: 8px; width: max-content; margin: 0 0 -40px auto; // collapse its own height to not push other components down } - - .mx_SpaceRoomDirectory_list { - // we don't want this container to get forced into the flexbox layout - display: contents; - } } .mx_SpaceRoomView_privateScope { @@ -388,7 +387,7 @@ $SpaceRoomViewInnerWidth: 428px; width: 432px; border-radius: 8px; background-color: $info-plinth-bg-color; - color: $secondary-fg-color; + color: $secondary-content; box-sizing: border-box; > h3 { @@ -415,7 +414,7 @@ $SpaceRoomViewInnerWidth: 428px; position: absolute; top: 14px; left: 14px; - background-color: $secondary-fg-color; + background-color: $secondary-content; } } @@ -438,7 +437,7 @@ $SpaceRoomViewInnerWidth: 428px; } .mx_SpaceRoomView_inviteTeammates_buttons { - color: $secondary-fg-color; + color: $secondary-content; margin-top: 28px; .mx_AccessibleButton { @@ -454,7 +453,7 @@ $SpaceRoomViewInnerWidth: 428px; width: 24px; top: 0; left: 0; - background-color: $secondary-fg-color; + background-color: $secondary-content; mask-repeat: no-repeat; mask-position: center; mask-size: contain; @@ -473,7 +472,7 @@ $SpaceRoomViewInnerWidth: 428px; } .mx_SpaceRoomView_info { - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-15px; line-height: $font-24px; margin: 20px 0; @@ -492,7 +491,7 @@ $SpaceRoomViewInnerWidth: 428px; left: -2px; mask-position: center; mask-repeat: no-repeat; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; } } diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index 833450a25b..e185197f25 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -80,7 +80,7 @@ limitations under the License. .mx_TabbedView_tabLabel_text { font-size: 15px; - color: $tertiary-fg-color; + color: $tertiary-content; } } diff --git a/res/css/structures/_ToastContainer.scss b/res/css/structures/_ToastContainer.scss index 5cd938f1ce..6024df5dc0 100644 --- a/res/css/structures/_ToastContainer.scss +++ b/res/css/structures/_ToastContainer.scss @@ -36,8 +36,8 @@ limitations under the License. .mx_Toast_toast { grid-row: 1 / 3; grid-column: 1; - color: $primary-fg-color; background-color: $system; + color: $primary-content; box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.5); border-radius: 8px; overflow: hidden; @@ -63,7 +63,7 @@ limitations under the License. &.mx_Toast_icon_verification::after { mask-image: url("$(res)/img/e2e/normal.svg"); - background-color: $primary-fg-color; + background-color: $primary-content; } &.mx_Toast_icon_verification_warning { @@ -82,7 +82,7 @@ limitations under the License. &.mx_Toast_icon_secure_backup::after { mask-image: url('$(res)/img/feather-customised/secure-backup.svg'); - background-color: $primary-fg-color; + background-color: $primary-content; } .mx_Toast_title, .mx_Toast_body { @@ -163,7 +163,7 @@ limitations under the License. } .mx_Toast_detail { - color: $secondary-fg-color; + color: $secondary-content; } .mx_Toast_deviceID { diff --git a/res/css/structures/_UserMenu.scss b/res/css/structures/_UserMenu.scss index 17e6ad75df..c10e7f60df 100644 --- a/res/css/structures/_UserMenu.scss +++ b/res/css/structures/_UserMenu.scss @@ -35,7 +35,7 @@ limitations under the License. // we cheat opacity on the theme colour with an after selector here &::after { content: ''; - border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse + border-bottom: 1px solid $primary-content; opacity: 0.2; display: block; padding-top: 8px; @@ -58,7 +58,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $tertiary-fg-color; + background: $tertiary-content; mask-image: url('$(res)/img/feather-customised/chevron-down.svg'); } } @@ -176,7 +176,7 @@ limitations under the License. width: 85%; opacity: 0.2; border: none; - border-bottom: 1px solid $primary-fg-color; // XXX: Variable abuse + border-bottom: 1px solid $primary-content; } &.mx_IconizedContextMenu { @@ -292,7 +292,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $primary-fg-color; + background: $primary-content; } } diff --git a/res/css/structures/_ViewSource.scss b/res/css/structures/_ViewSource.scss index 248eab5d88..e3d6135ef3 100644 --- a/res/css/structures/_ViewSource.scss +++ b/res/css/structures/_ViewSource.scss @@ -24,7 +24,7 @@ limitations under the License. .mx_ViewSource_heading { font-size: $font-17px; font-weight: 400; - color: $primary-fg-color; + color: $primary-content; margin-top: 0.7em; } diff --git a/res/css/structures/auth/_Login.scss b/res/css/structures/auth/_Login.scss index 9c98ca3a1c..c4aaaca1d0 100644 --- a/res/css/structures/auth/_Login.scss +++ b/res/css/structures/auth/_Login.scss @@ -96,3 +96,10 @@ div.mx_AccessibleButton_kind_link.mx_Login_forgot { cursor: not-allowed; } } +.mx_Login_spinner { + display: flex; + justify-content: center; + align-items: center; + align-content: center; + padding: 14px; +} diff --git a/res/css/views/audio_messages/_AudioPlayer.scss b/res/css/views/audio_messages/_AudioPlayer.scss index 77dcebbb9a..3c2551e36a 100644 --- a/res/css/views/audio_messages/_AudioPlayer.scss +++ b/res/css/views/audio_messages/_AudioPlayer.scss @@ -33,7 +33,7 @@ limitations under the License. } .mx_AudioPlayer_mediaName { - color: $primary-fg-color; + color: $primary-content; font-size: $font-15px; line-height: $font-15px; text-overflow: ellipsis; diff --git a/res/css/views/audio_messages/_SeekBar.scss b/res/css/views/audio_messages/_SeekBar.scss index d13fe4ac6a..03449d009b 100644 --- a/res/css/views/audio_messages/_SeekBar.scss +++ b/res/css/views/audio_messages/_SeekBar.scss @@ -27,7 +27,7 @@ limitations under the License. width: 100%; height: 1px; - background: $quaternary-fg-color; + background: $quaternary-content; outline: none; // remove blue selection border position: relative; // for before+after pseudo elements later on @@ -42,7 +42,7 @@ limitations under the License. width: 8px; height: 8px; border-radius: 8px; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; cursor: pointer; } @@ -50,7 +50,7 @@ limitations under the License. width: 8px; height: 8px; border-radius: 8px; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; cursor: pointer; // Firefox adds a border on the thumb @@ -63,7 +63,7 @@ limitations under the License. // in firefox, so it's just wasted CPU/GPU time. &::before { // ::before to ensure it ends up under the thumb content: ''; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; // Absolute positioning to ensure it overlaps with the existing bar position: absolute; @@ -81,7 +81,7 @@ limitations under the License. // This is firefox's built-in support for the above, with 100% less hacks. &::-moz-range-progress { - background-color: $tertiary-fg-color; + background-color: $tertiary-content; height: 1px; } diff --git a/res/css/views/auth/_AuthButtons.scss b/res/css/views/auth/_AuthButtons.scss index 8deb0f80ac..3a2ad2adf8 100644 --- a/res/css/views/auth/_AuthButtons.scss +++ b/res/css/views/auth/_AuthButtons.scss @@ -39,7 +39,7 @@ limitations under the License. min-width: 80px; background-color: $accent-color; - color: $primary-bg-color; + color: $background; cursor: pointer; diff --git a/res/css/views/avatars/_DecoratedRoomAvatar.scss b/res/css/views/avatars/_DecoratedRoomAvatar.scss index 257b512579..4922068462 100644 --- a/res/css/views/avatars/_DecoratedRoomAvatar.scss +++ b/res/css/views/avatars/_DecoratedRoomAvatar.scss @@ -47,7 +47,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $secondary-fg-color; + background: $secondary-content; mask-image: url('$(res)/img/globe.svg'); } diff --git a/res/css/views/beta/_BetaCard.scss b/res/css/views/beta/_BetaCard.scss index 2af4e79ecd..ff6910852c 100644 --- a/res/css/views/beta/_BetaCard.scss +++ b/res/css/views/beta/_BetaCard.scss @@ -29,7 +29,7 @@ limitations under the License. font-weight: $font-semi-bold; font-size: $font-18px; line-height: $font-22px; - color: $primary-fg-color; + color: $primary-content; margin: 4px 0 14px; .mx_BetaCard_betaPill { @@ -40,7 +40,7 @@ limitations under the License. .mx_BetaCard_caption { font-size: $font-15px; line-height: $font-20px; - color: $secondary-fg-color; + color: $secondary-content; margin-bottom: 20px; } @@ -54,7 +54,7 @@ limitations under the License. .mx_BetaCard_disclaimer { font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; margin-top: 20px; } } @@ -72,13 +72,13 @@ limitations under the License. margin: 16px 0 0; font-size: $font-15px; line-height: $font-24px; - color: $primary-fg-color; + color: $primary-content; .mx_SettingsFlag_microcopy { margin-top: 4px; font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; } } } diff --git a/res/css/views/context_menus/_IconizedContextMenu.scss b/res/css/views/context_menus/_IconizedContextMenu.scss index ff176eef7e..ca40f18cd4 100644 --- a/res/css/views/context_menus/_IconizedContextMenu.scss +++ b/res/css/views/context_menus/_IconizedContextMenu.scss @@ -36,7 +36,7 @@ limitations under the License. // // Therefore, we just hack in a line and border the thing ourselves &::before { - border-top: 1px solid $primary-fg-color; + border-top: 1px solid $primary-content; opacity: 0.1; content: ''; @@ -63,7 +63,7 @@ limitations under the License. padding-top: 12px; padding-bottom: 12px; text-decoration: none; - color: $primary-fg-color; + color: $primary-content; font-size: $font-15px; line-height: $font-24px; @@ -119,7 +119,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $primary-fg-color; + background: $primary-content; } } diff --git a/res/css/views/context_menus/_MessageContextMenu.scss b/res/css/views/context_menus/_MessageContextMenu.scss index 338841cce4..5af748e28d 100644 --- a/res/css/views/context_menus/_MessageContextMenu.scss +++ b/res/css/views/context_menus/_MessageContextMenu.scss @@ -30,7 +30,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $primary-fg-color; + background: $primary-content; } } diff --git a/res/css/views/context_menus/_StatusMessageContextMenu.scss b/res/css/views/context_menus/_StatusMessageContextMenu.scss index fceb7fba34..1a97fb56c7 100644 --- a/res/css/views/context_menus/_StatusMessageContextMenu.scss +++ b/res/css/views/context_menus/_StatusMessageContextMenu.scss @@ -27,7 +27,7 @@ input.mx_StatusMessageContextMenu_message { border-radius: 4px; border: 1px solid $input-border-color; padding: 6.5px 11px; - background-color: $primary-bg-color; + background-color: $background; font-weight: normal; margin: 0 0 10px; } diff --git a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss index 42e17c8d98..444b29c9bf 100644 --- a/res/css/views/dialogs/_AddExistingToSpaceDialog.scss +++ b/res/css/views/dialogs/_AddExistingToSpaceDialog.scss @@ -44,7 +44,7 @@ limitations under the License. > h3 { margin: 0; - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-12px; font-weight: $font-semi-bold; line-height: $font-15px; @@ -66,7 +66,7 @@ limitations under the License. flex-grow: 1; font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; .mx_ProgressBar { height: 8px; @@ -79,7 +79,7 @@ limitations under the License. margin-top: 8px; font-size: $font-15px; line-height: $font-24px; - color: $primary-fg-color; + color: $primary-content; } > * { @@ -105,7 +105,7 @@ limitations under the License. margin-top: 4px; font-size: $font-12px; line-height: $font-15px; - color: $primary-fg-color; + color: $primary-content; } } @@ -126,7 +126,7 @@ limitations under the License. &::before { content: ''; position: absolute; - background-color: $primary-fg-color; + background-color: $primary-content; mask-repeat: no-repeat; mask-position: center; mask-size: contain; @@ -145,7 +145,7 @@ limitations under the License. .mx_AddExistingToSpaceDialog { width: 480px; - color: $primary-fg-color; + color: $primary-content; display: flex; flex-direction: column; flex-wrap: nowrap; @@ -188,7 +188,7 @@ limitations under the License. padding-left: 0; flex: unset; height: unset; - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-15px; line-height: $font-24px; @@ -221,7 +221,7 @@ limitations under the License. } .mx_SubspaceSelector_onlySpace { - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-15px; line-height: $font-24px; } diff --git a/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss b/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss index beae03f00f..5d6c817b14 100644 --- a/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss +++ b/res/css/views/dialogs/_CommunityPrototypeInviteDialog.scss @@ -65,7 +65,7 @@ limitations under the License. .mx_CommunityPrototypeInviteDialog_personName { font-weight: 600; font-size: $font-14px; - color: $primary-fg-color; + color: $primary-content; margin-left: 7px; } diff --git a/res/css/views/dialogs/_ConfirmUserActionDialog.scss b/res/css/views/dialogs/_ConfirmUserActionDialog.scss index 284c171f4e..5ac0f07b14 100644 --- a/res/css/views/dialogs/_ConfirmUserActionDialog.scss +++ b/res/css/views/dialogs/_ConfirmUserActionDialog.scss @@ -35,8 +35,8 @@ limitations under the License. .mx_ConfirmUserActionDialog_reasonField { font-size: $font-14px; - color: $primary-fg-color; - background-color: $primary-bg-color; + color: $primary-content; + background-color: $background; border-radius: 3px; border: solid 1px $input-border-color; diff --git a/res/css/views/dialogs/_CreateGroupDialog.scss b/res/css/views/dialogs/_CreateGroupDialog.scss index f7bfc61a98..ef9c2b73d4 100644 --- a/res/css/views/dialogs/_CreateGroupDialog.scss +++ b/res/css/views/dialogs/_CreateGroupDialog.scss @@ -29,8 +29,8 @@ limitations under the License. border-radius: 3px; border: 1px solid $input-border-color; padding: 9px; - color: $primary-fg-color; - background-color: $primary-bg-color; + color: $primary-content; + background-color: $background; } .mx_CreateGroupDialog_input_hasPrefixAndSuffix { diff --git a/res/css/views/dialogs/_CreateRoomDialog.scss b/res/css/views/dialogs/_CreateRoomDialog.scss index e7cfbf6050..9cfa8ce25a 100644 --- a/res/css/views/dialogs/_CreateRoomDialog.scss +++ b/res/css/views/dialogs/_CreateRoomDialog.scss @@ -55,8 +55,8 @@ limitations under the License. border-radius: 3px; border: 1px solid $input-border-color; padding: 9px; - color: $primary-fg-color; - background-color: $primary-bg-color; + color: $primary-content; + background-color: $background; width: 100%; } diff --git a/res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss b/res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss index afa722e05e..6ff328f6ab 100644 --- a/res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss +++ b/res/css/views/dialogs/_CreateSpaceFromCommunityDialog.scss @@ -23,7 +23,7 @@ limitations under the License. .mx_CreateSpaceFromCommunityDialog { width: 480px; - color: $primary-fg-color; + color: $primary-content; display: flex; flex-direction: column; flex-wrap: nowrap; @@ -73,7 +73,7 @@ limitations under the License. flex-grow: 1; font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; .mx_ProgressBar { height: 8px; @@ -86,7 +86,7 @@ limitations under the License. margin-top: 8px; font-size: $font-15px; line-height: $font-24px; - color: $primary-fg-color; + color: $primary-content; } > * { @@ -112,7 +112,7 @@ limitations under the License. margin-top: 4px; font-size: $font-12px; line-height: $font-15px; - color: $primary-fg-color; + color: $primary-content; } } @@ -138,7 +138,7 @@ limitations under the License. &::before { content: ''; position: absolute; - background-color: $primary-fg-color; + background-color: $primary-content; mask-repeat: no-repeat; mask-position: center; mask-size: contain; diff --git a/res/css/views/dialogs/_CreateSubspaceDialog.scss b/res/css/views/dialogs/_CreateSubspaceDialog.scss index 1ec4731ae6..1ed10df35c 100644 --- a/res/css/views/dialogs/_CreateSubspaceDialog.scss +++ b/res/css/views/dialogs/_CreateSubspaceDialog.scss @@ -23,7 +23,7 @@ limitations under the License. .mx_CreateSubspaceDialog { width: 480px; - color: $primary-fg-color; + color: $primary-content; display: flex; flex-direction: column; flex-wrap: nowrap; @@ -57,7 +57,7 @@ limitations under the License. flex-grow: 1; font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; > * { vertical-align: middle; diff --git a/res/css/views/dialogs/_FeedbackDialog.scss b/res/css/views/dialogs/_FeedbackDialog.scss index fd225dd882..74733f7220 100644 --- a/res/css/views/dialogs/_FeedbackDialog.scss +++ b/res/css/views/dialogs/_FeedbackDialog.scss @@ -33,7 +33,7 @@ limitations under the License. padding-left: 52px; > p { - color: $tertiary-fg-color; + color: $tertiary-content; } .mx_AccessibleButton_kind_link { diff --git a/res/css/views/dialogs/_ForwardDialog.scss b/res/css/views/dialogs/_ForwardDialog.scss index e018f60172..da8ce3de5b 100644 --- a/res/css/views/dialogs/_ForwardDialog.scss +++ b/res/css/views/dialogs/_ForwardDialog.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_ForwardDialog { width: 520px; - color: $primary-fg-color; + color: $primary-content; display: flex; flex-direction: column; flex-wrap: nowrap; @@ -25,7 +25,7 @@ limitations under the License. > h3 { margin: 0 0 6px; - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-12px; font-weight: $font-semi-bold; line-height: $font-15px; diff --git a/res/css/views/dialogs/_GenericFeatureFeedbackDialog.scss b/res/css/views/dialogs/_GenericFeatureFeedbackDialog.scss index f83eed9c53..ab7496249d 100644 --- a/res/css/views/dialogs/_GenericFeatureFeedbackDialog.scss +++ b/res/css/views/dialogs/_GenericFeatureFeedbackDialog.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_GenericFeatureFeedbackDialog { .mx_GenericFeatureFeedbackDialog_subheading { - color: $primary-fg-color; + color: $primary-content; font-size: $font-14px; line-height: $font-20px; margin-bottom: 24px; diff --git a/res/css/views/dialogs/_HostSignupDialog.scss b/res/css/views/dialogs/_HostSignupDialog.scss index ac4bc41951..d8a6652a39 100644 --- a/res/css/views/dialogs/_HostSignupDialog.scss +++ b/res/css/views/dialogs/_HostSignupDialog.scss @@ -70,11 +70,11 @@ limitations under the License. } .mx_HostSignupDialog_text_dark { - color: $primary-fg-color; + color: $primary-content; } .mx_HostSignupDialog_text_light { - color: $secondary-fg-color; + color: $secondary-content; } .mx_HostSignup_maximize_button { diff --git a/res/css/views/dialogs/_InviteDialog.scss b/res/css/views/dialogs/_InviteDialog.scss index 9fc4b7a15c..3a2918f9ec 100644 --- a/res/css/views/dialogs/_InviteDialog.scss +++ b/res/css/views/dialogs/_InviteDialog.scss @@ -56,7 +56,7 @@ limitations under the License. box-sizing: border-box; min-width: 40%; flex: 1 !important; - color: $primary-fg-color !important; + color: $primary-content !important; } } @@ -94,7 +94,7 @@ limitations under the License. } > span { - color: $primary-fg-color; + color: $primary-content; } .mx_InviteDialog_subname { @@ -110,7 +110,7 @@ limitations under the License. font-size: $font-14px; > span { - color: $primary-fg-color; + color: $primary-content; font-weight: 600; } @@ -220,7 +220,7 @@ limitations under the License. .mx_InviteDialog_roomTile_name { font-weight: 600; font-size: $font-14px; - color: $primary-fg-color; + color: $primary-content; margin-left: 7px; } @@ -352,7 +352,7 @@ limitations under the License. border-right: 0; border-radius: 0; margin-top: 0; - border-color: $quaternary-fg-color; + border-color: $quaternary-content; input { font-size: 18px; @@ -418,7 +418,7 @@ limitations under the License. > h4 { font-size: $font-15px; line-height: $font-24px; - color: $secondary-fg-color; + color: $secondary-content; font-weight: normal; } @@ -432,14 +432,14 @@ limitations under the License. font-size: $font-15px; line-height: $font-24px; font-weight: $font-semi-bold; - color: $primary-fg-color; + color: $primary-content; } .mx_InviteDialog_multiInviterError_entry_userId { margin-left: 6px; font-size: $font-12px; line-height: $font-15px; - color: $tertiary-fg-color; + color: $tertiary-content; } } diff --git a/res/css/views/dialogs/_JoinRuleDropdown.scss b/res/css/views/dialogs/_JoinRuleDropdown.scss index c48a79af3c..91691cf53b 100644 --- a/res/css/views/dialogs/_JoinRuleDropdown.scss +++ b/res/css/views/dialogs/_JoinRuleDropdown.scss @@ -19,7 +19,7 @@ limitations under the License. font-weight: normal; font-family: $font-family; font-size: $font-14px; - color: $primary-fg-color; + color: $primary-content; .mx_Dropdown_input { border: 1px solid $input-border-color; @@ -44,7 +44,7 @@ limitations under the License. top: 8px; mask-repeat: no-repeat; mask-position: center; - background-color: $secondary-fg-color; + background-color: $secondary-content; } } } diff --git a/res/css/views/dialogs/_LeaveSpaceDialog.scss b/res/css/views/dialogs/_LeaveSpaceDialog.scss index c982f50e52..0d85a87faf 100644 --- a/res/css/views/dialogs/_LeaveSpaceDialog.scss +++ b/res/css/views/dialogs/_LeaveSpaceDialog.scss @@ -63,7 +63,7 @@ limitations under the License. font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; &::before { content: ''; @@ -72,7 +72,7 @@ limitations under the License. top: calc(50% - 8px); // vertical centering height: 16px; width: 16px; - background-color: $secondary-fg-color; + background-color: $secondary-content; mask-repeat: no-repeat; mask-size: contain; mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); @@ -81,7 +81,7 @@ limitations under the License. } > p { - color: $primary-fg-color; + color: $primary-content; } } diff --git a/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.scss b/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.scss index 91df76675a..9a05e7f20a 100644 --- a/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.scss +++ b/res/css/views/dialogs/_ManageRestrictedJoinRuleDialog.scss @@ -23,7 +23,7 @@ limitations under the License. .mx_ManageRestrictedJoinRuleDialog { width: 480px; - color: $primary-fg-color; + color: $primary-content; display: flex; flex-direction: column; flex-wrap: nowrap; @@ -52,7 +52,7 @@ limitations under the License. > h3 { margin: 0; - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-12px; font-weight: $font-semi-bold; line-height: $font-15px; @@ -85,7 +85,7 @@ limitations under the License. margin-top: 8px; font-size: $font-12px; line-height: $font-15px; - color: $tertiary-fg-color; + color: $tertiary-content; } .mx_Checkbox { @@ -113,7 +113,7 @@ limitations under the License. font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; &::before { content: ''; @@ -122,7 +122,7 @@ limitations under the License. top: calc(50% - 8px); // vertical centering height: 16px; width: 16px; - background-color: $secondary-fg-color; + background-color: $secondary-content; mask-repeat: no-repeat; mask-size: contain; mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); diff --git a/res/css/views/dialogs/_MessageEditHistoryDialog.scss b/res/css/views/dialogs/_MessageEditHistoryDialog.scss index e9d777effd..4574344a28 100644 --- a/res/css/views/dialogs/_MessageEditHistoryDialog.scss +++ b/res/css/views/dialogs/_MessageEditHistoryDialog.scss @@ -37,7 +37,7 @@ limitations under the License. list-style-type: none; font-size: $font-14px; padding: 0; - color: $primary-fg-color; + color: $primary-content; span.mx_EditHistoryMessage_deletion, span.mx_EditHistoryMessage_insertion { padding: 0px 2px; diff --git a/res/css/views/dialogs/_RegistrationEmailPromptDialog.scss b/res/css/views/dialogs/_RegistrationEmailPromptDialog.scss index 31fc6d7a04..02c89e2e42 100644 --- a/res/css/views/dialogs/_RegistrationEmailPromptDialog.scss +++ b/res/css/views/dialogs/_RegistrationEmailPromptDialog.scss @@ -19,7 +19,7 @@ limitations under the License. .mx_Dialog_content { margin-bottom: 24px; - color: $tertiary-fg-color; + color: $tertiary-content; } .mx_Dialog_primary { diff --git a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss index c97a3b69b7..f18b4917cf 100644 --- a/res/css/views/dialogs/_RoomSettingsDialogBridges.scss +++ b/res/css/views/dialogs/_RoomSettingsDialogBridges.scss @@ -72,7 +72,7 @@ limitations under the License. margin-top: 0px; margin-bottom: 0px; font-size: 16pt; - color: $primary-fg-color; + color: $primary-content; } > * { @@ -81,7 +81,7 @@ limitations under the License. } .workspace-channel-details { - color: $primary-fg-color; + color: $primary-content; font-weight: 600; .channel { diff --git a/res/css/views/dialogs/_ServerOfflineDialog.scss b/res/css/views/dialogs/_ServerOfflineDialog.scss index ae4b70beb3..7a1b0bbcab 100644 --- a/res/css/views/dialogs/_ServerOfflineDialog.scss +++ b/res/css/views/dialogs/_ServerOfflineDialog.scss @@ -17,10 +17,10 @@ limitations under the License. .mx_ServerOfflineDialog { .mx_ServerOfflineDialog_content { padding-right: 85px; - color: $primary-fg-color; + color: $primary-content; hr { - border-color: $primary-fg-color; + border-color: $primary-content; opacity: 0.1; border-bottom: none; } diff --git a/res/css/views/dialogs/_ServerPickerDialog.scss b/res/css/views/dialogs/_ServerPickerDialog.scss index b01b49d7af..9a05751f91 100644 --- a/res/css/views/dialogs/_ServerPickerDialog.scss +++ b/res/css/views/dialogs/_ServerPickerDialog.scss @@ -22,7 +22,7 @@ limitations under the License. margin-bottom: 0; > p { - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-14px; margin: 16px 0; @@ -38,7 +38,7 @@ limitations under the License. > h4 { font-size: $font-15px; font-weight: $font-semi-bold; - color: $secondary-fg-color; + color: $secondary-content; margin-left: 8px; } diff --git a/res/css/views/dialogs/_SetEmailDialog.scss b/res/css/views/dialogs/_SetEmailDialog.scss index 37bee7a9ff..a39d51dfce 100644 --- a/res/css/views/dialogs/_SetEmailDialog.scss +++ b/res/css/views/dialogs/_SetEmailDialog.scss @@ -19,7 +19,7 @@ limitations under the License. border: 1px solid $input-border-color; padding: 9px; color: $input-fg-color; - background-color: $primary-bg-color; + background-color: $background; font-size: $font-15px; width: 100%; max-width: 280px; diff --git a/res/css/views/dialogs/_SpaceSettingsDialog.scss b/res/css/views/dialogs/_SpaceSettingsDialog.scss index fa074fdbe8..a1fa9d52a8 100644 --- a/res/css/views/dialogs/_SpaceSettingsDialog.scss +++ b/res/css/views/dialogs/_SpaceSettingsDialog.scss @@ -15,7 +15,7 @@ limitations under the License. */ .mx_SpaceSettingsDialog { - color: $primary-fg-color; + color: $primary-content; .mx_SpaceSettings_errorText { font-weight: $font-semi-bold; @@ -50,13 +50,13 @@ limitations under the License. .mx_RadioButton_content { font-weight: $font-semi-bold; line-height: $font-18px; - color: $primary-fg-color; + color: $primary-content; } & + span { font-size: $font-15px; line-height: $font-18px; - color: $secondary-fg-color; + color: $secondary-content; margin-left: 26px; } } diff --git a/res/css/views/dialogs/security/_AccessSecretStorageDialog.scss b/res/css/views/dialogs/security/_AccessSecretStorageDialog.scss index ec3bea0ef7..98edbf8ad8 100644 --- a/res/css/views/dialogs/security/_AccessSecretStorageDialog.scss +++ b/res/css/views/dialogs/security/_AccessSecretStorageDialog.scss @@ -44,7 +44,7 @@ limitations under the License. margin-right: 8px; position: relative; top: 5px; - background-color: $primary-fg-color; + background-color: $primary-content; } .mx_AccessSecretStorageDialog_resetBadge::before { diff --git a/res/css/views/dialogs/security/_CreateSecretStorageDialog.scss b/res/css/views/dialogs/security/_CreateSecretStorageDialog.scss index d30803b1f0..b14206ff6d 100644 --- a/res/css/views/dialogs/security/_CreateSecretStorageDialog.scss +++ b/res/css/views/dialogs/security/_CreateSecretStorageDialog.scss @@ -56,7 +56,7 @@ limitations under the License. margin-right: 8px; position: relative; top: 5px; - background-color: $primary-fg-color; + background-color: $primary-content; } .mx_CreateSecretStorageDialog_secureBackupTitle::before { @@ -101,7 +101,7 @@ limitations under the License. margin-right: 8px; position: relative; top: 5px; - background-color: $primary-fg-color; + background-color: $primary-content; } .mx_CreateSecretStorageDialog_optionIcon_securePhrase { diff --git a/res/css/views/dialogs/security/_KeyBackupFailedDialog.scss b/res/css/views/dialogs/security/_KeyBackupFailedDialog.scss index 05ce158413..4a48012672 100644 --- a/res/css/views/dialogs/security/_KeyBackupFailedDialog.scss +++ b/res/css/views/dialogs/security/_KeyBackupFailedDialog.scss @@ -26,7 +26,7 @@ limitations under the License. &::before { mask: url("$(res)/img/e2e/lock-warning-filled.svg"); mask-repeat: no-repeat; - background-color: $primary-fg-color; + background-color: $primary-content; content: ""; position: absolute; top: -6px; diff --git a/res/css/views/directory/_NetworkDropdown.scss b/res/css/views/directory/_NetworkDropdown.scss index ae0927386a..93cecd8676 100644 --- a/res/css/views/directory/_NetworkDropdown.scss +++ b/res/css/views/directory/_NetworkDropdown.scss @@ -34,7 +34,7 @@ limitations under the License. box-sizing: border-box; border-radius: 4px; border: 1px solid $dialog-close-fg-color; - background-color: $primary-bg-color; + background-color: $background; max-height: calc(100vh - 20px); // allow 10px padding on both top and bottom overflow-y: auto; } @@ -153,7 +153,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-image: url('$(res)/img/feather-customised/chevron-down-thin.svg'); - background-color: $primary-fg-color; + background-color: $primary-content; } .mx_NetworkDropdown_handle_server { diff --git a/res/css/views/elements/_AddressSelector.scss b/res/css/views/elements/_AddressSelector.scss index 087504390c..a7d463353b 100644 --- a/res/css/views/elements/_AddressSelector.scss +++ b/res/css/views/elements/_AddressSelector.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_AddressSelector { position: absolute; - background-color: $primary-bg-color; + background-color: $background; width: 485px; max-height: 116px; overflow-y: auto; @@ -31,8 +31,8 @@ limitations under the License. } .mx_AddressSelector_addressListElement .mx_AddressTile { - background-color: $primary-bg-color; - border: solid 1px $primary-bg-color; + background-color: $background; + border: solid 1px $background; } .mx_AddressSelector_addressListElement.mx_AddressSelector_selected { diff --git a/res/css/views/elements/_AddressTile.scss b/res/css/views/elements/_AddressTile.scss index c42f52f8f4..90c40842f7 100644 --- a/res/css/views/elements/_AddressTile.scss +++ b/res/css/views/elements/_AddressTile.scss @@ -20,7 +20,7 @@ limitations under the License. background-color: rgba(74, 73, 74, 0.1); border: solid 1px $input-border-color; line-height: $font-26px; - color: $primary-fg-color; + color: $primary-content; font-size: $font-14px; font-weight: normal; margin-right: 4px; diff --git a/res/css/views/elements/_Dropdown.scss b/res/css/views/elements/_Dropdown.scss index 3b67e0191e..1acac70e42 100644 --- a/res/css/views/elements/_Dropdown.scss +++ b/res/css/views/elements/_Dropdown.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_Dropdown { position: relative; - color: $primary-fg-color; + color: $primary-content; } .mx_Dropdown_disabled { @@ -52,7 +52,7 @@ limitations under the License. padding-right: 9px; mask: url('$(res)/img/feather-customised/dropdown-arrow.svg'); mask-repeat: no-repeat; - background: $primary-fg-color; + background: $primary-content; } .mx_Dropdown_option { @@ -111,7 +111,7 @@ input.mx_Dropdown_option:focus { padding: 0px; border-radius: 4px; border: 1px solid $input-focused-border-color; - background-color: $primary-bg-color; + background-color: $background; max-height: 200px; overflow-y: auto; } diff --git a/res/css/views/elements/_EventTilePreview.scss b/res/css/views/elements/_EventTilePreview.scss new file mode 100644 index 0000000000..6bb726168f --- /dev/null +++ b/res/css/views/elements/_EventTilePreview.scss @@ -0,0 +1,22 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_EventTilePreview_loader { + &.mx_IRCLayout, + &.mx_GroupLayout { + padding: 9px 0; + } +} diff --git a/res/css/views/elements/_FacePile.scss b/res/css/views/elements/_FacePile.scss index c691baffb5..875e0e34d5 100644 --- a/res/css/views/elements/_FacePile.scss +++ b/res/css/views/elements/_FacePile.scss @@ -25,7 +25,7 @@ limitations under the License. } .mx_BaseAvatar_image { - border: 1px solid $primary-bg-color; + border: 1px solid $background; } .mx_BaseAvatar_initial { @@ -47,7 +47,7 @@ limitations under the License. left: 0; height: inherit; width: inherit; - background: $tertiary-fg-color; + background: $tertiary-content; mask-position: center; mask-size: 20px; mask-repeat: no-repeat; @@ -60,6 +60,6 @@ limitations under the License. margin-left: 12px; font-size: $font-14px; line-height: $font-24px; - color: $tertiary-fg-color; + color: $tertiary-content; } } diff --git a/res/css/views/elements/_Field.scss b/res/css/views/elements/_Field.scss index 50cd14c4da..71d37a015d 100644 --- a/res/css/views/elements/_Field.scss +++ b/res/css/views/elements/_Field.scss @@ -46,8 +46,8 @@ limitations under the License. // corners on the field above. border-radius: 4px; padding: 8px 9px; - color: $primary-fg-color; - background-color: $primary-bg-color; + color: $primary-content; + background-color: $background; flex: 1; min-width: 0; } @@ -67,7 +67,7 @@ limitations under the License. height: 6px; mask: url('$(res)/img/feather-customised/dropdown-arrow.svg'); mask-repeat: no-repeat; - background-color: $primary-fg-color; + background-color: $primary-content; z-index: 1; pointer-events: none; } @@ -98,14 +98,14 @@ limitations under the License. transition: font-size 0.25s ease-out 0.1s, color 0.25s ease-out 0.1s, - top 0.25s ease-out 0.1s, + transform 0.25s ease-out 0.1s, background-color 0.25s ease-out 0.1s; - color: $primary-fg-color; + color: $primary-content; background-color: transparent; font-size: $font-14px; + transform: translateY(0); position: absolute; left: 0px; - top: 0px; margin: 7px 8px; padding: 2px; pointer-events: none; // Allow clicks to fall through to the input @@ -124,10 +124,10 @@ limitations under the License. transition: font-size 0.25s ease-out 0s, color 0.25s ease-out 0s, - top 0.25s ease-out 0s, + transform 0.25s ease-out 0s, background-color 0.25s ease-out 0s; font-size: $font-10px; - top: -13px; + transform: translateY(-13px); padding: 0 2px; background-color: $field-focused-label-bg-color; pointer-events: initial; diff --git a/res/css/views/elements/_InviteReason.scss b/res/css/views/elements/_InviteReason.scss index 2c2e5687e6..8024ed59a3 100644 --- a/res/css/views/elements/_InviteReason.scss +++ b/res/css/views/elements/_InviteReason.scss @@ -32,12 +32,12 @@ limitations under the License. justify-content: center; align-items: center; cursor: pointer; - color: $secondary-fg-color; + color: $secondary-content; &::before { content: ""; margin-right: 8px; - background-color: $secondary-fg-color; + background-color: $secondary-content; mask-image: url('$(res)/img/feather-customised/eye.svg'); display: inline-block; width: 18px; diff --git a/res/css/views/elements/_MiniAvatarUploader.scss b/res/css/views/elements/_MiniAvatarUploader.scss index df4676ab56..46ffd9a01c 100644 --- a/res/css/views/elements/_MiniAvatarUploader.scss +++ b/res/css/views/elements/_MiniAvatarUploader.scss @@ -37,7 +37,7 @@ limitations under the License. right: -6px; bottom: -6px; - background-color: $primary-bg-color; + background-color: $background; border-radius: 50%; z-index: 1; @@ -45,7 +45,7 @@ limitations under the License. height: 100%; width: 100%; - background-color: $secondary-fg-color; + background-color: $secondary-content; mask-position: center; mask-repeat: no-repeat; mask-image: url('$(res)/img/element-icons/camera.svg'); diff --git a/res/css/views/elements/_RichText.scss b/res/css/views/elements/_RichText.scss index d60282695c..b9d845ea7a 100644 --- a/res/css/views/elements/_RichText.scss +++ b/res/css/views/elements/_RichText.scss @@ -43,7 +43,7 @@ a.mx_Pill { /* More specific to override `.markdown-body a` color */ .mx_EventTile_content .markdown-body a.mx_UserPill, .mx_UserPill { - color: $primary-fg-color; + color: $primary-content; background-color: $other-user-pill-bg-color; } diff --git a/res/css/views/elements/_SSOButtons.scss b/res/css/views/elements/_SSOButtons.scss index e02816780f..a98e7b4024 100644 --- a/res/css/views/elements/_SSOButtons.scss +++ b/res/css/views/elements/_SSOButtons.scss @@ -35,7 +35,7 @@ limitations under the License. font-size: $font-14px; font-weight: $font-semi-bold; border: 1px solid $input-border-color; - color: $primary-fg-color; + color: $primary-content; > img { object-fit: contain; diff --git a/res/css/views/elements/_ServerPicker.scss b/res/css/views/elements/_ServerPicker.scss index 188eb5d655..d828d7cb88 100644 --- a/res/css/views/elements/_ServerPicker.scss +++ b/res/css/views/elements/_ServerPicker.scss @@ -74,7 +74,7 @@ limitations under the License. .mx_ServerPicker_desc { margin-top: -12px; - color: $tertiary-fg-color; + color: $tertiary-content; grid-column: 1 / 2; grid-row: 3; margin-bottom: 16px; diff --git a/res/css/views/elements/_Spinner.scss b/res/css/views/elements/_Spinner.scss index 93d5e2d96c..2df46687af 100644 --- a/res/css/views/elements/_Spinner.scss +++ b/res/css/views/elements/_Spinner.scss @@ -37,7 +37,7 @@ limitations under the License. } .mx_Spinner_icon { - background-color: $primary-fg-color; + background-color: $primary-content; mask: url('$(res)/img/spinner.svg'); mask-size: contain; animation: 1.1s steps(12, end) infinite spin; diff --git a/res/css/views/elements/_TagComposer.scss b/res/css/views/elements/_TagComposer.scss index 2ffd601765..f5bdb8d2d5 100644 --- a/res/css/views/elements/_TagComposer.scss +++ b/res/css/views/elements/_TagComposer.scss @@ -25,7 +25,7 @@ limitations under the License. .mx_AccessibleButton { min-width: 70px; - padding: 0; // override from button styles + padding: 0 8px; // override from button styles margin-left: 16px; // distance from } @@ -50,7 +50,7 @@ limitations under the License. &::before { content: ''; border-radius: 20px; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; opacity: 0.15; position: absolute; top: 0; diff --git a/res/css/views/elements/_Tooltip.scss b/res/css/views/elements/_Tooltip.scss index d90c818f94..6c5a7da55a 100644 --- a/res/css/views/elements/_Tooltip.scss +++ b/res/css/views/elements/_Tooltip.scss @@ -84,7 +84,7 @@ limitations under the License. // These tooltips use an older style with a chevron .mx_Field_tooltip { background-color: $menu-bg-color; - color: $primary-fg-color; + color: $primary-content; border: 1px solid $menu-border-color; text-align: unset; diff --git a/res/css/views/emojipicker/_EmojiPicker.scss b/res/css/views/emojipicker/_EmojiPicker.scss index 400e40e233..91c68158c9 100644 --- a/res/css/views/emojipicker/_EmojiPicker.scss +++ b/res/css/views/emojipicker/_EmojiPicker.scss @@ -57,7 +57,7 @@ limitations under the License. } .mx_EmojiPicker_anchor::before { - background-color: $primary-fg-color; + background-color: $primary-content; content: ''; display: inline-block; mask-size: 100%; @@ -89,7 +89,7 @@ limitations under the License. margin: 8px; border-radius: 4px; border: 1px solid $input-border-color; - background-color: $primary-bg-color; + background-color: $background; display: flex; input { @@ -126,7 +126,7 @@ limitations under the License. .mx_EmojiPicker_search_icon::after { mask: url('$(res)/img/emojipicker/search.svg') no-repeat; mask-size: 100%; - background-color: $primary-fg-color; + background-color: $primary-content; content: ''; display: inline-block; width: 100%; diff --git a/res/css/views/groups/_GroupRoomList.scss b/res/css/views/groups/_GroupRoomList.scss index fefd17849c..2f6559f7c4 100644 --- a/res/css/views/groups/_GroupRoomList.scss +++ b/res/css/views/groups/_GroupRoomList.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_GroupRoomTile { position: relative; - color: $primary-fg-color; + color: $primary-content; cursor: pointer; display: flex; align-items: center; diff --git a/res/css/views/messages/_CallEvent.scss b/res/css/views/messages/_CallEvent.scss index 58d2e2fc32..7934f8f3c2 100644 --- a/res/css/views/messages/_CallEvent.scss +++ b/res/css/views/messages/_CallEvent.scss @@ -41,7 +41,7 @@ limitations under the License. height: 16px; width: 16px; - background-color: $tertiary-fg-color; + background-color: $secondary-content; mask-repeat: no-repeat; mask-size: contain; mask-position: center; @@ -116,7 +116,7 @@ limitations under the License. .mx_CallEvent_type { font-weight: 400; - color: $secondary-fg-color; + color: $secondary-content; font-size: 1.2rem; line-height: $font-13px; display: flex; @@ -132,7 +132,7 @@ limitations under the License. position: absolute; height: 13px; width: 13px; - background-color: $tertiary-fg-color; + background-color: $secondary-content; mask-repeat: no-repeat; mask-size: contain; } @@ -145,7 +145,7 @@ limitations under the License. display: flex; flex-direction: row; align-items: center; - color: $secondary-fg-color; + color: $secondary-content; margin-right: 16px; gap: 8px; min-width: max-content; diff --git a/res/css/views/messages/_MImageBody.scss b/res/css/views/messages/_MImageBody.scss index 765c74a36d..920c3011f5 100644 --- a/res/css/views/messages/_MImageBody.scss +++ b/res/css/views/messages/_MImageBody.scss @@ -36,6 +36,10 @@ $timelineImageBorderRadius: 4px; animation: mx--anim-pulse 1.75s infinite cubic-bezier(.4, 0, .6, 1); border-radius: $timelineImageBorderRadius; } + + .mx_no-image-placeholder { + background-color: $primary-content; + } } .mx_MImageBody_thumbnail_container { @@ -96,5 +100,5 @@ $timelineImageBorderRadius: 4px; } .mx_EventTile:hover .mx_HiddenImagePlaceholder { - background-color: $primary-bg-color; + background-color: $background; } diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index 69f3c672b7..6805036e3d 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -23,7 +23,7 @@ limitations under the License. height: 32px; line-height: $font-24px; border-radius: 8px; - background: $primary-bg-color; + background: $background; border: 1px solid $input-border-color; top: -32px; right: 8px; @@ -77,11 +77,11 @@ limitations under the License. mask-size: 18px; mask-repeat: no-repeat; mask-position: center; - background-color: $secondary-fg-color; + background-color: $secondary-content; } .mx_MessageActionBar_maskButton:hover::after { - background-color: $primary-fg-color; + background-color: $primary-content; } .mx_MessageActionBar_reactButton::after { @@ -92,6 +92,10 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/message-bar/reply.svg'); } +.mx_MessageActionBar_threadButton::after { + mask-image: url('$(res)/img/element-icons/message/thread.svg'); +} + .mx_MessageActionBar_editButton::after { mask-image: url('$(res)/img/element-icons/room/message-bar/edit.svg'); } diff --git a/res/css/views/messages/_ReactionsRow.scss b/res/css/views/messages/_ReactionsRow.scss index b2bca6dfb3..1b0b847932 100644 --- a/res/css/views/messages/_ReactionsRow.scss +++ b/res/css/views/messages/_ReactionsRow.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_ReactionsRow { margin: 6px 0; - color: $primary-fg-color; + color: $primary-content; .mx_ReactionsRow_addReactionButton { position: relative; @@ -36,7 +36,7 @@ limitations under the License. mask-size: 16px; mask-repeat: no-repeat; mask-position: center; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; mask-image: url('$(res)/img/element-icons/room/message-bar/emoji.svg'); } @@ -46,7 +46,7 @@ limitations under the License. &:hover, &.mx_ReactionsRow_addReactionButton_active { &::before { - background-color: $primary-fg-color; + background-color: $primary-content; } } } @@ -64,10 +64,10 @@ limitations under the License. vertical-align: middle; &:link, &:visited { - color: $tertiary-fg-color; + color: $tertiary-content; } &:hover { - color: $primary-fg-color; + color: $primary-content; } } diff --git a/res/css/views/right_panel/_BaseCard.scss b/res/css/views/right_panel/_BaseCard.scss index 9a5a59bda8..8c1a55fe05 100644 --- a/res/css/views/right_panel/_BaseCard.scss +++ b/res/css/views/right_panel/_BaseCard.scss @@ -93,7 +93,7 @@ limitations under the License. } > h1 { - color: $tertiary-fg-color; + color: $tertiary-content; font-size: $font-12px; font-weight: 500; } @@ -145,7 +145,7 @@ limitations under the License. justify-content: space-around; .mx_AccessibleButton_kind_secondary { - color: $secondary-fg-color; + color: $secondary-content; background-color: rgba(141, 151, 165, 0.2); font-weight: $font-semi-bold; font-size: $font-14px; diff --git a/res/css/views/right_panel/_PinnedMessagesCard.scss b/res/css/views/right_panel/_PinnedMessagesCard.scss index 785aee09ca..f3861a3dec 100644 --- a/res/css/views/right_panel/_PinnedMessagesCard.scss +++ b/res/css/views/right_panel/_PinnedMessagesCard.scss @@ -48,7 +48,7 @@ limitations under the License. height: 32px; line-height: $font-24px; border-radius: 8px; - background: $primary-bg-color; + background: $background; border: 1px solid $input-border-color; padding: 1px; width: max-content; @@ -66,7 +66,7 @@ limitations under the License. z-index: 1; &::after { - background-color: $primary-fg-color; + background-color: $primary-content; } } } @@ -75,7 +75,7 @@ limitations under the License. font-weight: $font-semi-bold; font-size: $font-15px; line-height: $font-24px; - color: $primary-fg-color; + color: $primary-content; margin-top: 24px; margin-bottom: 20px; } @@ -83,7 +83,7 @@ limitations under the License. > span { font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; } } } diff --git a/res/css/views/right_panel/_RoomSummaryCard.scss b/res/css/views/right_panel/_RoomSummaryCard.scss index dc7804d072..7ac4787111 100644 --- a/res/css/views/right_panel/_RoomSummaryCard.scss +++ b/res/css/views/right_panel/_RoomSummaryCard.scss @@ -27,7 +27,7 @@ limitations under the License. .mx_RoomSummaryCard_alias { font-size: $font-13px; - color: $secondary-fg-color; + color: $secondary-content; } h2, .mx_RoomSummaryCard_alias { @@ -115,7 +115,7 @@ limitations under the License. // as we will be applying it in its children padding: 0; height: auto; - color: $tertiary-fg-color; + color: $tertiary-content; .mx_RoomSummaryCard_icon_app { padding: 10px 48px 10px 12px; // based on typical mx_RoomSummaryCard_Button padding @@ -128,7 +128,7 @@ limitations under the License. } span { - color: $primary-fg-color; + color: $primary-content; } } @@ -232,6 +232,10 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/files.svg'); } +.mx_RoomSummaryCard_icon_threads::before { + mask-image: url('$(res)/img/element-icons/message/thread.svg'); +} + .mx_RoomSummaryCard_icon_share::before { mask-image: url('$(res)/img/element-icons/room/share.svg'); } diff --git a/res/css/views/right_panel/_UserInfo.scss b/res/css/views/right_panel/_UserInfo.scss index 6632ccddf9..edc82cfdbf 100644 --- a/res/css/views/right_panel/_UserInfo.scss +++ b/res/css/views/right_panel/_UserInfo.scss @@ -55,7 +55,7 @@ limitations under the License. } .mx_UserInfo_separator { - border-bottom: 1px solid rgba($primary-fg-color, .1); + border-bottom: 1px solid rgba($primary-content, .1); } .mx_UserInfo_memberDetailsContainer { diff --git a/res/css/views/right_panel/_WidgetCard.scss b/res/css/views/right_panel/_WidgetCard.scss index a90e744a5a..824f1fcb2f 100644 --- a/res/css/views/right_panel/_WidgetCard.scss +++ b/res/css/views/right_panel/_WidgetCard.scss @@ -51,7 +51,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-image: url('$(res)/img/element-icons/room/ellipsis.svg'); - background-color: $secondary-fg-color; + background-color: $secondary-content; } } } diff --git a/res/css/views/rooms/_AppsDrawer.scss b/res/css/views/rooms/_AppsDrawer.scss index fd80836237..cfcb0c48a2 100644 --- a/res/css/views/rooms/_AppsDrawer.scss +++ b/res/css/views/rooms/_AppsDrawer.scss @@ -64,7 +64,7 @@ $MiniAppTileHeight: 200px; &:hover { .mx_AppsContainer_resizerHandle::after { opacity: 0.8; - background: $primary-fg-color; + background: $primary-content; } .mx_ResizeHandle_horizontal::before { @@ -79,7 +79,7 @@ $MiniAppTileHeight: 200px; content: ''; - background-color: $primary-fg-color; + background-color: $primary-content; opacity: 0.8; } } diff --git a/res/css/views/rooms/_Autocomplete.scss b/res/css/views/rooms/_Autocomplete.scss index f8e0a382b1..fcdab37f5a 100644 --- a/res/css/views/rooms/_Autocomplete.scss +++ b/res/css/views/rooms/_Autocomplete.scss @@ -4,27 +4,29 @@ z-index: 1001; width: 100%; border: 1px solid $primary-hairline-color; - background: $primary-bg-color; + background: $background; border-bottom: none; border-radius: 8px 8px 0 0; - max-height: 50vh; - overflow: auto; + overflow: clip; + display: flex; + flex-direction: column; box-shadow: 0px -16px 32px $composer-shadow-color; } .mx_Autocomplete_ProviderSection { border-bottom: 1px solid $primary-hairline-color; + width: 100%; } /* a "block" completion takes up a whole line */ .mx_Autocomplete_Completion_block { - height: 34px; + min-height: 34px; display: flex; padding: 0 12px; user-select: none; cursor: pointer; align-items: center; - color: $primary-fg-color; + color: $primary-content; } .mx_Autocomplete_Completion_block * { @@ -40,7 +42,7 @@ user-select: none; cursor: pointer; align-items: center; - color: $primary-fg-color; + color: $primary-content; } .mx_Autocomplete_Completion_pill > * { @@ -59,8 +61,9 @@ .mx_Autocomplete_Completion_container_pill { margin: 12px; - display: flex; - flex-flow: wrap; + height: 100%; + overflow-y: scroll; + max-height: 35vh; } .mx_Autocomplete_Completion_container_truncate { @@ -68,7 +71,6 @@ .mx_Autocomplete_Completion_subtitle, .mx_Autocomplete_Completion_description { /* Ellipsis for long names/subtitles/descriptions */ - max-width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -83,7 +85,7 @@ .mx_Autocomplete_provider_name { margin: 12px; - color: $primary-fg-color; + color: $primary-content; font-weight: 400; opacity: 0.4; } diff --git a/res/css/views/rooms/_BasicMessageComposer.scss b/res/css/views/rooms/_BasicMessageComposer.scss index 544a96daba..752d3b0a54 100644 --- a/res/css/views/rooms/_BasicMessageComposer.scss +++ b/res/css/views/rooms/_BasicMessageComposer.scss @@ -31,7 +31,7 @@ limitations under the License. @keyframes visualbell { from { background-color: $visual-bell-bg-color; } - to { background-color: $primary-bg-color; } + to { background-color: $background; } } &.mx_BasicMessageComposer_input_error { diff --git a/res/css/views/rooms/_EditMessageComposer.scss b/res/css/views/rooms/_EditMessageComposer.scss index 214bfc4a1a..bf3c7c9b42 100644 --- a/res/css/views/rooms/_EditMessageComposer.scss +++ b/res/css/views/rooms/_EditMessageComposer.scss @@ -28,7 +28,7 @@ limitations under the License. .mx_BasicMessageComposer_input { border-radius: 4px; border: solid 1px $primary-hairline-color; - background-color: $primary-bg-color; + background-color: $background; max-height: 200px; padding: 3px 6px; diff --git a/res/css/views/rooms/_EntityTile.scss b/res/css/views/rooms/_EntityTile.scss index 27a4e67089..a2ebd6c11b 100644 --- a/res/css/views/rooms/_EntityTile.scss +++ b/res/css/views/rooms/_EntityTile.scss @@ -18,7 +18,7 @@ limitations under the License. .mx_EntityTile { display: flex; align-items: center; - color: $primary-fg-color; + color: $primary-content; cursor: pointer; .mx_E2EIcon { @@ -86,12 +86,12 @@ limitations under the License. .mx_EntityTile_ellipsis .mx_EntityTile_name { font-style: italic; - color: $primary-fg-color; + color: $primary-content; } .mx_EntityTile_invitePlaceholder .mx_EntityTile_name { font-style: italic; - color: $primary-fg-color; + color: $primary-content; } .mx_EntityTile_unavailable .mx_EntityTile_avatar, diff --git a/res/css/views/rooms/_EventBubbleTile.scss b/res/css/views/rooms/_EventBubbleTile.scss index c6170bf7c0..389a5c9706 100644 --- a/res/css/views/rooms/_EventBubbleTile.scss +++ b/res/css/views/rooms/_EventBubbleTile.scss @@ -23,16 +23,24 @@ limitations under the License. } .mx_EventTile[data-layout=bubble] { - position: relative; margin-top: var(--gutterSize); - margin-left: 50px; + margin-left: 49px; margin-right: 100px; + font-size: $font-14px; &.mx_EventTile_continuation { margin-top: 2px; } + &.mx_EventTile_highlight { + &::before { + background-color: $event-highlight-bg-color; + } + + color: $event-highlight-fg-color; + } + /* For replies */ .mx_EventTile { padding-top: 0; @@ -69,10 +77,11 @@ limitations under the License. max-width: 70%; } - .mx_SenderProfile { + > .mx_SenderProfile { position: relative; top: -2px; left: 2px; + font-size: $font-15px; } &[data-self=false] { @@ -188,8 +197,6 @@ limitations under the License. } .mx_ReplyThread { - margin: 0 calc(-1 * var(--gutterSize)); - .mx_EventTile_reply { max-width: 90%; padding: 0; @@ -223,11 +230,6 @@ limitations under the License. margin-left: -9px; } - .mx_ReplyThread { - border-left-width: 2px; - border-left-color: $eventbubble-reply-color; - } - /* Special layout scenario for "Unable To Decrypt (UTD)" events */ &.mx_EventTile_bad > .mx_EventTile_line { display: grid; @@ -264,6 +266,7 @@ limitations under the License. } .mx_EventTile.mx_EventTile_bubbleContainer[data-layout=bubble], +.mx_EventTile.mx_EventTile_leftAlignedBubble[data-layout=bubble], .mx_EventTile.mx_EventTile_info[data-layout=bubble], .mx_EventListSummary[data-layout=bubble][data-expanded=false] { --backgroundColor: transparent; @@ -283,6 +286,8 @@ limitations under the License. .mx_EventTile_line, .mx_EventTile_info { min-width: 100%; + // Preserve alignment with left edge of text in bubbles + margin: 0; } .mx_EventTile_e2eIcon { @@ -290,9 +295,10 @@ limitations under the License. } .mx_EventTile_line > a { + // Align timestamps with those of normal bubble tiles right: auto; - top: -15px; - left: -68px; + top: -11px; + left: -95px; } } @@ -322,11 +328,10 @@ limitations under the License. } .mx_EventTile_line { - margin: 0 5px; + margin: 0; > a { - left: auto; - right: 0; - transform: translateX(calc(100% + 5px)); + // Align timestamps with those of normal bubble tiles + left: -76px; } } @@ -336,7 +341,8 @@ limitations under the License. } .mx_EventListSummary[data-expanded=false][data-layout=bubble] { - padding: 0 34px; + // Align with left edge of bubble tiles + padding: 0 49px; } /* events that do not require bubble layout */ diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index 56cede0895..4495ec4f29 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -55,7 +55,7 @@ $hover-select-border: 4px; } .mx_SenderProfile { - color: $primary-fg-color; + color: $primary-content; font-size: $font-14px; display: inline-block; /* anti-zalgo, with overflow hidden */ overflow: hidden; @@ -161,7 +161,7 @@ $hover-select-border: 4px; // up with the other read receipts &::before { - background-color: $tertiary-fg-color; + background-color: $tertiary-content; mask-repeat: no-repeat; mask-position: center; mask-size: 14px; @@ -480,7 +480,7 @@ $hover-select-border: 4px; } pre code > * { - display: inline-block; + display: inline; } pre { @@ -514,7 +514,7 @@ $hover-select-border: 4px; .mx_EventTile:hover .mx_EventTile_body pre, .mx_EventTile.focus-visible:focus-within .mx_EventTile_body pre { - border: 1px solid #e5e5e5; // deliberate constant as we're behind an invert filter + border: 1px solid $tertiary-content; } .mx_EventTile_pre_container { @@ -618,7 +618,7 @@ $hover-select-border: 4px; } .mx_EventTile_keyRequestInfo_text a { - color: $primary-fg-color; + color: $primary-content; text-decoration: underline; cursor: pointer; } @@ -643,6 +643,7 @@ $hover-select-border: 4px; // Remove some of the default tile padding so that the error is centered margin-right: 0; + .mx_EventTile_line { padding-left: 0; margin-right: 0; @@ -674,3 +675,66 @@ $hover-select-border: 4px; margin-right: 0; } } + +.mx_ThreadInfo:hover { + cursor: pointer; +} + +.mx_ThreadView { + display: flex; + flex-direction: column; + + .mx_ScrollPanel { + margin-top: 20px; + + .mx_RoomView_MessageList { + padding: 0; + } + } + + .mx_EventTile_senderDetails { + display: flex; + align-items: center; + gap: 6px; + margin-bottom: 6px; + + a { + flex: 1; + min-width: none; + max-width: 100%; + display: flex; + align-items: center; + + .mx_SenderProfile { + flex: 1; + } + } + } + + .mx_ThreadView_List { + flex: 1; + overflow: scroll; + } + + .mx_EventTile_roomName { + display: none; + } + + .mx_EventTile_line { + padding-left: 0 !important; + order: 10 !important; + } + + .mx_EventTile { + width: 100%; + display: flex; + flex-direction: column; + margin-top: 0; + padding-bottom: 5px; + margin-bottom: 5px; + } + + .mx_MessageComposer_sendMessage { + margin-right: 0; + } +} diff --git a/res/css/views/rooms/_JumpToBottomButton.scss b/res/css/views/rooms/_JumpToBottomButton.scss index a8dc2ce11c..2b38b509de 100644 --- a/res/css/views/rooms/_JumpToBottomButton.scss +++ b/res/css/views/rooms/_JumpToBottomButton.scss @@ -56,7 +56,7 @@ limitations under the License. height: 38px; border-radius: 19px; box-sizing: border-box; - background: $primary-bg-color; + background: $background; border: 1.3px solid $muted-fg-color; cursor: pointer; } diff --git a/res/css/views/rooms/_MemberInfo.scss b/res/css/views/rooms/_MemberInfo.scss index 3f7f83d334..4abd9c7c30 100644 --- a/res/css/views/rooms/_MemberInfo.scss +++ b/res/css/views/rooms/_MemberInfo.scss @@ -111,7 +111,7 @@ limitations under the License. .mx_MemberInfo_field { cursor: pointer; font-size: $font-15px; - color: $primary-fg-color; + color: $primary-content; margin-left: 8px; line-height: $font-23px; } diff --git a/res/css/views/rooms/_MessageComposer.scss b/res/css/views/rooms/_MessageComposer.scss index 5e2eff4047..9ba966c083 100644 --- a/res/css/views/rooms/_MessageComposer.scss +++ b/res/css/views/rooms/_MessageComposer.scss @@ -130,7 +130,7 @@ limitations under the License. @keyframes visualbell { from { background-color: $visual-bell-bg-color; } - to { background-color: $primary-bg-color; } + to { background-color: $background; } } .mx_MessageComposer_input_error { @@ -160,8 +160,8 @@ limitations under the License. resize: none; outline: none; box-shadow: none; - color: $primary-fg-color; - background-color: $primary-bg-color; + color: $primary-content; + background-color: $background; font-size: $font-14px; max-height: 120px; overflow: auto; @@ -186,11 +186,14 @@ limitations under the License. } .mx_MessageComposer_button { + --size: 26px; position: relative; margin-right: 6px; cursor: pointer; - height: 26px; - width: 26px; + height: var(--size); + line-height: var(--size); + width: auto; + padding-left: calc(var(--size) + 5px); border-radius: 100%; &::before { @@ -207,8 +210,22 @@ limitations under the License. mask-position: center; } - &:hover { - background: rgba($accent-color, 0.1); + &::after { + content: ''; + position: absolute; + left: 0; + top: 0; + z-index: 0; + width: var(--size); + height: var(--size); + border-radius: 50%; + } + + &:hover, + &.mx_MessageComposer_closeButtonMenu { + &::after { + background: rgba($accent-color, 0.1); + } &::before { background-color: $accent-color; @@ -237,10 +254,18 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/room/composer/sticker.svg'); } +.mx_MessageComposer_buttonMenu::before { + mask-image: url('$(res)/img/image-view/more.svg'); +} + +.mx_MessageComposer_closeButtonMenu::before { + transform: rotate(90deg); + transform-origin: center; +} + .mx_MessageComposer_sendMessage { cursor: pointer; position: relative; - margin-right: 6px; width: 32px; height: 32px; border-radius: 100%; @@ -340,3 +365,28 @@ limitations under the License. height: 50px; } } + +/** + * Unstable compact mode + */ + +.mx_MessageComposer.mx_MessageComposer--compact { + margin-right: 0; + + .mx_MessageComposer_wrapper { + padding: 0 0 0 25px; + } + + .mx_MessageComposer_button:last-child { + margin-right: 0; + } + + .mx_MessageComposer_e2eIcon { + left: 0; + } +} + +.mx_MessageComposer_Menu .mx_CallContextMenu_item { + display: flex; + align-items: center; +} diff --git a/res/css/views/rooms/_NewRoomIntro.scss b/res/css/views/rooms/_NewRoomIntro.scss index e0cccfa885..f0e471d384 100644 --- a/res/css/views/rooms/_NewRoomIntro.scss +++ b/res/css/views/rooms/_NewRoomIntro.scss @@ -67,6 +67,6 @@ limitations under the License. > p { margin: 0; font-size: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; } } diff --git a/res/css/views/rooms/_NotificationBadge.scss b/res/css/views/rooms/_NotificationBadge.scss index 64b2623238..670e057cfa 100644 --- a/res/css/views/rooms/_NotificationBadge.scss +++ b/res/css/views/rooms/_NotificationBadge.scss @@ -42,7 +42,7 @@ limitations under the License. // These are the 3 background types &.mx_NotificationBadge_dot { - background-color: $primary-fg-color; // increased visibility + background-color: $primary-content; // increased visibility width: 6px; height: 6px; diff --git a/res/css/views/rooms/_PinnedEventTile.scss b/res/css/views/rooms/_PinnedEventTile.scss index 15b3c16faa..07978a8f65 100644 --- a/res/css/views/rooms/_PinnedEventTile.scss +++ b/res/css/views/rooms/_PinnedEventTile.scss @@ -67,7 +67,7 @@ limitations under the License. //left: 0; height: inherit; width: inherit; - background: $secondary-fg-color; + background: $secondary-content; mask-position: center; mask-size: 8px; mask-repeat: no-repeat; @@ -87,7 +87,7 @@ limitations under the License. .mx_PinnedEventTile_timestamp { font-size: inherit; line-height: inherit; - color: $secondary-fg-color; + color: $secondary-content; } .mx_AccessibleButton_kind_link { diff --git a/res/css/views/rooms/_ReplyPreview.scss b/res/css/views/rooms/_ReplyPreview.scss index 60feb39d11..70a820e412 100644 --- a/res/css/views/rooms/_ReplyPreview.scss +++ b/res/css/views/rooms/_ReplyPreview.scss @@ -16,7 +16,7 @@ limitations under the License. .mx_ReplyPreview { border: 1px solid $primary-hairline-color; - background: $primary-bg-color; + background: $background; border-bottom: none; border-radius: 8px 8px 0 0; max-height: 50vh; @@ -28,7 +28,7 @@ limitations under the License. .mx_ReplyPreview_header { margin: 8px; - color: $primary-fg-color; + color: $primary-content; font-weight: 400; opacity: 0.4; } diff --git a/res/css/views/rooms/_ReplyTile.scss b/res/css/views/rooms/_ReplyTile.scss index fd21e5f348..3ef6491ec9 100644 --- a/res/css/views/rooms/_ReplyTile.scss +++ b/res/css/views/rooms/_ReplyTile.scss @@ -42,7 +42,7 @@ limitations under the License. display: flex; flex-direction: column; text-decoration: none; - color: $primary-fg-color; + color: $primary-content; } .mx_RedactedBody { diff --git a/res/css/views/rooms/_RoomHeader.scss b/res/css/views/rooms/_RoomHeader.scss index 4142b0a2ef..81dfa90c96 100644 --- a/res/css/views/rooms/_RoomHeader.scss +++ b/res/css/views/rooms/_RoomHeader.scss @@ -17,7 +17,7 @@ limitations under the License. .mx_RoomHeader { flex: 0 0 50px; border-bottom: 1px solid $primary-hairline-color; - background-color: $roomheader-bg-color; + background-color: $background; .mx_RoomHeader_e2eIcon { height: 12px; @@ -74,7 +74,7 @@ limitations under the License. .mx_RoomHeader_buttons { display: flex; - background-color: $primary-bg-color; + background-color: $background; } .mx_RoomHeader_info { diff --git a/res/css/views/rooms/_RoomList.scss b/res/css/views/rooms/_RoomList.scss index 8eda25d0c9..7d967661a6 100644 --- a/res/css/views/rooms/_RoomList.scss +++ b/res/css/views/rooms/_RoomList.scss @@ -43,11 +43,11 @@ limitations under the License. div:first-child { font-weight: $font-semi-bold; line-height: $font-18px; - color: $primary-fg-color; + color: $primary-content; } .mx_AccessibleButton { - color: $primary-fg-color; + color: $primary-content; position: relative; padding: 8px 8px 8px 32px; font-size: inherit; @@ -64,7 +64,7 @@ limitations under the License. position: absolute; top: 8px; left: 8px; - background: $secondary-fg-color; + background: $secondary-content; mask-position: center; mask-size: contain; mask-repeat: no-repeat; diff --git a/res/css/views/rooms/_RoomSublist.scss b/res/css/views/rooms/_RoomSublist.scss index 146b3edf71..6db2185dd5 100644 --- a/res/css/views/rooms/_RoomSublist.scss +++ b/res/css/views/rooms/_RoomSublist.scss @@ -172,14 +172,12 @@ limitations under the License. } } - // In the general case, we leave height of headers alone even if sticky, so - // that the sublists below them do not jump. However, that leaves a gap - // when scrolled to the top above the first sublist (whose header can only - // ever stick to top), so we force height to 0 for only that first header. - // See also https://github.com/vector-im/element-web/issues/14429. - &:first-child .mx_RoomSublist_headerContainer { - height: 0; - padding-bottom: 4px; + // In the general case, we reserve space for each sublist header to prevent + // scroll jumps when they become sticky. However, that leaves a gap when + // scrolled to the top above the first sublist (whose header can only ever + // stick to top), so we make sure to exclude the first visible sublist. + &:not(.mx_RoomSublist_hidden) ~ .mx_RoomSublist .mx_RoomSublist_headerContainer { + height: 24px; } .mx_RoomSublist_resizeBox { @@ -233,7 +231,7 @@ limitations under the License. &:hover, &.mx_RoomSublist_hasMenuOpen { .mx_RoomSublist_resizerHandle { opacity: 0.8; - background-color: $primary-fg-color; + background-color: $primary-content; } } } diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index b8f4aeb6e7..0c04f27115 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -124,7 +124,7 @@ limitations under the License. mask-position: center; mask-size: contain; mask-repeat: no-repeat; - background: $primary-fg-color; + background: $primary-content; } } diff --git a/res/css/views/rooms/_SearchBar.scss b/res/css/views/rooms/_SearchBar.scss index d9f730a8b6..e08168a122 100644 --- a/res/css/views/rooms/_SearchBar.scss +++ b/res/css/views/rooms/_SearchBar.scss @@ -47,7 +47,7 @@ limitations under the License. padding: 5px; font-size: $font-15px; cursor: pointer; - color: $primary-fg-color; + color: $primary-content; border-bottom: 2px solid $accent-color; font-weight: 600; } diff --git a/res/css/views/rooms/_TopUnreadMessagesBar.scss b/res/css/views/rooms/_TopUnreadMessagesBar.scss index 8841b042a0..7c7d96e713 100644 --- a/res/css/views/rooms/_TopUnreadMessagesBar.scss +++ b/res/css/views/rooms/_TopUnreadMessagesBar.scss @@ -41,7 +41,7 @@ limitations under the License. height: 38px; border-radius: 19px; box-sizing: border-box; - background: $primary-bg-color; + background: $background; border: 1.3px solid $muted-fg-color; cursor: pointer; } @@ -62,7 +62,7 @@ limitations under the License. display: block; width: 18px; height: 18px; - background: $primary-bg-color; + background: $background; border: 1.3px solid $muted-fg-color; border-radius: 10px; margin: 5px auto; diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.scss b/res/css/views/rooms/_VoiceRecordComposerTile.scss index 8196d5c67a..69fe292c0a 100644 --- a/res/css/views/rooms/_VoiceRecordComposerTile.scss +++ b/res/css/views/rooms/_VoiceRecordComposerTile.scss @@ -48,7 +48,7 @@ limitations under the License. .mx_VoiceRecordComposerTile_uploadingState { margin-right: 10px; - color: $secondary-fg-color; + color: $secondary-content; } .mx_VoiceRecordComposerTile_failedState { diff --git a/res/css/views/rooms/_WhoIsTypingTile.scss b/res/css/views/rooms/_WhoIsTypingTile.scss index 1c0dabbeb5..49655742bb 100644 --- a/res/css/views/rooms/_WhoIsTypingTile.scss +++ b/res/css/views/rooms/_WhoIsTypingTile.scss @@ -36,7 +36,7 @@ limitations under the License. } .mx_WhoIsTypingTile_avatars .mx_BaseAvatar { - border: 1px solid $primary-bg-color; + border: 1px solid $background; border-radius: 40px; } @@ -45,7 +45,7 @@ limitations under the License. display: inline-block; color: #acacac; background-color: #ddd; - border: 1px solid $primary-bg-color; + border: 1px solid $background; border-radius: 40px; width: 24px; height: 24px; diff --git a/res/css/views/settings/_LayoutSwitcher.scss b/res/css/views/settings/_LayoutSwitcher.scss index 924fe5ae1b..00fb8aba56 100644 --- a/res/css/views/settings/_LayoutSwitcher.scss +++ b/res/css/views/settings/_LayoutSwitcher.scss @@ -21,7 +21,7 @@ limitations under the License. flex-direction: row; gap: 24px; - color: $primary-fg-color; + color: $primary-content; > .mx_LayoutSwitcher_RadioButton { flex-grow: 0; diff --git a/res/css/views/settings/_Notifications.scss b/res/css/views/settings/_Notifications.scss index f93e0a53a8..a0e46c0071 100644 --- a/res/css/views/settings/_Notifications.scss +++ b/res/css/views/settings/_Notifications.scss @@ -15,7 +15,7 @@ limitations under the License. */ .mx_UserNotifSettings { - color: $primary-fg-color; // override from default settings page styles + color: $primary-content; // override from default settings page styles .mx_UserNotifSettings_pushRulesTable { width: calc(100% + 12px); // +12px to line up center of 'Noisy' column with toggle switches @@ -34,7 +34,7 @@ limitations under the License. } tr > th:nth-child(n + 2) { - color: $secondary-fg-color; + color: $secondary-content; font-size: $font-12px; vertical-align: middle; width: 66px; diff --git a/res/css/views/settings/tabs/_SettingsTab.scss b/res/css/views/settings/tabs/_SettingsTab.scss index 3290a998ab..5aa9db7e86 100644 --- a/res/css/views/settings/tabs/_SettingsTab.scss +++ b/res/css/views/settings/tabs/_SettingsTab.scss @@ -25,7 +25,7 @@ limitations under the License. .mx_SettingsTab_heading { font-size: $font-20px; font-weight: 600; - color: $primary-fg-color; + color: $primary-content; margin-bottom: 10px; } @@ -37,7 +37,7 @@ limitations under the License. font-size: $font-16px; display: block; font-weight: 600; - color: $primary-fg-color; + color: $primary-content; margin-bottom: 10px; margin-top: 12px; } @@ -72,7 +72,7 @@ limitations under the License. vertical-align: middle; display: inline-block; font-size: $font-14px; - color: $primary-fg-color; + color: $primary-content; max-width: calc(100% - $font-48px); // Force word wrap instead of colliding with the switch box-sizing: border-box; padding-right: 10px; @@ -82,7 +82,7 @@ limitations under the License. margin-top: 4px; font-size: $font-12px; line-height: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; } .mx_SettingsTab_section .mx_SettingsFlag .mx_ToggleSwitch { diff --git a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss index 2aab201352..8fd0f14418 100644 --- a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss +++ b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss @@ -22,7 +22,7 @@ limitations under the License. .mx_SecurityRoomSettingsTab_spacesWithAccess { > h4 { - color: $secondary-fg-color; + color: $secondary-content; font-weight: $font-semi-bold; font-size: $font-12px; line-height: $font-15px; @@ -33,7 +33,7 @@ limitations under the License. font-weight: 500; font-size: $font-14px; line-height: 32px; // matches height of avatar for v-align - color: $secondary-fg-color; + color: $secondary-content; display: inline-block; img.mx_RoomAvatar_isSpaceRoom, @@ -89,7 +89,7 @@ limitations under the License. font-weight: $font-semi-bold; font-size: $font-15px; line-height: $font-24px; - color: $primary-fg-color; + color: $primary-content; display: block; } } @@ -100,7 +100,7 @@ limitations under the License. margin-bottom: 16px; font-size: $font-15px; line-height: $font-24px; - color: $secondary-fg-color; + color: $secondary-content; & + .mx_RadioButton { border-top: 1px solid $menu-border-color; diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss index d8e617a40d..57c6e9b865 100644 --- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss @@ -24,7 +24,7 @@ limitations under the License. } .mx_AppearanceUserSettingsTab_fontScaling { - color: $primary-fg-color; + color: $primary-content; } .mx_AppearanceUserSettingsTab_fontSlider { @@ -81,7 +81,7 @@ limitations under the License. .mx_AppearanceUserSettingsTab_themeSection { $radio-bg-color: $input-darker-bg-color; - color: $primary-fg-color; + color: $primary-content; > .mx_ThemeSelectors { display: flex; @@ -156,7 +156,7 @@ limitations under the License. } .mx_AppearanceUserSettingsTab_Advanced { - color: $primary-fg-color; + color: $primary-content; > * { margin-bottom: 16px; diff --git a/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss index 4cdfa0b40f..d1076205ad 100644 --- a/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss @@ -30,7 +30,7 @@ limitations under the License. font-weight: $font-semi-bold; font-size: $font-15px; line-height: $font-18px; - color: $primary-fg-color; + color: $primary-content; margin: 16px 0; .mx_BaseAvatar { diff --git a/res/css/views/spaces/_SpaceBasicSettings.scss b/res/css/views/spaces/_SpaceBasicSettings.scss index c73e0715dd..bff574ded3 100644 --- a/res/css/views/spaces/_SpaceBasicSettings.scss +++ b/res/css/views/spaces/_SpaceBasicSettings.scss @@ -27,7 +27,7 @@ limitations under the License. position: relative; height: 80px; width: 80px; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; border-radius: 16px; } diff --git a/res/css/views/spaces/_SpaceCreateMenu.scss b/res/css/views/spaces/_SpaceCreateMenu.scss index 41536bc8b1..3f526a6bba 100644 --- a/res/css/views/spaces/_SpaceCreateMenu.scss +++ b/res/css/views/spaces/_SpaceCreateMenu.scss @@ -28,7 +28,7 @@ $spacePanelWidth: 71px; padding: 24px; width: 480px; box-sizing: border-box; - background-color: $primary-bg-color; + background-color: $background; position: relative; > div { @@ -40,7 +40,7 @@ $spacePanelWidth: 71px; > p { font-size: $font-15px; - color: $secondary-fg-color; + color: $secondary-content; } .mx_SpaceFeedbackPrompt { @@ -76,7 +76,7 @@ $spacePanelWidth: 71px; width: 28px; top: 0; left: 0; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; transform: rotate(90deg); mask-repeat: no-repeat; mask-position: 2px 3px; @@ -108,7 +108,7 @@ $spacePanelWidth: 71px; line-height: $font-24px; > span { - color: $secondary-fg-color; + color: $secondary-content; position: relative; font-size: inherit; line-height: inherit; diff --git a/res/css/views/toasts/_IncomingCallToast.scss b/res/css/views/toasts/_IncomingCallToast.scss index eb80f2d5cf..cb05b1a977 100644 --- a/res/css/views/toasts/_IncomingCallToast.scss +++ b/res/css/views/toasts/_IncomingCallToast.scss @@ -43,7 +43,7 @@ limitations under the License. .mx_CallEvent_type { font-size: $font-12px; line-height: $font-15px; - color: $tertiary-fg-color; + color: $tertiary-content; margin-top: 4px; margin-bottom: 6px; @@ -62,7 +62,7 @@ limitations under the License. position: absolute; height: inherit; width: inherit; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; mask-repeat: no-repeat; mask-size: contain; } @@ -139,7 +139,7 @@ limitations under the License. height: inherit; width: inherit; - background-color: $tertiary-fg-color; + background-color: $tertiary-content; mask-repeat: no-repeat; mask-size: contain; mask-position: center; diff --git a/res/css/views/voip/_CallContainer.scss b/res/css/views/voip/_CallContainer.scss index d11ab9bf9f..a0137b18e8 100644 --- a/res/css/views/voip/_CallContainer.scss +++ b/res/css/views/voip/_CallContainer.scss @@ -26,19 +26,6 @@ limitations under the License. // different level. pointer-events: none; - .mx_CallPreview { - pointer-events: initial; // restore pointer events so the user can leave/interact - - .mx_VideoFeed_remote.mx_VideoFeed_voice { - min-height: 150px; - } - - .mx_VideoFeed_local { - border-radius: 8px; - overflow: hidden; - } - } - .mx_AppTile_persistedWrapper div { min-width: 350px; } diff --git a/res/css/views/voip/_CallPreview.scss b/res/css/views/voip/_CallPreview.scss index 92348fb465..0fd97d4676 100644 --- a/res/css/views/voip/_CallPreview.scss +++ b/res/css/views/voip/_CallPreview.scss @@ -18,4 +18,15 @@ limitations under the License. position: fixed; left: 0; top: 0; + + pointer-events: initial; // restore pointer events so the user can leave/interact + + .mx_VideoFeed_remote.mx_VideoFeed_voice { + min-height: 150px; + } + + .mx_VideoFeed_local { + border-radius: 8px; + overflow: hidden; + } } diff --git a/res/css/views/voip/_CallView.scss b/res/css/views/voip/_CallView.scss index 63ca91267f..aa0aa4e2a6 100644 --- a/res/css/views/voip/_CallView.scss +++ b/res/css/views/voip/_CallView.scss @@ -74,9 +74,9 @@ limitations under the License. > .mx_VideoFeed { width: 100%; height: 100%; + border-width: 0 !important; // Override mx_VideoFeed_speaking &.mx_VideoFeed_voice { - background-color: $inverted-bg-color; display: flex; justify-content: center; align-items: center; diff --git a/res/css/views/voip/_CallViewForRoom.scss b/res/css/views/voip/_CallViewForRoom.scss index 769e00338e..d23fcc18bc 100644 --- a/res/css/views/voip/_CallViewForRoom.scss +++ b/res/css/views/voip/_CallViewForRoom.scss @@ -39,7 +39,7 @@ limitations under the License. width: 100%; max-width: 64px; - background-color: $primary-fg-color; + background-color: $primary-content; } } } diff --git a/res/css/views/voip/_CallViewHeader.scss b/res/css/views/voip/_CallViewHeader.scss index 014cfce478..0575f4f535 100644 --- a/res/css/views/voip/_CallViewHeader.scss +++ b/res/css/views/voip/_CallViewHeader.scss @@ -53,7 +53,7 @@ limitations under the License. height: 20px; width: 20px; vertical-align: middle; - background-color: $secondary-fg-color; + background-color: $secondary-content; mask-repeat: no-repeat; mask-size: contain; mask-position: center; @@ -90,7 +90,7 @@ limitations under the License. .mx_CallViewHeader_callTypeSmall { font-size: 12px; - color: $secondary-fg-color; + color: $secondary-content; line-height: initial; height: 15px; overflow: hidden; @@ -113,7 +113,7 @@ limitations under the License. height: 16px; width: 16px; - background-color: $secondary-fg-color; + background-color: $secondary-content; mask-repeat: no-repeat; mask-size: contain; mask-position: center; diff --git a/res/css/views/voip/_CallViewSidebar.scss b/res/css/views/voip/_CallViewSidebar.scss index dbadc22028..fd9c76defc 100644 --- a/res/css/views/voip/_CallViewSidebar.scss +++ b/res/css/views/voip/_CallViewSidebar.scss @@ -33,10 +33,9 @@ limitations under the License. > .mx_VideoFeed { width: 100%; + border-radius: 4px; &.mx_VideoFeed_voice { - border-radius: 4px; - display: flex; align-items: center; justify-content: center; diff --git a/res/css/views/voip/_DialPad.scss b/res/css/views/voip/_DialPad.scss index eefd2e9ba5..288f1f5d31 100644 --- a/res/css/views/voip/_DialPad.scss +++ b/res/css/views/voip/_DialPad.scss @@ -33,7 +33,7 @@ limitations under the License. width: 40px; height: 40px; - background-color: $dialpad-button-bg-color; + background-color: $quinary-content; border-radius: 40px; font-size: 18px; font-weight: 600; diff --git a/res/css/views/voip/_DialPadContextMenu.scss b/res/css/views/voip/_DialPadContextMenu.scss index 527d223ffc..d2014241e9 100644 --- a/res/css/views/voip/_DialPadContextMenu.scss +++ b/res/css/views/voip/_DialPadContextMenu.scss @@ -30,7 +30,7 @@ limitations under the License. margin-right: 20px; /* a separator between the input line and the dial buttons */ - border-bottom: 1px solid $quaternary-fg-color; + border-bottom: 1px solid $quaternary-content; transition: border-bottom 0.25s; } diff --git a/res/css/views/voip/_DialPadModal.scss b/res/css/views/voip/_DialPadModal.scss index b8042f77ae..f378507f90 100644 --- a/res/css/views/voip/_DialPadModal.scss +++ b/res/css/views/voip/_DialPadModal.scss @@ -30,7 +30,7 @@ limitations under the License. margin-right: 40px; /* a separator between the input line and the dial buttons */ - border-bottom: 1px solid $quaternary-fg-color; + border-bottom: 1px solid $quaternary-content; transition: border-bottom 0.25s; } diff --git a/res/css/views/voip/_VideoFeed.scss b/res/css/views/voip/_VideoFeed.scss index 7a8d39dfe3..1f17a54692 100644 --- a/res/css/views/voip/_VideoFeed.scss +++ b/res/css/views/voip/_VideoFeed.scss @@ -17,12 +17,23 @@ limitations under the License. .mx_VideoFeed { overflow: hidden; position: relative; + box-sizing: border-box; + border: transparent 2px solid; + display: flex; &.mx_VideoFeed_voice { background-color: $inverted-bg-color; aspect-ratio: 16 / 9; } + &.mx_VideoFeed_speaking { + border: $accent-color 2px solid; + + .mx_VideoFeed_video { + border-radius: 0; + } + } + .mx_VideoFeed_video { width: 100%; background-color: transparent; diff --git a/res/img/element-icons/message/thread.svg b/res/img/element-icons/message/thread.svg new file mode 100644 index 0000000000..b4a7cc0066 --- /dev/null +++ b/res/img/element-icons/message/thread.svg @@ -0,0 +1,4 @@ + + + + diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss index 8c305b9828..0bc61d438d 100644 --- a/res/themes/dark/css/_dark.scss +++ b/res/themes/dark/css/_dark.scss @@ -20,29 +20,18 @@ $space-nav: rgba($panel-base, 0.1); // unified palette // try to use these colors when possible -$bg-color: $background; -$base-color: $bg-color; -$base-text-color: $primary-content; $header-panel-bg-color: #20252B; $header-panel-border-color: #000000; $header-panel-text-primary-color: #B9BEC6; $header-panel-text-secondary-color: #c8c8cd; -$text-primary-color: $primary-content; $text-secondary-color: #B9BEC6; -$quaternary-fg-color: $quaternary-content; $search-bg-color: #181b21; $search-placeholder-color: #61708b; $room-highlight-color: #343a46; // typical text (dark-on-white in light skin) -$primary-fg-color: $text-primary-color; -$primary-bg-color: $bg-color; $muted-fg-color: $header-panel-text-primary-color; -// additional text colors -$secondary-fg-color: $secondary-content; -$tertiary-fg-color: $tertiary-content; - // used for dialog box text $light-fg-color: $header-panel-text-secondary-color; @@ -61,7 +50,7 @@ $info-plinth-fg-color: #888; $preview-bar-bg-color: $header-panel-bg-color; $groupFilterPanel-bg-color: rgba(38, 39, 43, 0.82); -$inverted-bg-color: $base-color; +$inverted-bg-color: $background; // used by AddressSelector $selected-color: $room-highlight-color; @@ -82,7 +71,7 @@ $input-focused-border-color: #238cf5; $input-valid-border-color: $accent-color; $input-invalid-border-color: $warning-color; -$field-focused-label-bg-color: $bg-color; +$field-focused-label-bg-color: $background; $resend-button-divider-color: #b9bec64a; // muted-text with a 4A opacity. @@ -93,15 +82,15 @@ $scrollbar-track-color: transparent; // context menus $menu-border-color: $header-panel-border-color; $menu-bg-color: $header-panel-bg-color; -$menu-box-shadow-color: $bg-color; +$menu-box-shadow-color: $background; $menu-selected-color: $room-highlight-color; $avatar-initial-color: #ffffff; -$avatar-bg-color: $bg-color; +$avatar-bg-color: $background; -$h3-color: $primary-fg-color; +$h3-color: $primary-content; -$dialog-title-fg-color: $base-text-color; +$dialog-title-fg-color: $primary-content; $dialog-backdrop-color: #000; $dialog-shadow-color: rgba(0, 0, 0, 0.48); $dialog-close-fg-color: #9fa9ba; @@ -117,11 +106,10 @@ $settings-profile-button-bg-color: #e7e7e7; $settings-profile-button-fg-color: $settings-profile-overlay-placeholder-fg-color; $settings-subsection-fg-color: $text-secondary-color; -$topleftmenu-color: $text-primary-color; -$roomheader-color: $text-primary-color; -$roomheader-bg-color: $bg-color; +$topleftmenu-color: $primary-content; +$roomheader-color: $primary-content; $roomheader-addroom-bg-color: rgba(92, 100, 112, 0.3); -$roomheader-addroom-fg-color: $text-primary-color; +$roomheader-addroom-fg-color: $primary-content; $groupFilterPanel-button-color: $header-panel-text-primary-color; $groupheader-button-color: $header-panel-text-primary-color; $rightpanel-button-color: $header-panel-text-primary-color; @@ -135,18 +123,16 @@ $composer-e2e-icon-color: $header-panel-text-primary-color; // ******************** $theme-button-bg-color: #e3e8f0; -$dialpad-button-bg-color: $quinary-content; $roomlist-button-bg-color: rgba(141, 151, 165, 0.2); // Buttons include the filter box, explore button, and sublist buttons -$roomlist-filter-active-bg-color: $bg-color; $roomlist-bg-color: rgba(33, 38, 44, 0.90); -$roomlist-header-color: $tertiary-fg-color; -$roomsublist-divider-color: $primary-fg-color; +$roomlist-header-color: $tertiary-content; +$roomsublist-divider-color: $primary-content; $roomsublist-skeleton-ui-bg: linear-gradient(180deg, #3e444c 0%, #3e444c00 100%); $groupFilterPanel-divider-color: $roomlist-header-color; -$roomtile-preview-color: $secondary-fg-color; +$roomtile-preview-color: $secondary-content; $roomtile-default-badge-bg-color: #61708b; $roomtile-selected-bg-color: rgba(141, 151, 165, 0.2); @@ -170,12 +156,12 @@ $event-highlight-bg-color: #25271F; $event-timestamp-color: $text-secondary-color; // Tabbed views -$tab-label-fg-color: $text-primary-color; -$tab-label-active-fg-color: $text-primary-color; +$tab-label-fg-color: $primary-content; +$tab-label-active-fg-color: $primary-content; $tab-label-bg-color: transparent; $tab-label-active-bg-color: $accent-color; -$tab-label-icon-bg-color: $text-primary-color; -$tab-label-active-icon-bg-color: $text-primary-color; +$tab-label-icon-bg-color: $primary-content; +$tab-label-active-icon-bg-color: $primary-content; // Buttons $button-primary-fg-color: $primary-content; @@ -198,6 +184,9 @@ $visual-bell-bg-color: #800; $room-warning-bg-color: $header-panel-bg-color; +$authpage-body-bg-color: $background; +$authpage-primary-color: $primary-content; + $dark-panel-bg-color: $header-panel-bg-color; $panel-gradient: rgba(34, 38, 46, 0), rgba(34, 38, 46, 1); @@ -217,30 +206,31 @@ $kbd-border-color: #000000; $tooltip-timeline-bg-color: $groupFilterPanel-bg-color; $tooltip-timeline-fg-color: $primary-content; -$interactive-tooltip-bg-color: $base-color; +$interactive-tooltip-bg-color: $background; $interactive-tooltip-fg-color: $primary-content; $breadcrumb-placeholder-bg-color: #272c35; $user-tile-hover-bg-color: $header-panel-bg-color; -$message-body-panel-fg-color: $secondary-fg-color; +$message-body-panel-fg-color: $secondary-content; $message-body-panel-bg-color: $quinary-content; -$message-body-panel-icon-fg-color: $secondary-fg-color; -$message-body-panel-icon-bg-color: $system; // "System Dark" +$message-body-panel-icon-bg-color: $system; +$message-body-panel-icon-fg-color: $secondary-content; -$voice-record-stop-border-color: $quaternary-fg-color; -$voice-record-waveform-incomplete-fg-color: $quaternary-fg-color; -$voice-record-icon-color: $quaternary-fg-color; +$voice-record-stop-border-color: $quaternary-content; +$voice-record-waveform-incomplete-fg-color: $quaternary-content; +$voice-record-icon-color: $quaternary-content; $voice-playback-button-bg-color: $message-body-panel-icon-bg-color; $voice-playback-button-fg-color: $message-body-panel-icon-fg-color; // Appearance tab colors $appearance-tab-border-color: $room-highlight-color; -// blur amounts for left left panel (only for element theme, used in _mods.scss) -$roomlist-background-blur-amount: 60px; -$groupFilterPanel-background-blur-amount: 30px; +// blur amounts for left left panel (only for element theme) +:root { + --lp-background-blur: 45px; +} $composer-shadow-color: rgba(0, 0, 0, 0.28); @@ -248,7 +238,7 @@ $composer-shadow-color: rgba(0, 0, 0, 0.28); $eventbubble-self-bg: #14322E; $eventbubble-others-bg: $event-selected-color; $eventbubble-bg-hover: #1C2026; -$eventbubble-avatar-outline: $bg-color; +$eventbubble-avatar-outline: $background; $eventbubble-reply-color: #C1C6CD; // ***** Mixins! ***** diff --git a/res/themes/dark/css/dark.scss b/res/themes/dark/css/dark.scss index 600cfd528a..df83d6db88 100644 --- a/res/themes/dark/css/dark.scss +++ b/res/themes/dark/css/dark.scss @@ -2,10 +2,6 @@ @import "../../light/css/_paths.scss"; @import "../../light/css/_fonts.scss"; @import "../../light/css/_light.scss"; -// important this goes before _mods, -// as $groupFilterPanel-background-blur-amount and -// $roomlist-background-blur-amount -// are overridden in _dark.scss @import "_dark.scss"; @import "../../light/css/_mods.scss"; @import "../../../../res/css/_components.scss"; diff --git a/res/themes/legacy-dark/css/_legacy-dark.scss b/res/themes/legacy-dark/css/_legacy-dark.scss index 3e3412c6c1..d5bc5e6dd7 100644 --- a/res/themes/legacy-dark/css/_legacy-dark.scss +++ b/res/themes/legacy-dark/css/_legacy-dark.scss @@ -24,7 +24,12 @@ $primary-bg-color: $bg-color; $muted-fg-color: $header-panel-text-primary-color; // Legacy theme backports -$quaternary-fg-color: #6F7882; +$primary-content: $primary-fg-color; +$secondary-content: $secondary-fg-color; +$tertiary-content: $tertiary-fg-color; +$quaternary-content: #6F7882; +$quinary-content: $quaternary-content; +$background: $primary-bg-color; // used for dialog box text $light-fg-color: $header-panel-text-secondary-color; @@ -117,7 +122,6 @@ $composer-e2e-icon-color: $header-panel-text-primary-color; // ******************** $theme-button-bg-color: #e3e8f0; -$dialpad-button-bg-color: #6F7882; $roomlist-button-bg-color: #1A1D23; // Buttons include the filter box, explore button, and sublist buttons diff --git a/res/themes/legacy-light/css/_legacy-light.scss b/res/themes/legacy-light/css/_legacy-light.scss index 3f722bcb30..47247e5e23 100644 --- a/res/themes/legacy-light/css/_legacy-light.scss +++ b/res/themes/legacy-light/css/_legacy-light.scss @@ -32,7 +32,12 @@ $primary-bg-color: #ffffff; $muted-fg-color: #61708b; // Commonly used in headings and relevant alt text // Legacy theme backports -$quaternary-fg-color: #C1C6CD; +$primary-content: $primary-fg-color; +$secondary-content: $secondary-fg-color; +$tertiary-content: $tertiary-fg-color; +$quaternary-content: #C1C6CD; +$quinary-content: #e3e8f0; +$background: $primary-bg-color; // used for dialog box text $light-fg-color: #747474; @@ -186,8 +191,6 @@ $voipcall-plinth-color: $system; // ******************** $theme-button-bg-color: #e3e8f0; -$dialpad-button-bg-color: #e3e8f0; - $roomlist-button-bg-color: #fff; // Buttons include the filter box, explore button, and sublist buttons $roomlist-filter-active-bg-color: $roomlist-button-bg-color; diff --git a/res/themes/light-custom/css/_custom.scss b/res/themes/light-custom/css/_custom.scss index 6c37351414..455798a556 100644 --- a/res/themes/light-custom/css/_custom.scss +++ b/res/themes/light-custom/css/_custom.scss @@ -38,7 +38,7 @@ $lightbox-border-color: var(--timeline-background-color); $menu-bg-color: var(--timeline-background-color); $avatar-bg-color: var(--timeline-background-color); $message-action-bar-bg-color: var(--timeline-background-color); -$primary-bg-color: var(--timeline-background-color); +$background: var(--timeline-background-color); $togglesw-ball-color: var(--timeline-background-color); $droptarget-bg-color: var(--timeline-background-color-50pct); //still needs alpha at .5 $authpage-modal-bg-color: var(--timeline-background-color-50pct); //still needs alpha at .59 @@ -69,7 +69,7 @@ $roomlist-bg-color: var(--roomlist-background-color); // // --timeline-text-color $message-action-bar-fg-color: var(--timeline-text-color); -$primary-fg-color: var(--timeline-text-color); +$primary-content: var(--timeline-text-color); $settings-profile-overlay-placeholder-fg-color: var(--timeline-text-color); $roomtopic-color: var(--timeline-text-color-50pct); $tab-label-fg-color: var(--timeline-text-color); @@ -82,6 +82,8 @@ $tab-label-fg-color: var(--timeline-text-color); // was #4e5054 $authpage-lang-color: var(--timeline-text-color); $roomheader-color: var(--timeline-text-color); +// was #232f32 +$authpage-primary-color: var(--timeline-text-color); // --roomlist-text-secondary-color $roomtile-preview-color: var(--roomlist-text-secondary-color); $roomlist-header-color: var(--roomlist-text-secondary-color); @@ -139,7 +141,7 @@ $event-selected-color: var(--timeline-highlights-color); $event-highlight-bg-color: var(--timeline-highlights-color); // // redirect some variables away from their hardcoded values in the light theme -$settings-grey-fg-color: $primary-fg-color; +$settings-grey-fg-color: $primary-content; // --eventbubble colors $eventbubble-self-bg: var(--eventbubble-self-bg, $eventbubble-self-bg); diff --git a/res/themes/light/css/_light.scss b/res/themes/light/css/_light.scss index e64fe12d3b..96e5fd7155 100644 --- a/res/themes/light/css/_light.scss +++ b/res/themes/light/css/_light.scss @@ -37,14 +37,9 @@ $accent-color: $accent; $accent-bg-color: rgba(3, 179, 129, 0.16); $notice-primary-color: #ff4b55; $notice-primary-bg-color: rgba(255, 75, 85, 0.16); -$primary-fg-color: #2e2f32; -$secondary-fg-color: $secondary-content; -$tertiary-fg-color: #8D99A5; -$quaternary-fg-color: $quaternary-content; $header-panel-bg-color: #f3f8fd; // typical text (dark-on-white in light skin) -$primary-bg-color: $background; $muted-fg-color: #61708b; // Commonly used in headings and relevant alt text // used for dialog box text @@ -59,7 +54,7 @@ $accent-color-50pct: rgba($accent-color, 0.5); $accent-color-darker: #92caad; $accent-color-alt: #238CF5; -$selection-fg-color: $primary-bg-color; +$selection-fg-color: $background; $focus-brightness: 105%; @@ -173,7 +168,6 @@ $rte-group-pill-color: #aaa; $topleftmenu-color: #212121; $roomheader-color: #45474a; -$roomheader-bg-color: $primary-bg-color; $roomheader-addroom-bg-color: rgba(92, 100, 112, 0.2); $roomheader-addroom-fg-color: #5c6470; $groupFilterPanel-button-color: #91A1C0; @@ -191,19 +185,16 @@ $voipcall-plinth-color: $system; // ******************** $theme-button-bg-color: $quinary-content; -$dialpad-button-bg-color: $quinary-content; - $roomlist-button-bg-color: rgba(141, 151, 165, 0.2); // Buttons include the filter box, explore button, and sublist buttons -$roomlist-filter-active-bg-color: $background; $roomlist-bg-color: rgba(245, 245, 245, 0.90); -$roomlist-header-color: $tertiary-fg-color; -$roomsublist-divider-color: $primary-fg-color; +$roomlist-header-color: $tertiary-content; +$roomsublist-divider-color: $primary-content; $roomsublist-skeleton-ui-bg: linear-gradient(180deg, #ffffff 0%, #ffffff00 100%); $groupFilterPanel-divider-color: $roomlist-header-color; -$roomtile-preview-color: $secondary-fg-color; +$roomtile-preview-color: $secondary-content; $roomtile-default-badge-bg-color: #61708b; $roomtile-selected-bg-color: #FFF; @@ -318,8 +309,8 @@ $authpage-secondary-color: #61708b; $dark-panel-bg-color: $secondary-accent-color; $panel-gradient: rgba(242, 245, 248, 0), rgba(242, 245, 248, 1); -$message-action-bar-bg-color: $primary-bg-color; -$message-action-bar-fg-color: $primary-fg-color; +$message-action-bar-bg-color: $background; +$message-action-bar-fg-color: $primary-content; $message-action-bar-border-color: #e9edf1; $message-action-bar-hover-border-color: $focus-bg-color; @@ -342,10 +333,10 @@ $breadcrumb-placeholder-bg-color: #e8eef5; $user-tile-hover-bg-color: $header-panel-bg-color; -$message-body-panel-fg-color: $secondary-fg-color; +$message-body-panel-fg-color: $secondary-content; $message-body-panel-bg-color: $quinary-content; -$message-body-panel-icon-fg-color: $secondary-fg-color; $message-body-panel-icon-bg-color: $system; +$message-body-panel-icon-fg-color: $secondary-content; // These two don't change between themes. They are the $warning-color, but we don't // want custom themes to affect them by accident. @@ -353,25 +344,25 @@ $voice-record-stop-symbol-color: #ff4b55; $voice-record-live-circle-color: #ff4b55; $voice-record-stop-border-color: $quinary-content; -$voice-record-waveform-incomplete-fg-color: $quaternary-fg-color; -$voice-record-icon-color: $tertiary-fg-color; +$voice-record-waveform-incomplete-fg-color: $quaternary-content; +$voice-record-icon-color: $tertiary-content; $voice-playback-button-bg-color: $message-body-panel-icon-bg-color; $voice-playback-button-fg-color: $message-body-panel-icon-fg-color; // FontSlider colors $appearance-tab-border-color: $input-darker-bg-color; -// blur amounts for left left panel (only for element theme, used in _mods.scss) -$roomlist-background-blur-amount: 40px; -$groupFilterPanel-background-blur-amount: 20px; - +// blur amounts for left left panel (only for element theme) +:root { + --lp-background-blur: 40px; +} $composer-shadow-color: rgba(0, 0, 0, 0.04); // Bubble tiles $eventbubble-self-bg: #F0FBF8; $eventbubble-others-bg: $system; $eventbubble-bg-hover: #FAFBFD; -$eventbubble-avatar-outline: $primary-bg-color; +$eventbubble-avatar-outline: $background; $eventbubble-reply-color: $quaternary-content; // ***** Mixins! ***** diff --git a/res/themes/light/css/_mods.scss b/res/themes/light/css/_mods.scss index fbca58dfb1..15f6d4b0fe 100644 --- a/res/themes/light/css/_mods.scss +++ b/res/themes/light/css/_mods.scss @@ -4,27 +4,6 @@ // set the user avatar (if any) as a background so // it can be blurred by the tag panel and room list -@supports (backdrop-filter: none) { - .mx_LeftPanel { - background-image: var(--avatar-url, unset); - background-repeat: no-repeat; - background-size: cover; - background-position: left top; - } - - .mx_GroupFilterPanel { - backdrop-filter: blur($groupFilterPanel-background-blur-amount); - } - - .mx_SpacePanel { - backdrop-filter: blur($groupFilterPanel-background-blur-amount); - } - - .mx_LeftPanel .mx_LeftPanel_roomListContainer { - backdrop-filter: blur($roomlist-background-blur-amount); - } -} - .mx_RoomSublist_showNButton { background-color: transparent !important; } diff --git a/scripts/ci/js-sdk-to-release.js b/scripts/ci/js-sdk-to-release.js new file mode 100755 index 0000000000..e1fecfde03 --- /dev/null +++ b/scripts/ci/js-sdk-to-release.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node + +const fsProm = require('fs/promises'); + +const PKGJSON = 'node_modules/matrix-js-sdk/package.json'; + +async function main() { + const pkgJson = JSON.parse(await fsProm.readFile(PKGJSON, 'utf8')); + for (const field of ['main', 'typings']) { + if (pkgJson["matrix_lib_"+field] !== undefined) { + pkgJson[field] = pkgJson["matrix_lib_"+field]; + } + } + await fsProm.writeFile(PKGJSON, JSON.stringify(pkgJson, null, 2)); +} + +main(); diff --git a/scripts/fetchdep.sh b/scripts/fetchdep.sh index 0990af70ce..ec021236d9 100755 --- a/scripts/fetchdep.sh +++ b/scripts/fetchdep.sh @@ -10,6 +10,7 @@ defbranch="$3" rm -r "$defrepo" || true +# A function that clones a branch of a repo based on the org, repo and branch clone() { org=$1 repo=$2 @@ -21,45 +22,38 @@ clone() { fi } -# Try the PR author's branch in case it exists on the deps as well. -# First we check if GITHUB_HEAD_REF is defined, -# Then we check if BUILDKITE_BRANCH is defined, -# if they aren't we can assume this is a Netlify build -if [ -n "$GITHUB_HEAD_REF" ]; then - head=$GITHUB_HEAD_REF -elif [ -n "$BUILDKITE_BRANCH" ]; then - head=$BUILDKITE_BRANCH -else - # Netlify doesn't give us info about the fork so we have to get it from GitHub API - apiEndpoint="https://api.github.com/repos/matrix-org/matrix-react-sdk/pulls/" - apiEndpoint+=$REVIEW_ID - head=$(curl $apiEndpoint | jq -r '.head.label') -fi +# A function that gets info about a PR from the GitHub API based on its number +getPRInfo() { + number=$1 + if [ -n "$number" ]; then + echo "Getting info about a PR with number $number" -# If head is set, it will contain on Buildkite either: -# * "branch" when the author's branch and target branch are in the same repo -# * "fork:branch" when the author's branch is in their fork or if this is a Netlify build -# We can split on `:` into an array to check. -# For GitHub Actions we need to inspect GITHUB_REPOSITORY and GITHUB_ACTOR -# to determine whether the branch is from a fork or not -BRANCH_ARRAY=(${head//:/ }) -if [[ "${#BRANCH_ARRAY[@]}" == "1" ]]; then + apiEndpoint="https://api.github.com/repos/matrix-org/matrix-react-sdk/pulls/" + apiEndpoint+=$number - if [ -n "$GITHUB_HEAD_REF" ]; then - if [[ "$GITHUB_REPOSITORY" == "$deforg"* ]]; then - clone $deforg $defrepo $GITHUB_HEAD_REF - else - REPO_ARRAY=(${GITHUB_REPOSITORY//\// }) - clone $REPO_ARRAY[0] $defrepo $GITHUB_HEAD_REF - fi - else - clone $deforg $defrepo $BUILDKITE_BRANCH + head=$(curl $apiEndpoint | jq -r '.head.label') fi +} -elif [[ "${#BRANCH_ARRAY[@]}" == "2" ]]; then - clone ${BRANCH_ARRAY[0]} $defrepo ${BRANCH_ARRAY[1]} +# Some CIs don't give us enough info, so we just get the PR number and ask the +# GH API for more info - "fork:branch". Some give us this directly. +if [ -n "$BUILDKITE_BRANCH" ]; then + # BuildKite + head=$BUILDKITE_BRANCH +elif [ -n "$PR_NUMBER" ]; then + # GitHub + getPRInfo $PR_NUMBER +elif [ -n "$REVIEW_ID" ]; then + # Netlify + getPRInfo $REVIEW_ID fi +# $head will always be in the format "fork:branch", so we split it by ":" into +# an array. The first element will then be the fork and the second the branch. +# Based on that we clone +BRANCH_ARRAY=(${head//:/ }) +clone ${BRANCH_ARRAY[0]} $defrepo ${BRANCH_ARRAY[1]} + # Try the target branch of the push or PR. if [ -n $GITHUB_BASE_REF ]; then clone $deforg $defrepo $GITHUB_BASE_REF diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 9d6bc2c6fb..8ad93fa960 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -93,6 +93,26 @@ declare global { mxSetupEncryptionStore?: SetupEncryptionStore; mxRoomScrollStateStore?: RoomScrollStateStore; mxOnRecaptchaLoaded?: () => void; + electron?: Electron; + } + + interface DesktopCapturerSource { + id: string; + name: string; + thumbnailURL: string; + } + + interface GetSourcesOptions { + types: Array; + thumbnailSize?: { + height: number; + width: number; + }; + fetchWindowIcons?: boolean; + } + + interface Electron { + getDesktopCapturerSources(options: GetSourcesOptions): Promise>; } interface Document { diff --git a/src/CallHandler.tsx b/src/CallHandler.tsx index f2142f56f4..fe938c9929 100644 --- a/src/CallHandler.tsx +++ b/src/CallHandler.tsx @@ -250,7 +250,15 @@ export default class CallHandler extends EventEmitter { * @returns {boolean} */ private areAnyCallsUnsilenced(): boolean { - return this.calls.size > this.silencedCalls.size; + for (const call of this.calls.values()) { + if ( + call.state === CallState.Ringing && + !this.isCallSilenced(call.callId) + ) { + return true; + } + } + return false; } private async checkProtocols(maxTries) { @@ -464,85 +472,7 @@ export default class CallHandler extends EventEmitter { this.removeCallForRoom(mappedRoomId); }); call.on(CallEvent.State, (newState: CallState, oldState: CallState) => { - if (!this.matchesCallForThisRoom(call)) return; - - this.setCallState(call, newState); - - switch (oldState) { - case CallState.Ringing: - this.pause(AudioID.Ring); - break; - case CallState.InviteSent: - this.pause(AudioID.Ringback); - break; - } - - if (newState !== CallState.Ringing) { - this.silencedCalls.delete(call.callId); - } - - switch (newState) { - case CallState.Ringing: { - const incomingCallPushRule = ( - new PushProcessor(MatrixClientPeg.get()).getPushRuleById(RuleId.IncomingCall) - ); - const pushRuleEnabled = incomingCallPushRule?.enabled; - const tweakSetToRing = incomingCallPushRule?.actions.some((action: Tweaks) => ( - action.set_tweak === TweakName.Sound && - action.value === "ring" - )); - - if (pushRuleEnabled && tweakSetToRing) { - this.play(AudioID.Ring); - } else { - this.silenceCall(call.callId); - } - break; - } - case CallState.InviteSent: { - this.play(AudioID.Ringback); - break; - } - case CallState.Ended: { - const hangupReason = call.hangupReason; - Analytics.trackEvent('voip', 'callEnded', 'hangupReason', hangupReason); - this.removeCallForRoom(mappedRoomId); - if (oldState === CallState.InviteSent && call.hangupParty === CallParty.Remote) { - this.play(AudioID.Busy); - - // Don't show a modal when we got rejected/the call was hung up - if (!hangupReason || [CallErrorCode.UserHangup, "user hangup"].includes(hangupReason)) break; - - let title; - let description; - // TODO: We should either do away with these or figure out a copy for each code (expect user_hangup...) - if (call.hangupReason === CallErrorCode.UserBusy) { - title = _t("User Busy"); - description = _t("The user you called is busy."); - } else { - title = _t("Call Failed"); - description = _t("The call could not be established"); - } - - Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, { - title, description, - }); - } else if ( - hangupReason === CallErrorCode.AnsweredElsewhere && oldState === CallState.Connecting - ) { - Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, { - title: _t("Answered Elsewhere"), - description: _t("The call was answered on another device."), - }); - } else if (oldState !== CallState.Fledgling && oldState !== CallState.Ringing) { - // don't play the end-call sound for calls that never got off the ground - this.play(AudioID.CallEnd); - } - - this.logCallStats(call, mappedRoomId); - break; - } - } + this.onCallStateChanged(newState, oldState, call); }); call.on(CallEvent.Replaced, (newCall: MatrixCall) => { if (!this.matchesCallForThisRoom(call)) return; @@ -555,8 +485,8 @@ export default class CallHandler extends EventEmitter { this.pause(AudioID.Ringback); } - this.calls.set(mappedRoomId, newCall); - this.emit(CallHandlerEvent.CallsChanged, this.calls); + this.removeCallForRoom(mappedRoomId); + this.addCallForRoom(mappedRoomId, newCall); this.setCallListeners(newCall); this.setCallState(newCall, newCall.state); }); @@ -591,13 +521,95 @@ export default class CallHandler extends EventEmitter { this.removeCallForRoom(mappedRoomId); mappedRoomId = newMappedRoomId; console.log("Moving call to room " + mappedRoomId); - this.calls.set(mappedRoomId, call); - this.emit(CallHandlerEvent.CallChangeRoom, call); + this.addCallForRoom(mappedRoomId, call, true); } } }); } + private onCallStateChanged = (newState: CallState, oldState: CallState, call: MatrixCall): void => { + if (!this.matchesCallForThisRoom(call)) return; + + const mappedRoomId = this.roomIdForCall(call); + this.setCallState(call, newState); + + switch (oldState) { + case CallState.Ringing: + this.pause(AudioID.Ring); + break; + case CallState.InviteSent: + this.pause(AudioID.Ringback); + break; + } + + if (newState !== CallState.Ringing) { + this.silencedCalls.delete(call.callId); + } + + switch (newState) { + case CallState.Ringing: { + const incomingCallPushRule = ( + new PushProcessor(MatrixClientPeg.get()).getPushRuleById(RuleId.IncomingCall) + ); + const pushRuleEnabled = incomingCallPushRule?.enabled; + const tweakSetToRing = incomingCallPushRule?.actions.some((action: Tweaks) => ( + action.set_tweak === TweakName.Sound && + action.value === "ring" + )); + + if (pushRuleEnabled && tweakSetToRing) { + this.play(AudioID.Ring); + } else { + this.silenceCall(call.callId); + } + break; + } + case CallState.InviteSent: { + this.play(AudioID.Ringback); + break; + } + case CallState.Ended: { + const hangupReason = call.hangupReason; + Analytics.trackEvent('voip', 'callEnded', 'hangupReason', hangupReason); + this.removeCallForRoom(mappedRoomId); + if (oldState === CallState.InviteSent && call.hangupParty === CallParty.Remote) { + this.play(AudioID.Busy); + + // Don't show a modal when we got rejected/the call was hung up + if (!hangupReason || [CallErrorCode.UserHangup, "user hangup"].includes(hangupReason)) break; + + let title; + let description; + // TODO: We should either do away with these or figure out a copy for each code (expect user_hangup...) + if (call.hangupReason === CallErrorCode.UserBusy) { + title = _t("User Busy"); + description = _t("The user you called is busy."); + } else { + title = _t("Call Failed"); + description = _t("The call could not be established"); + } + + Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, { + title, description, + }); + } else if ( + hangupReason === CallErrorCode.AnsweredElsewhere && oldState === CallState.Connecting + ) { + Modal.createTrackedDialog('Call Handler', 'Call Failed', ErrorDialog, { + title: _t("Answered Elsewhere"), + description: _t("The call was answered on another device."), + }); + } else if (oldState !== CallState.Fledgling && oldState !== CallState.Ringing) { + // don't play the end-call sound for calls that never got off the ground + this.play(AudioID.CallEnd); + } + + this.logCallStats(call, mappedRoomId); + break; + } + } + }; + private async logCallStats(call: MatrixCall, mappedRoomId: string) { const stats = await call.getCurrentCallStats(); logger.debug( @@ -743,9 +755,15 @@ export default class CallHandler extends EventEmitter { console.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms"); const call = MatrixClientPeg.get().createCall(mappedRoomId); - console.log("Adding call for room ", roomId); - this.calls.set(roomId, call); - this.emit(CallHandlerEvent.CallsChanged, this.calls); + try { + this.addCallForRoom(roomId, call); + } catch (e) { + Modal.createTrackedDialog('Call Handler', 'Existing Call with user', ErrorDialog, { + title: _t('Already in call'), + description: _t("You're already in a call with this person."), + }); + return; + } if (transferee) { this.transferees[call.callId] = transferee; } @@ -797,13 +815,8 @@ export default class CallHandler extends EventEmitter { return; } - if (this.getCallForRoom(room.roomId)) { - Modal.createTrackedDialog('Call Handler', 'Existing Call with user', ErrorDialog, { - title: _t('Already in call'), - description: _t("You're already in a call with this person."), - }); - return; - } + // We leave the check for whether there's already a call in this room until later, + // otherwise it can race. const members = room.getJoinedMembers(); if (members.length <= 1) { @@ -857,10 +870,11 @@ export default class CallHandler extends EventEmitter { } Analytics.trackEvent('voip', 'receiveCall', 'type', call.type); - console.log("Adding call for room ", mappedRoomId); - this.calls.set(mappedRoomId, call); - this.emit(CallHandlerEvent.CallsChanged, this.calls); + + this.addCallForRoom(mappedRoomId, call); this.setCallListeners(call); + // Explicitly handle first state change + this.onCallStateChanged(call.state, null, call); // get ready to send encrypted events in the room, so if the user does answer // the call, we'll be ready to send. NB. This is the protocol-level room ID not @@ -871,6 +885,8 @@ export default class CallHandler extends EventEmitter { break; case 'hangup': case 'reject': + this.stopRingingIfPossible(this.calls.get(payload.room_id).callId); + if (!this.calls.get(payload.room_id)) { return; // no call to hangup } @@ -883,11 +899,15 @@ export default class CallHandler extends EventEmitter { // the hangup event away) break; case 'hangup_all': + this.stopRingingIfPossible(this.calls.get(payload.room_id).callId); + for (const call of this.calls.values()) { call.hangup(CallErrorCode.UserHangup, false); } break; case 'answer': { + this.stopRingingIfPossible(this.calls.get(payload.room_id).callId); + if (!this.calls.has(payload.room_id)) { return; // no call to answer } @@ -922,6 +942,12 @@ export default class CallHandler extends EventEmitter { } }; + private stopRingingIfPossible(callId: string): void { + this.silencedCalls.delete(callId); + if (this.areAnyCallsUnsilenced()) return; + this.pause(AudioID.Ring); + } + private async dialNumber(number: string) { const results = await this.pstnLookup(number); if (!results || results.length === 0 || !results[0].userid) { @@ -1123,4 +1149,21 @@ export default class CallHandler extends EventEmitter { messaging.transport.send(ElementWidgetActions.HangupCall, {}); }); } + + private addCallForRoom(roomId: string, call: MatrixCall, changedRooms = false): void { + if (this.calls.has(roomId)) { + console.log(`Couldn't add call to room ${roomId}: already have a call for this room`); + throw new Error("Already have a call for room " + roomId); + } + + console.log("setting call for room " + roomId); + this.calls.set(roomId, call); + + // Should we always emit CallsChanged too? + if (changedRooms) { + this.emit(CallHandlerEvent.CallChangeRoom, call); + } else { + this.emit(CallHandlerEvent.CallsChanged, this.calls); + } + } } diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index 14a0c1ed51..40f8e307a5 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -39,6 +39,8 @@ import { import { IUpload } from "./models/IUpload"; import { IAbortablePromise, IImageInfo } from "matrix-js-sdk/src/@types/partials"; import { BlurhashEncoder } from "./BlurhashEncoder"; +import SettingsStore from "./settings/SettingsStore"; +import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics"; const MAX_WIDTH = 800; const MAX_HEIGHT = 600; @@ -539,6 +541,10 @@ export default class ContentMessages { msgtype: "", // set later }; + if (SettingsStore.getValue("Performance.addSendMessageTimingMetadata")) { + decorateStartSendingTime(content); + } + // if we have a mime type for the file, add it to the message metadata if (file.type) { content.info.mimetype = file.type; @@ -614,6 +620,11 @@ export default class ContentMessages { }).then(function() { if (upload.canceled) throw new UploadCanceledError(); const prom = matrixClient.sendMessage(roomId, content); + if (SettingsStore.getValue("Performance.addSendMessageTimingMetadata")) { + prom.then(resp => { + sendRoundTripMetric(matrixClient, roomId, resp.event_id); + }); + } CountlyAnalytics.instance.trackSendMessage(startTime, prom, roomId, false, false, content); return prom; }, function(err) { diff --git a/src/DateUtils.ts b/src/DateUtils.ts index e8b81ca315..c81099b893 100644 --- a/src/DateUtils.ts +++ b/src/DateUtils.ts @@ -136,6 +136,18 @@ export function formatCallTime(delta: Date): string { return output; } +export function formatSeconds(inSeconds: number): string { + const hours = Math.floor(inSeconds / (60 * 60)).toFixed(0).padStart(2, '0'); + const minutes = Math.floor((inSeconds % (60 * 60)) / 60).toFixed(0).padStart(2, '0'); + const seconds = Math.floor(((inSeconds % (60 * 60)) % 60)).toFixed(0).padStart(2, '0'); + + let output = ""; + if (hours !== "00") output += `${hours}:`; + output += `${minutes}:${seconds}`; + + return output; +} + const MILLIS_IN_DAY = 86400000; export function wantsDateSeparator(prevEventDate: Date, nextEventDate: Date): boolean { if (!nextEventDate || !prevEventDate) { diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index 51c624e3c3..1a551d7813 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -100,6 +100,7 @@ export default class DeviceListener { * @param {String[]} deviceIds List of device IDs to dismiss notifications for */ async dismissUnverifiedSessions(deviceIds: Iterable) { + console.log("Dismissing unverified sessions: " + Array.from(deviceIds).join(',')); for (const d of deviceIds) { this.dismissed.add(d); } @@ -285,6 +286,9 @@ export default class DeviceListener { } } + console.log("Old unverified sessions: " + Array.from(oldUnverifiedDeviceIds).join(',')); + console.log("New unverified sessions: " + Array.from(newUnverifiedDeviceIds).join(',')); + // Display or hide the batch toast for old unverified sessions if (oldUnverifiedDeviceIds.size > 0) { showBulkUnverifiedSessionsToast(oldUnverifiedDeviceIds); diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index f43351aab2..7d0ff560b7 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -213,6 +213,7 @@ class MatrixClientPegClass implements IMatrixClientPeg { opts.pendingEventOrdering = PendingEventOrdering.Detached; opts.lazyLoadMembers = true; opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours + opts.experimentalThreadSupport = SettingsStore.getValue("feature_thread"); // Connect the matrix client to the dispatcher and setting handlers MatrixActionCreators.start(this.matrixClient); diff --git a/src/MediaDeviceHandler.ts b/src/MediaDeviceHandler.ts index 073f24523d..154f167745 100644 --- a/src/MediaDeviceHandler.ts +++ b/src/MediaDeviceHandler.ts @@ -17,8 +17,8 @@ limitations under the License. import SettingsStore from "./settings/SettingsStore"; import { SettingLevel } from "./settings/SettingLevel"; -import { setMatrixCallAudioInput, setMatrixCallVideoInput } from "matrix-js-sdk/src/matrix"; import EventEmitter from 'events'; +import { MatrixClientPeg } from "./MatrixClientPeg"; // XXX: MediaDeviceKind is a union type, so we make our own enum export enum MediaDeviceKindEnum { @@ -74,8 +74,8 @@ export default class MediaDeviceHandler extends EventEmitter { const audioDeviceId = SettingsStore.getValue("webrtc_audioinput"); const videoDeviceId = SettingsStore.getValue("webrtc_videoinput"); - setMatrixCallAudioInput(audioDeviceId); - setMatrixCallVideoInput(videoDeviceId); + MatrixClientPeg.get().getMediaHandler().setAudioInput(audioDeviceId); + MatrixClientPeg.get().getMediaHandler().setVideoInput(videoDeviceId); } public setAudioOutput(deviceId: string): void { @@ -90,7 +90,7 @@ export default class MediaDeviceHandler extends EventEmitter { */ public setAudioInput(deviceId: string): void { SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId); - setMatrixCallAudioInput(deviceId); + MatrixClientPeg.get().getMediaHandler().setAudioInput(deviceId); } /** @@ -100,7 +100,7 @@ export default class MediaDeviceHandler extends EventEmitter { */ public setVideoInput(deviceId: string): void { SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId); - setMatrixCallVideoInput(deviceId); + MatrixClientPeg.get().getMediaHandler().setVideoInput(deviceId); } public setDevice(deviceId: string, kind: MediaDeviceKindEnum): void { diff --git a/src/PasswordReset.js b/src/PasswordReset.ts similarity index 89% rename from src/PasswordReset.js rename to src/PasswordReset.ts index 88ae00d088..76f54de245 100644 --- a/src/PasswordReset.js +++ b/src/PasswordReset.ts @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { createClient } from 'matrix-js-sdk/src/matrix'; +import { createClient, IRequestTokenResponse, MatrixClient } from 'matrix-js-sdk/src/matrix'; import { _t } from './languageHandler'; /** @@ -26,12 +26,18 @@ import { _t } from './languageHandler'; * API on the homeserver in question with the new password. */ export default class PasswordReset { + private client: MatrixClient; + private clientSecret: string; + private identityServerDomain: string; + private password: string; + private sessionId: string; + /** * Configure the endpoints for password resetting. * @param {string} homeserverUrl The URL to the HS which has the account to reset. * @param {string} identityUrl The URL to the IS which has linked the email -> mxid mapping. */ - constructor(homeserverUrl, identityUrl) { + constructor(homeserverUrl: string, identityUrl: string) { this.client = createClient({ baseUrl: homeserverUrl, idBaseUrl: identityUrl, @@ -47,7 +53,7 @@ export default class PasswordReset { * @param {string} newPassword The new password for the account. * @return {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked(). */ - resetPassword(emailAddress, newPassword) { + public resetPassword(emailAddress: string, newPassword: string): Promise { this.password = newPassword; return this.client.requestPasswordEmailToken(emailAddress, this.clientSecret, 1).then((res) => { this.sessionId = res.sid; @@ -69,7 +75,7 @@ export default class PasswordReset { * with a "message" property which contains a human-readable message detailing why * the reset failed, e.g. "There is no mapped matrix user ID for the given email address". */ - async checkEmailLinkClicked() { + public async checkEmailLinkClicked(): Promise { const creds = { sid: this.sessionId, client_secret: this.clientSecret, diff --git a/src/Resend.ts b/src/Resend.ts index 38b84a28e0..be9fb9550b 100644 --- a/src/Resend.ts +++ b/src/Resend.ts @@ -48,11 +48,6 @@ export default class Resend { // XXX: temporary logging to try to diagnose // https://github.com/vector-im/element-web/issues/3148 console.log('Resend got send failure: ' + err.name + '(' + err + ')'); - - dis.dispatch({ - action: 'message_send_failed', - event: event, - }); }); } diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx index b4deb6d8c4..902c82fff8 100644 --- a/src/SlashCommands.tsx +++ b/src/SlashCommands.tsx @@ -50,7 +50,6 @@ import CallHandler from "./CallHandler"; import { guessAndSetDMRoom } from "./Rooms"; import { upgradeRoom } from './utils/RoomUpgrade'; import UploadConfirmDialog from './components/views/dialogs/UploadConfirmDialog'; -import ErrorDialog from './components/views/dialogs/ErrorDialog'; import DevtoolsDialog from './components/views/dialogs/DevtoolsDialog'; import RoomUpgradeWarningDialog from "./components/views/dialogs/RoomUpgradeWarningDialog"; import InfoDialog from "./components/views/dialogs/InfoDialog"; @@ -245,21 +244,6 @@ export const Commands = [ }, category: CommandCategories.messages, }), - new Command({ - command: 'ddg', - args: '', - description: _td('Searches DuckDuckGo for results'), - runFn: function() { - // TODO Don't explain this away, actually show a search UI here. - Modal.createTrackedDialog('Slash Commands', '/ddg is not a command', ErrorDialog, { - title: _t('/ddg is not a command'), - description: _t('To use it, just wait for autocomplete results to load and tab through them.'), - }); - return success(); - }, - category: CommandCategories.actions, - hideCompletionAfterSpace: true, - }), new Command({ command: 'upgraderoom', args: '', diff --git a/src/TextForEvent.tsx b/src/TextForEvent.tsx index b9295be3ed..0e9dc1cf15 100644 --- a/src/TextForEvent.tsx +++ b/src/TextForEvent.tsx @@ -441,6 +441,15 @@ function textForPowerEvent(event: MatrixEvent): () => string | null { }); } +const onPinnedOrUnpinnedMessageClick = (messageId: string, roomId: string): void => { + defaultDispatcher.dispatch({ + action: 'view_room', + event_id: messageId, + highlighted: true, + room_id: roomId, + }); +}; + const onPinnedMessagesClick = (): void => { defaultDispatcher.dispatch({ action: Action.SetRightPanelPhase, @@ -452,17 +461,77 @@ const onPinnedMessagesClick = (): void => { function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null { if (!SettingsStore.getValue("feature_pinning")) return null; const senderName = event.sender ? event.sender.name : event.getSender(); + const roomId = event.getRoomId(); + + const pinned = event.getContent().pinned ?? []; + const previouslyPinned = event.getPrevContent().pinned ?? []; + const newlyPinned = pinned.filter(item => previouslyPinned.indexOf(item) < 0); + const newlyUnpinned = previouslyPinned.filter(item => pinned.indexOf(item) < 0); + + if (newlyPinned.length === 1 && newlyUnpinned.length === 0) { + // A single message was pinned, include a link to that message. + if (allowJSX) { + const messageId = newlyPinned.pop(); + + return () => ( + + { _t( + "%(senderName)s pinned a message to this room. See all pinned messages.", + { senderName }, + { + "a": (sub) => + onPinnedOrUnpinnedMessageClick(messageId, roomId)}> + { sub } + , + "b": (sub) => + + { sub } + , + }, + ) } + + ); + } + + return () => _t("%(senderName)s pinned a message to this room. See all pinned messages.", { senderName }); + } + + if (newlyUnpinned.length === 1 && newlyPinned.length === 0) { + // A single message was unpinned, include a link to that message. + if (allowJSX) { + const messageId = newlyUnpinned.pop(); + + return () => ( + + { _t( + "%(senderName)s unpinned a message from this room. See all pinned messages.", + { senderName }, + { + "a": (sub) => + onPinnedOrUnpinnedMessageClick(messageId, roomId)}> + { sub } + , + "b": (sub) => + + { sub } + , + }, + ) } + + ); + } + + return () => _t("%(senderName)s unpinned a message from this room. See all pinned messages.", { senderName }); + } if (allowJSX) { return () => ( - { - _t( - "%(senderName)s changed the pinned messages for the room.", - { senderName }, - { "a": (sub) => { sub } }, - ) - } + { _t( + "%(senderName)s changed the pinned messages for the room.", + { senderName }, + { "a": (sub) => { sub } }, + ) } ); } diff --git a/src/audio/ManagedPlayback.ts b/src/audio/ManagedPlayback.ts index bff6ce7088..5db07671f1 100644 --- a/src/audio/ManagedPlayback.ts +++ b/src/audio/ManagedPlayback.ts @@ -26,7 +26,7 @@ export class ManagedPlayback extends Playback { } public async play(): Promise { - this.manager.playOnly(this); + this.manager.pauseAllExcept(this); return super.play(); } diff --git a/src/audio/Playback.ts b/src/audio/Playback.ts index 9dad828a79..03f3bad760 100644 --- a/src/audio/Playback.ts +++ b/src/audio/Playback.ts @@ -117,6 +117,8 @@ export class Playback extends EventEmitter implements IDestroyable { } public destroy() { + // Dev note: It's critical that we call stop() during cleanup to ensure that downstream callers + // are aware of the final clock position before the user triggered an unload. // noinspection JSIgnoredPromiseFromCall - not concerned about being called async here this.stop(); this.removeAllListeners(); @@ -177,9 +179,12 @@ export class Playback extends EventEmitter implements IDestroyable { this.waveformObservable.update(this.resampledWaveform); - this.emit(PlaybackState.Stopped); // signal that we're not decoding anymore this.clock.flagLoadTime(); // must happen first because setting the duration fires a clock update this.clock.durationSeconds = this.element ? this.element.duration : this.audioBuf.duration; + + // Signal that we're not decoding anymore. This is done last to ensure the clock is updated for + // when the downstream callers try to use it. + this.emit(PlaybackState.Stopped); // signal that we're not decoding anymore } private onPlaybackEnd = async () => { diff --git a/src/audio/PlaybackClock.ts b/src/audio/PlaybackClock.ts index 712d1bfa94..5716d6ac2f 100644 --- a/src/audio/PlaybackClock.ts +++ b/src/audio/PlaybackClock.ts @@ -89,9 +89,9 @@ export class PlaybackClock implements IDestroyable { return this.observable; } - private checkTime = () => { + private checkTime = (force = false) => { const now = this.timeSeconds; // calculated dynamically - if (this.lastCheck !== now) { + if (this.lastCheck !== now || force) { this.observable.update([now, this.durationSeconds]); this.lastCheck = now; } @@ -141,7 +141,7 @@ export class PlaybackClock implements IDestroyable { public syncTo(contextTime: number, clipTime: number) { this.clipStart = contextTime - clipTime; this.stopped = false; // count as a mid-stream pause (if we were stopped) - this.checkTime(); + this.checkTime(true); } public destroy() { diff --git a/src/audio/PlaybackManager.ts b/src/audio/PlaybackManager.ts index 58fa61df56..58c0b9b624 100644 --- a/src/audio/PlaybackManager.ts +++ b/src/audio/PlaybackManager.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { DEFAULT_WAVEFORM, Playback } from "./Playback"; +import { DEFAULT_WAVEFORM, Playback, PlaybackState } from "./Playback"; import { ManagedPlayback } from "./ManagedPlayback"; /** @@ -34,12 +34,14 @@ export class PlaybackManager { } /** - * Stops all other playback instances. If no playback is provided, all instances - * are stopped. + * Pauses all other playback instances. If no playback is provided, all playing + * instances are paused. * @param playback Optional. The playback to leave untouched. */ - public playOnly(playback?: Playback) { - this.instances.filter(p => p !== playback).forEach(p => p.stop()); + public pauseAllExcept(playback?: Playback) { + this.instances + .filter(p => p !== playback && p.currentState === PlaybackState.Playing) + .forEach(p => p.pause()); } public destroyPlaybackInstance(playback: ManagedPlayback) { diff --git a/src/audio/PlaybackQueue.ts b/src/audio/PlaybackQueue.ts new file mode 100644 index 0000000000..611b88938a --- /dev/null +++ b/src/audio/PlaybackQueue.ts @@ -0,0 +1,219 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { Playback, PlaybackState } from "./Playback"; +import { UPDATE_EVENT } from "../stores/AsyncStore"; +import { MatrixClientPeg } from "../MatrixClientPeg"; +import { arrayFastClone } from "../utils/arrays"; +import { PlaybackManager } from "./PlaybackManager"; +import { isVoiceMessage } from "../utils/EventUtils"; +import RoomViewStore from "../stores/RoomViewStore"; +import { EventType } from "matrix-js-sdk/src/@types/event"; + +/** + * Audio playback queue management for a given room. This keeps track of where the user + * was at for each playback, what order the playbacks were played in, and triggers subsequent + * playbacks. + * + * Currently this is only intended to be used by voice messages. + * + * The primary mechanics are: + * * Persisted clock state for each playback instance (tied to Event ID). + * * Limited memory of playback order (see code; not persisted). + * * Autoplay of next eligible playback instance. + */ +export class PlaybackQueue { + private static queues = new Map(); // keyed by room ID + + private playbacks = new Map(); // keyed by event ID + private clockStates = new Map(); // keyed by event ID + private playbackIdOrder: string[] = []; // event IDs, last == current + private currentPlaybackId: string; // event ID, broken out from above for ease of use + private recentFullPlays = new Set(); // event IDs + + constructor(private client: MatrixClient, private room: Room) { + this.loadClocks(); + + RoomViewStore.addListener(() => { + if (RoomViewStore.getRoomId() === this.room.roomId) { + // Reset the state of the playbacks before they start mounting and enqueuing updates. + // We reset the entirety of the queue, including order, to ensure the user isn't left + // confused with what order the messages are playing in. + this.currentPlaybackId = null; // this in particular stops autoplay when the room is switched to + this.recentFullPlays = new Set(); + this.playbackIdOrder = []; + } + }); + } + + public static forRoom(roomId: string): PlaybackQueue { + const cli = MatrixClientPeg.get(); + const room = cli.getRoom(roomId); + if (!room) throw new Error("Unknown room"); + if (PlaybackQueue.queues.has(room.roomId)) { + return PlaybackQueue.queues.get(room.roomId); + } + const queue = new PlaybackQueue(cli, room); + PlaybackQueue.queues.set(room.roomId, queue); + return queue; + } + + private persistClocks() { + localStorage.setItem( + `mx_voice_message_clocks_${this.room.roomId}`, + JSON.stringify(Array.from(this.clockStates.entries())), + ); + } + + private loadClocks() { + const val = localStorage.getItem(`mx_voice_message_clocks_${this.room.roomId}`); + if (!!val) { + this.clockStates = new Map(JSON.parse(val)); + } + } + + public unsortedEnqueue(mxEvent: MatrixEvent, playback: Playback) { + // We don't ever detach our listeners: we expect the Playback to clean up for us + this.playbacks.set(mxEvent.getId(), playback); + playback.on(UPDATE_EVENT, (state) => this.onPlaybackStateChange(playback, mxEvent, state)); + playback.clockInfo.liveData.onUpdate((clock) => this.onPlaybackClock(playback, mxEvent, clock)); + } + + private onPlaybackStateChange(playback: Playback, mxEvent: MatrixEvent, newState: PlaybackState) { + // Remember where the user got to in playback + const wasLastPlaying = this.currentPlaybackId === mxEvent.getId(); + if (newState === PlaybackState.Stopped && this.clockStates.has(mxEvent.getId()) && !wasLastPlaying) { + // noinspection JSIgnoredPromiseFromCall + playback.skipTo(this.clockStates.get(mxEvent.getId())); + } else if (newState === PlaybackState.Stopped) { + // Remove the now-useless clock for some space savings + this.clockStates.delete(mxEvent.getId()); + + if (wasLastPlaying) { + this.recentFullPlays.add(this.currentPlaybackId); + const orderClone = arrayFastClone(this.playbackIdOrder); + const last = orderClone.pop(); + if (last === this.currentPlaybackId) { + const next = orderClone.pop(); + if (next) { + const instance = this.playbacks.get(next); + if (!instance) { + console.warn( + "Voice message queue desync: Missing playback for next message: " + + `Current=${this.currentPlaybackId} Last=${last} Next=${next}`, + ); + } else { + this.playbackIdOrder = orderClone; + PlaybackManager.instance.pauseAllExcept(instance); + + // This should cause a Play event, which will re-populate our playback order + // and update our current playback ID. + // noinspection JSIgnoredPromiseFromCall + instance.play(); + } + } else { + // else no explicit next event, so find an event we haven't played that comes next. The live + // timeline is already most recent last, so we can iterate down that. + const timeline = arrayFastClone(this.room.getLiveTimeline().getEvents()); + let scanForVoiceMessage = false; + let nextEv: MatrixEvent; + for (const event of timeline) { + if (event.getId() === mxEvent.getId()) { + scanForVoiceMessage = true; + continue; + } + if (!scanForVoiceMessage) continue; + + if (!isVoiceMessage(event)) { + const evType = event.getType(); + if (evType !== EventType.RoomMessage && evType !== EventType.Sticker) { + continue; // Event can be skipped for automatic playback consideration + } + break; // Stop automatic playback: next useful event is not a voice message + } + + const havePlayback = this.playbacks.has(event.getId()); + const isRecentlyCompleted = this.recentFullPlays.has(event.getId()); + if (havePlayback && !isRecentlyCompleted) { + nextEv = event; + break; + } + } + if (!nextEv) { + // if we don't have anywhere to go, reset the recent playback queue so the user + // can start a new chain of playbacks. + this.recentFullPlays = new Set(); + this.playbackIdOrder = []; + } else { + this.playbackIdOrder = orderClone; + + const instance = this.playbacks.get(nextEv.getId()); + PlaybackManager.instance.pauseAllExcept(instance); + + // This should cause a Play event, which will re-populate our playback order + // and update our current playback ID. + // noinspection JSIgnoredPromiseFromCall + instance.play(); + } + } + } else { + console.warn( + "Voice message queue desync: Expected playback stop to be last in order. " + + `Current=${this.currentPlaybackId} Last=${last} EventID=${mxEvent.getId()}`, + ); + } + } + } + + if (newState === PlaybackState.Playing) { + const order = this.playbackIdOrder; + if (this.currentPlaybackId !== mxEvent.getId() && !!this.currentPlaybackId) { + if (order.length === 0 || order[order.length - 1] !== this.currentPlaybackId) { + const lastInstance = this.playbacks.get(this.currentPlaybackId); + if ( + lastInstance.currentState === PlaybackState.Playing + || lastInstance.currentState === PlaybackState.Paused + ) { + order.push(this.currentPlaybackId); + } + } + } + + this.currentPlaybackId = mxEvent.getId(); + if (order.length === 0 || order[order.length - 1] !== this.currentPlaybackId) { + order.push(this.currentPlaybackId); + } + } + + // Only persist clock information on pause/stop (end) to avoid overwhelming the storage. + // This should get triggered from normal voice message component unmount due to the playback + // stopping itself for cleanup. + if (newState === PlaybackState.Paused || newState === PlaybackState.Stopped) { + this.persistClocks(); + } + } + + private onPlaybackClock(playback: Playback, mxEvent: MatrixEvent, clocks: number[]) { + if (playback.currentState === PlaybackState.Decoding) return; // ignore pre-ready values + + if (playback.currentState !== PlaybackState.Stopped) { + this.clockStates.set(mxEvent.getId(), clocks[0]); // [0] is the current seek position + } + } +} diff --git a/src/audio/RecorderWorklet.ts b/src/audio/RecorderWorklet.ts index 2d1bb0bcd2..73b053db93 100644 --- a/src/audio/RecorderWorklet.ts +++ b/src/audio/RecorderWorklet.ts @@ -45,7 +45,13 @@ class MxVoiceWorklet extends AudioWorkletProcessor { process(inputs, outputs, parameters) { const currentSecond = roundTimeToTargetFreq(currentTime); - if (currentSecond === this.nextAmplitudeSecond) { + // We special case the first ping because there's a fairly good chance that we'll miss the zeroth + // update. Firefox for instance takes 0.06 seconds (roughly) to call this function for the first + // time. Edge and Chrome occasionally lag behind too, but for the most part are on time. + // + // When this doesn't work properly we end up producing a waveform of nulls and no live preview + // of the recorded message. + if (currentSecond === this.nextAmplitudeSecond || this.nextAmplitudeSecond === 0) { // We're expecting exactly one mono input source, so just grab the very first frame of // samples for the analysis. const monoChan = inputs[0][0]; diff --git a/src/autocomplete/Autocompleter.ts b/src/autocomplete/Autocompleter.ts index acc7846510..4c9e82f290 100644 --- a/src/autocomplete/Autocompleter.ts +++ b/src/autocomplete/Autocompleter.ts @@ -20,7 +20,6 @@ import { Room } from 'matrix-js-sdk/src/models/room'; import CommandProvider from './CommandProvider'; import CommunityProvider from './CommunityProvider'; -import DuckDuckGoProvider from './DuckDuckGoProvider'; import RoomProvider from './RoomProvider'; import UserProvider from './UserProvider'; import EmojiProvider from './EmojiProvider'; @@ -55,7 +54,6 @@ const PROVIDERS = [ EmojiProvider, NotifProvider, CommandProvider, - DuckDuckGoProvider, ]; if (SpaceStore.spacesEnabled) { diff --git a/src/autocomplete/CommandProvider.tsx b/src/autocomplete/CommandProvider.tsx index d56adc026c..143b7e4cdc 100644 --- a/src/autocomplete/CommandProvider.tsx +++ b/src/autocomplete/CommandProvider.tsx @@ -53,7 +53,7 @@ export default class CommandProvider extends AutocompleteProvider { // The input looks like a command with arguments, perform exact match const name = command[1].substr(1); // strip leading `/` if (CommandMap.has(name) && CommandMap.get(name).isEnabled()) { - // some commands, namely `me` and `ddg` don't suit having the usage shown whilst typing their arguments + // some commands, namely `me` don't suit having the usage shown whilst typing their arguments if (CommandMap.get(name).hideCompletionAfterSpace) return []; matches = [CommandMap.get(name)]; } @@ -95,7 +95,7 @@ export default class CommandProvider extends AutocompleteProvider { renderCompletions(completions: React.ReactNode[]): React.ReactNode { return (
diff --git a/src/autocomplete/DuckDuckGoProvider.tsx b/src/autocomplete/DuckDuckGoProvider.tsx deleted file mode 100644 index c41a91b97f..0000000000 --- a/src/autocomplete/DuckDuckGoProvider.tsx +++ /dev/null @@ -1,115 +0,0 @@ -/* -Copyright 2016 Aviral Dasgupta -Copyright 2017 Vector Creations Ltd -Copyright 2017, 2018 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import { _t } from '../languageHandler'; -import AutocompleteProvider from './AutocompleteProvider'; - -import { TextualCompletion } from './Components'; -import { ICompletion, ISelectionRange } from "./Autocompleter"; - -const DDG_REGEX = /\/ddg\s+(.+)$/g; -const REFERRER = 'vector'; - -export default class DuckDuckGoProvider extends AutocompleteProvider { - constructor() { - super(DDG_REGEX); - } - - static getQueryUri(query: string) { - return `https://api.duckduckgo.com/?q=${encodeURIComponent(query)}` - + `&format=json&no_redirect=1&no_html=1&t=${encodeURIComponent(REFERRER)}`; - } - - async getCompletions( - query: string, - selection: ISelectionRange, - force = false, - limit = -1, - ): Promise { - const { command, range } = this.getCurrentCommand(query, selection); - if (!query || !command) { - return []; - } - - const response = await fetch(DuckDuckGoProvider.getQueryUri(command[1]), { - method: 'GET', - }); - const json = await response.json(); - const maxLength = limit > -1 ? limit : json.Results.length; - const results = json.Results.slice(0, maxLength).map((result) => { - return { - completion: result.Text, - component: ( - - ), - range, - }; - }); - if (json.Answer) { - results.unshift({ - completion: json.Answer, - component: ( - - ), - range, - }); - } - if (json.RelatedTopics && json.RelatedTopics.length > 0) { - results.unshift({ - completion: json.RelatedTopics[0].Text, - component: ( - - ), - range, - }); - } - if (json.AbstractText) { - results.unshift({ - completion: json.AbstractText, - component: ( - - ), - range, - }); - } - return results; - } - - getName() { - return '🔍 ' + _t('Results from DuckDuckGo'); - } - - renderCompletions(completions: React.ReactNode[]): React.ReactNode { - return ( -
- { completions } -
- ); - } -} diff --git a/src/autocomplete/EmojiProvider.tsx b/src/autocomplete/EmojiProvider.tsx index 0aae8c6372..326651e037 100644 --- a/src/autocomplete/EmojiProvider.tsx +++ b/src/autocomplete/EmojiProvider.tsx @@ -67,7 +67,7 @@ export default class EmojiProvider extends AutocompleteProvider { constructor() { super(EMOJI_REGEX); this.matcher = new QueryMatcher(SORTED_EMOJI, { - keys: ['emoji.emoticon'], + keys: [], funcs: [o => o.emoji.shortcodes.map(s => `:${s}:`)], // For matching against ascii equivalents shouldMatchWordsOnly: false, @@ -91,7 +91,8 @@ export default class EmojiProvider extends AutocompleteProvider { let completions = []; const { command, range } = this.getCurrentCommand(query, selection); - if (command) { + + if (command && command[0].length > 2) { const matchedString = command[0]; completions = this.matcher.match(matchedString, limit); diff --git a/src/components/structures/BackdropPanel.tsx b/src/components/structures/BackdropPanel.tsx new file mode 100644 index 0000000000..08f6c33738 --- /dev/null +++ b/src/components/structures/BackdropPanel.tsx @@ -0,0 +1,44 @@ +/* +Copyright 2021 New Vector Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { CSSProperties } from "react"; + +interface IProps { + backgroundImage?: string; + blurMultiplier?: number; +} + +export const BackdropPanel: React.FC = ({ backgroundImage, blurMultiplier }) => { + if (!backgroundImage) return null; + + const styles: CSSProperties = {}; + if (blurMultiplier) { + const rootStyle = getComputedStyle(document.documentElement); + const blurValue = rootStyle.getPropertyValue('--lp-background-blur'); + const pixelsValue = blurValue.replace('px', ''); + const parsed = parseInt(pixelsValue, 10); + if (!isNaN(parsed)) { + styles.filter = `blur(${parsed * blurMultiplier}px)`; + } + } + return
+ +
; +}; +export default BackdropPanel; diff --git a/src/components/structures/CallEventGrouper.ts b/src/components/structures/CallEventGrouper.ts index b48bb32efe..84e004d1de 100644 --- a/src/components/structures/CallEventGrouper.ts +++ b/src/components/structures/CallEventGrouper.ts @@ -25,6 +25,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher"; export enum CallEventGrouperEvent { StateChanged = "state_changed", SilencedChanged = "silenced_changed", + LengthChanged = "length_changed", } const CONNECTING_STATES = [ @@ -104,8 +105,12 @@ export default class CallEventGrouper extends EventEmitter { return ![...this.events].some((event) => event.sender?.userId === MatrixClientPeg.get().getUserId()); } - private get callId(): string { - return [...this.events][0].getContent().call_id; + private get callId(): string | undefined { + return [...this.events][0]?.getContent()?.call_id; + } + + private get roomId(): string | undefined { + return [...this.events][0]?.getRoomId(); } private onSilencedCallsChanged = () => { @@ -113,19 +118,29 @@ export default class CallEventGrouper extends EventEmitter { this.emit(CallEventGrouperEvent.SilencedChanged, newState); }; + private onLengthChanged = (length: number): void => { + this.emit(CallEventGrouperEvent.LengthChanged, length); + }; + public answerCall = () => { - this.call?.answer(); + defaultDispatcher.dispatch({ + action: 'answer', + room_id: this.roomId, + }); }; public rejectCall = () => { - this.call?.reject(); + defaultDispatcher.dispatch({ + action: 'reject', + room_id: this.roomId, + }); }; public callBack = () => { defaultDispatcher.dispatch({ action: 'place_call', type: this.isVoice ? CallType.Voice : CallType.Video, - room_id: [...this.events][0]?.getRoomId(), + room_id: this.roomId, }); }; @@ -139,6 +154,7 @@ export default class CallEventGrouper extends EventEmitter { private setCallListeners() { if (!this.call) return; this.call.addListener(CallEvent.State, this.setState); + this.call.addListener(CallEvent.LengthChanged, this.onLengthChanged); } private setState = () => { diff --git a/src/components/structures/ContextMenu.tsx b/src/components/structures/ContextMenu.tsx index 332b6cd318..d65f8e3a10 100644 --- a/src/components/structures/ContextMenu.tsx +++ b/src/components/structures/ContextMenu.tsx @@ -322,10 +322,16 @@ export class ContextMenu extends React.PureComponent { const menuClasses = classNames({ 'mx_ContextualMenu': true, - 'mx_ContextualMenu_left': !hasChevron && position.left, - 'mx_ContextualMenu_right': !hasChevron && position.right, - 'mx_ContextualMenu_top': !hasChevron && position.top, - 'mx_ContextualMenu_bottom': !hasChevron && position.bottom, + /** + * In some cases we may get the number of 0, which still means that we're supposed to properly + * add the specific position class, but as it was falsy things didn't work as intended. + * In addition, defensively check for counter cases where we may get more than one value, + * even if we shouldn't. + */ + 'mx_ContextualMenu_left': !hasChevron && position.left !== undefined && !position.right, + 'mx_ContextualMenu_right': !hasChevron && position.right !== undefined && !position.left, + 'mx_ContextualMenu_top': !hasChevron && position.top !== undefined && !position.bottom, + 'mx_ContextualMenu_bottom': !hasChevron && position.bottom !== undefined && !position.top, 'mx_ContextualMenu_withChevron_left': chevronFace === ChevronFace.Left, 'mx_ContextualMenu_withChevron_right': chevronFace === ChevronFace.Right, 'mx_ContextualMenu_withChevron_top': chevronFace === ChevronFace.Top, @@ -404,17 +410,27 @@ export class ContextMenu extends React.PureComponent { } } +export type ToRightOf = { + left: number; + top: number; + chevronOffset: number; +}; + // Placement method for to position context menu to right of elementRect with chevronOffset -export const toRightOf = (elementRect: Pick, chevronOffset = 12) => { +export const toRightOf = (elementRect: Pick, chevronOffset = 12): ToRightOf => { const left = elementRect.right + window.pageXOffset + 3; let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset; top -= chevronOffset + 8; // where 8 is half the height of the chevron return { left, top, chevronOffset }; }; +export type AboveLeftOf = IPosition & { + chevronFace: ChevronFace; +}; + // Placement method for to position context menu right-aligned and flowing to the left of elementRect, // and either above or below: wherever there is more space (maybe this should be aboveOrBelowLeftOf?) -export const aboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFace.None, vPadding = 0) => { +export const aboveLeftOf = (elementRect: DOMRect, chevronFace = ChevronFace.None, vPadding = 0): AboveLeftOf => { const menuOptions: IPosition & { chevronFace: ChevronFace } = { chevronFace }; const buttonRight = elementRect.right + window.pageXOffset; diff --git a/src/components/structures/GroupFilterPanel.js b/src/components/structures/GroupFilterPanel.tsx similarity index 71% rename from src/components/structures/GroupFilterPanel.js rename to src/components/structures/GroupFilterPanel.tsx index 5d1be64f25..3e7c6e9b17 100644 --- a/src/components/structures/GroupFilterPanel.js +++ b/src/components/structures/GroupFilterPanel.tsx @@ -15,6 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import type { EventSubscription } from "fbemitter"; import React from 'react'; import GroupFilterOrderStore from '../../stores/GroupFilterOrderStore'; @@ -30,22 +31,43 @@ import AutoHideScrollbar from "./AutoHideScrollbar"; import SettingsStore from "../../settings/SettingsStore"; import UserTagTile from "../views/elements/UserTagTile"; import { replaceableComponent } from "../../utils/replaceableComponent"; +import UIStore from "../../stores/UIStore"; + +interface IGroupFilterPanelProps { + +} + +// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript +type OrderedTagsTemporaryType = Array<{}>; +// FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript +type SelectedTagsTemporaryType = Array<{}>; + +interface IGroupFilterPanelState { + // FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript + orderedTags: OrderedTagsTemporaryType; + // FIXME: Properly type this after migrating GroupFilterOrderStore.js to Typescript + selectedTags: SelectedTagsTemporaryType; +} @replaceableComponent("structures.GroupFilterPanel") -class GroupFilterPanel extends React.Component { - static contextType = MatrixClientContext; +class GroupFilterPanel extends React.Component { + public static contextType = MatrixClientContext; - state = { + public state = { orderedTags: [], selectedTags: [], }; - componentDidMount() { - this.unmounted = false; - this.context.on("Group.myMembership", this._onGroupMyMembership); - this.context.on("sync", this._onClientSync); + private ref = React.createRef(); + private unmounted = false; + private groupFilterOrderStoreToken?: EventSubscription; - this._groupFilterOrderStoreToken = GroupFilterOrderStore.addListener(() => { + public componentDidMount() { + this.unmounted = false; + this.context.on("Group.myMembership", this.onGroupMyMembership); + this.context.on("sync", this.onClientSync); + + this.groupFilterOrderStoreToken = GroupFilterOrderStore.addListener(() => { if (this.unmounted) { return; } @@ -56,23 +78,25 @@ class GroupFilterPanel extends React.Component { }); // This could be done by anything with a matrix client dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); + UIStore.instance.trackElementDimensions("GroupPanel", this.ref.current); } - componentWillUnmount() { + public componentWillUnmount() { this.unmounted = true; - this.context.removeListener("Group.myMembership", this._onGroupMyMembership); - this.context.removeListener("sync", this._onClientSync); - if (this._groupFilterOrderStoreToken) { - this._groupFilterOrderStoreToken.remove(); + this.context.removeListener("Group.myMembership", this.onGroupMyMembership); + this.context.removeListener("sync", this.onClientSync); + if (this.groupFilterOrderStoreToken) { + this.groupFilterOrderStoreToken.remove(); } + UIStore.instance.stopTrackingElementDimensions("GroupPanel"); } - _onGroupMyMembership = () => { + private onGroupMyMembership = () => { if (this.unmounted) return; dis.dispatch(GroupActions.fetchJoinedGroups(this.context)); }; - _onClientSync = (syncState, prevState) => { + private onClientSync = (syncState, prevState) => { // Consider the client reconnected if there is no error with syncing. // This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP. const reconnected = syncState !== "ERROR" && prevState !== syncState; @@ -82,18 +106,18 @@ class GroupFilterPanel extends React.Component { } }; - onClick = e => { + private onClick = e => { // only dispatch if its not a no-op if (this.state.selectedTags.length > 0) { dis.dispatch({ action: 'deselect_tags' }); } }; - onClearFilterClick = ev => { + private onClearFilterClick = ev => { dis.dispatch({ action: 'deselect_tags' }); }; - renderGlobalIcon() { + private renderGlobalIcon() { if (!SettingsStore.getValue("feature_communities_v2_prototypes")) return null; return ( @@ -104,7 +128,7 @@ class GroupFilterPanel extends React.Component { ); } - render() { + public render() { const DNDTagTile = sdk.getComponent('elements.DNDTagTile'); const ActionButton = sdk.getComponent('elements.ActionButton'); @@ -147,7 +171,7 @@ class GroupFilterPanel extends React.Component { ); } - return
+ return
{ private ref: React.RefObject = createRef(); private listContainerRef: React.RefObject = createRef(); - private groupFilterPanelWatcherRef: string; - private bgImageWatcherRef: string; private focusedElement = null; private isDoingStickyHeaders = false; @@ -80,22 +72,16 @@ export default class LeftPanel extends React.Component { this.state = { showBreadcrumbs: BreadcrumbsStore.instance.visible, - showGroupFilterPanel: SettingsStore.getValue('TagPanel.enableTagPanel'), activeSpace: SpaceStore.instance.activeSpace, }; BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); - OwnProfileStore.instance.on(UPDATE_EVENT, this.onBackgroundImageUpdate); SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace); - this.bgImageWatcherRef = SettingsStore.watchSetting( - "RoomList.backgroundImage", null, this.onBackgroundImageUpdate); - this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => { - this.setState({ showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel") }); - }); } public componentDidMount() { + UIStore.instance.trackElementDimensions("LeftPanel", this.ref.current); UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current); UIStore.instance.on("ListContainer", this.refreshStickyHeaders); // Using the passive option to not block the main thread @@ -104,11 +90,8 @@ export default class LeftPanel extends React.Component { } public componentWillUnmount() { - SettingsStore.unwatchSetting(this.groupFilterPanelWatcherRef); - SettingsStore.unwatchSetting(this.bgImageWatcherRef); BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); - OwnProfileStore.instance.off(UPDATE_EVENT, this.onBackgroundImageUpdate); SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace); UIStore.instance.stopTrackingElementDimensions("ListContainer"); UIStore.instance.removeListener("ListContainer", this.refreshStickyHeaders); @@ -149,23 +132,6 @@ export default class LeftPanel extends React.Component { } }; - private onBackgroundImageUpdate = () => { - // Note: we do this in the LeftPanel as it uses this variable most prominently. - const avatarSize = 32; // arbitrary - let avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize); - const settingBgMxc = SettingsStore.getValue("RoomList.backgroundImage"); - if (settingBgMxc) { - avatarUrl = mediaFromMxc(settingBgMxc).getSquareThumbnailHttp(avatarSize); - } - - const avatarUrlProp = `url(${avatarUrl})`; - if (!avatarUrl) { - document.body.style.removeProperty("--avatar-url"); - } else if (document.body.style.getPropertyValue("--avatar-url") !== avatarUrlProp) { - document.body.style.setProperty("--avatar-url", avatarUrlProp); - } - }; - private handleStickyHeaders(list: HTMLDivElement) { if (this.isDoingStickyHeaders) return; this.isDoingStickyHeaders = true; @@ -433,23 +399,15 @@ export default class LeftPanel extends React.Component { mx_LeftPanel_exploreButton_space: !!this.state.activeSpace, })} onClick={this.onExplore} - title={_t("Explore rooms")} + title={this.state.activeSpace + ? _t("Explore %(spaceName)s", { spaceName: this.state.activeSpace.name }) + : _t("Explore rooms")} />
); } public render(): React.ReactNode { - let leftLeftPanel; - if (this.state.showGroupFilterPanel) { - leftLeftPanel = ( -
- - { SettingsStore.getValue("feature_custom_tags") ? : null } -
- ); - } - const roomList = { return (
- { leftLeftPanel }