diff options
Diffstat (limited to 'doc/docs/.vuepress/theme/components/DropdownLink.vue')
-rw-r--r-- | doc/docs/.vuepress/theme/components/DropdownLink.vue | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/doc/docs/.vuepress/theme/components/DropdownLink.vue b/doc/docs/.vuepress/theme/components/DropdownLink.vue new file mode 100644 index 0000000..be6563f --- /dev/null +++ b/doc/docs/.vuepress/theme/components/DropdownLink.vue | |||
@@ -0,0 +1,252 @@ | |||
1 | <template> | ||
2 | <div | ||
3 | class="dropdown-wrapper" | ||
4 | :class="{ open }" | ||
5 | > | ||
6 | <button | ||
7 | class="dropdown-title" | ||
8 | type="button" | ||
9 | :aria-label="dropdownAriaLabel" | ||
10 | @click="handleDropdown" | ||
11 | > | ||
12 | <span class="title">{{ item.text }}</span> | ||
13 | <span | ||
14 | class="arrow down" | ||
15 | /> | ||
16 | </button> | ||
17 | <button | ||
18 | class="mobile-dropdown-title" | ||
19 | type="button" | ||
20 | :aria-label="dropdownAriaLabel" | ||
21 | @click="setOpen(!open)" | ||
22 | > | ||
23 | <span class="title">{{ item.text }}</span> | ||
24 | <span | ||
25 | class="arrow" | ||
26 | :class="open ? 'down' : 'right'" | ||
27 | /> | ||
28 | </button> | ||
29 | |||
30 | <DropdownTransition> | ||
31 | <ul | ||
32 | v-show="open" | ||
33 | class="nav-dropdown" | ||
34 | > | ||
35 | <li | ||
36 | v-for="(subItem, index) in item.items" | ||
37 | :key="subItem.link || index" | ||
38 | class="dropdown-item" | ||
39 | > | ||
40 | <h4 v-if="subItem.type === 'links'"> | ||
41 | {{ subItem.text }} | ||
42 | </h4> | ||
43 | |||
44 | <ul | ||
45 | v-if="subItem.type === 'links'" | ||
46 | class="dropdown-subitem-wrapper" | ||
47 | > | ||
48 | <li | ||
49 | v-for="childSubItem in subItem.items" | ||
50 | :key="childSubItem.link" | ||
51 | class="dropdown-subitem" | ||
52 | > | ||
53 | <NavLink | ||
54 | :item="childSubItem" | ||
55 | @focusout=" | ||
56 | isLastItemOfArray(childSubItem, subItem.items) && | ||
57 | isLastItemOfArray(subItem, item.items) && | ||
58 | setOpen(false) | ||
59 | " | ||
60 | /> | ||
61 | </li> | ||
62 | </ul> | ||
63 | |||
64 | <NavLink | ||
65 | v-else | ||
66 | :item="subItem" | ||
67 | @focusout="isLastItemOfArray(subItem, item.items) && setOpen(false)" | ||
68 | /> | ||
69 | </li> | ||
70 | </ul> | ||
71 | </DropdownTransition> | ||
72 | </div> | ||
73 | </template> | ||
74 | |||
75 | <script> | ||
76 | import NavLink from '@theme/components/NavLink.vue' | ||
77 | import DropdownTransition from '@theme/components/DropdownTransition.vue' | ||
78 | import last from 'lodash/last' | ||
79 | |||
80 | export default { | ||
81 | name: 'DropdownLink', | ||
82 | |||
83 | components: { | ||
84 | NavLink, | ||
85 | DropdownTransition | ||
86 | }, | ||
87 | |||
88 | props: { | ||
89 | item: { | ||
90 | required: true | ||
91 | } | ||
92 | }, | ||
93 | |||
94 | data () { | ||
95 | return { | ||
96 | open: false | ||
97 | } | ||
98 | }, | ||
99 | |||
100 | computed: { | ||
101 | dropdownAriaLabel () { | ||
102 | return this.item.ariaLabel || this.item.text | ||
103 | } | ||
104 | }, | ||
105 | |||
106 | watch: { | ||
107 | $route () { | ||
108 | this.open = false | ||
109 | } | ||
110 | }, | ||
111 | |||
112 | methods: { | ||
113 | setOpen (value) { | ||
114 | this.open = value | ||
115 | }, | ||
116 | |||
117 | isLastItemOfArray (item, array) { | ||
118 | return last(array) === item | ||
119 | }, | ||
120 | |||
121 | /** | ||
122 | * Open the dropdown when user tab and click from keyboard. | ||
123 | * | ||
124 | * Use event.detail to detect tab and click from keyboard. Ref: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail | ||
125 | * The Tab + Click is UIEvent > KeyboardEvent, so the detail is 0. | ||
126 | */ | ||
127 | handleDropdown () { | ||
128 | const isTriggerByTab = event.detail === 0 | ||
129 | if (isTriggerByTab) this.setOpen(!this.open) | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | </script> | ||
134 | |||
135 | <style lang="stylus"> | ||
136 | .dropdown-wrapper | ||
137 | cursor pointer | ||
138 | .dropdown-title | ||
139 | display block | ||
140 | font-size 0.9rem | ||
141 | font-family inherit | ||
142 | cursor inherit | ||
143 | padding inherit | ||
144 | line-height 1.4rem | ||
145 | background transparent | ||
146 | border none | ||
147 | font-weight 500 | ||
148 | color $textColor | ||
149 | &:hover | ||
150 | border-color transparent | ||
151 | .arrow | ||
152 | vertical-align middle | ||
153 | margin-top -1px | ||
154 | margin-left 0.4rem | ||
155 | .mobile-dropdown-title | ||
156 | @extends .dropdown-title | ||
157 | display none | ||
158 | font-weight 600 | ||
159 | font-size inherit | ||
160 | &:hover | ||
161 | color $accentColor | ||
162 | .nav-dropdown | ||
163 | .dropdown-item | ||
164 | color inherit | ||
165 | line-height 1.7rem | ||
166 | h4 | ||
167 | margin 0.45rem 0 0 | ||
168 | border-top 1px solid #eee | ||
169 | padding 1rem 1.5rem 0.45rem 1.25rem | ||
170 | .dropdown-subitem-wrapper | ||
171 | padding 0 | ||
172 | list-style none | ||
173 | .dropdown-subitem | ||
174 | font-size 0.9em | ||
175 | a | ||
176 | display block | ||
177 | line-height 1.7rem | ||
178 | position relative | ||
179 | border-bottom none | ||
180 | font-weight 400 | ||
181 | margin-bottom 0 | ||
182 | padding 0 1.5rem 0 1.25rem | ||
183 | &:hover | ||
184 | color $accentColor | ||
185 | &.router-link-active | ||
186 | color $accentColor | ||
187 | &::after | ||
188 | content "" | ||
189 | width 0 | ||
190 | height 0 | ||
191 | border-left 5px solid $accentColor | ||
192 | border-top 3px solid transparent | ||
193 | border-bottom 3px solid transparent | ||
194 | position absolute | ||
195 | top calc(50% - 2px) | ||
196 | left 9px | ||
197 | &:first-child h4 | ||
198 | margin-top 0 | ||
199 | padding-top 0 | ||
200 | border-top 0 | ||
201 | |||
202 | @media (max-width: $MQMobile) | ||
203 | .dropdown-wrapper | ||
204 | &.open .dropdown-title | ||
205 | margin-bottom 0.5rem | ||
206 | .dropdown-title | ||
207 | display: none | ||
208 | .mobile-dropdown-title | ||
209 | display: block | ||
210 | .nav-dropdown | ||
211 | transition height .1s ease-out | ||
212 | overflow hidden | ||
213 | .dropdown-item | ||
214 | h4 | ||
215 | border-top 0 | ||
216 | margin-top 0 | ||
217 | padding-top 0 | ||
218 | h4, & > a | ||
219 | font-size 15px | ||
220 | line-height 2rem | ||
221 | .dropdown-subitem | ||
222 | font-size 14px | ||
223 | padding-left 1rem | ||
224 | |||
225 | @media (min-width: $MQMobile) | ||
226 | .dropdown-wrapper | ||
227 | height 1.8rem | ||
228 | &:hover .nav-dropdown, | ||
229 | &.open .nav-dropdown | ||
230 | // override the inline style. | ||
231 | display block !important | ||
232 | &.open:blur | ||
233 | display none | ||
234 | .nav-dropdown | ||
235 | display none | ||
236 | // Avoid height shaked by clicking | ||
237 | height auto !important | ||
238 | box-sizing border-box; | ||
239 | max-height calc(100vh - 2.7rem) | ||
240 | overflow-y auto | ||
241 | position absolute | ||
242 | top 100% | ||
243 | right 0 | ||
244 | background-color #fff | ||
245 | padding 0.6rem 0 | ||
246 | border 1px solid #ddd | ||
247 | border-bottom-color #ccc | ||
248 | text-align left | ||
249 | border-radius 0.25rem | ||
250 | white-space nowrap | ||
251 | margin 0 | ||
252 | </style> | ||