index.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <template>
  2. <div
  3. v-if="store.isRendered"
  4. ref="sideBarEl"
  5. class="w-screen h-screen fixed top-0 left-0 z-10"
  6. >
  7. <div
  8. :class="store.isVisible ? 'bg-opacity-70' : 'bg-opacity-0'"
  9. class="w-full h-full bg-black animate__animated animate__faster animate__fadeIn duration-500"
  10. @click="store.hide"
  11. />
  12. <div
  13. :class="
  14. store.isVisible
  15. ? 'animate__animated animate__faster animate__slideInLeft'
  16. : 'animate__animated animate__faster animate__slideOutLeft'
  17. "
  18. class="absolute top-0 min-w-[330px] h-full bg-background-100 p-4"
  19. :style="`left: -${translateTo}px`"
  20. >
  21. <div
  22. class="w-full h-full flex flex-col gap-[10px] show transition-all"
  23. :class="store.isVisible ? 'opacity-100' : 'opacity-0'"
  24. >
  25. <div class="flex items-center gap-4 mb-4">
  26. <img
  27. v-if="info"
  28. :src="info.user_info.image"
  29. class="w-[72px] h-[72px] rounded-full show"
  30. >
  31. <div
  32. v-else
  33. class="w-[72px] h-[72px] rounded-full loading"
  34. />
  35. <div class="w-fit flex flex-col text-foreground">
  36. <h1
  37. v-if="info"
  38. class="text-2xl show"
  39. v-text="info.user_info.name"
  40. />
  41. <div
  42. v-else
  43. class="w-48 h-8 rounded-md loading"
  44. />
  45. <div class="flex justify-between opacity-60">
  46. <template v-if="info">
  47. <h3
  48. class="show"
  49. v-text="info.main_info.Группа"
  50. />
  51. <h3
  52. class="show"
  53. v-text="info.courses[0].title"
  54. />
  55. </template>
  56. <template v-else>
  57. <div
  58. class="h-6 w-16 mt-2 rounded-md loading"
  59. />
  60. <div
  61. class="h-6 w-16 mt-2 rounded-md loading"
  62. />
  63. </template>
  64. </div>
  65. </div>
  66. </div>
  67. <div class="w-full bg-foreground opacity-25 h-[1px]" />
  68. <div class="flex flex-col divide-y-[1px] divide-background-200">
  69. <NuxtLink
  70. v-for="(link, idx) in links"
  71. :key="idx"
  72. :to="link.route"
  73. @click="store.isVisible = false"
  74. >
  75. <BaseSideBarElement
  76. :type="link.icon"
  77. :text="link.name"
  78. :color="useRouter().currentRoute.value.path === link.route ? '#FF4646' : '#EDE8D8'"
  79. />
  80. </NuxtLink>
  81. </div>
  82. <div class="flex-auto flex flex-col justify-end divide-y-[1px] divide-background-200">
  83. <div class="w-full bg-foreground opacity-25 h-[1px]" />
  84. <NuxtLink
  85. to="/settings"
  86. @click="store.isVisible = false"
  87. >
  88. <BaseSideBarElement
  89. type="cog"
  90. text="Настройки"
  91. :color="useRouter().currentRoute.value.path === '/settings' ? '#FF4646' : '#EDE8D8'"
  92. />
  93. </NuxtLink>
  94. <NuxtLink
  95. to="/about"
  96. @click="store.isVisible = false"
  97. >
  98. <BaseSideBarElement
  99. type="alert-circle"
  100. text="О программе"
  101. :color="useRouter().currentRoute.value.path === '/about' ? '#FF4646' : '#EDE8D8'"
  102. />
  103. </NuxtLink>
  104. <BaseSideBarElement
  105. type="logout"
  106. text="Выйти из аккаунта"
  107. color="#EDE8D8"
  108. @click="user.logout()"
  109. />
  110. </div>
  111. </div>
  112. </div>
  113. </div>
  114. </template>
  115. <script setup lang="ts">
  116. import { useSwipe } from '@vueuse/core'
  117. import { useSideBar } from '~/store/useSideBar'
  118. import { useUser } from '~/store/useUser'
  119. import type { UserData } from '~/types/userData'
  120. const store = useSideBar()
  121. const sideBarEl = ref(null)
  122. const translateTo = ref(null)
  123. const { direction } = useSwipe(sideBarEl, {
  124. onSwipeEnd() {
  125. if (direction.value === 'left') store.hide()
  126. },
  127. })
  128. const user = useUser()
  129. const api = useApi()
  130. const links = ref<{
  131. name: string
  132. icon: 'home' | 'license' | 'calendar' | 'mail' | 'bell' | 'photo' | 'chart'
  133. route: string
  134. }[]>([
  135. {
  136. name: 'Новости',
  137. icon: 'home',
  138. route: '/news',
  139. },
  140. {
  141. name: 'Блог',
  142. icon: 'license',
  143. route: '/blog',
  144. },
  145. {
  146. name: 'Расписание',
  147. icon: 'calendar',
  148. route: '/timetable',
  149. },
  150. {
  151. name: 'Сообщения',
  152. icon: 'mail',
  153. route: '/messenger',
  154. },
  155. {
  156. name: 'Уведомления',
  157. icon: 'bell',
  158. route: '/notifications',
  159. },
  160. {
  161. name: 'Галерея',
  162. icon: 'photo',
  163. route: '/gallery',
  164. },
  165. {
  166. name: 'Оценки',
  167. icon: 'chart',
  168. route: '/marks',
  169. },
  170. ])
  171. const info = ref()
  172. onMounted(
  173. async () =>
  174. (info.value = await api.get<UserData>(
  175. `/user/info?access_token=${user.data.access_token}`,
  176. )),
  177. )
  178. </script>