index.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <script setup lang="ts">
  2. import { useRoute } from "vue-router";
  3. import { defineAsyncComponent, watch, onMounted } from "vue";
  4. import { storeToRefs } from "pinia";
  5. import { useUserAuthStore } from "@/stores/userAuth";
  6. import { useStationStore } from "@/stores/station";
  7. import { useTabQueryHandler } from "@/composables/useTabQueryHandler";
  8. const Queue = defineAsyncComponent(() => import("@/components/Queue.vue"));
  9. const Users = defineAsyncComponent(
  10. () => import("@/pages/Station/Sidebar/Users.vue")
  11. );
  12. const Request = defineAsyncComponent(() => import("@/components/Request.vue"));
  13. const route = useRoute();
  14. const userAuthStore = useUserAuthStore();
  15. const stationStore = useStationStore();
  16. const { tab, showTab } = useTabQueryHandler("queue");
  17. const { loggedIn } = storeToRefs(userAuthStore);
  18. const { station } = storeToRefs(stationStore);
  19. const { hasPermission } = stationStore;
  20. const canRequest = (requireLogin = true) =>
  21. station.value &&
  22. (!requireLogin || loggedIn.value) &&
  23. station.value.requests &&
  24. station.value.requests.enabled &&
  25. (station.value.requests.access === "user" ||
  26. (station.value.requests.access === "owner" &&
  27. hasPermission("stations.request")));
  28. watch(
  29. () => [station.value.requests, hasPermission("stations.request")],
  30. () => {
  31. if (tab.value === "request" && !canRequest()) showTab("queue");
  32. }
  33. );
  34. onMounted(() => {
  35. if (
  36. route.query.tab === "queue" ||
  37. route.query.tab === "users" ||
  38. route.query.tab === "request"
  39. )
  40. tab.value = route.query.tab;
  41. });
  42. </script>
  43. <template>
  44. <div class="tabs-container">
  45. <div class="tab-selection">
  46. <button
  47. class="button is-default"
  48. :class="{ selected: tab === 'queue' }"
  49. @click="showTab('queue')"
  50. >
  51. Queue
  52. </button>
  53. <button
  54. class="button is-default"
  55. :class="{ selected: tab === 'users' }"
  56. @click="showTab('users')"
  57. >
  58. Users
  59. </button>
  60. <button
  61. v-if="canRequest()"
  62. class="button is-default"
  63. :class="{ selected: tab === 'request' }"
  64. @click="showTab('request')"
  65. >
  66. Request
  67. </button>
  68. <button
  69. v-else-if="canRequest(false)"
  70. class="button is-default"
  71. content="Login to request songs"
  72. v-tippy="{ theme: 'info' }"
  73. >
  74. Request
  75. </button>
  76. </div>
  77. <Queue class="tab" v-show="tab === 'queue'" @on-change-tab="showTab" />
  78. <Users class="tab" v-show="tab === 'users'" />
  79. <Request
  80. v-if="canRequest()"
  81. v-show="tab === 'request'"
  82. class="tab requests-tab"
  83. sector="station"
  84. />
  85. </div>
  86. </template>
  87. <style lang="less" scoped>
  88. .night-mode {
  89. .tab-selection .button {
  90. background: var(--dark-grey);
  91. color: var(--white);
  92. }
  93. .tab.requests-tab {
  94. background-color: var(--dark-grey-3) !important;
  95. border: 0 !important;
  96. }
  97. }
  98. .tabs-container .tab {
  99. width: 100%;
  100. height: calc(100% - 36px);
  101. position: absolute;
  102. border: 1px solid var(--light-grey-3);
  103. border-top: 0;
  104. }
  105. .tab-selection {
  106. display: flex;
  107. overflow-x: auto;
  108. .button {
  109. border-radius: @border-radius @border-radius 0 0;
  110. border: 0;
  111. text-transform: uppercase;
  112. font-size: 17px;
  113. color: var(--dark-grey-3);
  114. background-color: var(--light-grey-2);
  115. flex-grow: 1;
  116. &:not(:first-of-type) {
  117. margin-left: 5px;
  118. }
  119. }
  120. .selected {
  121. background-color: var(--primary-color) !important;
  122. color: var(--white) !important;
  123. font-weight: 600;
  124. }
  125. }
  126. :deep(.nothing-here-text) {
  127. height: 100%;
  128. }
  129. :deep(.tab) {
  130. .nothing-here-text:not(:only-child) {
  131. height: calc(100% - 40px);
  132. }
  133. &.requests-tab {
  134. background-color: var(--white);
  135. margin-bottom: 20px;
  136. border-radius: 0 0 @border-radius @border-radius;
  137. max-height: 100%;
  138. padding: 15px 10px;
  139. overflow-y: auto;
  140. .scrollable-list {
  141. padding: 10px 0;
  142. }
  143. }
  144. }
  145. :deep(.tab-actionable-button) {
  146. width: calc(100% - 20px);
  147. height: 40px;
  148. border-radius: @border-radius;
  149. margin: 10px;
  150. position: absolute;
  151. bottom: 0;
  152. border: 0;
  153. background-color: var(--primary-color) !important;
  154. color: var(--white) !important;
  155. &:active,
  156. &:focus {
  157. border: 0;
  158. }
  159. &:hover,
  160. &:focus {
  161. background-color: var(--primary-color) !important;
  162. filter: brightness(90%);
  163. }
  164. }
  165. :deep(.scrollable-list) {
  166. width: 100%;
  167. max-height: calc(100% - 40px - 20px);
  168. overflow: auto;
  169. padding: 10px;
  170. .song-item:not(:last-of-type) {
  171. margin-bottom: 10px;
  172. }
  173. }
  174. </style>