Merge branch 'develop' into improved-forwarding-ui

pull/21833/head
Robin Townsend 2021-05-21 08:15:09 -04:00
commit f34d61cf5d
24 changed files with 213 additions and 297 deletions

View File

@ -115,8 +115,3 @@ limitations under the License.
border-top: 8px solid $menu-bg-color;
border-right: 8px solid transparent;
}
.mx_ContextualMenu_spinner {
display: block;
margin: 0 auto;
}

View File

@ -18,7 +18,11 @@ limitations under the License.
display: inline;
}
.mx_InlineSpinner_spin img {
.mx_InlineSpinner img, .mx_InlineSpinner_icon {
margin: 0px 6px;
vertical-align: -3px;
}
.mx_InlineSpinner_icon {
display: inline-block;
}

View File

@ -28,8 +28,7 @@ limitations under the License.
top: 0;
}
&::before, &::after {
content: '';
.mx_MiniAvatarUploader_indicator {
position: absolute;
height: 26px;
@ -37,27 +36,22 @@ limitations under the License.
right: -6px;
bottom: -6px;
}
&::before {
background-color: $primary-bg-color;
border-radius: 50%;
z-index: 1;
}
&::after {
background-color: $secondary-fg-color;
mask-position: center;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/element-icons/camera.svg');
mask-size: 16px;
z-index: 2;
}
.mx_MiniAvatarUploader_cameraIcon {
height: 100%;
width: 100%;
&.mx_MiniAvatarUploader_busy::after {
background: url("$(res)/img/spinner.gif") no-repeat center;
background-size: 80%;
mask: unset;
background-color: $secondary-fg-color;
mask-position: center;
mask-repeat: no-repeat;
mask-image: url('$(res)/img/element-icons/camera.svg');
mask-size: 16px;
z-index: 2;
}
}
}

View File

@ -26,3 +26,19 @@ limitations under the License.
.mx_MatrixChat_middlePanel .mx_Spinner {
height: auto;
}
@keyframes spin {
from {
transform: rotateZ(0deg);
}
to {
transform: rotateZ(360deg);
}
}
.mx_Spinner_icon {
background-color: $primary-fg-color;
mask: url('$(res)/img/spinner.svg');
mask-size: contain;
animation: 1.1s steps(12, end) infinite spin;
}

View File

@ -36,6 +36,7 @@ limitations under the License.
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre-wrap;
}
.mx_RoomSummaryCard_avatar {

View File

@ -18,8 +18,8 @@ limitations under the License.
margin: 40px 0 48px 64px;
.mx_MiniAvatarUploader_hasAvatar:not(.mx_MiniAvatarUploader_busy):not(:hover) {
&::before, &::after {
content: unset;
.mx_MiniAvatarUploader_indicator {
display: none;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,141 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink" preserveAspectRatio="none" viewBox="0 0 375 375" style="background-color:#FFFFFF00; overflow:visible">
<title>start</title>
<!-- Layers -->
<!-- Layer: Icon -->
<svg x="188" y="187" width="0.01" height="0.01" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 1 1;0 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="188;187.75;187.5"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 1 1;0 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="187;187.25;187.5"/>
<g transform="scale(1 1)">
<g transform="rotate(0)">
<animateTransform attributeName="transform" calcMode="spline" dur="2" fill="freeze" keySplines="0.42 0 1 1;0 0 0.58 1" keyTimes="0;0.5;1"
repeatCount="indefinite" type="rotate" values="0;180;360"/>
<svg x="-100" y="-100" width="200" height="200" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 1 1;0 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-100;-117.5;-100"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 1 1;0 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-100;-117.5;-100"/>
<animate attributeName="width" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 1 1;0 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="200;235;200"/>
<animate attributeName="height" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 1 1;0 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="200;235;200"/>
<g clip-path="">
<g filter="">
<!-- Layer: 1024@2x -->
<svg x="100" y="100" width="0.01" height="0.01" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="100;117.5;100"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="100;117.5;100"/>
<g transform="scale(1 1)">
<g transform="rotate(0)">
<svg x="-100" y="-100" width="200" height="200" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-100;-117.5;-100"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-100;-117.5;-100"/>
<animate attributeName="width" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="200;235;200"/>
<animate attributeName="height" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="200;235;200"/>
<g clip-path="">
<g filter="">
<!-- Layer: Path -->
<svg x="118" y="46" width="0.01" height="0.01" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="118;138.65;118"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="46;54.05;46"/>
<g transform="scale(1 1)">
<g transform="rotate(0)">
<svg x="-46" y="-46" width="92" height="92" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="width" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<animate attributeName="height" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<g clip-path="">
<g filter="">
<path d="M0,12c0,-6.627,5.373,-12,12,-12 44.183,0,80,35.817,80,80 0,6.627,-5.373,12,-12,12 -6.627,0,-12,-5.373,-12,-12 0,-30.928,-25.072,-56,-56,-56 -6.627,0,-12,-5.373,-12,-12zM0,12" fill="#0DBD8B" id="path" stroke="#00000000" stroke-dasharray="0" stroke-dashoffset="0" stroke-miterlimit="10" stroke-width="0">
<animate attributeName="d" calcMode="spline" dur="2s" fill="freeze" href="#path" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="M0,12c0,-6.627,5.373,-12,12,-12 44.183,0,80,35.817,80,80 0,6.627,-5.373,12,-12,12 -6.627,0,-12,-5.373,-12,-12 0,-30.928,-25.072,-56,-56,-56 -6.627,0,-12,-5.373,-12,-12zM0,12;M0,14.1c0,-7.787,6.313,-14.1,14.1,-14.1 51.915,0,94,42.085,94,94 0,7.787,-6.313,14.1,-14.1,14.1 -7.787,0,-14.1,-6.313,-14.1,-14.1 0,-36.34,-29.46,-65.8,-65.8,-65.8 -7.787,0,-14.1,-6.313,-14.1,-14.1zM0,14.1;M0,12c0,-6.627,5.373,-12,12,-12 44.183,0,80,35.817,80,80 0,6.627,-5.373,12,-12,12 -6.627,0,-12,-5.373,-12,-12 0,-30.928,-25.072,-56,-56,-56 -6.627,0,-12,-5.373,-12,-12zM0,12"/>
</path>
</g>
</g>
</svg>
</g>
</g>
</svg>
<!-- Layer: Path -->
<svg x="82" y="154" width="0.01" height="0.01" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="82;96.35;82"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="154;180.95;154"/>
<g transform="scale(1 1)">
<g transform="rotate(0)">
<svg x="-46" y="-46" width="92" height="92" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="width" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<animate attributeName="height" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<g clip-path="">
<g filter="">
<path d="M92,80c0,6.627,-5.373,12,-12,12 -44.183,0,-80,-35.817,-80,-80 0,-6.627,5.373,-12,12,-12 6.627,0,12,5.373,12,12 0,30.928,25.072,56,56,56 6.627,0,12,5.373,12,12zM92,80" fill="#0DBD8B" id="path_1" stroke="#00000000" stroke-dasharray="0" stroke-dashoffset="0" stroke-miterlimit="10" stroke-width="0">
<animate attributeName="d" calcMode="spline" dur="2s" fill="freeze" href="#path_1" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="M92,80c0,6.627,-5.373,12,-12,12 -44.183,0,-80,-35.817,-80,-80 0,-6.627,5.373,-12,12,-12 6.627,0,12,5.373,12,12 0,30.928,25.072,56,56,56 6.627,0,12,5.373,12,12zM92,80;M108.1,94c0,7.787,-6.313,14.1,-14.1,14.1 -51.915,0,-94,-42.085,-94,-94 0,-7.787,6.313,-14.1,14.1,-14.1 7.787,0,14.1,6.313,14.1,14.1 0,36.34,29.46,65.8,65.8,65.8 7.787,0,14.1,6.313,14.1,14.1zM108.1,94;M92,80c0,6.627,-5.373,12,-12,12 -44.183,0,-80,-35.817,-80,-80 0,-6.627,5.373,-12,12,-12 6.627,0,12,5.373,12,12 0,30.928,25.072,56,56,56 6.627,0,12,5.373,12,12zM92,80"/>
</path>
</g>
</g>
</svg>
</g>
</g>
</svg>
<!-- Layer: Path -->
<svg x="46" y="82" width="0.01" height="0.01" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="46;54.05;46"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="82;96.35;82"/>
<g transform="scale(1 1)">
<g transform="rotate(0)">
<svg x="-46" y="-46" width="92" height="92" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="width" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<animate attributeName="height" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<g clip-path="">
<g filter="">
<path d="M12,92c-6.627,0,-12,-5.373,-12,-12 0,-44.183,35.817,-80,80,-80 6.627,0,12,5.373,12,12 0,6.627,-5.373,12,-12,12 -30.928,0,-56,25.072,-56,56 0,6.627,-5.373,12,-12,12zM12,92" fill="#0DBD8B" id="path_2" stroke="#00000000" stroke-dasharray="0" stroke-dashoffset="0" stroke-miterlimit="10" stroke-width="0">
<animate attributeName="d" calcMode="spline" dur="2s" fill="freeze" href="#path_2" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="M12,92c-6.627,0,-12,-5.373,-12,-12 0,-44.183,35.817,-80,80,-80 6.627,0,12,5.373,12,12 0,6.627,-5.373,12,-12,12 -30.928,0,-56,25.072,-56,56 0,6.627,-5.373,12,-12,12zM12,92;M14.1,108.1c-7.787,0,-14.1,-6.313,-14.1,-14.1 0,-51.915,42.085,-94,94,-94 7.787,0,14.1,6.313,14.1,14.1 0,7.787,-6.313,14.1,-14.1,14.1 -36.34,0,-65.8,29.46,-65.8,65.8 0,7.787,-6.313,14.1,-14.1,14.1zM14.1,108.1;M12,92c-6.627,0,-12,-5.373,-12,-12 0,-44.183,35.817,-80,80,-80 6.627,0,12,5.373,12,12 0,6.627,-5.373,12,-12,12 -30.928,0,-56,25.072,-56,56 0,6.627,-5.373,12,-12,12zM12,92"/>
</path>
</g>
</g>
</svg>
</g>
</g>
</svg>
<!-- Layer: Path -->
<svg x="154" y="118" width="0.01" height="0.01" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="154;180.95;154"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="118;138.65;118"/>
<g transform="scale(1 1)">
<g transform="rotate(0)">
<svg x="-46" y="-46" width="92" height="92" style ="overflow:visible" opacity="1">
<animate attributeName="x" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="y" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="-46;-54.05;-46"/>
<animate attributeName="width" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<animate attributeName="height" calcMode="spline" dur="2s" fill="freeze" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="92;108.1;92"/>
<g clip-path="">
<g filter="">
<path d="M80,0c6.627,0,12,5.373,12,12 0,44.183,-35.817,80,-80,80 -6.627,0,-12,-5.373,-12,-12 0,-6.627,5.373,-12,12,-12 30.928,0,56,-25.072,56,-56 0,-6.627,5.373,-12,12,-12zM80,0" fill="#0DBD8B" id="path_3" stroke="#00000000" stroke-dasharray="0" stroke-dashoffset="0" stroke-miterlimit="10" stroke-width="0">
<animate attributeName="d" calcMode="spline" dur="2s" fill="freeze" href="#path_3" keySplines="0.42 0 0.58 1;0.42 0 0.58 1" keyTimes="0;0.5;1" repeatCount="indefinite" values="M80,0c6.627,0,12,5.373,12,12 0,44.183,-35.817,80,-80,80 -6.627,0,-12,-5.373,-12,-12 0,-6.627,5.373,-12,12,-12 30.928,0,56,-25.072,56,-56 0,-6.627,5.373,-12,12,-12zM80,0;M94,0c7.787,0,14.1,6.313,14.1,14.1 0,51.915,-42.085,94,-94,94 -7.787,0,-14.1,-6.313,-14.1,-14.1 0,-7.787,6.313,-14.1,14.1,-14.1 36.34,0,65.8,-29.46,65.8,-65.8 0,-7.787,6.313,-14.1,14.1,-14.1zM94,0;M80,0c6.627,0,12,5.373,12,12 0,44.183,-35.817,80,-80,80 -6.627,0,-12,-5.373,-12,-12 0,-6.627,5.373,-12,12,-12 30.928,0,56,-25.072,56,-56 0,-6.627,5.373,-12,12,-12zM80,0"/>
</path>
</g>
</g>
</svg>
</g>
</g>
</svg>
</g>
</g>
</svg>
</g>
</g>
</svg>
</g>
</g>
</svg>
</g>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
viewBox="0 0 33.866666 33.866668"
version="1.1"
id="svg920"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
sodipodi:docname="spinner.svg">
<defs
id="defs914" />
<metadata
id="metadata917">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="stroke-width:0;fill-opacity:0.30000001"
d="M 59,95.605469 V 123 c 0,2.77 2.23,5 5,5 2.77,0 5,-2.23 5,-5 V 95.605469 A 31.999998,31.999998 0 0 1 64,96 31.999998,31.999998 0 0 1 59,95.605469 Z"
transform="scale(0.26458333)"
id="path2350" />
<path
style="stroke-width:0;fill-opacity:0.7020452"
d="M 64,0 C 61.23,0 59,2.2300001 59,5 V 32.394531 A 31.999998,31.999998 0 0 1 64,32 31.999998,31.999998 0 0 1 69,32.394531 V 5 C 69,2.2300001 66.77,0 64,0 Z"
transform="scale(0.26458333)"
id="rect2283" />
<path
style="stroke-width:0;fill-opacity:0.30000001"
d="M 43.867188,88.871094 30.169922,112.5957 c -1.385,2.39889 -0.568812,5.44508 1.830078,6.83008 2.39889,1.385 5.445078,0.56881 6.830078,-1.83008 L 52.527344,93.873047 a 31.999998,31.999998 0 0 1 -8.660156,-5.001953 z"
transform="scale(0.26458333)"
id="path2346" />
<path
style="stroke-width:0;fill-opacity:0.80019373"
d="m 93.150391,7.9121094 c -1.599848,0.111837 -3.114844,0.992881 -3.980469,2.4921876 L 75.472656,34.126953 a 31.999998,31.999998 0 0 1 8.660156,5.001953 L 97.830078,15.404297 C 99.215078,13.005407 98.39889,9.9592187 96,8.5742188 95.100416,8.0548438 94.110299,7.8450072 93.150391,7.9121094 Z"
transform="scale(0.26458333)"
id="rect2285" />
<path
style="stroke-width:0;fill-opacity:0.30000001"
d="M 34.126953,75.474609 10.404297,89.169922 C 8.0054066,90.554922 7.1892188,93.60111 8.5742188,96 c 1.3849999,2.39889 4.4311882,3.215078 6.8300782,1.830078 L 39.128906,84.132812 a 31.999998,31.999998 0 0 1 -5.001953,-8.658203 z"
transform="scale(0.26458333)"
id="path2342" />
<path
style="stroke-width:0;fill-opacity:0.90226436"
d="m 115.44531,29.507812 c -0.95991,-0.0671 -1.95002,0.142735 -2.84961,0.66211 L 88.871094,43.867188 a 31.999998,31.999998 0 0 1 5.001953,8.658203 L 117.5957,38.830078 c 2.39889,-1.385 3.21508,-4.431188 1.83008,-6.830078 -0.86562,-1.499306 -2.38062,-2.38035 -3.98047,-2.492188 z"
transform="scale(0.26458333)"
id="rect2287" />
<path
style="stroke-width:0;fill-opacity:1"
d="M 95.605469,59 A 31.999998,31.999998 0 0 1 96,64 31.999998,31.999998 0 0 1 95.605469,69 H 123 c 2.77,0 5,-2.23 5,-5 0,-2.77 -2.23,-5 -5,-5 z"
transform="scale(0.26458333)"
id="path2338" />
<path
style="stroke-width:0;fill-opacity:0.40288368"
d="m 5,59 c -2.7699999,0 -5,2.23 -5,5 0,2.77 2.2300001,5 5,5 H 32.394531 A 31.999998,31.999998 0 0 1 32,64 31.999998,31.999998 0 0 1 32.394531,59 Z"
transform="scale(0.26458333)"
id="rect2289" />
<path
style="stroke-width:0;fill-opacity:0.30000001"
d="m 93.873047,75.472656 a 31.999998,31.999998 0 0 1 -5.001953,8.660156 L 112.5957,97.830078 c 2.39889,1.385 5.44508,0.568812 6.83008,-1.830078 1.385,-2.39889 0.56881,-5.445078 -1.83008,-6.830078 z"
transform="scale(0.26458333)"
id="path2334" />
<path
style="stroke-width:0;fill-opacity:0.49898377"
d="M 12.554688,29.507812 C 10.95484,29.61965 9.4398437,30.500694 8.5742188,32 c -1.385,2.39889 -0.5688122,5.445078 1.8300782,6.830078 l 23.722656,13.697266 a 31.999998,31.999998 0 0 1 5.001953,-8.660156 L 15.404297,30.169922 c -0.899584,-0.519375 -1.889701,-0.729212 -2.849609,-0.66211 z"
transform="scale(0.26458333)"
id="rect2291" />
<path
style="stroke-width:0;fill-opacity:0.30000001"
d="m 84.132812,88.871094 a 31.999998,31.999998 0 0 1 -8.658203,5.001953 L 89.169922,117.5957 c 1.385,2.39889 4.431188,3.21508 6.830078,1.83008 2.39889,-1.385 3.215078,-4.43119 1.830078,-6.83008 z"
transform="scale(0.26458333)"
id="path2330" />
<path
style="stroke-width:0;fill-opacity:0.5998317"
d="M 34.849609,7.9121094 C 33.889701,7.8450072 32.899584,8.0548438 32,8.5742188 29.60111,9.9592187 28.784922,13.005407 30.169922,15.404297 l 13.697266,23.724609 a 31.999998,31.999998 0 0 1 8.658203,-5.001953 L 38.830078,10.404297 C 37.964453,8.9049904 36.449457,8.0239464 34.849609,7.9121094 Z"
transform="scale(0.26458333)"
id="rect2293" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -1583,33 +1583,6 @@ export default class RoomView extends React.Component<IProps, IState> {
this.setState({auxPanelMaxHeight: auxPanelMaxHeight});
};
private onFullscreenClick = () => {
dis.dispatch({
action: 'video_fullscreen',
fullscreen: true,
}, true);
};
private onMuteAudioClick = () => {
const call = this.getCallForRoom();
if (!call) {
return;
}
const newState = !call.isMicrophoneMuted();
call.setMicrophoneMuted(newState);
this.forceUpdate(); // TODO: just update the voip buttons
};
private onMuteVideoClick = () => {
const call = this.getCallForRoom();
if (!call) {
return;
}
const newState = !call.isLocalVideoMuted();
call.setLocalVideoMuted(newState);
this.forceUpdate(); // TODO: just update the voip buttons
};
private onStatusBarVisible = () => {
if (this.unmounted) return;
this.setState({
@ -1625,24 +1598,6 @@ export default class RoomView extends React.Component<IProps, IState> {
});
};
/**
* called by the parent component when PageUp/Down/etc is pressed.
*
* We pass it down to the scroll panel.
*/
private handleScrollKey = ev => {
let panel;
if (this.searchResultsPanel.current) {
panel = this.searchResultsPanel.current;
} else if (this.messagePanel) {
panel = this.messagePanel;
}
if (panel) {
panel.handleScrollKey(ev);
}
};
/**
* get any current call for this room
*/

View File

@ -76,7 +76,7 @@ export interface ISpaceSummaryEvent {
order?: string;
suggested?: boolean;
auto_join?: boolean;
via?: string;
via?: string[];
};
}
/* eslint-enable camelcase */
@ -356,9 +356,9 @@ export const useSpaceSummary = (cli: MatrixClient, space: Room, refreshToken?: a
parentChildRelations.getOrCreate(ev.room_id, new Map()).set(ev.state_key, ev);
childParentRelations.getOrCreate(ev.state_key, new Set()).add(ev.room_id);
}
if (Array.isArray(ev.content["via"])) {
if (Array.isArray(ev.content.via)) {
const set = viaMap.getOrCreate(ev.state_key, new Set());
ev.content["via"].forEach(via => set.add(via));
ev.content.via.forEach(via => set.add(via));
}
});

View File

@ -806,7 +806,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
let suggestedRooms = SpaceStore.instance.suggestedRooms;
if (SpaceStore.instance.activeSpace !== this.props.space) {
// the space store has the suggested rooms loaded for a different space, fetch the right ones
suggestedRooms = (await SpaceStore.instance.fetchSuggestedRooms(this.props.space, 1)).rooms;
suggestedRooms = (await SpaceStore.instance.fetchSuggestedRooms(this.props.space, 1));
}
if (suggestedRooms.length) {
@ -814,9 +814,11 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
defaultDispatcher.dispatch({
action: "view_room",
room_id: room.room_id,
room_alias: room.canonical_alias || room.aliases?.[0],
via_servers: room.viaServers,
oobData: {
avatarUrl: room.avatar_url,
name: room.name || room.canonical_alias || room.aliases.pop() || _t("Empty room"),
name: room.name || room.canonical_alias || room.aliases?.[0] || _t("Empty room"),
},
});
return;

View File

@ -16,7 +16,6 @@ limitations under the License.
import React from "react";
import {_t} from "../../../languageHandler";
import SettingsStore from "../../../settings/SettingsStore";
import {replaceableComponent} from "../../../utils/replaceableComponent";
@replaceableComponent("views.elements.InlineSpinner")
@ -24,24 +23,14 @@ export default class InlineSpinner extends React.Component {
render() {
const w = this.props.w || 16;
const h = this.props.h || 16;
const imgClass = this.props.imgClassName || "";
let imageSource;
if (SettingsStore.getValue('feature_new_spinner')) {
imageSource = require("../../../../res/img/spinner.svg");
} else {
imageSource = require("../../../../res/img/spinner.gif");
}
return (
<div className="mx_InlineSpinner">
<img
src={imageSource}
width={w}
height={h}
className={imgClass}
<div
className="mx_InlineSpinner_icon mx_Spinner_icon"
style={{width: w, height: h}}
aria-label={_t("Loading...")}
/>
></div>
</div>
);
}

View File

@ -19,6 +19,7 @@ import {EventType} from 'matrix-js-sdk/src/@types/event';
import classNames from 'classnames';
import AccessibleButton from "./AccessibleButton";
import Spinner from "./Spinner";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {useTimeout} from "../../../hooks/useTimeout";
import Analytics from "../../../Analytics";
@ -88,6 +89,12 @@ const MiniAvatarUploader: React.FC<IProps> = ({ hasAvatar, hasAvatarLabel, noAva
>
{ children }
<div className="mx_MiniAvatarUploader_indicator">
{ busy ?
<Spinner w={20} h={20} /> :
<div className="mx_MiniAvatarUploader_cameraIcon"></div> }
</div>
<div className={classNames("mx_Tooltip", {
"mx_Tooltip_visible": visible,
"mx_Tooltip_invisible": !visible,

View File

@ -18,33 +18,21 @@ limitations under the License.
import React from "react";
import PropTypes from "prop-types";
import {_t} from "../../../languageHandler";
import SettingsStore from "../../../settings/SettingsStore";
const Spinner = ({w = 32, h = 32, imgClassName, message}) => {
let imageSource;
if (SettingsStore.getValue('feature_new_spinner')) {
imageSource = require("../../../../res/img/spinner.svg");
} else {
imageSource = require("../../../../res/img/spinner.gif");
}
const Spinner = ({w = 32, h = 32, message}) => (
<div className="mx_Spinner">
{ message && <React.Fragment><div className="mx_Spinner_Msg">{ message }</div>&nbsp;</React.Fragment> }
<div
className="mx_Spinner_icon"
style={{width: w, height: h}}
aria-label={_t("Loading...")}
></div>
</div>
);
return (
<div className="mx_Spinner">
{ message && <React.Fragment><div className="mx_Spinner_Msg">{ message}</div>&nbsp;</React.Fragment> }
<img
src={imageSource}
width={w}
height={h}
className={imgClassName}
aria-label={_t("Loading...")}
/>
</div>
);
};
Spinner.propTypes = {
w: PropTypes.number,
h: PropTypes.number,
imgClassName: PropTypes.string,
message: PropTypes.node,
};

View File

@ -198,7 +198,8 @@ export default class ReactionsRow extends React.PureComponent<IProps, IState> {
const cli = this.context;
let addReactionButton;
if (cli.getRoom(mxEvent.getRoomId()).currentState.maySendEvent(EventType.Reaction, cli.getUserId())) {
const room = cli.getRoom(mxEvent.getRoomId());
if (room.getMyMembership() === "join" && room.currentState.maySendEvent(EventType.Reaction, cli.getUserId())) {
addReactionButton = <ReactButton mxEvent={mxEvent} reactions={reactions} />;
}

View File

@ -45,6 +45,7 @@ import {ChevronFace, ContextMenuTooltipButton, useContextMenu} from "../../struc
import WidgetContextMenu from "../context_menus/WidgetContextMenu";
import {useRoomMemberCount} from "../../../hooks/useRoomMembers";
import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
import RoomName from "../elements/RoomName";
interface IProps {
room: Room;
@ -249,7 +250,13 @@ const RoomSummaryCard: React.FC<IProps> = ({ room, onClose }) => {
/>
</div>
<h2 title={room.name}>{ room.name }</h2>
<RoomName room={room}>
{ name => (
<h2 title={name}>
{ name }
</h2>
)}
</RoomName>
<div className="mx_RoomSummaryCard_alias" title={alias}>
{ alias }
</div>

View File

@ -1307,7 +1307,7 @@ const BasicUserInfo: React.FC<{
}
if (pendingUpdateCount > 0) {
spinner = <Spinner imgClassName="mx_ContextualMenu_spinner" />;
spinner = <Spinner />;
}
let memberDetails;

View File

@ -46,11 +46,10 @@ import { IconizedContextMenuOption, IconizedContextMenuOptionList } from "../con
import AccessibleButton from "../elements/AccessibleButton";
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
import CallHandler from "../../../CallHandler";
import SpaceStore, {SUGGESTED_ROOMS} from "../../../stores/SpaceStore";
import SpaceStore, {ISuggestedRoom, SUGGESTED_ROOMS} from "../../../stores/SpaceStore";
import {showAddExistingRooms, showCreateNewRoom, showSpaceInvite} from "../../../utils/space";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import RoomAvatar from "../avatars/RoomAvatar";
import { ISpaceSummaryRoom } from "../../structures/SpaceRoomDirectory";
interface IProps {
onKeyDown: (ev: React.KeyboardEvent) => void;
@ -66,7 +65,7 @@ interface IState {
sublists: ITagMap;
isNameFiltering: boolean;
currentRoomId?: string;
suggestedRooms: ISpaceSummaryRoom[];
suggestedRooms: ISuggestedRoom[];
}
const TAG_ORDER: TagID[] = [
@ -363,7 +362,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
return room;
};
private updateSuggestedRooms = (suggestedRooms: ISpaceSummaryRoom[]) => {
private updateSuggestedRooms = (suggestedRooms: ISuggestedRoom[]) => {
this.setState({ suggestedRooms });
};
@ -443,7 +442,9 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
const viewRoom = () => {
defaultDispatcher.dispatch({
action: "view_room",
room_alias: room.canonical_alias || room.aliases?.[0],
room_id: room.room_id,
via_servers: room.viaServers,
oobData: {
avatarUrl: room.avatar_url,
name,

View File

@ -18,6 +18,7 @@ limitations under the License.
import * as React from "react";
import { createRef, ReactComponentElement } from "react";
import { normalize } from "matrix-js-sdk/src/utils";
import { Room } from "matrix-js-sdk/src/models/room";
import classNames from 'classnames';
import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex";
@ -259,7 +260,7 @@ export default class RoomSublist extends React.Component<IProps, IState> {
const nameCondition = RoomListStore.instance.getFirstNameFilterCondition();
if (nameCondition) {
stateUpdates.filteredExtraTiles = this.props.extraTiles
.filter(t => nameCondition.matches(t.props.displayName || ""));
.filter(t => nameCondition.matches(normalize(t.props.displayName || "")));
} else if (this.state.filteredExtraTiles) {
stateUpdates.filteredExtraTiles = null;
}

View File

@ -793,7 +793,6 @@
"Send and receive voice messages": "Send and receive voice messages",
"Render LaTeX maths in messages": "Render LaTeX maths in messages",
"Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.": "Communities v2 prototypes. Requires compatible homeserver. Highly experimental - use with caution.",
"New spinner design": "New spinner design",
"Message Pinning": "Message Pinning",
"Custom user status messages": "Custom user status messages",
"Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)",

View File

@ -344,7 +344,10 @@ export function setLanguage(preferredLangs: string | string[]) {
counterpart.registerTranslations(langToUse, langData);
counterpart.setLocale(langToUse);
SettingsStore.setValue("language", null, SettingLevel.DEVICE, langToUse);
console.log("set language to " + langToUse);
// Adds a lot of noise to test runs, so disable logging there.
if (process.env.NODE_ENV !== "test") {
console.log("set language to " + langToUse);
}
// Set 'en' as fallback language:
if (langToUse !== "en") {

View File

@ -197,12 +197,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
default: false,
controller: new IncompatibleController("feature_spaces"),
},
"feature_new_spinner": {
isFeature: true,
displayName: _td("New spinner design"),
supportedLevels: LEVELS_FEATURE,
default: false,
},
"feature_pinning": {
isFeature: true,
displayName: _td("Message Pinning"),
@ -730,7 +724,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {
default: Layout.Group,
},
"showChatEffects": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
displayName: _td("Show chat effects (animations when receiving e.g. confetti)"),
default: true,
controller: new ReducedMotionController(),

View File

@ -45,6 +45,10 @@ export const UPDATE_INVITED_SPACES = Symbol("invited-spaces");
export const UPDATE_SELECTED_SPACE = Symbol("selected-space");
// Space Room ID will be emitted when a Space's children change
export interface ISuggestedRoom extends ISpaceSummaryRoom {
viaServers: string[];
}
const MAX_SUGGESTED_ROOMS = 20;
const getSpaceContextKey = (space?: Room) => `mx_space_context_${space?.roomId || "ALL_ROOMS"}`;
@ -89,7 +93,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
private spaceFilteredRooms = new Map<string, Set<string>>();
// The space currently selected in the Space Panel - if null then All Rooms is selected
private _activeSpace?: Room = null;
private _suggestedRooms: ISpaceSummaryRoom[] = [];
private _suggestedRooms: ISuggestedRoom[] = [];
private _invitedSpaces = new Set<Room>();
public get invitedSpaces(): Room[] {
@ -104,7 +108,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
return this._activeSpace || null;
}
public get suggestedRooms(): ISpaceSummaryRoom[] {
public get suggestedRooms(): ISuggestedRoom[] {
return this._suggestedRooms;
}
@ -158,31 +162,41 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
}
if (space) {
const data = await this.fetchSuggestedRooms(space);
const suggestedRooms = await this.fetchSuggestedRooms(space);
if (this._activeSpace === space) {
this._suggestedRooms = data.rooms.filter(roomInfo => {
return roomInfo.room_type !== RoomType.Space
&& this.matrixClient.getRoom(roomInfo.room_id)?.getMyMembership() !== "join";
});
this._suggestedRooms = suggestedRooms;
this.emit(SUGGESTED_ROOMS, this._suggestedRooms);
}
}
}
public fetchSuggestedRooms = async (space: Room, limit = MAX_SUGGESTED_ROOMS) => {
public fetchSuggestedRooms = async (space: Room, limit = MAX_SUGGESTED_ROOMS): Promise<ISuggestedRoom[]> => {
try {
const data: {
rooms: ISpaceSummaryRoom[];
events: ISpaceSummaryEvent[];
} = await this.matrixClient.getSpaceSummary(space.roomId, 0, true, false, limit);
return data;
const viaMap = new EnhancedMap<string, Set<string>>();
data.events.forEach(ev => {
if (ev.type === EventType.SpaceChild && ev.content.via?.length) {
ev.content.via.forEach(via => {
viaMap.getOrCreate(ev.state_key, new Set()).add(via);
});
}
});
return data.rooms.filter(roomInfo => {
return roomInfo.room_type !== RoomType.Space
&& this.matrixClient.getRoom(roomInfo.room_id)?.getMyMembership() !== "join";
}).map(roomInfo => ({
...roomInfo,
viaServers: Array.from(viaMap.get(roomInfo.room_id) || []),
}));
} catch (e) {
console.error(e);
}
return {
rooms: [],
events: [],
};
return [];
};
public addRoomToSpace(space: Room, roomId: string, via: string[], suggested = false, autoJoin = false) {
@ -222,7 +236,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
return room?.currentState.getStateEvents(EventType.SpaceParent)
.filter(ev => {
const content = ev.getContent();
if (!content?.via) return false;
if (!content?.via?.length) return false;
// TODO apply permissions check to verify that the parent mapping is valid
if (canonicalOnly && !content?.canonical) return false;
return true;

View File

@ -17,7 +17,7 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room";
import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition";
import { EventEmitter } from "events";
import { removeHiddenChars } from "matrix-js-sdk/src/utils";
import { normalize } from "matrix-js-sdk/src/utils";
import { throttle } from "lodash";
/**
@ -62,20 +62,10 @@ export class NameFilterCondition extends EventEmitter implements IFilterConditio
if (!room.name) return false; // should realistically not happen: the js-sdk always calculates a name
return this.matches(room.name);
return this.matches(room.normalizedName);
}
private normalize(val: string): string {
// Note: we have to match the filter with the removeHiddenChars() room name because the
// function strips spaces and other characters (M becomes RN for example, in lowercase).
return removeHiddenChars(val.toLowerCase())
// Strip all punctuation
.replace(/[\\'!"#$%&()*+,\-./:;<=>?@[\]^_`{|}~\u2000-\u206f\u2e00-\u2e7f]/g, "")
// We also doubly convert to lowercase to work around oddities of the library.
.toLowerCase();
}
public matches(val: string): boolean {
return this.normalize(val).includes(this.normalize(this.search));
public matches(normalizedName: string): boolean {
return normalizedName.includes(normalize(this.search));
}
}