@internetarchive/ia-topnav 1.4.1-webdev-8238.0 → 2.0.0

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.
Files changed (68) hide show
  1. package/.prettierignore +1 -1
  2. package/LICENSE +661 -661
  3. package/README.md +147 -147
  4. package/demo/index.html +28 -28
  5. package/dist/src/data/menus.js +0 -2
  6. package/dist/src/data/menus.js.map +1 -1
  7. package/dist/src/ia-topnav.d.ts +7 -10
  8. package/dist/src/ia-topnav.js +95 -133
  9. package/dist/src/ia-topnav.js.map +1 -1
  10. package/dist/src/login-button.js +17 -17
  11. package/dist/src/login-button.js.map +1 -1
  12. package/dist/src/models.d.ts +0 -4
  13. package/dist/src/models.js.map +1 -1
  14. package/dist/src/primary-nav.d.ts +5 -4
  15. package/dist/src/primary-nav.js +98 -119
  16. package/dist/src/primary-nav.js.map +1 -1
  17. package/dist/src/styles/ia-topnav.js +82 -87
  18. package/dist/src/styles/ia-topnav.js.map +1 -1
  19. package/dist/src/styles/primary-nav.js +353 -308
  20. package/dist/src/styles/primary-nav.js.map +1 -1
  21. package/dist/test/ia-topnav.test.js +27 -69
  22. package/dist/test/ia-topnav.test.js.map +1 -1
  23. package/dist/test/primary-nav.test.js +38 -9
  24. package/dist/test/primary-nav.test.js.map +1 -1
  25. package/eslint.config.mjs +53 -53
  26. package/package.json +72 -72
  27. package/prettier.config.js +9 -9
  28. package/src/data/menus.ts +650 -652
  29. package/src/ia-topnav.ts +318 -366
  30. package/src/login-button.ts +78 -78
  31. package/src/models.ts +58 -63
  32. package/src/primary-nav.ts +277 -296
  33. package/src/styles/ia-topnav.ts +85 -90
  34. package/src/styles/primary-nav.ts +356 -311
  35. package/ssl/server.key +28 -28
  36. package/test/ia-topnav.test.ts +282 -343
  37. package/test/primary-nav.test.ts +135 -94
  38. package/tsconfig.json +31 -31
  39. package/web-dev-server.config.mjs +32 -32
  40. package/web-test-runner.config.mjs +41 -41
  41. package/dist/src/lib/location-handler.d.ts +0 -1
  42. package/dist/src/lib/location-handler.js +0 -5
  43. package/dist/src/lib/location-handler.js.map +0 -1
  44. package/dist/src/nav-search.d.ts +0 -19
  45. package/dist/src/nav-search.js +0 -127
  46. package/dist/src/nav-search.js.map +0 -1
  47. package/dist/src/search-menu.d.ts +0 -20
  48. package/dist/src/search-menu.js +0 -162
  49. package/dist/src/search-menu.js.map +0 -1
  50. package/dist/src/styles/nav-search.d.ts +0 -2
  51. package/dist/src/styles/nav-search.js +0 -136
  52. package/dist/src/styles/nav-search.js.map +0 -1
  53. package/dist/src/styles/search-menu.d.ts +0 -2
  54. package/dist/src/styles/search-menu.js +0 -118
  55. package/dist/src/styles/search-menu.js.map +0 -1
  56. package/dist/test/nav-search.test.d.ts +0 -1
  57. package/dist/test/nav-search.test.js +0 -47
  58. package/dist/test/nav-search.test.js.map +0 -1
  59. package/dist/test/search-menu.test.d.ts +0 -1
  60. package/dist/test/search-menu.test.js +0 -42
  61. package/dist/test/search-menu.test.js.map +0 -1
  62. package/src/lib/location-handler.ts +0 -5
  63. package/src/nav-search.ts +0 -117
  64. package/src/search-menu.ts +0 -156
  65. package/src/styles/nav-search.ts +0 -136
  66. package/src/styles/search-menu.ts +0 -118
  67. package/test/nav-search.test.ts +0 -70
  68. package/test/search-menu.test.ts +0 -58
package/src/ia-topnav.ts CHANGED
@@ -1,366 +1,318 @@
1
- import { LitElement, PropertyValues, html, nothing } from 'lit';
2
- import { customElement, property, state } from 'lit/decorators.js';
3
-
4
- import { buildTopNavMenus, defaultTopNavConfig } from './data/menus';
5
- import './desktop-subnav';
6
- import './dropdown-menu';
7
- import './media-slider';
8
- import {
9
- IATopNavConfig,
10
- IATopNavMenuConfig,
11
- IATopNavSecondIdentitySlotMode,
12
- } from './models';
13
- import './primary-nav';
14
- import './search-menu';
15
- import './signed-out-dropdown';
16
- import iaTopNavCSS from './styles/ia-topnav';
17
- import './user-menu';
18
- import KeyboardNavigation from './lib/keyboard-navigation';
19
-
20
- @customElement('ia-topnav')
21
- export class IATopNav extends LitElement {
22
- @property({ type: Boolean }) localLinks = false;
23
-
24
- @property({ type: String }) waybackPagesArchived = '';
25
-
26
- @property({ type: String }) baseHost = 'https://archive.org';
27
-
28
- @property({ type: String }) mediaBaseHost = 'https://archive.org';
29
-
30
- @property({ type: Boolean }) admin = false;
31
-
32
- @property({ type: Boolean }) canManageFlags = false;
33
-
34
- @property({ type: Object }) config: IATopNavConfig = defaultTopNavConfig;
35
-
36
- @property({ type: Boolean }) hideSearch = false;
37
-
38
- @property({ type: String }) itemIdentifier = '';
39
-
40
- @property({ type: Boolean }) mediaSliderOpen = false;
41
-
42
- @property({ type: String }) openMenu = '';
43
-
44
- @property({ type: String }) screenName: string = '';
45
-
46
- @property({ type: String }) searchIn = '';
47
-
48
- @property({ type: String }) searchQuery = '';
49
-
50
- @property({ type: String }) selectedMenuOption = '';
51
-
52
- @property({ type: String }) username: string = '';
53
-
54
- @property({ type: String }) userProfileImagePath =
55
- '/services/img/user/profile';
56
-
57
- @property({ type: String })
58
- secondIdentitySlotMode: IATopNavSecondIdentitySlotMode = '';
59
-
60
- @property({ type: Object }) currentTab?: {
61
- mediatype: string;
62
- moveTo: string;
63
- };
64
-
65
- @state() private menus: IATopNavMenuConfig = buildTopNavMenus();
66
- private previousKeydownListener: // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
- ((this: HTMLElement, ev: KeyboardEvent) => any) | undefined;
68
-
69
- private keyboardNavigation?: KeyboardNavigation;
70
-
71
- private get normalizedBaseHost() {
72
- return !this.localLinks ? this.baseHost : '';
73
- }
74
-
75
- static get styles() {
76
- return iaTopNavCSS;
77
- }
78
-
79
- updated(props: PropertyValues) {
80
- if (
81
- props.has('username') ||
82
- props.has('waybackPagesArchived') ||
83
- props.has('itemIdentifier') ||
84
- props.has('localLinks') ||
85
- props.has('baseHost')
86
- ) {
87
- this.menuSetup();
88
- }
89
-
90
- if (this.openMenu === 'search') {
91
- const targetElement =
92
- this.renderRoot.querySelector('search-menu')?.shadowRoot;
93
- if (targetElement) {
94
- this.keyboardNavigation = new KeyboardNavigation(
95
- targetElement as unknown as HTMLElement,
96
- this.openMenu,
97
- );
98
-
99
- if (this.previousKeydownListener) {
100
- this.removeEventListener('keydown', this.previousKeydownListener);
101
- }
102
- this.addEventListener('keydown', this.keyboardNavigation.handleKeyDown);
103
- this.previousKeydownListener = this.keyboardNavigation.handleKeyDown;
104
- }
105
- }
106
- }
107
-
108
- firstUpdated() {
109
- // close open menu on `esc` click
110
- document.addEventListener(
111
- 'keydown',
112
- (e) => {
113
- if (e.key === 'Escape') {
114
- this.openMenu = '';
115
- this.mediaSliderOpen = false;
116
- }
117
- },
118
- false,
119
- );
120
- }
121
-
122
- menuSetup() {
123
- // re/build the nav
124
- this.menus = buildTopNavMenus(
125
- this.username,
126
- this.normalizedBaseHost,
127
- this.waybackPagesArchived,
128
- this.itemIdentifier,
129
- );
130
- }
131
-
132
- menuToggled(e: CustomEvent) {
133
- const currentMenu = this.openMenu;
134
- this.openMenu = currentMenu === e.detail.menuName ? '' : e.detail.menuName;
135
- // Keeps media slider open if media menu is open
136
- if (this.openMenu === 'media') {
137
- return;
138
- }
139
- this.closeMediaSlider();
140
- }
141
-
142
- navSearchBlurEvent(e: CustomEvent) {
143
- if (this.previousKeydownListener) {
144
- this.removeEventListener('keydown', this.previousKeydownListener);
145
- }
146
-
147
- const isUploadButton = e.detail?.isUploadButton;
148
- if (!isUploadButton) {
149
- const searchMenu = this.renderRoot.querySelector(
150
- 'search-menu',
151
- ) as HTMLElement;
152
- const elements = this.keyboardNavigation?.getFocusableElements();
153
- if (searchMenu && elements?.length) {
154
- elements[0].focus();
155
- }
156
- }
157
- }
158
-
159
- openMediaSlider() {
160
- this.mediaSliderOpen = true;
161
- }
162
-
163
- closeMediaSlider() {
164
- this.mediaSliderOpen = false;
165
- this.selectedMenuOption = '';
166
- }
167
-
168
- closeMenus() {
169
- this.openMenu = '';
170
- this.closeMediaSlider();
171
- }
172
-
173
- searchInChanged(e: CustomEvent) {
174
- this.searchIn = e.detail.searchIn;
175
- }
176
-
177
- trackClick(e: CustomEvent) {
178
- this.dispatchEvent(
179
- new CustomEvent('analyticsClick', {
180
- bubbles: true,
181
- composed: true,
182
- detail: e.detail,
183
- }),
184
- );
185
- }
186
-
187
- trackSubmit(e: CustomEvent) {
188
- this.dispatchEvent(
189
- new CustomEvent('analyticsSubmit', {
190
- bubbles: true,
191
- composed: true,
192
- detail: e.detail,
193
- }),
194
- );
195
- }
196
-
197
- mediaTypeSelected(e: CustomEvent) {
198
- if (this.selectedMenuOption === e.detail.mediatype) {
199
- this.closeMediaSlider();
200
- return;
201
- }
202
- this.selectedMenuOption = e.detail.mediatype;
203
- this.openMediaSlider();
204
- }
205
-
206
- get searchMenuOpened() {
207
- return this.openMenu === 'search';
208
- }
209
-
210
- get signedOutOpened() {
211
- return this.openMenu === 'login';
212
- }
213
-
214
- get userMenuOpened() {
215
- return this.openMenu === 'user';
216
- }
217
-
218
- get searchMenuTabIndex() {
219
- return this.searchMenuOpened ? '' : '-1';
220
- }
221
-
222
- get userMenuTabIndex() {
223
- return this.userMenuOpened ? '' : '-1';
224
- }
225
-
226
- get signedOutTabIndex() {
227
- return this.signedOutOpened ? '' : '-1';
228
- }
229
-
230
- get closeLayerClass() {
231
- return !!this.openMenu || this.mediaSliderOpen ? 'visible' : '';
232
- }
233
-
234
- get userMenu() {
235
- return html`
236
- <user-menu
237
- .baseHost=${this.normalizedBaseHost}
238
- .config=${this.config}
239
- .menuItems=${this.userMenuItems}
240
- ?open=${this.openMenu === 'user'}
241
- .username=${this.username}
242
- ?hideSearch=${this.hideSearch}
243
- tabindex="${this.userMenuTabIndex}"
244
- @menuToggled=${this.menuToggled}
245
- @trackClick=${this.trackClick}
246
- @focusToOtherMenuItem=${(e: CustomEvent) =>
247
- (this.currentTab = e.detail)}
248
- ></user-menu>
249
- `;
250
- }
251
-
252
- get signedOutDropdown() {
253
- return html`
254
- <signed-out-dropdown
255
- .baseHost=${this.normalizedBaseHost}
256
- .config=${this.config}
257
- .open=${this.signedOutOpened}
258
- ?hideSearch=${this.hideSearch}
259
- tabindex="${this.signedOutTabIndex}"
260
- .menuItems=${this.signedOutMenuItems}
261
- @focusToOtherMenuItem=${(e: CustomEvent) => {
262
- this.currentTab = e.detail;
263
- }}
264
- ></signed-out-dropdown>
265
- `;
266
- }
267
-
268
- get signedOutMenuItems() {
269
- return this.menus.signedOut;
270
- }
271
-
272
- /**
273
- * Most users just get the basic menu items.
274
- * For users with `/items` priv, additional admin menu items are included too.
275
- * Having the `/flags` priv adds a further admin item for managing flags.
276
- */
277
- get userMenuItems() {
278
- const basicItems = this.menus.user;
279
-
280
- let adminItems = this.menus.userAdmin;
281
- if (this.canManageFlags) {
282
- adminItems = adminItems.concat(this.menus.userAdminFlags);
283
- }
284
-
285
- return this.itemIdentifier && this.admin
286
- ? [basicItems, adminItems]
287
- : [basicItems];
288
- }
289
-
290
- get allowSecondaryIcon() {
291
- return this.secondIdentitySlotMode === 'allow';
292
- }
293
-
294
- get secondLogoSlot() {
295
- return this.allowSecondaryIcon
296
- ? html`
297
- <slot name="opt-sec-logo" slot="opt-sec-logo"></slot>
298
- <slot name="opt-sec-logo-mobile" slot="opt-sec-logo-mobile"></slot>
299
- `
300
- : nothing;
301
- }
302
-
303
- get separatorTemplate() {
304
- return html`<li class="divider" role="presentation"></li>`;
305
- }
306
-
307
- render() {
308
- return html`
309
- <div class="topnav">
310
- <primary-nav
311
- .baseHost=${this.normalizedBaseHost}
312
- .mediaBaseHost=${this.mediaBaseHost}
313
- .config=${this.config}
314
- .openMenu=${this.openMenu}
315
- .screenName=${this.screenName}
316
- .searchIn=${this.searchIn}
317
- .searchQuery=${this.searchQuery}
318
- .secondIdentitySlotMode=${this.secondIdentitySlotMode}
319
- .selectedMenuOption=${this.selectedMenuOption}
320
- .username=${this.username}
321
- .userProfileImagePath=${this.userProfileImagePath}
322
- .currentTab=${this.currentTab}
323
- ?hideSearch=${this.hideSearch}
324
- @mediaTypeSelected=${this.mediaTypeSelected}
325
- @trackClick=${this.trackClick}
326
- @trackSubmit=${this.trackSubmit}
327
- @menuToggled=${this.menuToggled}
328
- @navSearchBlur=${this.navSearchBlurEvent}
329
- >
330
- ${this.secondLogoSlot}
331
- </primary-nav>
332
- <media-slider
333
- .baseHost=${this.normalizedBaseHost}
334
- .config=${this.config}
335
- .selectedMenuOption=${this.selectedMenuOption}
336
- .mediaSliderOpen=${this.mediaSliderOpen}
337
- .menus=${this.menus}
338
- tabindex="${this.mediaSliderOpen ? '1' : '-1'}"
339
- @focusToOtherMenuItem=${(e: CustomEvent) =>
340
- (this.currentTab = e.detail)}
341
- ></media-slider>
342
- </div>
343
- ${this.username ? this.userMenu : this.signedOutDropdown}
344
- <search-menu
345
- .baseHost=${this.normalizedBaseHost}
346
- .config=${this.config}
347
- .openMenu=${this.openMenu}
348
- tabindex="${this.searchMenuTabIndex}"
349
- ?hideSearch=${this.hideSearch}
350
- @searchInChanged=${this.searchInChanged}
351
- @trackClick=${this.trackClick}
352
- @trackSubmit=${this.trackSubmit}
353
- ></search-menu>
354
- <desktop-subnav
355
- .baseHost=${this.normalizedBaseHost}
356
- .menuItems=${this.menus.more.links}
357
- @focus=${this.closeMenus}
358
- ></desktop-subnav>
359
- <div
360
- id="close-layer"
361
- class="${this.closeLayerClass}"
362
- @click=${this.closeMenus}
363
- ></div>
364
- `;
365
- }
366
- }
1
+ import { LitElement, PropertyValues, html, nothing } from 'lit';
2
+ import { customElement, property, state } from 'lit/decorators.js';
3
+
4
+ import { buildTopNavMenus, defaultTopNavConfig } from './data/menus';
5
+ import './desktop-subnav';
6
+ import './dropdown-menu';
7
+ import './media-slider';
8
+ import {
9
+ IATopNavConfig,
10
+ IATopNavMenuConfig,
11
+ IATopNavSecondIdentitySlotMode,
12
+ } from './models';
13
+ import './primary-nav';
14
+ import './signed-out-dropdown';
15
+ import iaTopNavCSS from './styles/ia-topnav';
16
+ import './user-menu';
17
+
18
+ @customElement('ia-topnav')
19
+ export class IATopNav extends LitElement {
20
+ @property({ type: Boolean }) localLinks = false;
21
+
22
+ @property({ type: String }) waybackPagesArchived = '';
23
+
24
+ @property({ type: String }) baseHost = 'https://archive.org';
25
+
26
+ @property({ type: String }) mediaBaseHost = 'https://archive.org';
27
+
28
+ @property({ type: Boolean }) admin = false;
29
+
30
+ @property({ type: Boolean }) canManageFlags = false;
31
+
32
+ @property({ type: Object }) config: IATopNavConfig = defaultTopNavConfig;
33
+
34
+ @property({ type: Boolean }) hideSearch = false;
35
+
36
+ @property({ type: String }) itemIdentifier = '';
37
+
38
+ @property({ type: Boolean }) mediaSliderOpen = false;
39
+
40
+ @property({ type: String }) openMenu = '';
41
+
42
+ @property({ type: String }) screenName: string = '';
43
+
44
+ @property({ type: String }) selectedMenuOption = '';
45
+
46
+ @property({ type: String }) username: string = '';
47
+
48
+ @property({ type: String }) userProfileImagePath =
49
+ '/services/img/user/profile';
50
+
51
+ @property({ type: String })
52
+ secondIdentitySlotMode: IATopNavSecondIdentitySlotMode = '';
53
+
54
+ @property({ type: Object }) currentTab?: {
55
+ mediatype: string;
56
+ moveTo: string;
57
+ };
58
+
59
+ @state() private menus: IATopNavMenuConfig = buildTopNavMenus();
60
+
61
+ private boundHandleKeydown = this.handleDocumentKeydown.bind(this);
62
+
63
+ private boundHandleClick = this.handleDocumentClick.bind(this);
64
+
65
+ private get normalizedBaseHost() {
66
+ return !this.localLinks ? this.baseHost : '';
67
+ }
68
+
69
+ static get styles() {
70
+ return iaTopNavCSS;
71
+ }
72
+
73
+ updated(props: PropertyValues) {
74
+ if (
75
+ props.has('username') ||
76
+ props.has('waybackPagesArchived') ||
77
+ props.has('itemIdentifier') ||
78
+ props.has('localLinks') ||
79
+ props.has('baseHost')
80
+ ) {
81
+ this.menuSetup();
82
+ }
83
+ }
84
+
85
+ connectedCallback() {
86
+ super.connectedCallback();
87
+ document.addEventListener('keydown', this.boundHandleKeydown);
88
+ document.addEventListener('click', this.boundHandleClick);
89
+ }
90
+
91
+ disconnectedCallback() {
92
+ super.disconnectedCallback();
93
+ document.removeEventListener('keydown', this.boundHandleKeydown);
94
+ document.removeEventListener('click', this.boundHandleClick);
95
+ }
96
+
97
+ private handleDocumentKeydown(e: KeyboardEvent) {
98
+ if (e.key === 'Escape') {
99
+ this.openMenu = '';
100
+ this.mediaSliderOpen = false;
101
+ }
102
+ }
103
+
104
+ private handleDocumentClick(e: MouseEvent) {
105
+ if (!this.openMenu) return;
106
+ const path = e.composedPath();
107
+ if (!path.includes(this)) {
108
+ this.closeMenus();
109
+ }
110
+ }
111
+
112
+ menuSetup() {
113
+ // re/build the nav
114
+ this.menus = buildTopNavMenus(
115
+ this.username,
116
+ this.normalizedBaseHost,
117
+ this.waybackPagesArchived,
118
+ this.itemIdentifier,
119
+ );
120
+ }
121
+
122
+ menuToggled(e: CustomEvent) {
123
+ const currentMenu = this.openMenu;
124
+ this.openMenu = currentMenu === e.detail.menuName ? '' : e.detail.menuName;
125
+ // Keeps media slider open if media menu is open
126
+ if (this.openMenu === 'media') {
127
+ return;
128
+ }
129
+ this.closeMediaSlider();
130
+ }
131
+
132
+ openMediaSlider() {
133
+ this.mediaSliderOpen = true;
134
+ }
135
+
136
+ closeMediaSlider() {
137
+ this.mediaSliderOpen = false;
138
+ this.selectedMenuOption = '';
139
+ }
140
+
141
+ closeMenus() {
142
+ this.openMenu = '';
143
+ this.closeMediaSlider();
144
+ }
145
+
146
+ trackClick(e: CustomEvent) {
147
+ this.dispatchEvent(
148
+ new CustomEvent('analyticsClick', {
149
+ bubbles: true,
150
+ composed: true,
151
+ detail: e.detail,
152
+ }),
153
+ );
154
+ }
155
+
156
+ trackSubmit(e: CustomEvent) {
157
+ this.dispatchEvent(
158
+ new CustomEvent('analyticsSubmit', {
159
+ bubbles: true,
160
+ composed: true,
161
+ detail: e.detail,
162
+ }),
163
+ );
164
+ }
165
+
166
+ mediaTypeSelected(e: CustomEvent) {
167
+ if (this.selectedMenuOption === e.detail.mediatype) {
168
+ this.closeMediaSlider();
169
+ return;
170
+ }
171
+ this.selectedMenuOption = e.detail.mediatype;
172
+ this.openMediaSlider();
173
+ }
174
+
175
+ get signedOutOpened() {
176
+ return this.openMenu === 'login';
177
+ }
178
+
179
+ get userMenuOpened() {
180
+ return this.openMenu === 'user';
181
+ }
182
+
183
+ get userMenuTabIndex() {
184
+ return this.userMenuOpened ? '' : '-1';
185
+ }
186
+
187
+ get signedOutTabIndex() {
188
+ return this.signedOutOpened ? '' : '-1';
189
+ }
190
+
191
+ get closeLayerClass() {
192
+ return !!this.openMenu || this.mediaSliderOpen ? 'visible' : '';
193
+ }
194
+
195
+ get userMenu() {
196
+ return html`
197
+ <user-menu
198
+ .baseHost=${this.normalizedBaseHost}
199
+ .config=${this.config}
200
+ .menuItems=${this.userMenuItems}
201
+ ?open=${this.openMenu === 'user'}
202
+ .username=${this.username}
203
+ ?hideSearch=${this.hideSearch}
204
+ tabindex="${this.userMenuTabIndex}"
205
+ @menuToggled=${this.menuToggled}
206
+ @trackClick=${this.trackClick}
207
+ @focusToOtherMenuItem=${(e: CustomEvent) =>
208
+ (this.currentTab = e.detail)}
209
+ ></user-menu>
210
+ `;
211
+ }
212
+
213
+ get signedOutDropdown() {
214
+ return html`
215
+ <signed-out-dropdown
216
+ .baseHost=${this.normalizedBaseHost}
217
+ .config=${this.config}
218
+ .open=${this.signedOutOpened}
219
+ ?hideSearch=${this.hideSearch}
220
+ tabindex="${this.signedOutTabIndex}"
221
+ .menuItems=${this.signedOutMenuItems}
222
+ @focusToOtherMenuItem=${(e: CustomEvent) => {
223
+ this.currentTab = e.detail;
224
+ }}
225
+ ></signed-out-dropdown>
226
+ `;
227
+ }
228
+
229
+ get signedOutMenuItems() {
230
+ return this.menus.signedOut;
231
+ }
232
+
233
+ /**
234
+ * Most users just get the basic menu items.
235
+ * For users with `/items` priv, additional admin menu items are included too.
236
+ * Having the `/flags` priv adds a further admin item for managing flags.
237
+ */
238
+ get userMenuItems() {
239
+ const basicItems = this.menus.user;
240
+
241
+ let adminItems = this.menus.userAdmin;
242
+ if (this.canManageFlags) {
243
+ adminItems = adminItems.concat(this.menus.userAdminFlags);
244
+ }
245
+
246
+ return this.itemIdentifier && this.admin
247
+ ? [basicItems, adminItems]
248
+ : [basicItems];
249
+ }
250
+
251
+ get allowSecondaryIcon() {
252
+ return this.secondIdentitySlotMode === 'allow';
253
+ }
254
+
255
+ get searchSlot() {
256
+ return html`<slot name="search" slot="search"></slot>`;
257
+ }
258
+
259
+ get secondLogoSlot() {
260
+ return this.allowSecondaryIcon
261
+ ? html`
262
+ <slot name="opt-sec-logo" slot="opt-sec-logo"></slot>
263
+ <slot name="opt-sec-logo-mobile" slot="opt-sec-logo-mobile"></slot>
264
+ `
265
+ : nothing;
266
+ }
267
+
268
+ get separatorTemplate() {
269
+ return html`<li class="divider" role="presentation"></li>`;
270
+ }
271
+
272
+ render() {
273
+ return html`
274
+ <div class="topnav">
275
+ <primary-nav
276
+ .baseHost=${this.normalizedBaseHost}
277
+ .mediaBaseHost=${this.mediaBaseHost}
278
+ .config=${this.config}
279
+ .openMenu=${this.openMenu}
280
+ .screenName=${this.screenName}
281
+ .secondIdentitySlotMode=${this.secondIdentitySlotMode}
282
+ .selectedMenuOption=${this.selectedMenuOption}
283
+ .username=${this.username}
284
+ .userProfileImagePath=${this.userProfileImagePath}
285
+ .currentTab=${this.currentTab}
286
+ ?hideSearch=${this.hideSearch}
287
+ @mediaTypeSelected=${this.mediaTypeSelected}
288
+ @trackClick=${this.trackClick}
289
+ @trackSubmit=${this.trackSubmit}
290
+ @menuToggled=${this.menuToggled}
291
+ >
292
+ ${this.secondLogoSlot} ${this.searchSlot}
293
+ </primary-nav>
294
+ <media-slider
295
+ .baseHost=${this.normalizedBaseHost}
296
+ .config=${this.config}
297
+ .selectedMenuOption=${this.selectedMenuOption}
298
+ .mediaSliderOpen=${this.mediaSliderOpen}
299
+ .menus=${this.menus}
300
+ tabindex="${this.mediaSliderOpen ? '1' : '-1'}"
301
+ @focusToOtherMenuItem=${(e: CustomEvent) =>
302
+ (this.currentTab = e.detail)}
303
+ ></media-slider>
304
+ </div>
305
+ ${this.username ? this.userMenu : this.signedOutDropdown}
306
+ <desktop-subnav
307
+ .baseHost=${this.normalizedBaseHost}
308
+ .menuItems=${this.menus.more.links}
309
+ @focus=${this.closeMenus}
310
+ ></desktop-subnav>
311
+ <div
312
+ id="close-layer"
313
+ class="${this.closeLayerClass}"
314
+ @click=${this.closeMenus}
315
+ ></div>
316
+ `;
317
+ }
318
+ }