Home.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. <template>
  2. <div>
  3. <div class="app" :class="{'nightMode': nightMode}">
  4. <main-header></main-header>
  5. <div class="group">
  6. <div class="group-title">Official Stations</div>
  7. <router-link
  8. class="card station-card"
  9. :to="{ name: 'official', params: { id: station.name } }"
  10. v-for="(station, index) in stations.official"
  11. :key="index"
  12. :class="{'isPrivate': station.privacy === 'private'}"
  13. >
  14. <div class="card-image">
  15. <figure class="image is-square">
  16. <img
  17. :src="station.currentSong.thumbnail"
  18. onerror="this.src='/assets/notes-transparent.png'"
  19. />
  20. </figure>
  21. </div>
  22. <div class="card-content">
  23. <div class="media">
  24. <div class="media-left displayName">
  25. <h5>{{ station.displayName }}</h5>
  26. </div>
  27. </div>
  28. <div class="content">{{ station.description }}</div>
  29. <div class="under-content">
  30. <i class="material-icons" title="How many users there are in the station.">people</i>
  31. <span
  32. class="users-count"
  33. title="How many users there are in the station."
  34. >&nbsp;{{station.userCount}}</span>
  35. <i
  36. class="material-icons right-icon"
  37. v-if="station.privacy !== 'public'"
  38. title="This station is not visible to other users."
  39. >lock</i>
  40. </div>
  41. </div>
  42. <router-link
  43. href="#"
  44. class="absolute-a"
  45. :to="{ name: 'official', params: { id: station.name } }"
  46. ></router-link>
  47. </router-link>
  48. </div>
  49. <div class="group">
  50. <div class="group-title">
  51. Community Stations&nbsp;
  52. <a
  53. v-on:click="toggleModal({
  54. sector: 'home',
  55. modal: 'createCommunityStation'
  56. })"
  57. v-if="$parent.loggedIn"
  58. href="#"
  59. >
  60. <i class="material-icons community-button">add_circle_outline</i>
  61. </a>
  62. </div>
  63. <router-link
  64. :to="{ name: 'community', params: { id: station.name } }"
  65. class="card station-card"
  66. v-for="(station, index) in stations.community"
  67. :key="index"
  68. :class="{'isPrivate': station.privacy === 'private','isMine': isOwner(station)}"
  69. >
  70. <div class="card-image">
  71. <figure class="image is-square">
  72. <img
  73. :src="station.currentSong.thumbnail"
  74. onerror="this.src='/assets/notes-transparent.png'"
  75. />
  76. </figure>
  77. </div>
  78. <div class="card-content">
  79. <div class="media">
  80. <div class="media-left displayName">
  81. <h5>{{ station.displayName }}</h5>
  82. </div>
  83. </div>
  84. <div class="content">{{ station.description }}</div>
  85. <div class="under-content">
  86. <i class="material-icons" title="How many users there are in the station.">people</i>
  87. <span
  88. class="users-count"
  89. title="How many users there are in the station."
  90. >&nbsp;{{station.userCount}}</span>
  91. <i
  92. class="material-icons right-icon"
  93. v-if="station.privacy !== 'public'"
  94. title="This station is not visible to other users."
  95. >lock</i>
  96. <i
  97. class="material-icons right-icon"
  98. v-if="isOwner(station)"
  99. title="This is your station."
  100. >home</i>
  101. </div>
  102. </div>
  103. <router-link
  104. href="#"
  105. class="absolute-a"
  106. :to="{ name: 'community', params: { id: station.name } }"
  107. />
  108. </router-link>
  109. </div>
  110. <main-footer></main-footer>
  111. </div>
  112. <create-community-station v-if="modals.createCommunityStation"></create-community-station>
  113. </div>
  114. </template>
  115. <script>
  116. import { mapState, mapActions } from "vuex";
  117. import MainHeader from "../MainHeader.vue";
  118. import MainFooter from "../MainFooter.vue";
  119. import CreateCommunityStation from "../Modals/CreateCommunityStation.vue";
  120. import auth from "../../auth";
  121. import io from "../../io";
  122. export default {
  123. data() {
  124. return {
  125. recaptcha: {
  126. key: ""
  127. },
  128. stations: {
  129. official: [],
  130. community: []
  131. },
  132. nightMode: false
  133. };
  134. },
  135. computed: mapState("modals", {
  136. modals: state => state.modals.home
  137. }),
  138. mounted() {
  139. let _this = this;
  140. auth.getStatus((authenticated, role, username, userId) => {
  141. io.getSocket(socket => {
  142. _this.socket = socket;
  143. if (_this.socket.connected) _this.init();
  144. io.onConnect(() => {
  145. _this.init();
  146. });
  147. _this.socket.on("event:stations.created", station => {
  148. if (!station.currentSong)
  149. station.currentSong = {
  150. thumbnail: "/assets/notes-transparent.png"
  151. };
  152. if (station.currentSong && !station.currentSong.thumbnail)
  153. station.currentSong.thumbnail = "/assets/notes-transparent.png";
  154. _this.stations[station.type].push(station);
  155. });
  156. _this.socket.on("event:userCount.updated", (stationId, userCount) => {
  157. _this.stations.official.forEach(station => {
  158. if (station._id === stationId) {
  159. station.userCount = userCount;
  160. }
  161. });
  162. _this.stations.community.forEach(station => {
  163. if (station._id === stationId) {
  164. station.userCount = userCount;
  165. }
  166. });
  167. });
  168. _this.socket.on("event:station.nextSong", (stationId, newSong) => {
  169. _this.stations.official.forEach(station => {
  170. if (station._id === stationId) {
  171. if (!newSong)
  172. newSong = { thumbnail: "/assets/notes-transparent.png" };
  173. if (newSong && !newSong.thumbnail)
  174. newSong.thumbnail = "/assets/notes-transparent.png";
  175. station.currentSong = newSong;
  176. }
  177. });
  178. _this.stations.community.forEach(station => {
  179. if (station._id === stationId) {
  180. if (!newSong)
  181. newSong = { thumbnail: "/assets/notes-transparent.png" };
  182. if (newSong && !newSong.thumbnail)
  183. newSong.thumbnail = "/assets/notes-transparent.png";
  184. station.currentSong = newSong;
  185. }
  186. });
  187. });
  188. });
  189. });
  190. },
  191. methods: {
  192. init: function() {
  193. let _this = this;
  194. auth.getStatus((authenticated, role, username, userId) => {
  195. _this.socket.emit("stations.index", data => {
  196. _this.stations.community = [];
  197. _this.stations.official = [];
  198. if (data.status === "success")
  199. data.stations.forEach(station => {
  200. if (!station.currentSong)
  201. station.currentSong = {
  202. thumbnail: "/assets/notes-transparent.png"
  203. };
  204. if (station.currentSong && !station.currentSong.thumbnail)
  205. station.currentSong.thumbnail = "/assets/notes-transparent.png";
  206. if (station.privacy !== "public")
  207. station.class = { "station-red": true };
  208. else if (station.type === "community" && station.owner === userId)
  209. station.class = { "station-blue": true };
  210. if (station.type == "official")
  211. _this.stations.official.push(station);
  212. else _this.stations.community.push(station);
  213. });
  214. });
  215. _this.socket.emit("apis.joinRoom", "home", () => {});
  216. });
  217. },
  218. isOwner: function(station) {
  219. let _this = this;
  220. return (
  221. station.owner === _this.$parent.userId && station.privacy === "public"
  222. );
  223. },
  224. ...mapActions("modals", ["toggleModal"])
  225. },
  226. components: { MainHeader, MainFooter, CreateCommunityStation }
  227. };
  228. </script>
  229. <style lang='scss'>
  230. * {
  231. box-sizing: border-box;
  232. }
  233. html {
  234. width: 100%;
  235. height: 100%;
  236. color: rgba(0, 0, 0, 0.87);
  237. body {
  238. width: 100%;
  239. height: 100%;
  240. margin: 0;
  241. padding: 0;
  242. }
  243. }
  244. @media only screen and (min-width: 1200px) {
  245. html {
  246. font-size: 15px;
  247. }
  248. }
  249. @media only screen and (min-width: 992px) {
  250. html {
  251. font-size: 14.5px;
  252. }
  253. }
  254. @media only screen and (min-width: 0) {
  255. html {
  256. font-size: 14px;
  257. }
  258. }
  259. .under-content {
  260. width: calc(100% - 40px);
  261. left: 20px;
  262. right: 20px;
  263. bottom: 10px;
  264. text-align: left;
  265. height: 25px;
  266. position: absolute;
  267. margin-bottom: 10px;
  268. line-height: 1;
  269. font-size: 24px;
  270. vertical-align: middle;
  271. * {
  272. z-index: 10;
  273. position: relative;
  274. }
  275. .right-icon {
  276. float: right;
  277. }
  278. }
  279. .users-count {
  280. font-size: 20px;
  281. position: relative;
  282. top: -4px;
  283. }
  284. .right {
  285. float: right;
  286. }
  287. .group {
  288. min-height: 64px;
  289. }
  290. .station-card {
  291. margin: 10px;
  292. cursor: pointer;
  293. height: 475px;
  294. transition: all ease-in-out 0.2s;
  295. .card-content {
  296. max-height: 159px;
  297. .content {
  298. word-wrap: break-word;
  299. overflow: hidden;
  300. text-overflow: ellipsis;
  301. display: -webkit-box;
  302. -webkit-box-orient: vertical;
  303. -webkit-line-clamp: 3;
  304. line-height: 20px;
  305. max-height: 60px;
  306. }
  307. }
  308. }
  309. .station-card:hover {
  310. box-shadow: 0 2px 3px rgba(10, 10, 10, 0.3), 0 0 10px rgba(10, 10, 10, 0.3);
  311. transition: all ease-in-out 0.2s;
  312. }
  313. /*.isPrivate {
  314. background-color: #F8BBD0;
  315. }
  316. .isMine {
  317. background-color: #29B6F6;
  318. }*/
  319. .community-button {
  320. cursor: pointer;
  321. transition: 0.25s ease color;
  322. font-size: 30px;
  323. color: #4a4a4a;
  324. }
  325. .community-button:hover {
  326. color: #03a9f4;
  327. }
  328. .station-privacy {
  329. text-transform: capitalize;
  330. }
  331. .label {
  332. display: flex;
  333. }
  334. .g-recaptcha {
  335. display: flex;
  336. justify-content: center;
  337. margin-top: 20px;
  338. }
  339. .group {
  340. text-align: center;
  341. width: 100%;
  342. margin: 64px 0 0 0;
  343. .group-title {
  344. float: left;
  345. clear: none;
  346. width: 100%;
  347. height: 64px;
  348. line-height: 48px;
  349. text-align: center;
  350. font-size: 48px;
  351. margin-bottom: 25px;
  352. }
  353. }
  354. .group .card {
  355. display: inline-flex;
  356. flex-direction: column;
  357. overflow: hidden;
  358. .content {
  359. text-align: left;
  360. word-wrap: break-word;
  361. }
  362. .media {
  363. display: flex;
  364. align-items: center;
  365. .station-status {
  366. line-height: 13px;
  367. }
  368. h5 {
  369. margin: 0;
  370. }
  371. }
  372. }
  373. .displayName {
  374. word-wrap: break-word;
  375. width: 80%;
  376. word-wrap: break-word;
  377. overflow: hidden;
  378. text-overflow: ellipsis;
  379. display: -webkit-box;
  380. -webkit-box-orient: vertical;
  381. -webkit-line-clamp: 1;
  382. line-height: 30px;
  383. max-height: 30px;
  384. }
  385. .nightMode {
  386. background-color: rgb(51, 51, 51);
  387. color: #e6e6e6;
  388. .community-button {
  389. cursor: pointer;
  390. transition: 0.25s ease color;
  391. font-size: 30px;
  392. color: #e6e6e6;
  393. }
  394. .community-button:hover {
  395. color: #03a9f4;
  396. }
  397. .station-card {
  398. margin: 10px;
  399. cursor: pointer;
  400. height: 475px;
  401. background-color: rgb(51, 51, 51);
  402. color: #e6e6e6;
  403. .card-content {
  404. max-height: 159px;
  405. color: #e6e6e6;
  406. .content {
  407. word-wrap: break-word;
  408. overflow: hidden;
  409. text-overflow: ellipsis;
  410. display: -webkit-box;
  411. -webkit-box-orient: vertical;
  412. -webkit-line-clamp: 3;
  413. line-height: 20px;
  414. max-height: 60px;
  415. color: #e6e6e6;
  416. }
  417. }
  418. }
  419. .station-card:hover {
  420. box-shadow: 0 2px 3px rgba(10, 10, 10, 0.3), 0 0 10px rgba(10, 10, 10, 0.3);
  421. }
  422. .isPrivate {
  423. background-color: #d01657;
  424. }
  425. .isMine {
  426. background-color: #0777ab;
  427. }
  428. }
  429. </style>