@internetarchive/ia-topnav 1.3.5-alpha7 → 1.3.5-alpha9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/ia-topnav.js +7 -1
- package/src/lib/keyboard-navigation.js +130 -0
- package/src/media-button.js +1 -1
- package/src/media-menu.js +21 -1
- package/src/media-slider.js +21 -7
- package/src/nav-search.js +0 -1
- package/src/primary-nav.js +33 -20
- package/src/search-menu.js +1 -2
- package/src/styles/dropdown-menu.js +2 -0
- package/src/styles/media-menu.js +1 -5
- package/src/styles/primary-nav.js +15 -8
- package/src/user-menu.js +14 -0
package/package.json
CHANGED
package/src/ia-topnav.js
CHANGED
|
@@ -62,6 +62,7 @@ export default class IATopNav extends LitElement {
|
|
|
62
62
|
username: { type: String },
|
|
63
63
|
userProfileImagePath: { type: String },
|
|
64
64
|
secondIdentitySlotMode: { type: String },
|
|
65
|
+
currentTab: { type: Object },
|
|
65
66
|
};
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -77,11 +78,12 @@ export default class IATopNav extends LitElement {
|
|
|
77
78
|
this.searchIn = '';
|
|
78
79
|
this.selectedMenuOption = '';
|
|
79
80
|
this.secondIdentitySlotMode = '';
|
|
81
|
+
this.currentTab = {};
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
updated(props) {
|
|
83
85
|
if (props.has('username') || props.has('localLinks') || props.has('baseHost') ||
|
|
84
|
-
|
|
86
|
+
props.has('waybackPagesArchived') || props.has('itemIdentifier')) {
|
|
85
87
|
this.menuSetup();
|
|
86
88
|
}
|
|
87
89
|
}
|
|
@@ -199,6 +201,7 @@ export default class IATopNav extends LitElement {
|
|
|
199
201
|
tabindex="${this.userMenuTabIndex}"
|
|
200
202
|
@menuToggled=${this.menuToggled}
|
|
201
203
|
@trackClick=${this.trackClick}
|
|
204
|
+
@moveFocusToOthers=${(e) => this.currentTab = e.detail}
|
|
202
205
|
></user-menu>
|
|
203
206
|
`;
|
|
204
207
|
}
|
|
@@ -274,6 +277,7 @@ export default class IATopNav extends LitElement {
|
|
|
274
277
|
.selectedMenuOption=${this.selectedMenuOption}
|
|
275
278
|
.username=${this.username}
|
|
276
279
|
.userProfileImagePath=${this.userProfileImagePath}
|
|
280
|
+
.currentTab=${this.currentTab}
|
|
277
281
|
?hideSearch=${this.hideSearch}
|
|
278
282
|
@mediaTypeSelected=${this.mediaTypeSelected}
|
|
279
283
|
@toggleSearchMenu=${this.toggleSearchMenu}
|
|
@@ -289,6 +293,8 @@ export default class IATopNav extends LitElement {
|
|
|
289
293
|
.selectedMenuOption=${this.selectedMenuOption}
|
|
290
294
|
.mediaSliderOpen=${this.mediaSliderOpen}
|
|
291
295
|
.menus=${this.menus}
|
|
296
|
+
tabindex="${this.mediaSliderOpen ? '1' : ''}"
|
|
297
|
+
@moveFocusToOthers=${(e) => this.currentTab = e.detail}
|
|
292
298
|
></media-slider>
|
|
293
299
|
</div>
|
|
294
300
|
${this.username ? this.userMenu : this.signedOutDropdown}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export default class KeyboardNavigation {
|
|
5
|
+
/**
|
|
6
|
+
* Constructor for the KeyboardNavigation class.
|
|
7
|
+
* @param {HTMLElement} elementsContainer - The container element that holds the focusable elements.
|
|
8
|
+
* @param {string} menuOption - The type of menu option ('web' or 'usermenu').
|
|
9
|
+
*/
|
|
10
|
+
constructor(elementsContainer, menuOption) {
|
|
11
|
+
this.elementsContainer = elementsContainer;
|
|
12
|
+
this.menuOption = menuOption;
|
|
13
|
+
this.focusableElements = this.getFocusableElements();
|
|
14
|
+
this.focusedIndex = this.getInitialFocusedIndex();
|
|
15
|
+
|
|
16
|
+
this.focusableElements[this.focusedIndex]?.focus();
|
|
17
|
+
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Returns the initial focused index based on the menu option.
|
|
22
|
+
* @returns {number} The initial focused index (0 for 'web', 1 for 'usermenu').
|
|
23
|
+
*/
|
|
24
|
+
getInitialFocusedIndex() {
|
|
25
|
+
return this.menuOption === 'usermenu' ? 1 : 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Gets an array of focusable elements within the container.
|
|
30
|
+
* @returns {HTMLElement[]} An array of focusable elements.
|
|
31
|
+
*/
|
|
32
|
+
getFocusableElements() {
|
|
33
|
+
const focusableTagSelectors = 'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])';
|
|
34
|
+
const isDisabledOrHidden = el => !el.hasAttribute('disabled') && !el.getAttribute('aria-hidden');
|
|
35
|
+
|
|
36
|
+
let elements;
|
|
37
|
+
if (this.menuOption === 'web') {
|
|
38
|
+
const waybackSlider = this.elementsContainer.querySelector('wayback-slider').shadowRoot;
|
|
39
|
+
const waybackSearch = waybackSlider.querySelector('wayback-search');
|
|
40
|
+
const waybackSearchElements = Array.from(waybackSearch.shadowRoot.querySelectorAll(focusableTagSelectors));
|
|
41
|
+
|
|
42
|
+
const normalElements = Array.from(waybackSlider.querySelectorAll(focusableTagSelectors));
|
|
43
|
+
|
|
44
|
+
const savePageForm = waybackSlider.querySelector('save-page-form');
|
|
45
|
+
const savePageFormElements = Array.from(savePageForm.shadowRoot.querySelectorAll(focusableTagSelectors));
|
|
46
|
+
|
|
47
|
+
elements = [...waybackSearchElements, ...normalElements, ...savePageFormElements];
|
|
48
|
+
} else {
|
|
49
|
+
elements = this.elementsContainer.querySelectorAll(focusableTagSelectors);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return Array.from(elements).filter(isDisabledOrHidden);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Handles keyboard events and focuses the appropriate element.
|
|
57
|
+
* @param {KeyboardEvent} event - The keyboard event object.
|
|
58
|
+
*/
|
|
59
|
+
handleKeyDown(event) {
|
|
60
|
+
const { key } = event;
|
|
61
|
+
const isArrowKey = ['ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft'].includes(key);
|
|
62
|
+
const isTabKey = key === 'Tab';
|
|
63
|
+
|
|
64
|
+
if (isArrowKey) {
|
|
65
|
+
this.handleArrowKey(key);
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
} else if (isTabKey) {
|
|
68
|
+
this.handleTabKey(event);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Handles arrow key events and focuses the next or previous element.
|
|
74
|
+
* @param {string} key - The key that was pressed ('ArrowDown', 'ArrowRight', 'ArrowUp', or 'ArrowLeft').
|
|
75
|
+
*/
|
|
76
|
+
handleArrowKey(key) {
|
|
77
|
+
const isDownOrRight = ['ArrowDown', 'ArrowRight'].includes(key);
|
|
78
|
+
isDownOrRight ? this.focusNext() : this.focusPrevious();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Focuses the previous focusable element in the container.
|
|
83
|
+
*/
|
|
84
|
+
focusPrevious() {
|
|
85
|
+
if (this.focusableElements.length === 0) return;
|
|
86
|
+
this.focusedIndex = (this.focusedIndex - 1 + this.focusableElements.length) % this.focusableElements.length;
|
|
87
|
+
this.focusableElements[this.focusedIndex]?.focus();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Focuses the next focusable element in the container.
|
|
92
|
+
*/
|
|
93
|
+
focusNext() {
|
|
94
|
+
if (this.focusableElements.length === 0) return;
|
|
95
|
+
this.focusedIndex = (this.focusedIndex + 1) % this.focusableElements.length;
|
|
96
|
+
this.focusableElements[this.focusedIndex]?.focus();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Handles the Tab key event and focuses the next or previous menu item.
|
|
101
|
+
* @param {KeyboardEvent} event - The keyboard event object.
|
|
102
|
+
*/
|
|
103
|
+
handleTabKey(event) {
|
|
104
|
+
console.log(this.menuOption)
|
|
105
|
+
if (this.menuOption) {
|
|
106
|
+
const isShiftPressed = event.shiftKey;
|
|
107
|
+
this.focusNextMenuItem(isShiftPressed);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this.focusableElements[this.focusedIndex]?.blur();
|
|
111
|
+
event.preventDefault();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Focuses the next or previous menu item based on the provided flag.
|
|
116
|
+
* @param {boolean} isPrevious - A flag indicating whether to focus the previous menu item.
|
|
117
|
+
*/
|
|
118
|
+
focusNextMenuItem(isPrevious = false) {
|
|
119
|
+
this.elementsContainer.dispatchEvent(
|
|
120
|
+
new CustomEvent('moveFocusToOthers', {
|
|
121
|
+
bubbles: true,
|
|
122
|
+
composed: true,
|
|
123
|
+
detail: {
|
|
124
|
+
mediatype: this.menuOption,
|
|
125
|
+
moveTo: isPrevious ? 'prev' : 'next',
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
package/src/media-button.js
CHANGED
|
@@ -103,7 +103,7 @@ class MediaButton extends TrackedElement {
|
|
|
103
103
|
@click=${this.followable ? this.trackClick : this.onClick}
|
|
104
104
|
data-event-click-tracking="${this.analyticsEvent}"
|
|
105
105
|
title="${this.tooltipPrefix} ${this.mediatype} menu"
|
|
106
|
-
tabindex="${this.openMenu === 'media' ? '' : '
|
|
106
|
+
tabindex="${this.openMenu === 'media' ? '' : '0'}"
|
|
107
107
|
>
|
|
108
108
|
${this.menuItem}
|
|
109
109
|
</a>
|
package/src/media-menu.js
CHANGED
|
@@ -67,6 +67,7 @@ class MediaMenu extends LitElement {
|
|
|
67
67
|
config: { type: Object },
|
|
68
68
|
openMenu: { type: String },
|
|
69
69
|
selectedMenuOption: { type: String },
|
|
70
|
+
currentTab: { type: Object },
|
|
70
71
|
};
|
|
71
72
|
}
|
|
72
73
|
|
|
@@ -75,6 +76,25 @@ class MediaMenu extends LitElement {
|
|
|
75
76
|
this.config = {};
|
|
76
77
|
this.openMenu = '';
|
|
77
78
|
this.selectedMenuOption = '';
|
|
79
|
+
this.currentTab = {};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
updated(props) {
|
|
83
|
+
if (props.has('currentTab')) {
|
|
84
|
+
const mediaButtons = Array.from(this.shadowRoot.querySelectorAll('media-button'));
|
|
85
|
+
|
|
86
|
+
mediaButtons.map((button, index) => {
|
|
87
|
+
const linkItem = button.shadowRoot.querySelector('a.menu-item');
|
|
88
|
+
if (linkItem) {
|
|
89
|
+
if (linkItem.classList.contains(`${this.selectedMenuOption}`)) {
|
|
90
|
+
linkItem.classList.remove('selected');
|
|
91
|
+
linkItem.blur();
|
|
92
|
+
|
|
93
|
+
mediaButtons[this.currentTab.moveTo === 'next' ? index + 1 : index - 1].shadowRoot.querySelector('a.menu-item').focus();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
78
98
|
}
|
|
79
99
|
|
|
80
100
|
get mediaMenuOptionsTemplate() {
|
|
@@ -96,6 +116,7 @@ class MediaMenu extends LitElement {
|
|
|
96
116
|
.mediatype=${menu}
|
|
97
117
|
.openMenu=${this.openMenu}
|
|
98
118
|
.selected=${selected}
|
|
119
|
+
.selectedMenuOption=${this.selectedMenuOption}
|
|
99
120
|
data-mediatype="${menu}"
|
|
100
121
|
></media-button>
|
|
101
122
|
`;
|
|
@@ -117,7 +138,6 @@ class MediaMenu extends LitElement {
|
|
|
117
138
|
<div class="overflow-clip">
|
|
118
139
|
<nav
|
|
119
140
|
class="media-menu-inner"
|
|
120
|
-
aria-hidden="${!this.menuOpened}"
|
|
121
141
|
aria-expanded="${this.menuOpened}"
|
|
122
142
|
>
|
|
123
143
|
<div class="menu-group">
|
package/src/media-slider.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LitElement, html } from 'https://offshoot.prod.archive.org/lit.js';
|
|
2
2
|
import './media-subnav.js';
|
|
3
3
|
import mediaSliderCSS from './styles/media-slider.js';
|
|
4
|
+
import KeyboardNavigation from './lib/keyboard-navigation.js';
|
|
4
5
|
|
|
5
6
|
class MediaSlider extends LitElement {
|
|
6
7
|
static get styles() {
|
|
@@ -26,6 +27,19 @@ class MediaSlider extends LitElement {
|
|
|
26
27
|
this.selectedMenuOption = 'texts';
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
updated(props) {
|
|
31
|
+
if (props.has('selectedMenuOption') && this.selectedMenuOption) {
|
|
32
|
+
const container = this.shadowRoot?.querySelector('.has-focused')?.shadowRoot;
|
|
33
|
+
|
|
34
|
+
if (container) {
|
|
35
|
+
const keyboardNavigation = new KeyboardNavigation(container, this.selectedMenuOption);
|
|
36
|
+
this.addEventListener('keydown', keyboardNavigation.handleKeyDown);
|
|
37
|
+
this.removeEventListener('keydown', this.previousKeydownListener);
|
|
38
|
+
this.previousKeydownListener = keyboardNavigation.handleKeyDown;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
29
43
|
shouldUpdate() {
|
|
30
44
|
const scrollPane = this.shadowRoot ? this.shadowRoot.querySelector('.information-menu') : null;
|
|
31
45
|
|
|
@@ -47,49 +61,49 @@ class MediaSlider extends LitElement {
|
|
|
47
61
|
<media-subnav
|
|
48
62
|
.baseHost=${this.baseHost}
|
|
49
63
|
.config=${this.config}
|
|
50
|
-
class="${this.selectedMenuOption === 'audio' ? '' : 'hidden'}"
|
|
64
|
+
class="${this.selectedMenuOption === 'audio' ? 'has-focused' : 'hidden'}"
|
|
51
65
|
menu="audio"
|
|
52
66
|
.menuItems=${this.menus.audio}
|
|
53
67
|
></media-subnav>
|
|
54
68
|
<media-subnav
|
|
55
69
|
.baseHost=${this.baseHost}
|
|
56
70
|
.config=${this.config}
|
|
57
|
-
class="${this.selectedMenuOption === 'images' ? '' : 'hidden'}"
|
|
71
|
+
class="${this.selectedMenuOption === 'images' ? 'has-focused' : 'hidden'}"
|
|
58
72
|
menu="images"
|
|
59
73
|
.menuItems=${this.menus.images}
|
|
60
74
|
></media-subnav>
|
|
61
75
|
<media-subnav
|
|
62
76
|
.baseHost=${this.baseHost}
|
|
63
77
|
.config=${this.config}
|
|
64
|
-
class="${this.selectedMenuOption === 'software' ? '' : 'hidden'}"
|
|
78
|
+
class="${this.selectedMenuOption === 'software' ? 'has-focused' : 'hidden'}"
|
|
65
79
|
menu="software"
|
|
66
80
|
.menuItems=${this.menus.software}
|
|
67
81
|
></media-subnav>
|
|
68
82
|
<media-subnav
|
|
69
83
|
.baseHost=${this.baseHost}
|
|
70
84
|
.config=${this.config}
|
|
71
|
-
class="${this.selectedMenuOption === 'texts' ? '' : 'hidden'}"
|
|
85
|
+
class="${this.selectedMenuOption === 'texts' ? 'has-focused' : 'hidden'}"
|
|
72
86
|
menu="texts"
|
|
73
87
|
.menuItems=${this.menus.texts}
|
|
74
88
|
></media-subnav>
|
|
75
89
|
<media-subnav
|
|
76
90
|
.baseHost=${this.baseHost}
|
|
77
91
|
.config=${this.config}
|
|
78
|
-
class="${this.selectedMenuOption === 'video' ? '' : 'hidden'}"
|
|
92
|
+
class="${this.selectedMenuOption === 'video' ? 'has-focused' : 'hidden'}"
|
|
79
93
|
menu="video"
|
|
80
94
|
.menuItems=${this.menus.video}
|
|
81
95
|
></media-subnav>
|
|
82
96
|
<media-subnav
|
|
83
97
|
.baseHost=${this.baseHost}
|
|
84
98
|
.config=${this.config}
|
|
85
|
-
class="${this.selectedMenuOption === 'web' ? '' : 'hidden'}"
|
|
99
|
+
class="${this.selectedMenuOption === 'web' ? 'has-focused' : 'hidden'}"
|
|
86
100
|
menu="web"
|
|
87
101
|
.menuItems=${this.menus.web}
|
|
88
102
|
></media-subnav>
|
|
89
103
|
<media-subnav
|
|
90
104
|
.baseHost=${this.baseHost}
|
|
91
105
|
.config=${this.config}
|
|
92
|
-
class="${this.selectedMenuOption === 'more' ? '' : 'hidden'}"
|
|
106
|
+
class="${this.selectedMenuOption === 'more' ? 'has-focused' : 'hidden'}"
|
|
93
107
|
menu="more"
|
|
94
108
|
.menuItems=${this.menus.more}
|
|
95
109
|
></media-subnav>
|
package/src/nav-search.js
CHANGED
package/src/primary-nav.js
CHANGED
|
@@ -31,6 +31,7 @@ class PrimaryNav extends TrackedElement {
|
|
|
31
31
|
userMenuOpen: { type: Boolean },
|
|
32
32
|
username: { type: String },
|
|
33
33
|
userProfileImagePath: { type: String },
|
|
34
|
+
currentTab: { type: Object },
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -44,6 +45,7 @@ class PrimaryNav extends TrackedElement {
|
|
|
44
45
|
this.userMenuOpen = false;
|
|
45
46
|
this.mediaBaseHost = 'https://archive.org';
|
|
46
47
|
this.secondIdentitySlotMode = '';
|
|
48
|
+
this.currentTab = {};
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
toggleMediaMenu(e) {
|
|
@@ -79,6 +81,21 @@ class PrimaryNav extends TrackedElement {
|
|
|
79
81
|
);
|
|
80
82
|
}
|
|
81
83
|
|
|
84
|
+
updated(props) {
|
|
85
|
+
const { currentTab } = this;
|
|
86
|
+
const isUserMenuTab = currentTab && currentTab.mediatype === 'usermenu';
|
|
87
|
+
if (props.has('currentTab') && isUserMenuTab) {
|
|
88
|
+
console.log(currentTab)
|
|
89
|
+
const focusElement = currentTab.moveTo === 'next'
|
|
90
|
+
? this.shadowRoot.querySelector('a.upload')
|
|
91
|
+
: this.shadowRoot.querySelector('.media-menu-container');
|
|
92
|
+
|
|
93
|
+
if (focusElement) {
|
|
94
|
+
focusElement.focus();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
82
99
|
get userIcon() {
|
|
83
100
|
const userMenuClass = this.openMenu === 'user' ? 'active' : '';
|
|
84
101
|
const userMenuToolTip = this.openMenu === 'user' ? 'Close user menu' : 'Expand user menu';
|
|
@@ -87,7 +104,6 @@ class PrimaryNav extends TrackedElement {
|
|
|
87
104
|
<button
|
|
88
105
|
class="user-menu ${userMenuClass}"
|
|
89
106
|
title="${userMenuToolTip}"
|
|
90
|
-
tabindex="-1"
|
|
91
107
|
@click="${this.toggleUserMenu}"
|
|
92
108
|
data-event-click-tracking="${this.config.eventCategory}|NavUserMenu"
|
|
93
109
|
>
|
|
@@ -107,7 +123,6 @@ class PrimaryNav extends TrackedElement {
|
|
|
107
123
|
.config=${this.config}
|
|
108
124
|
.dropdownOpen=${this.signedOutMenuOpen}
|
|
109
125
|
.openMenu=${this.openMenu}
|
|
110
|
-
tabindex="-1"
|
|
111
126
|
@signedOutMenuToggled=${this.signedOutMenuToggled}
|
|
112
127
|
></login-button>
|
|
113
128
|
`;
|
|
@@ -157,7 +172,6 @@ class PrimaryNav extends TrackedElement {
|
|
|
157
172
|
return html`
|
|
158
173
|
<a href="${formatUrl('/create', this.baseHost)}"
|
|
159
174
|
class="upload"
|
|
160
|
-
tabindex="1"
|
|
161
175
|
@focus=${this.toggleMediaMenu}
|
|
162
176
|
>
|
|
163
177
|
${icons.upload}
|
|
@@ -188,6 +202,15 @@ class PrimaryNav extends TrackedElement {
|
|
|
188
202
|
const mediaMenuTabIndex = this.openMenu === 'media' ? '' : '-1';
|
|
189
203
|
return html`
|
|
190
204
|
<nav class=${this.hideSearch ? 'hide-search' : nothing}>
|
|
205
|
+
<button
|
|
206
|
+
class="hamburger"
|
|
207
|
+
@click="${this.toggleMediaMenu}"
|
|
208
|
+
data-event-click-tracking="${this.config.eventCategory}|NavHamburger"
|
|
209
|
+
title="Open main menu"
|
|
210
|
+
>
|
|
211
|
+
<icon-hamburger ?active=${this.openMenu === 'media'}></icon-hamburger>
|
|
212
|
+
</button>
|
|
213
|
+
|
|
191
214
|
<div class=${`branding ${this.secondLogoClass}`}>
|
|
192
215
|
<a
|
|
193
216
|
href=${formatUrl('/', this.baseHost)}
|
|
@@ -200,30 +223,20 @@ class PrimaryNav extends TrackedElement {
|
|
|
200
223
|
>
|
|
201
224
|
${this.secondLogoSlot}
|
|
202
225
|
</div>
|
|
203
|
-
|
|
204
|
-
<div class="right-side-section">
|
|
205
|
-
${this.mobileDonateHeart}
|
|
206
|
-
${this.searchMenu}
|
|
207
|
-
${this.uploadButtonTemplate}
|
|
208
|
-
${this.userStateTemplate}
|
|
209
|
-
</div>
|
|
210
226
|
<media-menu
|
|
211
227
|
.baseHost=${this.baseHost}
|
|
212
228
|
.config=${this.config}
|
|
213
229
|
?mediaMenuAnimate="${this.mediaMenuAnimate}"
|
|
214
|
-
tabindex="${mediaMenuTabIndex}"
|
|
215
230
|
.selectedMenuOption=${this.selectedMenuOption}
|
|
216
231
|
.openMenu=${this.openMenu}
|
|
232
|
+
.currentTab=${this.currentTab}
|
|
217
233
|
></media-menu>
|
|
218
|
-
<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
>
|
|
225
|
-
<icon-hamburger ?active=${this.openMenu === 'media'}></icon-hamburger>
|
|
226
|
-
</button>
|
|
234
|
+
<div class="right-side-section">
|
|
235
|
+
${this.mobileDonateHeart}
|
|
236
|
+
${this.userStateTemplate}
|
|
237
|
+
${this.uploadButtonTemplate}
|
|
238
|
+
${this.searchMenu}
|
|
239
|
+
</div>
|
|
227
240
|
</nav>
|
|
228
241
|
`;
|
|
229
242
|
}
|
package/src/search-menu.js
CHANGED
|
@@ -100,7 +100,7 @@ class SearchMenu extends TrackedElement {
|
|
|
100
100
|
}
|
|
101
101
|
return html`
|
|
102
102
|
<label @click="${this.selectSearchType}">
|
|
103
|
-
<input
|
|
103
|
+
<input form="nav-search" type="radio" name="sin" value="${value}" ?checked=${isDefault} @change=${this.searchInChanged} />
|
|
104
104
|
Search ${label}
|
|
105
105
|
</label>
|
|
106
106
|
`;
|
|
@@ -134,7 +134,6 @@ class SearchMenu extends TrackedElement {
|
|
|
134
134
|
href="${formatUrl('/advancedsearch.php', this.baseHost)}"
|
|
135
135
|
@click=${this.trackClick}
|
|
136
136
|
data-event-click-tracking="${this.config.eventCategory}|NavAdvancedSearch"
|
|
137
|
-
tabindex="4"
|
|
138
137
|
>Advanced Search</a
|
|
139
138
|
>
|
|
140
139
|
</div>
|
|
@@ -92,6 +92,7 @@ export default css`
|
|
|
92
92
|
|
|
93
93
|
@media (min-width: 890px) {
|
|
94
94
|
nav {
|
|
95
|
+
display: flex;
|
|
95
96
|
overflow: visible;
|
|
96
97
|
top: 0;
|
|
97
98
|
left: auto;
|
|
@@ -146,6 +147,7 @@ export default css`
|
|
|
146
147
|
a:focus {
|
|
147
148
|
color: var(--linkHoverColor);
|
|
148
149
|
background: var(--linkColor);
|
|
150
|
+
outline: none;
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
.initial,
|
package/src/styles/media-menu.js
CHANGED
|
@@ -23,10 +23,6 @@ export default css`
|
|
|
23
23
|
|
|
24
24
|
/* Mobile view styles */
|
|
25
25
|
@media (max-width: 889px) {
|
|
26
|
-
.media-menu-container {
|
|
27
|
-
position: relative;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
26
|
.media-menu-inner {
|
|
31
27
|
position: absolute;
|
|
32
28
|
width: 100%;
|
|
@@ -39,7 +35,7 @@ export default css`
|
|
|
39
35
|
.overflow-clip {
|
|
40
36
|
position: absolute;
|
|
41
37
|
z-index: -1; /** needs to be under the navigation, otherwise it intercepts clicks */
|
|
42
|
-
top:
|
|
38
|
+
top: 4rem;
|
|
43
39
|
left: 0;
|
|
44
40
|
height: 0;
|
|
45
41
|
width: 100%;
|
|
@@ -9,8 +9,7 @@ export default css`
|
|
|
9
9
|
|
|
10
10
|
nav {
|
|
11
11
|
position: relative;
|
|
12
|
-
display:
|
|
13
|
-
display: grid;
|
|
12
|
+
display: flex;
|
|
14
13
|
height: 4rem;
|
|
15
14
|
grid-template-areas: 'hamburger empty heart search user';
|
|
16
15
|
-ms-grid-columns: 4rem minmax(1rem, 100%) 4rem 4rem 4rem;
|
|
@@ -29,6 +28,7 @@ export default css`
|
|
|
29
28
|
|
|
30
29
|
.right-side-section {
|
|
31
30
|
display: flex;
|
|
31
|
+
margin-left: auto;
|
|
32
32
|
user-select: none;
|
|
33
33
|
}
|
|
34
34
|
button {
|
|
@@ -86,6 +86,9 @@ export default css`
|
|
|
86
86
|
fill: var(--activeColor);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
.mobile-donate-link {
|
|
90
|
+
display: inline-block;
|
|
91
|
+
}
|
|
89
92
|
.mobile-donate-link svg {
|
|
90
93
|
height: 4rem;
|
|
91
94
|
width: 4rem;
|
|
@@ -151,7 +154,8 @@ export default css`
|
|
|
151
154
|
height: 100%;
|
|
152
155
|
}
|
|
153
156
|
|
|
154
|
-
.user-menu:hover
|
|
157
|
+
.user-menu:hover,
|
|
158
|
+
.user-menu:focus {
|
|
155
159
|
color: var(--linkHoverColor);
|
|
156
160
|
}
|
|
157
161
|
|
|
@@ -187,6 +191,13 @@ export default css`
|
|
|
187
191
|
slot[name='opt-sec-logo'] {
|
|
188
192
|
display: none;
|
|
189
193
|
}
|
|
194
|
+
|
|
195
|
+
.right-side-section {
|
|
196
|
+
display: initial;
|
|
197
|
+
}
|
|
198
|
+
.right-side-section .user-info {
|
|
199
|
+
float: right;
|
|
200
|
+
}
|
|
190
201
|
}
|
|
191
202
|
|
|
192
203
|
@media (min-width: 890px) {
|
|
@@ -195,12 +206,8 @@ export default css`
|
|
|
195
206
|
--userIconHeight: 3.2rem;
|
|
196
207
|
}
|
|
197
208
|
|
|
198
|
-
.right-side-section {
|
|
199
|
-
display: contents;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
209
|
nav {
|
|
203
|
-
display:
|
|
210
|
+
display: flex;
|
|
204
211
|
z-index: 4;
|
|
205
212
|
height: 5rem;
|
|
206
213
|
padding-right: 1.5rem;
|
package/src/user-menu.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { html } from 'https://offshoot.prod.archive.org/lit.js';
|
|
2
2
|
import DropdownMenu from './dropdown-menu.js';
|
|
3
3
|
import userMenuCSS from './styles/user-menu.js';
|
|
4
|
+
import KeyboardNavigation from './lib/keyboard-navigation.js';
|
|
4
5
|
|
|
5
6
|
class UserMenu extends DropdownMenu {
|
|
6
7
|
static get styles() {
|
|
@@ -21,6 +22,19 @@ class UserMenu extends DropdownMenu {
|
|
|
21
22
|
this.username = '';
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
updated(props) {
|
|
26
|
+
if (props.has('open') && this.open) {
|
|
27
|
+
const container = this.shadowRoot?.querySelector('.nav-container');
|
|
28
|
+
|
|
29
|
+
if (container) {
|
|
30
|
+
const keyboardNavigation = new KeyboardNavigation(container, 'usermenu');
|
|
31
|
+
this.addEventListener('keydown', keyboardNavigation.handleKeyDown);
|
|
32
|
+
this.removeEventListener('keydown', this.previousKeydownListener);
|
|
33
|
+
this.previousKeydownListener = keyboardNavigation.handleKeyDown;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
render() {
|
|
25
39
|
return html`
|
|
26
40
|
<div class="nav-container">
|