1
+ import { select } from "../../../util/dom.js" ;
1
2
2
3
export { SimpleNavigationProjector }
3
4
4
5
const PAGE_CLASS = "simpleNavigationProjector" ;
5
6
7
+ const iconSVGStr = `
8
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
9
+ <path d="M8 5L15.0368 11.9632L8 18.9263" stroke="url(#paint0_linear_1028_8530)"/>
10
+ <defs>
11
+ <linearGradient id="paint0_linear_1028_8530" x1="7.98915" y1="5" x2="18.7337" y2="14.9252" gradientUnits="userSpaceOnUse">
12
+ <stop offset="0" stop-color="#FF2CA5"/>
13
+ <stop offset="1" stop-color="#6000FF"/>
14
+ </linearGradient>
15
+ </svg>
16
+ ` ;
17
+
6
18
/**
7
19
* A projector of anchors to all pages that are registered in the {@link SiteControllerType}.
8
20
* It binds each anchor to the "visited" state and highlights the currently selected page (uriHash).
9
21
* The highlighting is part of the style but layouting of the anchors is left to the parent
10
22
* such that the same projector can be used for horizontal and vertical display.
11
23
* @constructor
12
24
* @param { !SiteControllerType } siteController - the source of the information that we display
13
- * @param { !HTMLDivElement } root - where to mount the view
25
+ * @param { !HTMLDivElement } root - where to mount the view
26
+ * @param { Boolean= } canHide - whether this navigation can hide itself, defaults to false
14
27
* @return { NavigationProjectorType }
15
28
* @example
16
29
* // set up
@@ -24,9 +37,9 @@ const PAGE_CLASS = "simpleNavigationProjector";
24
37
* SimpleNavigationProjector(siteController, siteProjector.topNavigationElement);
25
38
*/
26
39
27
- const SimpleNavigationProjector = ( siteController , root ) => {
40
+ const SimpleNavigationProjector = ( siteController , root , canHide = false ) => {
28
41
29
- root . innerHTML = ` <nav class="${ PAGE_CLASS } "></nav> ` ;
42
+ root . innerHTML = `<nav class="${ PAGE_CLASS } "></nav> ` ;
30
43
31
44
const projectNavigation = ( ) => {
32
45
@@ -35,10 +48,10 @@ const SimpleNavigationProjector = (siteController, root) => {
35
48
document . head . innerHTML += projectorStyle ;
36
49
}
37
50
38
- const navigationDiv = root . querySelector ( `nav.${ PAGE_CLASS } ` ) ;
51
+ const [ navigationEl ] = select ( root , `nav.${ PAGE_CLASS } ` ) ;
39
52
40
53
// view is just so many anchors
41
- navigationDiv . innerHTML =
54
+ navigationEl . innerHTML = ( canHide ? `<div class="toggler"> ${ iconSVGStr } </div>` : '' ) +
42
55
Object . entries ( siteController . getAllPages ( ) )
43
56
. map ( ( [ hash , page ] ) => `<a href="${ hash } ">${ page . titleText } </a>` )
44
57
. join ( " " ) ;
@@ -49,13 +62,18 @@ const SimpleNavigationProjector = (siteController, root) => {
49
62
Object . entries ( siteController . getAllPages ( ) )
50
63
. forEach ( ( [ hash , page ] ) => page . onVisited ( visited => {
51
64
if ( ! visited ) return ;
52
- navigationDiv . querySelector ( `a[href="${ hash } "]` ) . classList . add ( "visited" ) ;
65
+ navigationEl . querySelector ( `a[href="${ hash } "]` ) ? .classList ? .add ( "visited" ) ;
53
66
} ) ) ;
54
67
// update which anchor shows the current page
55
68
siteController . onUriHashChanged ( ( newHash , oldHash ) => {
56
- navigationDiv . querySelector ( `a[href="${ oldHash } "]` ) ?. classList ?. remove ( "current" ) ;
57
- navigationDiv . querySelector ( `a[href="${ newHash } "]` ) ?. classList ?. add ( "current" ) ;
69
+ navigationEl . querySelector ( `a[href="${ oldHash } "]` ) ?. classList ?. remove ( "current" ) ;
70
+ navigationEl . querySelector ( `a[href="${ newHash } "]` ) ?. classList ?. add ( "current" ) ;
58
71
} ) ;
72
+
73
+ if ( canHide ) {
74
+ navigationEl . classList . toggle ( "hide" ) ;
75
+ select ( navigationEl , ".toggler" ) . head ( ) . onclick = _evt => navigationEl . classList . toggle ( "hide" ) ;
76
+ }
59
77
} ;
60
78
61
79
projectNavigation ( ) ;
@@ -65,18 +83,44 @@ const projectorStyle = `
65
83
<style data-style-id="${ PAGE_CLASS } ">
66
84
@layer navigationLayer {
67
85
.${ PAGE_CLASS } {
86
+ &.hide {
87
+ .toggler {
88
+ rotate: 0deg;
89
+ }
90
+ a, a.current { /* hide the anchors */
91
+ width: 0;
92
+ color: transparent;
93
+ pointer-events: none;
94
+ }
95
+ }
96
+ .toggler { /* provide a box for the svg */
97
+ justify-self: center;
98
+ width: 2rem;
99
+ aspect-ratio: 1 / 1;
100
+ rotate: 180deg;
101
+ transition: rotate .3s ease-in-out;
102
+ }
103
+ svg {
104
+ fill: none;
105
+ stroke-width: 2;
106
+ stroke-linecap: round;
107
+ stroke-linejoin: round;
108
+ }
68
109
a {
69
- text-wrap: nowrap;
70
- font-family: system-ui;
110
+ color: revert;
111
+ pointer-events: revert;
112
+ user-select: none;
113
+ text-wrap: nowrap;
114
+ font-family: system-ui;
71
115
}
72
116
a.visited {
73
- text-decoration: none;
117
+ text-decoration: none;
74
118
}
75
119
a.visited:not(.current) {
76
- filter: brightness(150%) grayscale(60%);
120
+ filter: brightness(150%) grayscale(60%);
77
121
}
78
122
a.current {
79
- color: var(--kolibri-color-accent, deeppink);
123
+ color: var(--kolibri-color-accent, deeppink);
80
124
}
81
125
}
82
126
}
0 commit comments