CustomNavBar.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <script lang="ts" setup>
  2. import { useWindowScroll } from "@vueuse/core";
  3. import { ref, watchPostEffect, computed } from "vue";
  4. import { useData } from "vitepress";
  5. import { useSidebar } from "vitepress/theme";
  6. import VPNavBarAppearance from "vitepress/dist/client/theme-default/components/VPNavBarAppearance.vue";
  7. import VPNavBarExtra from "vitepress/dist/client/theme-default/components/VPNavBarExtra.vue";
  8. import VPNavBarHamburger from "vitepress/dist/client/theme-default/components/VPNavBarHamburger.vue";
  9. import VPNavBarMenu from "vitepress/dist/client/theme-default/components/VPNavBarMenu.vue";
  10. import VPNavBarSearch from "vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
  11. import VPNavBarSocialLinks from "vitepress/dist/client/theme-default/components/VPNavBarSocialLinks.vue";
  12. import VPNavBarTitle from "vitepress/dist/client/theme-default/components/VPNavBarTitle.vue";
  13. import VPNavBarTranslations from "vitepress/dist/client/theme-default/components/VPNavBarTranslations.vue";
  14. import CustomNavBarTranslations from './CustomNavBarTranslations.vue'
  15. defineProps<{
  16. isScreenOpen: boolean;
  17. }>();
  18. defineEmits<{
  19. (e: "toggle-screen"): void;
  20. }>();
  21. const { y } = useWindowScroll();
  22. const { hasSidebar } = useSidebar();
  23. const { frontmatter } = useData();
  24. const classes = ref<Record<string, boolean>>({});
  25. watchPostEffect(() => {
  26. classes.value = {
  27. "has-sidebar": hasSidebar.value,
  28. home: frontmatter.value.layout === "home",
  29. top: y.value === 0,
  30. };
  31. });
  32. const hasSearch = computed(() => {
  33. return frontmatter.value.layout !== 'home'
  34. })
  35. </script>
  36. <template>
  37. <div class="VPNavBar" :class="classes">
  38. <div class="wrapper">
  39. <div class="container">
  40. <div class="title">
  41. <VPNavBarTitle>
  42. <template #nav-bar-title-before
  43. ><slot name="nav-bar-title-before"
  44. /></template>
  45. <template #nav-bar-title-after><slot name="nav-bar-title-after" /></template>
  46. </VPNavBarTitle>
  47. </div>
  48. <div class="content">
  49. <div class="content-body">
  50. <slot name="nav-bar-content-before" />
  51. <VPNavBarSearch class="search" :class="{ 'hide-search': !hasSearch }" />
  52. <VPNavBarMenu class="menu" />
  53. <CustomNavBarTranslations class="translations" />
  54. <VPNavBarAppearance class="appearance" />
  55. <VPNavBarSocialLinks class="social-links" />
  56. <!-- <VPNavBarExtra class="extra" /> -->
  57. <slot name="nav-bar-content-after" />
  58. <!-- <VPNavBarHamburger
  59. class="hamburger"
  60. :active="isScreenOpen"
  61. @click="$emit('toggle-screen')"
  62. /> -->
  63. </div>
  64. </div>
  65. </div>
  66. </div>
  67. <div class="divider">
  68. <div class="divider-line" />
  69. </div>
  70. </div>
  71. </template>
  72. <style scoped lang="scss">
  73. .search {
  74. justify-content: end;
  75. &.hide-search > :deep(div) {
  76. display: none;
  77. }
  78. }
  79. </style>
  80. <style scoped>
  81. .VPNavBar {
  82. position: relative;
  83. height: var(--vp-nav-height);
  84. pointer-events: none;
  85. white-space: nowrap;
  86. transition: background-color 0.5s;
  87. }
  88. .VPNavBar:not(.home) {
  89. background-color: var(--vp-nav-bg-color);
  90. }
  91. @media (min-width: 960px) {
  92. .VPNavBar:not(.home) {
  93. background-color: transparent;
  94. }
  95. .VPNavBar:not(.has-sidebar):not(.home.top) {
  96. background-color: var(--vp-nav-bg-color);
  97. }
  98. }
  99. .wrapper {
  100. padding: 0 8px 0 24px;
  101. }
  102. @media (min-width: 768px) {
  103. .wrapper {
  104. padding: 0 32px;
  105. }
  106. }
  107. @media (min-width: 960px) {
  108. .VPNavBar.has-sidebar .wrapper {
  109. padding: 0;
  110. }
  111. }
  112. .container {
  113. display: flex;
  114. justify-content: space-between;
  115. margin: 0 auto;
  116. max-width: calc(var(--vp-layout-max-width) - 64px);
  117. height: var(--vp-nav-height);
  118. pointer-events: none;
  119. }
  120. .container > .title,
  121. .container > .content {
  122. pointer-events: none;
  123. overflow: hidden;
  124. }
  125. .container :deep(*) {
  126. pointer-events: auto;
  127. }
  128. @media (min-width: 960px) {
  129. .VPNavBar.has-sidebar .container {
  130. max-width: 100%;
  131. }
  132. }
  133. .title {
  134. flex-shrink: 0;
  135. height: calc(var(--vp-nav-height) - 1px);
  136. transition: background-color 0.5s;
  137. }
  138. @media (min-width: 960px) {
  139. .VPNavBar.has-sidebar .title {
  140. position: absolute;
  141. top: 0;
  142. left: 0;
  143. z-index: 2;
  144. padding: 0 32px;
  145. width: var(--vp-sidebar-width);
  146. height: var(--vp-nav-height);
  147. background-color: transparent;
  148. }
  149. }
  150. @media (min-width: 1440px) {
  151. .VPNavBar.has-sidebar .title {
  152. padding-left: max(32px, calc((100% - (var(--vp-layout-max-width) - 64px)) / 2));
  153. width: calc(
  154. (100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - 32px
  155. );
  156. }
  157. }
  158. .content {
  159. flex-grow: 1;
  160. }
  161. @media (min-width: 960px) {
  162. .VPNavBar.has-sidebar .content {
  163. position: relative;
  164. z-index: 1;
  165. padding-right: 32px;
  166. padding-left: var(--vp-sidebar-width);
  167. }
  168. }
  169. @media (min-width: 1440px) {
  170. .VPNavBar.has-sidebar .content {
  171. padding-right: calc((100vw - var(--vp-layout-max-width)) / 2 + 32px);
  172. padding-left: calc(
  173. (100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)
  174. );
  175. }
  176. }
  177. .content-body {
  178. display: flex;
  179. justify-content: flex-end;
  180. align-items: center;
  181. height: var(--vp-nav-height);
  182. transition: background-color 0.5s;
  183. }
  184. @media (min-width: 960px) {
  185. .VPNavBar:not(.home.top) .content-body {
  186. position: relative;
  187. background-color: var(--vp-nav-bg-color);
  188. }
  189. .VPNavBar:not(.has-sidebar):not(.home.top) .content-body {
  190. background-color: transparent;
  191. }
  192. }
  193. @media (max-width: 767px) {
  194. .content-body {
  195. column-gap: 0.5rem;
  196. }
  197. }
  198. .menu + .translations::before,
  199. .menu + .appearance::before,
  200. .menu + .social-links::before,
  201. .translations + .appearance::before,
  202. .appearance + .social-links::before {
  203. margin-right: 8px;
  204. margin-left: 8px;
  205. width: 1px;
  206. height: 24px;
  207. background-color: var(--vp-c-divider);
  208. content: "";
  209. }
  210. .menu + .appearance::before,
  211. .translations + .appearance::before {
  212. margin-right: 16px;
  213. }
  214. .appearance + .social-links::before {
  215. margin-left: 16px;
  216. }
  217. .social-links {
  218. margin-right: -8px;
  219. }
  220. .divider {
  221. width: 100%;
  222. height: 1px;
  223. }
  224. @media (min-width: 960px) {
  225. .VPNavBar.has-sidebar .divider {
  226. padding-left: var(--vp-sidebar-width);
  227. }
  228. }
  229. @media (min-width: 1440px) {
  230. .VPNavBar.has-sidebar .divider {
  231. padding-left: calc(
  232. (100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)
  233. );
  234. }
  235. }
  236. .divider-line {
  237. width: 100%;
  238. height: 1px;
  239. transition: background-color 0.5s;
  240. }
  241. .VPNavBar:not(.home) .divider-line {
  242. background-color: var(--vp-c-gutter);
  243. }
  244. @media (min-width: 960px) {
  245. .VPNavBar:not(.home.top) .divider-line {
  246. background-color: var(--vp-c-gutter);
  247. }
  248. .VPNavBar:not(.has-sidebar):not(.home.top) .divider {
  249. background-color: var(--vp-c-gutter);
  250. }
  251. }
  252. </style>