index.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. <template>
  2. <div>
  3. <metadata title="Home" />
  4. <div class="app">
  5. <main-header
  6. :hide-logo="true"
  7. :transparent="true"
  8. :hide-logged-out="true"
  9. />
  10. <div class="header" :class="{ loggedIn }">
  11. <img
  12. class="background"
  13. src="/assets/homebg.jpeg"
  14. />
  15. <div class="overlay"></div>
  16. <div class="content-container">
  17. <div class="content">
  18. <img
  19. class="logo"
  20. src="/assets/white_wordmark.png"
  21. :alt="`${this.siteName}` || `Musare`"
  22. />
  23. <div v-if="!loggedIn" class="buttons">
  24. <button
  25. class="button login"
  26. @click="
  27. openModal({
  28. sector: 'header',
  29. modal: 'login'
  30. })
  31. "
  32. >
  33. Login
  34. </button>
  35. <button
  36. class="button register"
  37. @click="
  38. openModal({
  39. sector: 'header',
  40. modal: 'register'
  41. })
  42. "
  43. >
  44. Register
  45. </button>
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. <div v-if="favoriteStations.length > 0" class="group">
  51. <div class="group-title">
  52. <div>
  53. <h2>My Favorites</h2>
  54. </div>
  55. </div>
  56. <router-link
  57. v-for="(station, index) in favoriteStations"
  58. :key="index"
  59. :to="{
  60. name: 'station',
  61. params: { id: station.name }
  62. }"
  63. class="card station-card"
  64. :class="{
  65. isPrivate: station.privacy === 'private',
  66. isMine: isOwner(station)
  67. }"
  68. :style="'--station-theme: ' + station.themeCode"
  69. >
  70. <div class="card-image">
  71. <figure class="image is-square">
  72. <div
  73. v-if="station.currentSong.ytThumbnail"
  74. class="ytThumbnailBg"
  75. :style="{
  76. 'background-image':
  77. 'url(' +
  78. station.currentSong.ytThumbnail +
  79. ')'
  80. }"
  81. ></div>
  82. <img
  83. v-if="station.currentSong.ytThumbnail"
  84. :src="station.currentSong.ytThumbnail"
  85. onerror="this.src='/assets/notes-transparent.png'"
  86. />
  87. <img
  88. v-else
  89. :src="station.currentSong.thumbnail"
  90. onerror="this.src='/assets/notes-transparent.png'"
  91. />
  92. </figure>
  93. </div>
  94. <div class="card-content">
  95. <div class="media">
  96. <div class="media-left displayName">
  97. <i
  98. v-if="loggedIn && !station.isFavorited"
  99. @click.prevent="favoriteStation(station)"
  100. class="favorite material-icons"
  101. >star_border</i
  102. >
  103. <i
  104. v-if="loggedIn && station.isFavorited"
  105. @click.prevent="unfavoriteStation(station)"
  106. class="favorite material-icons"
  107. >star</i
  108. >
  109. <h5>{{ station.displayName }}</h5>
  110. <i
  111. v-if="station.type === 'official'"
  112. class="material-icons verified-station"
  113. title="Verified station"
  114. >
  115. check_circle
  116. </i>
  117. </div>
  118. </div>
  119. <div class="content">
  120. {{ station.description }}
  121. </div>
  122. <div class="under-content">
  123. <p class="hostedBy">
  124. Hosted by
  125. <span class="host">
  126. <span
  127. v-if="station.type === 'official'"
  128. title="Musare"
  129. >Musare</span
  130. >
  131. <user-id-to-username
  132. v-else
  133. :user-id="station.owner"
  134. :link="true"
  135. />
  136. </span>
  137. </p>
  138. <div class="icons">
  139. <i
  140. v-if="
  141. station.type === 'community' &&
  142. isOwner(station)
  143. "
  144. class="homeIcon material-icons"
  145. title="This is your station."
  146. >home</i
  147. >
  148. <i
  149. v-if="station.privacy === 'private'"
  150. class="privateIcon material-icons"
  151. title="This station is not visible to other users."
  152. >lock</i
  153. >
  154. <i
  155. v-if="station.privacy === 'unlisted'"
  156. class="unlistedIcon material-icons"
  157. title="Unlisted Station"
  158. >link</i
  159. >
  160. </div>
  161. </div>
  162. </div>
  163. <div class="bottomBar">
  164. <i
  165. v-if="station.paused && station.currentSong.title"
  166. class="material-icons"
  167. title="Station Paused"
  168. >pause</i
  169. >
  170. <i
  171. v-else-if="station.currentSong.title"
  172. class="material-icons"
  173. >music_note</i
  174. >
  175. <i v-else class="material-icons">music_off</i>
  176. <span
  177. v-if="station.currentSong.title"
  178. class="songTitle"
  179. :title="
  180. station.currentSong.artists.length > 0
  181. ? 'Now Playing: ' +
  182. station.currentSong.title +
  183. ' by ' +
  184. station.currentSong.artists.join(',')
  185. : 'Now Playing: ' +
  186. station.currentSong.title
  187. "
  188. >{{ station.currentSong.title }}
  189. {{
  190. station.currentSong.artists.length > 0
  191. ? " by " +
  192. station.currentSong.artists.join(",")
  193. : ""
  194. }}</span
  195. >
  196. <span v-else class="songTitle">No Songs Playing</span>
  197. </div>
  198. </router-link>
  199. </div>
  200. <div class="group bottom">
  201. <div class="group-title">
  202. <div>
  203. <h1>Stations</h1>
  204. </div>
  205. </div>
  206. <a
  207. v-if="loggedIn"
  208. @click="
  209. openModal({
  210. sector: 'home',
  211. modal: 'createCommunityStation'
  212. })
  213. "
  214. class="card station-card createStation"
  215. :style="'--station-theme: rgb(2, 166, 242)'"
  216. >
  217. <div class="card-image">
  218. <figure class="image is-square">
  219. <i class="material-icons">radio</i>
  220. <!-- <img src="/assets/notes-transparent.png" /> -->
  221. </figure>
  222. </div>
  223. <div class="card-content">
  224. <div class="media">
  225. <div class="media-left displayName">
  226. <h5>Create Station</h5>
  227. </div>
  228. </div>
  229. <div class="content">
  230. Click here to create your own station!
  231. </div>
  232. </div>
  233. <div class="bottomBar"></div>
  234. </a>
  235. <router-link
  236. v-for="(station, index) in filteredStations"
  237. :key="index"
  238. :to="{
  239. name: 'station',
  240. params: { id: station.name }
  241. }"
  242. class="card station-card"
  243. :class="{
  244. isPrivate: station.privacy === 'private',
  245. isMine: isOwner(station)
  246. }"
  247. :style="'--station-theme: ' + station.themeCode"
  248. >
  249. <div class="card-image">
  250. <figure class="image is-square">
  251. <div
  252. v-if="station.currentSong.ytThumbnail"
  253. class="ytThumbnailBg"
  254. :style="{
  255. 'background-image':
  256. 'url(' +
  257. station.currentSong.ytThumbnail +
  258. ')'
  259. }"
  260. ></div>
  261. <img
  262. v-if="station.currentSong.ytThumbnail"
  263. :src="station.currentSong.ytThumbnail"
  264. onerror="this.src='/assets/notes-transparent.png'"
  265. />
  266. <img
  267. v-else
  268. :src="station.currentSong.thumbnail"
  269. onerror="this.src='/assets/notes-transparent.png'"
  270. />
  271. </figure>
  272. </div>
  273. <div class="card-content">
  274. <div class="media">
  275. <div class="media-left displayName">
  276. <i
  277. v-if="loggedIn && !station.isFavorited"
  278. @click.prevent="favoriteStation(station)"
  279. class="favorite material-icons"
  280. >star_border</i
  281. >
  282. <i
  283. v-if="loggedIn && station.isFavorited"
  284. @click.prevent="unfavoriteStation(station)"
  285. class="favorite material-icons"
  286. >star</i
  287. >
  288. <h5>{{ station.displayName }}</h5>
  289. <i
  290. v-if="station.type === 'official'"
  291. class="material-icons verified-station"
  292. title="Verified station"
  293. >
  294. check_circle
  295. </i>
  296. </div>
  297. </div>
  298. <div class="content">
  299. {{ station.description }}
  300. </div>
  301. <div class="under-content">
  302. <p class="hostedBy">
  303. Hosted by
  304. <span class="host">
  305. <span
  306. v-if="station.type === 'official'"
  307. title="Musare"
  308. >Musare</span
  309. >
  310. <user-id-to-username
  311. v-else
  312. :user-id="station.owner"
  313. :link="true"
  314. />
  315. </span>
  316. </p>
  317. <div class="icons">
  318. <i
  319. v-if="
  320. station.type === 'community' &&
  321. isOwner(station)
  322. "
  323. class="homeIcon material-icons"
  324. title="This is your station."
  325. >home</i
  326. >
  327. <i
  328. v-if="station.privacy === 'private'"
  329. class="privateIcon material-icons"
  330. title="This station is not visible to other users."
  331. >lock</i
  332. >
  333. <i
  334. v-if="station.privacy === 'unlisted'"
  335. class="unlistedIcon material-icons"
  336. title="Unlisted Station"
  337. >link</i
  338. >
  339. </div>
  340. </div>
  341. </div>
  342. <div class="bottomBar">
  343. <i
  344. v-if="station.paused && station.currentSong.title"
  345. class="material-icons"
  346. title="Station Paused"
  347. >pause</i
  348. >
  349. <i
  350. v-else-if="station.currentSong.title"
  351. class="material-icons"
  352. >music_note</i
  353. >
  354. <i v-else class="material-icons">music_off</i>
  355. <span
  356. v-if="station.currentSong.title"
  357. class="songTitle"
  358. :title="
  359. station.currentSong.artists.length > 0
  360. ? 'Now Playing: ' +
  361. station.currentSong.title +
  362. ' by ' +
  363. station.currentSong.artists.join(',')
  364. : 'Now Playing: ' +
  365. station.currentSong.title
  366. "
  367. >{{ station.currentSong.title }}
  368. {{
  369. station.currentSong.artists.length > 0
  370. ? " by " +
  371. station.currentSong.artists.join(",")
  372. : ""
  373. }}</span
  374. >
  375. <span v-else class="songTitle">No Songs Playing</span>
  376. </div>
  377. </router-link>
  378. <h4 v-if="stations.length === 0">
  379. There are no stations to display
  380. </h4>
  381. </div>
  382. <main-footer />
  383. </div>
  384. <create-community-station v-if="modals.createCommunityStation" />
  385. </div>
  386. </template>
  387. <script>
  388. import { mapState, mapActions } from "vuex";
  389. import Toast from "toasters";
  390. import MainHeader from "../../components/layout/MainHeader.vue";
  391. import MainFooter from "../../components/layout/MainFooter.vue";
  392. import CreateCommunityStation from "./CreateCommunityStation.vue";
  393. import UserIdToUsername from "../../components/common/UserIdToUsername.vue";
  394. import io from "../../io";
  395. export default {
  396. components: {
  397. MainHeader,
  398. MainFooter,
  399. CreateCommunityStation,
  400. UserIdToUsername
  401. },
  402. data() {
  403. return {
  404. recaptcha: {
  405. key: ""
  406. },
  407. stations: [],
  408. searchQuery: "",
  409. siteName: "Musare"
  410. };
  411. },
  412. computed: {
  413. ...mapState({
  414. loggedIn: state => state.user.auth.loggedIn,
  415. userId: state => state.user.auth.userId,
  416. modals: state => state.modalVisibility.modals.home
  417. }),
  418. filteredStations() {
  419. const privacyOrder = ["public", "unlisted", "private"];
  420. return this.stations
  421. .filter(
  422. station =>
  423. JSON.stringify(Object.values(station)).indexOf(
  424. this.searchQuery
  425. ) !== -1
  426. )
  427. .sort(
  428. (a, b) =>
  429. this.isOwner(b) - this.isOwner(a) ||
  430. this.isPlaying(b) - this.isPlaying(a) ||
  431. a.paused - b.paused ||
  432. privacyOrder.indexOf(a.privacy) -
  433. privacyOrder.indexOf(b.privacy) ||
  434. b.userCount - a.userCount
  435. );
  436. },
  437. favoriteStations() {
  438. return this.filteredStations.filter(
  439. station => station.isFavorited === true
  440. );
  441. }
  442. },
  443. mounted() {
  444. lofig.get("siteSettings.siteName").then(siteName => {
  445. this.siteName = siteName;
  446. });
  447. io.getSocket(socket => {
  448. this.socket = socket;
  449. if (this.socket.connected) this.init();
  450. io.onConnect(() => {
  451. this.init();
  452. });
  453. this.socket.on("event:stations.created", res => {
  454. const station = res;
  455. if (
  456. this.stations.find(_station => _station._id === station._id)
  457. ) {
  458. this.stations.forEach(s => {
  459. const _station = s;
  460. if (_station._id === station._id) {
  461. _station.privacy = station.privacy;
  462. }
  463. });
  464. } else {
  465. if (!station.currentSong)
  466. station.currentSong = {
  467. thumbnail: "/assets/notes-transparent.png"
  468. };
  469. if (station.currentSong && !station.currentSong.thumbnail)
  470. station.currentSong.ytThumbnail = `https://img.youtube.com/vi/${station.currentSong.songId}/mqdefault.jpg`;
  471. this.stations.push(station);
  472. }
  473. });
  474. this.socket.on("event:station.removed", response => {
  475. const { stationId } = response;
  476. const station = this.stations.find(
  477. station => station._id === stationId
  478. );
  479. if (station) {
  480. const stationIndex = this.stations.indexOf(station);
  481. this.stations.splice(stationIndex, 1);
  482. }
  483. });
  484. this.socket.on(
  485. "event:userCount.updated",
  486. (stationId, userCount) => {
  487. this.stations.forEach(s => {
  488. const station = s;
  489. if (station._id === stationId) {
  490. station.userCount = userCount;
  491. }
  492. });
  493. }
  494. );
  495. this.socket.on("event:station.updatePrivacy", response => {
  496. const { stationId, privacy } = response;
  497. this.stations.forEach(s => {
  498. const station = s;
  499. if (station._id === stationId) {
  500. station.privacy = privacy;
  501. }
  502. });
  503. });
  504. this.socket.on("event:station.updateName", response => {
  505. const { stationId, name } = response;
  506. this.stations.forEach(s => {
  507. const station = s;
  508. if (station._id === stationId) {
  509. station.name = name;
  510. }
  511. });
  512. });
  513. this.socket.on("event:station.updateDisplayName", response => {
  514. const { stationId, displayName } = response;
  515. this.stations.forEach(s => {
  516. const station = s;
  517. if (station._id === stationId) {
  518. station.displayName = displayName;
  519. }
  520. });
  521. });
  522. this.socket.on("event:station.updateDescription", response => {
  523. const { stationId, description } = response;
  524. this.stations.forEach(s => {
  525. const station = s;
  526. if (station._id === stationId) {
  527. station.description = description;
  528. }
  529. });
  530. });
  531. this.socket.on("event:station.updateTheme", response => {
  532. const { stationId, theme } = response;
  533. this.stations.forEach(s => {
  534. const station = s;
  535. if (station._id === stationId) {
  536. station.theme = theme;
  537. if (theme === "blue") {
  538. station.themeCode = "rgb(2, 166, 242)";
  539. } else if (theme === "purple") {
  540. station.themeCode = "rgb(143, 40, 140)";
  541. } else if (theme === "teal") {
  542. station.themeCode = "rgb(0, 209, 178)";
  543. } else if (theme === "orange") {
  544. station.themeCode = "rgb(255, 94, 0)";
  545. } else {
  546. station.themeCode = "rgb(2, 166, 242)";
  547. }
  548. }
  549. });
  550. });
  551. this.socket.on("event:station.nextSong", (stationId, song) => {
  552. let newSong = song;
  553. this.stations.forEach(s => {
  554. const station = s;
  555. if (station._id === stationId) {
  556. if (!newSong)
  557. newSong = {
  558. thumbnail: "/assets/notes-transparent.png"
  559. };
  560. if (newSong && !newSong.thumbnail)
  561. newSong.ytThumbnail = `https://img.youtube.com/vi/${newSong.songId}/mqdefault.jpg`;
  562. station.currentSong = newSong;
  563. }
  564. });
  565. });
  566. this.socket.on("event:station.pause", response => {
  567. const { stationId } = response;
  568. this.stations.forEach(s => {
  569. const station = s;
  570. if (station._id === stationId) {
  571. station.paused = true;
  572. }
  573. });
  574. });
  575. this.socket.on("event:station.resume", response => {
  576. const { stationId } = response;
  577. this.stations.forEach(s => {
  578. const station = s;
  579. if (station._id === stationId) {
  580. station.paused = false;
  581. }
  582. });
  583. });
  584. this.socket.on("event:user.favoritedStation", stationId => {
  585. this.stations.forEach(s => {
  586. const station = s;
  587. if (station._id === stationId) {
  588. station.isFavorited = true;
  589. }
  590. });
  591. });
  592. this.socket.on("event:user.unfavoritedStation", stationId => {
  593. this.stations.forEach(s => {
  594. const station = s;
  595. if (station._id === stationId) {
  596. station.isFavorited = false;
  597. }
  598. });
  599. });
  600. });
  601. },
  602. methods: {
  603. init() {
  604. this.socket.emit("stations.index", data => {
  605. this.stations = [];
  606. if (data.status === "success")
  607. data.stations.forEach(station => {
  608. const modifiableStation = station;
  609. if (!modifiableStation.currentSong)
  610. modifiableStation.currentSong = {
  611. thumbnail: "/assets/notes-transparent.png"
  612. };
  613. if (
  614. modifiableStation.currentSong &&
  615. !modifiableStation.currentSong.thumbnail
  616. )
  617. modifiableStation.currentSong.ytThumbnail = `https://img.youtube.com/vi/${station.currentSong.songId}/mqdefault.jpg`;
  618. if (modifiableStation.theme === "blue") {
  619. modifiableStation.themeCode = "rgb(2, 166, 242)";
  620. } else if (modifiableStation.theme === "purple") {
  621. modifiableStation.themeCode = "rgb(143, 40, 140)";
  622. } else if (modifiableStation.theme === "teal") {
  623. modifiableStation.themeCode = "rgb(0, 209, 178)";
  624. } else if (modifiableStation.theme === "orange") {
  625. modifiableStation.themeCode = "rgb(255, 94, 0)";
  626. } else {
  627. modifiableStation.themeCode = "rgb(2, 166, 242)";
  628. }
  629. this.stations.push(modifiableStation);
  630. });
  631. });
  632. this.socket.emit("apis.joinRoom", "home", () => {});
  633. },
  634. isOwner(station) {
  635. return station.owner === this.userId;
  636. },
  637. isPlaying(station) {
  638. return typeof station.currentSong.title !== "undefined";
  639. },
  640. favoriteStation(station) {
  641. this.socket.emit("stations.favoriteStation", station._id, res => {
  642. if (res.status === "success") {
  643. new Toast({
  644. content: "Successfully favorited station.",
  645. timeout: 4000
  646. });
  647. } else new Toast({ content: res.message, timeout: 8000 });
  648. });
  649. },
  650. unfavoriteStation(station) {
  651. this.socket.emit("stations.unfavoriteStation", station._id, res => {
  652. if (res.status === "success") {
  653. new Toast({
  654. content: "Successfully unfavorited station.",
  655. timeout: 4000
  656. });
  657. } else new Toast({ content: res.message, timeout: 8000 });
  658. });
  659. },
  660. ...mapActions("modalVisibility", ["openModal"]),
  661. ...mapActions("station", ["updateIfStationIsFavorited"])
  662. }
  663. };
  664. </script>
  665. <style lang="scss">
  666. @import "../../styles/global.scss";
  667. * {
  668. box-sizing: border-box;
  669. }
  670. html {
  671. width: 100%;
  672. height: 100%;
  673. color: rgba(0, 0, 0, 0.87);
  674. body {
  675. width: 100%;
  676. height: 100%;
  677. margin: 0;
  678. padding: 0;
  679. }
  680. }
  681. .night-mode {
  682. .header .overlay {
  683. background: linear-gradient(
  684. 180deg,
  685. rgba(34, 34, 34, 0.8) 0%,
  686. rgba(34, 34, 34, 0.95) 31.25%,
  687. rgba(34, 34, 34, 0.9) 54.17%,
  688. rgba(34, 34, 34, 0.8) 100%
  689. );
  690. }
  691. .card,
  692. .card-content,
  693. .card-content div {
  694. background-color: $night-mode-bg-secondary;
  695. }
  696. .card-content .icons i,
  697. .group-title i {
  698. color: $night-mode-text;
  699. }
  700. .card-image .image {
  701. background-color: #333;
  702. }
  703. .card-content .under-content .hostedBy {
  704. color: $night-mode-text;
  705. }
  706. }
  707. @media only screen and (min-width: 1200px) {
  708. html {
  709. font-size: 15px;
  710. }
  711. }
  712. @media only screen and (min-width: 992px) {
  713. html {
  714. font-size: 14.5px;
  715. }
  716. }
  717. @media only screen and (min-width: 0) {
  718. html {
  719. font-size: 14px;
  720. }
  721. }
  722. .header {
  723. display: flex;
  724. height: 35vh;
  725. margin-top: -64px;
  726. border-radius: 0% 0% 33% 33% / 0% 0% 7% 7%;
  727. img.background {
  728. height: 35vh;
  729. width: 100%;
  730. object-fit: cover;
  731. object-position: center;
  732. filter: blur(1px);
  733. border-radius: 0% 0% 33% 33% / 0% 0% 7% 7%;
  734. overflow: hidden;
  735. }
  736. .overlay {
  737. background: linear-gradient(
  738. 180deg,
  739. rgba(3, 169, 244, 0.8) 0%,
  740. rgba(3, 169, 244, 0.95) 31.25%,
  741. rgba(3, 169, 244, 0.9) 54.17%,
  742. rgba(3, 169, 244, 0.8) 100%
  743. );
  744. position: absolute;
  745. height: 35vh;
  746. width: 100%;
  747. border-radius: 0% 0% 33% 33% / 0% 0% 7% 7%;
  748. overflow: hidden;
  749. }
  750. .content-container {
  751. position: absolute;
  752. left: 0;
  753. right: 0;
  754. margin-left: auto;
  755. margin-right: auto;
  756. text-align: center;
  757. height: 100%;
  758. height: 35vh;
  759. .content {
  760. position: absolute;
  761. top: 50%;
  762. left: 0;
  763. right: 0;
  764. transform: translateY(-50%);
  765. background-color: transparent !important;
  766. img.logo {
  767. max-height: 90px;
  768. font-size: 40px;
  769. color: white;
  770. font-family: Pacifico, cursive;
  771. }
  772. .buttons {
  773. display: flex;
  774. justify-content: center;
  775. margin-top: 20px;
  776. flex-wrap: wrap;
  777. .login,
  778. .register {
  779. margin: 5px 10px;
  780. padding: 10px 15px;
  781. border-radius: 5px;
  782. font-size: 18px;
  783. width: 100%;
  784. max-width: 250px;
  785. font-weight: 600;
  786. border: 0;
  787. height: inherit;
  788. }
  789. .login {
  790. background: white;
  791. color: $musare-blue;
  792. }
  793. .register {
  794. background: $purple;
  795. color: white;
  796. }
  797. }
  798. }
  799. }
  800. &.loggedIn {
  801. height: 20vh;
  802. .overlay,
  803. .content-container,
  804. img.background {
  805. height: 20vh;
  806. }
  807. }
  808. }
  809. @media only screen and (max-width: 550px) {
  810. .header {
  811. height: 45vh;
  812. .overlay,
  813. .content-container,
  814. img.background {
  815. height: 45vh;
  816. }
  817. }
  818. }
  819. .under-content {
  820. height: 20px;
  821. position: relative;
  822. line-height: 1;
  823. font-size: 24px;
  824. display: flex;
  825. align-items: center;
  826. text-align: left;
  827. margin-top: 10px;
  828. p {
  829. font-size: 15px;
  830. line-height: 15px;
  831. display: inline;
  832. }
  833. i {
  834. font-size: 20px;
  835. }
  836. * {
  837. z-index: 10;
  838. position: relative;
  839. }
  840. .icons {
  841. position: absolute;
  842. right: 0;
  843. .material-icons {
  844. font-size: 22px;
  845. }
  846. .material-icons:first-child {
  847. margin-left: 5px;
  848. }
  849. .unlistedIcon {
  850. color: $light-orange;
  851. }
  852. .privateIcon {
  853. color: $dark-pink;
  854. }
  855. .homeIcon {
  856. color: $light-purple;
  857. }
  858. }
  859. .hostedBy {
  860. font-weight: 400;
  861. font-size: 12px;
  862. color: $black;
  863. .host,
  864. .host a {
  865. font-weight: 400;
  866. color: var(--station-theme);
  867. &:hover,
  868. &:focus {
  869. filter: brightness(90%);
  870. }
  871. }
  872. }
  873. }
  874. .app {
  875. display: flex;
  876. flex-direction: column;
  877. }
  878. .users-count {
  879. font-size: 20px;
  880. position: relative;
  881. top: -4px;
  882. }
  883. .group {
  884. min-height: 64px;
  885. flex: 1 0 auto;
  886. }
  887. .station-card {
  888. display: inline-flex;
  889. flex-direction: row;
  890. overflow: hidden;
  891. margin: 10px;
  892. cursor: pointer;
  893. height: 150px;
  894. width: calc(100% - 30px);
  895. max-width: 400px;
  896. flex-wrap: wrap;
  897. border-radius: 5px;
  898. box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
  899. transition: all ease-in-out 0.2s;
  900. .card-content {
  901. padding: 10px 10px 10px 15px;
  902. display: flex;
  903. flex-direction: column;
  904. flex-grow: 1;
  905. -webkit-line-clamp: 2;
  906. .media {
  907. display: flex;
  908. align-items: center;
  909. margin-bottom: 0;
  910. .displayName {
  911. display: flex;
  912. align-items: center;
  913. width: 100%;
  914. overflow: hidden;
  915. text-overflow: ellipsis;
  916. display: flex;
  917. line-height: 30px;
  918. max-height: 30px;
  919. .favorite {
  920. position: absolute;
  921. color: $yellow;
  922. right: 10px;
  923. top: 10px;
  924. font-size: 28px;
  925. }
  926. h5 {
  927. font-size: 20px;
  928. font-weight: 400;
  929. margin: 0;
  930. display: inline;
  931. margin-right: 6px;
  932. line-height: 30px;
  933. text-overflow: ellipsis;
  934. overflow: hidden;
  935. white-space: nowrap;
  936. max-width: 200px;
  937. }
  938. i {
  939. font-size: 22px;
  940. }
  941. .verified-station {
  942. color: var(--station-theme);
  943. }
  944. }
  945. }
  946. .content {
  947. word-wrap: break-word;
  948. overflow: hidden;
  949. text-overflow: ellipsis;
  950. display: -webkit-box;
  951. -webkit-box-orient: vertical;
  952. -webkit-line-clamp: 3;
  953. line-height: 20px;
  954. flex-grow: 1;
  955. text-align: left;
  956. word-wrap: break-word;
  957. margin-bottom: 0;
  958. }
  959. }
  960. .card-image {
  961. width: 120px;
  962. .image {
  963. box-shadow: 1px 0 3px rgba(100, 100, 100, 0.3);
  964. .ytThumbnailBg {
  965. background: url("/assets/notes-transparent.png") no-repeat
  966. center center;
  967. background-size: cover;
  968. height: 100%;
  969. width: 100%;
  970. position: absolute;
  971. top: 0;
  972. filter: blur(1px);
  973. }
  974. img {
  975. height: auto;
  976. width: 120px;
  977. top: 0;
  978. margin-top: auto;
  979. margin-bottom: auto;
  980. z-index: 1;
  981. }
  982. }
  983. }
  984. .bottomBar {
  985. position: relative;
  986. display: flex;
  987. align-items: center;
  988. background: var(--station-theme);
  989. // box-shadow: inset 0px 2px 4px rgba(100, 100, 100, 0.3);
  990. width: 100%;
  991. height: 30px;
  992. line-height: 30px;
  993. color: $white;
  994. font-weight: 400;
  995. font-size: 12px;
  996. padding: 0 5px;
  997. flex-basis: 100%;
  998. i.material-icons {
  999. vertical-align: middle;
  1000. margin-left: 5px;
  1001. font-size: 18px;
  1002. }
  1003. .songTitle {
  1004. text-align: left;
  1005. vertical-align: middle;
  1006. margin-left: 5px;
  1007. line-height: 30px;
  1008. flex: 2 1 0;
  1009. overflow: hidden;
  1010. text-overflow: ellipsis;
  1011. white-space: nowrap;
  1012. }
  1013. }
  1014. &.createStation {
  1015. .card-image .image.is-square .material-icons {
  1016. position: absolute;
  1017. top: 25px;
  1018. bottom: 25px;
  1019. left: 0;
  1020. right: 0;
  1021. text-align: center;
  1022. font-size: 70px;
  1023. color: var(--station-theme);
  1024. }
  1025. .card-content {
  1026. .media {
  1027. margin-top: auto;
  1028. .displayName h5 {
  1029. font-weight: 600;
  1030. }
  1031. }
  1032. .content {
  1033. flex-grow: unset;
  1034. margin-bottom: auto;
  1035. }
  1036. }
  1037. }
  1038. }
  1039. .station-card:hover {
  1040. box-shadow: 0 2px 3px rgba(10, 10, 10, 0.3), 0 0 10px rgba(10, 10, 10, 0.3);
  1041. transition: all ease-in-out 0.2s;
  1042. }
  1043. /*.isPrivate {
  1044. background-color: #F8BBD0;
  1045. }
  1046. .isMine {
  1047. background-color: #29B6F6;
  1048. }*/
  1049. .community-button {
  1050. cursor: pointer;
  1051. transition: 0.25s ease color;
  1052. font-size: 30px;
  1053. color: #4a4a4a;
  1054. }
  1055. .community-button:hover {
  1056. color: #03a9f4;
  1057. }
  1058. .station-privacy {
  1059. text-transform: capitalize;
  1060. }
  1061. .label {
  1062. display: flex;
  1063. }
  1064. .g-recaptcha {
  1065. display: flex;
  1066. justify-content: center;
  1067. margin-top: 20px;
  1068. }
  1069. .group {
  1070. text-align: center;
  1071. width: 100%;
  1072. margin: 10px 0;
  1073. .group-title {
  1074. display: flex;
  1075. align-items: center;
  1076. justify-content: center;
  1077. margin: 25px 0;
  1078. h1 {
  1079. display: inline-block;
  1080. font-size: 45px;
  1081. margin: 0;
  1082. }
  1083. h2 {
  1084. font-size: 35px;
  1085. margin: 0;
  1086. }
  1087. a {
  1088. display: flex;
  1089. margin-left: 8px;
  1090. }
  1091. }
  1092. &.bottom {
  1093. margin-bottom: 40px;
  1094. }
  1095. }
  1096. </style>