Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 914b612

Browse files
authored
Spotlight search labs (#7116)
1 parent c568338 commit 914b612

File tree

12 files changed

+906
-53
lines changed

12 files changed

+906
-53
lines changed

res/css/_components.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
@import "./views/dialogs/_ShareDialog.scss";
114114
@import "./views/dialogs/_SlashCommandHelpDialog.scss";
115115
@import "./views/dialogs/_SpaceSettingsDialog.scss";
116+
@import "./views/dialogs/_SpotlightDialog.scss";
116117
@import "./views/dialogs/_TabbedIntegrationManagerDialog.scss";
117118
@import "./views/dialogs/_TermsDialog.scss";
118119
@import "./views/dialogs/_UntrustedDeviceDialog.scss";

res/css/views/avatars/_DecoratedRoomAvatar.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ limitations under the License.
3939
content: '';
4040
width: 8px;
4141
height: 8px;
42+
right: 0;
4243
position: absolute;
4344
border-radius: 8px;
4445
}
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.mx_SpotlightDialog_wrapper .mx_Dialog {
18+
border-radius: 8px;
19+
overflow-y: initial;
20+
position: relative;
21+
height: 60%;
22+
padding: 0;
23+
contain: unset; // needed for .mx_SpotlightDialog_keyboardPrompt to not be culled
24+
25+
.mx_SpotlightDialog_keyboardPrompt {
26+
position: absolute;
27+
padding: 8px;
28+
border-radius: 8px;
29+
background-color: $background;
30+
top: -60px; // relative to the top of the modal
31+
left: 50%;
32+
transform: translateX(-50%);
33+
font-size: $font-12px;
34+
line-height: $font-15px;
35+
color: $secondary-content;
36+
37+
> span > div {
38+
display: inline-block;
39+
padding: 2px 4px;
40+
margin: 0 4px;
41+
border-radius: 6px;
42+
background-color: $quinary-content;
43+
vertical-align: middle;
44+
color: $tertiary-content;
45+
}
46+
}
47+
}
48+
49+
.mx_SpotlightDialog {
50+
height: 100%;
51+
display: flex;
52+
flex-direction: column;
53+
54+
.mx_Dialog_header {
55+
margin-bottom: 0;
56+
}
57+
58+
.mx_SpotlightDialog_searchBox {
59+
margin: 0;
60+
border: none;
61+
padding: 12px 16px;
62+
border-bottom: 1px solid $system;
63+
64+
> input {
65+
display: block;
66+
box-sizing: border-box;
67+
background-color: transparent;
68+
width: 100%;
69+
height: 32px;
70+
padding: 0;
71+
color: $tertiary-content;
72+
font-weight: normal;
73+
font-size: $font-15px;
74+
line-height: $font-24px;
75+
}
76+
}
77+
78+
#mx_SpotlightDialog_content {
79+
margin: 16px;
80+
height: 100%;
81+
overflow-y: auto;
82+
83+
.mx_SpotlightDialog_section {
84+
> h4 {
85+
font-weight: $font-semi-bold;
86+
font-size: $font-12px;
87+
line-height: $font-15px;
88+
color: $secondary-content;
89+
margin-top: 0;
90+
margin-bottom: 8px;
91+
}
92+
93+
& + .mx_SpotlightDialog_section {
94+
margin-top: 24px;
95+
}
96+
}
97+
98+
.mx_SpotlightDialog_recentlyViewed {
99+
> div {
100+
display: flex;
101+
white-space: nowrap;
102+
overflow-x: hidden;
103+
}
104+
105+
.mx_AccessibleButton {
106+
border-radius: 8px;
107+
padding: 4px;
108+
color: $primary-content;
109+
font-size: $font-12px;
110+
line-height: $font-15px;
111+
display: inline-block;
112+
width: 50px;
113+
min-width: 50px;
114+
box-sizing: border-box;
115+
text-align: center;
116+
overflow: hidden;
117+
text-overflow: ellipsis;
118+
119+
.mx_DecoratedRoomAvatar {
120+
margin: 0 5px 4px; // maintain centering
121+
}
122+
123+
& + .mx_AccessibleButton {
124+
margin-left: 16px;
125+
}
126+
127+
&:hover, &[aria-selected=true] {
128+
background-color: $quinary-content;
129+
}
130+
}
131+
}
132+
133+
.mx_SpotlightDialog_results,
134+
.mx_SpotlightDialog_recentSearches,
135+
.mx_SpotlightDialog_otherSearches {
136+
.mx_AccessibleButton {
137+
padding: 6px 4px;
138+
border-radius: 8px;
139+
font-size: $font-15px;
140+
line-height: $font-24px;
141+
color: $primary-content;
142+
position: relative;
143+
display: flex;
144+
align-items: center;
145+
white-space: nowrap;
146+
text-overflow: ellipsis;
147+
overflow: hidden;
148+
149+
.mx_BaseAvatar {
150+
margin-right: 8px;
151+
display: inline-block;
152+
height: 20px;
153+
}
154+
155+
&:hover, &[aria-selected=true] {
156+
background-color: $system;
157+
158+
.mx_SpotlightDialog_enterPrompt {
159+
display: inline-block;
160+
}
161+
}
162+
}
163+
}
164+
165+
.mx_SpotlightDialog_otherSearches {
166+
.mx_SpotlightDialog_startChat,
167+
.mx_SpotlightDialog_explorePublicRooms {
168+
padding-left: 32px;
169+
position: relative;
170+
171+
&::before {
172+
background-color: $secondary-content;
173+
content: "";
174+
mask-repeat: no-repeat;
175+
mask-position: center;
176+
mask-size: contain;
177+
width: 20px;
178+
height: 20px;
179+
position: absolute;
180+
left: 4px;
181+
top: 50%;
182+
transform: translateY(-50%);
183+
}
184+
}
185+
186+
.mx_SpotlightDialog_startChat::before {
187+
mask-image: url('$(res)/img/element-icons/room/members.svg');
188+
}
189+
190+
.mx_SpotlightDialog_explorePublicRooms::before {
191+
mask-image: url('$(res)/img/element-icons/roomlist/explore.svg');
192+
}
193+
194+
.mx_SpotlightDialog_otherSearches_messageSearchText {
195+
font-size: $font-15px;
196+
line-height: $font-24px;
197+
}
198+
199+
.mx_SpotlightDialog_otherSearches_messageSearchIcon {
200+
display: inline-block;
201+
margin-left: 8px;
202+
width: 20px;
203+
height: 20px;
204+
background-color: $secondary-content;
205+
vertical-align: text-bottom;
206+
mask-repeat: no-repeat;
207+
mask-position: center;
208+
mask-size: contain;
209+
mask-image: url('$(res)/img/element-icons/room/search-inset.svg');
210+
}
211+
}
212+
213+
.mx_SpotlightDialog_result_details {
214+
margin-left: 8px;
215+
margin-right: 8px;
216+
color: $tertiary-content;
217+
font-size: $font-12px;
218+
line-height: $font-15px;
219+
min-width: 0;
220+
overflow: hidden;
221+
text-overflow: ellipsis;
222+
}
223+
224+
.mx_SpotlightDialog_recentSearches {
225+
overflow-y: hidden;
226+
height: calc(100% - 190px);
227+
228+
> h4 > .mx_AccessibleButton_kind_link {
229+
padding: 0;
230+
float: right;
231+
font-weight: normal;
232+
font-size: $font-12px;
233+
line-height: $font-15px;
234+
color: $secondary-content;
235+
}
236+
}
237+
238+
.mx_SpotlightDialog_enterPrompt {
239+
padding: 2px 4px;
240+
font-size: $font-12px;
241+
line-height: $font-15px;
242+
color: $tertiary-content;
243+
border-radius: 6px;
244+
background-color: $quinary-content;
245+
margin: 0 4px 0 auto;
246+
display: none;
247+
}
248+
}
249+
250+
.mx_SpotlightDialog_footer {
251+
font-size: $font-12px;
252+
line-height: $font-15px;
253+
color: $secondary-content;
254+
padding: 16px 16px 20px;
255+
display: flex;
256+
border-top: 1px solid $quinary-content;
257+
258+
> span {
259+
position: relative;
260+
padding-left: 20px;
261+
align-self: center;
262+
263+
&::before {
264+
background-color: $secondary-content;
265+
content: "";
266+
mask-repeat: no-repeat;
267+
mask-position: center;
268+
mask-size: contain;
269+
mask-image: url('$(res)/img/element-icons/room/room-summary.svg');
270+
width: 16px;
271+
height: 16px;
272+
position: absolute;
273+
left: 0;
274+
top: 50%;
275+
transform: translateY(-50%);
276+
}
277+
}
278+
279+
.mx_AccessibleButton_kind_primary_outline {
280+
padding: 4px 8px;
281+
border-color: $secondary-content;
282+
color: $secondary-content;
283+
margin-left: auto;
284+
}
285+
}
286+
}

src/Rooms.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export function roomContextDetailsText(room: Room): string {
162162

163163
const dmPartner = DMRoomMap.shared().getUserIdForRoomId(room.roomId);
164164
if (dmPartner) {
165-
return room.getMember(dmPartner)?.rawDisplayName;
165+
return dmPartner;
166166
}
167167

168168
const [parent, ...otherParents] = SpaceStore.instance.getKnownParents(room.roomId);

src/accessibility/RovingTabIndex.tsx

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ import { FocusHandler, Ref } from "./roving/types";
4343
* https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets#Technique_1_Roving_tabindex
4444
*/
4545

46-
const DOCUMENT_POSITION_PRECEDING = 2;
47-
4846
export interface IState {
4947
activeRef: Ref;
5048
refs: Ref[];
@@ -55,7 +53,7 @@ interface IContext {
5553
dispatch: Dispatch<IAction>;
5654
}
5755

58-
const RovingTabIndexContext = createContext<IContext>({
56+
export const RovingTabIndexContext = createContext<IContext>({
5957
state: {
6058
activeRef: null,
6159
refs: [], // list of refs in DOM order
@@ -80,37 +78,29 @@ interface IAction {
8078
export const reducer = (state: IState, action: IAction) => {
8179
switch (action.type) {
8280
case Type.Register: {
83-
let left = 0;
84-
let right = state.refs.length - 1;
85-
let index = state.refs.length; // by default append to the end
86-
87-
// do a binary search to find the right slot
88-
while (left <= right) {
89-
index = Math.floor((left + right) / 2);
90-
const ref = state.refs[index];
81+
if (!state.activeRef) {
82+
// Our list of refs was empty, set activeRef to this first item
83+
state.activeRef = action.payload.ref;
84+
}
9185

92-
if (ref === action.payload.ref) {
93-
return state; // already in refs, this should not happen
86+
// Sadly due to the potential of DOM elements swapping order we can't do anything fancy like a binary insert
87+
state.refs.push(action.payload.ref);
88+
state.refs.sort((a, b) => {
89+
if (a === b) {
90+
return 0;
9491
}
9592

96-
if (action.payload.ref.current.compareDocumentPosition(ref.current) & DOCUMENT_POSITION_PRECEDING) {
97-
left = ++index;
93+
const position = a.current.compareDocumentPosition(b.current);
94+
95+
if (position & Node.DOCUMENT_POSITION_FOLLOWING || position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
96+
return -1;
97+
} else if (position & Node.DOCUMENT_POSITION_PRECEDING || position & Node.DOCUMENT_POSITION_CONTAINS) {
98+
return 1;
9899
} else {
99-
right = index - 1;
100+
return 0;
100101
}
101-
}
102-
103-
if (!state.activeRef) {
104-
// Our list of refs was empty, set activeRef to this first item
105-
state.activeRef = action.payload.ref;
106-
}
102+
});
107103

108-
// update the refs list
109-
if (index < state.refs.length) {
110-
state.refs.splice(index, 0, action.payload.ref);
111-
} else {
112-
state.refs.push(action.payload.ref);
113-
}
114104
return { ...state };
115105
}
116106

0 commit comments

Comments
 (0)