HeaderBar.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. <template>
  2. <header ref="header">
  3. <div class="logo">
  4. <div class="small">
  5. <span> RS </span>
  6. </div>
  7. <div class="big">
  8. <span> RedstoneServer </span>
  9. </div>
  10. </div>
  11. <nav ref="navigation">
  12. <div class="topbar" ref="topbar">
  13. <router-link class="t_link link" :to="element.val" v-for="element in primary" :key="element.key">{{ element.key }}</router-link>
  14. </div>
  15. <div class="wrapper">
  16. <span class="t_link_d t_link link" ref="dropdownArrow">VV</span>
  17. <div class="dropdown">
  18. <router-link class="d_link link" :to="element.val" v-for="element in secondary" :key="element.key">{{ element.key }}</router-link>
  19. </div>
  20. </div>
  21. </nav>
  22. <div class="user">
  23. <div v-if="user">
  24. <span v-if="!compressed">Username: {{ user.username }} </span>
  25. <span v-else>Hi, {{ user.username }} </span>
  26. <span class="link" @click="logout">Logout</span>
  27. </div>
  28. <router-link class="link" to="/login" v-else>Login</router-link>
  29. </div>
  30. </header>
  31. </template>
  32. <script>
  33. export default {
  34. data () {
  35. return {
  36. links: {
  37. primary: {
  38. 'Startpage': '/',
  39. 'Applications': '/applications',
  40. 'Development Blog': '/devblog',
  41. },
  42. secondary: {
  43. 'Impressum': '/impressum',
  44. },
  45. },
  46. intLinks: {
  47. primary: [],
  48. secondary: [],
  49. },
  50. primary: [],
  51. secondary: [],
  52. compressed: false,
  53. }
  54. },
  55. created() {
  56. //Convert the given links to arrays for later processing.
  57. this.intLinks.primary = this.convertToArray(this.links.primary)
  58. this.intLinks.secondary = this.convertToArray(this.links.secondary)
  59. },
  60. computed: {
  61. user() {
  62. return this.$store.state.user
  63. },
  64. },
  65. methods: {
  66. updateMenu() {
  67. //Empty to measure the whole available space.
  68. this.primary = []
  69. this.compressed = false
  70. this.$nextTick(() => {
  71. let menubar = this.$refs.topbar
  72. //Subtract safety pixels, scrollbars come a bit later after resize.
  73. let maxWidth = this.$refs.navigation.clientWidth - this.$refs.dropdownArrow.offsetWidth - 30
  74. //Add all preprocessed links to measure them in current env.
  75. this.primary = this.intLinks.primary
  76. this.$nextTick(() => {
  77. let sizes = []
  78. for(let el of menubar.childNodes) {
  79. sizes.push(el.offsetWidth)
  80. }
  81. this.primary = []
  82. this.secondary = []
  83. let linkSize = this.intLinks.primary.length
  84. let tmp = 0;
  85. for(let i = 0; i < linkSize; i++) {
  86. tmp += sizes[i] //Add the size of the current element
  87. if(maxWidth > tmp) {
  88. this.primary.push(this.intLinks.primary[i])
  89. } else {
  90. this.secondary.push(this.intLinks.primary[i])
  91. }
  92. }
  93. this.secondary = this.secondary.concat(this.intLinks.secondary)
  94. //TODO: Improve, set dropdown to middle when this mode.
  95. //Check if there is still no space, if so, minimized view.
  96. this.$nextTick(() => {
  97. if(this.$refs.header.scrollWidth > (window.innerWidth || document.documentElement.clientWidth)) {
  98. this.compressed = true
  99. }
  100. })
  101. })
  102. })
  103. },
  104. convertToArray(obj) {
  105. let els = []
  106. for(let key in obj) {
  107. if(obj.hasOwnProperty(key)) {
  108. els.push({
  109. key: key,
  110. val: obj[key],
  111. })
  112. }
  113. }
  114. return els
  115. },
  116. logout() {
  117. this.core.logout()
  118. },
  119. },
  120. watch: {
  121. user: function() {
  122. this.updateMenu()
  123. }
  124. },
  125. mounted() {
  126. window.addEventListener('resize', this.updateMenu)
  127. //Initial menu sorting
  128. this.updateMenu()
  129. },
  130. beforeDestroy() {
  131. //TBI never will be closed...!
  132. window.removeEventListener('resize', this.updateMenu)
  133. },
  134. }
  135. </script>
  136. <style scoped>
  137. /*
  138. Whole line:
  139. */
  140. header {
  141. display: flex;
  142. white-space: nowrap;
  143. background-color: #222;
  144. font-size: 1.5em;
  145. }
  146. nav {
  147. flex-grow: 100;
  148. /* try permanent? */
  149. display: flex;
  150. justify-content: center;
  151. align-items: center;
  152. }
  153. /*
  154. Dropdown mechanic:
  155. */
  156. .dropdown {
  157. position: absolute;
  158. display: none;
  159. background-color: #222;
  160. right: 50%;
  161. transform: translateX(50%);
  162. }
  163. .wrapper:hover > .dropdown {
  164. display: block;
  165. }
  166. .wrapper {
  167. position: relative;
  168. display: inline;
  169. }
  170. .topbar {
  171. display: inline;
  172. }
  173. /*
  174. Generic link properties:
  175. */
  176. .link {
  177. padding: 0em 0.2em;
  178. color: #aaa;
  179. text-decoration: none;
  180. }
  181. .link:hover {
  182. color: #ddd;
  183. background-color: #333;
  184. }
  185. /*
  186. Specific link properties:
  187. */
  188. .t_link {
  189. border-right: 1px solid #aaa;
  190. }
  191. .d_link {
  192. display: block;
  193. border-top: 1px solid #aaa;
  194. }
  195. .t_link_d {
  196. border-right: none;
  197. }
  198. /*
  199. Header compression:
  200. */
  201. .logo > .small {
  202. display: none;
  203. }
  204. @media (max-width: 600px) {
  205. /* Switch to the small logo */
  206. .logo > .small {
  207. display: initial;
  208. }
  209. .logo > .big {
  210. display: none;
  211. }
  212. /* Center the dropdown menu */
  213. .wrapper {
  214. position: initial;
  215. }
  216. }
  217. </style>