diff options
Diffstat (limited to '')
| -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> | ||
