index.vue 4.5 KB

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