App.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281
  1. <template>
  2. <div class="upper-container">
  3. <banned v-if="banned" />
  4. <div v-else class="upper-container">
  5. <router-view
  6. :key="$route.fullPath"
  7. class="main-container"
  8. :class="{ 'main-container-modal-active': aModalIsOpen }"
  9. />
  10. <what-is-new v-show="modals.whatIsNew" />
  11. <login-modal v-if="modals.login" />
  12. <register-modal v-if="modals.register" />
  13. <create-playlist-modal v-if="modals.createPlaylist" />
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. import { mapState, mapActions, mapGetters } from "vuex";
  19. import Toast from "toasters";
  20. import { defineAsyncComponent } from "vue";
  21. import ws from "./ws";
  22. import aw from "./aw";
  23. import keyboardShortcuts from "./keyboardShortcuts";
  24. export default {
  25. components: {
  26. WhatIsNew: defineAsyncComponent(() =>
  27. import("@/components/modals/WhatIsNew.vue")
  28. ),
  29. LoginModal: defineAsyncComponent(() =>
  30. import("@/components/modals/Login.vue")
  31. ),
  32. RegisterModal: defineAsyncComponent(() =>
  33. import("@/components/modals/Register.vue")
  34. ),
  35. CreatePlaylistModal: defineAsyncComponent(() =>
  36. import("@/components/modals/CreatePlaylist.vue")
  37. ),
  38. Banned: defineAsyncComponent(() => import("@/pages/Banned.vue"))
  39. },
  40. replace: false,
  41. data() {
  42. return {
  43. apiDomain: "",
  44. socketConnected: true,
  45. keyIsDown: false
  46. };
  47. },
  48. computed: {
  49. ...mapState({
  50. loggedIn: state => state.user.auth.loggedIn,
  51. role: state => state.user.auth.role,
  52. username: state => state.user.auth.username,
  53. userId: state => state.user.auth.userId,
  54. banned: state => state.user.auth.banned,
  55. modals: state => state.modalVisibility.modals,
  56. currentlyActive: state => state.modalVisibility.currentlyActive,
  57. nightmode: state => state.user.preferences.nightmode,
  58. activityWatch: state => state.user.preferences.activityWatch
  59. }),
  60. ...mapGetters({
  61. socket: "websockets/getSocket"
  62. }),
  63. aModalIsOpen() {
  64. return Object.keys(this.currentlyActive).length > 0;
  65. }
  66. },
  67. watch: {
  68. socketConnected(connected) {
  69. if (!connected) this.disconnectedMessage.show();
  70. else this.disconnectedMessage.hide();
  71. },
  72. nightmode(nightmode) {
  73. if (nightmode) this.enableNightMode();
  74. else this.disableNightMode();
  75. },
  76. activityWatch(activityWatch) {
  77. if (activityWatch) aw.enable();
  78. else aw.disable();
  79. }
  80. },
  81. async mounted() {
  82. document.onkeydown = ev => {
  83. const event = ev || window.event;
  84. const { keyCode } = event;
  85. const shift = event.shiftKey;
  86. const ctrl = event.ctrlKey;
  87. const alt = event.altKey;
  88. const identifier = `${keyCode}.${shift}.${ctrl}`;
  89. if (this.keyIsDown === identifier) return;
  90. this.keyIsDown = identifier;
  91. keyboardShortcuts.handleKeyDown(event, keyCode, shift, ctrl, alt);
  92. };
  93. document.onkeyup = () => {
  94. this.keyIsDown = "";
  95. };
  96. // ctrl + alt + n
  97. keyboardShortcuts.registerShortcut("nightmode", {
  98. keyCode: 78,
  99. ctrl: true,
  100. alt: true,
  101. handler: () => {
  102. localStorage.setItem("nightmode", !this.nightmode);
  103. if (this.loggedIn) {
  104. this.socket.dispatch(
  105. "users.updatePreferences",
  106. {
  107. nightmode: !this.nightmode,
  108. autoSkipDisliked: false,
  109. activityLogPublic: false,
  110. anonymousSongRequests: false,
  111. activityWatch: false
  112. },
  113. res => {
  114. if (res.status !== "success")
  115. new Toast(res.message);
  116. }
  117. );
  118. }
  119. this.changeNightmode(!this.nightmode);
  120. }
  121. });
  122. keyboardShortcuts.registerShortcut("closeModal", {
  123. keyCode: 27,
  124. shift: false,
  125. ctrl: false,
  126. handler: () => {
  127. if (Object.keys(this.currentlyActive).length !== 0)
  128. this.closeCurrentModal();
  129. }
  130. });
  131. if (localStorage.getItem("github_redirect")) {
  132. this.$router.push(localStorage.getItem("github_redirect"));
  133. localStorage.removeItem("github_redirect");
  134. }
  135. this.disconnectedMessage = new Toast({
  136. content: "Could not connect to the server.",
  137. persistent: true,
  138. interactable: false
  139. });
  140. this.disconnectedMessage.hide();
  141. ws.onConnect(true, () => {
  142. this.socketConnected = true;
  143. });
  144. ws.onDisconnect(true, () => {
  145. this.socketConnected = false;
  146. });
  147. this.apiDomain = await lofig.get("apiDomain");
  148. this.$router.isReady(() => {
  149. if (this.$route.query.err) {
  150. let { err } = this.$route.query;
  151. err = err
  152. .replace(new RegExp("<", "g"), "&lt;")
  153. .replace(new RegExp(">", "g"), "&gt;");
  154. this.$router.push({ query: {} });
  155. new Toast({ content: err, timeout: 20000 });
  156. }
  157. if (this.$route.query.msg) {
  158. let { msg } = this.$route.query;
  159. msg = msg
  160. .replace(new RegExp("<", "g"), "&lt;")
  161. .replace(new RegExp(">", "g"), "&gt;");
  162. this.$router.push({ query: {} });
  163. new Toast({ content: msg, timeout: 20000 });
  164. }
  165. });
  166. if (localStorage.getItem("nightmode") === "true") {
  167. this.changeNightmode(true);
  168. this.enableNightMode();
  169. }
  170. this.socket.dispatch("users.getPreferences", res => {
  171. if (res.status === "success") {
  172. const { preferences } = res.data;
  173. this.changeAutoSkipDisliked(preferences.autoSkipDisliked);
  174. this.changeNightmode(preferences.nightmode);
  175. this.changeActivityLogPublic(preferences.activityLogPublic);
  176. this.changeAnonymousSongRequests(
  177. preferences.anonymousSongRequests
  178. );
  179. this.changeActivityWatch(preferences.activityWatch);
  180. if (this.nightmode) this.enableNightMode();
  181. else this.disableNightMode();
  182. }
  183. });
  184. this.socket.on("keep.event:user.session.deleted", () =>
  185. window.location.reload()
  186. );
  187. },
  188. methods: {
  189. enableNightMode: () => {
  190. document
  191. .getElementsByTagName("body")[0]
  192. .classList.add("night-mode");
  193. },
  194. disableNightMode: () => {
  195. document
  196. .getElementsByTagName("body")[0]
  197. .classList.remove("night-mode");
  198. },
  199. ...mapActions("modalVisibility", ["closeCurrentModal"]),
  200. ...mapActions("user/preferences", [
  201. "changeNightmode",
  202. "changeAutoSkipDisliked",
  203. "changeActivityLogPublic",
  204. "changeAnonymousSongRequests",
  205. "changeActivityWatch"
  206. ])
  207. }
  208. };
  209. </script>
  210. <style lang="scss">
  211. @import "tippy.js/dist/tippy.css";
  212. @import "tippy.js/animations/scale.css";
  213. :root {
  214. --primary-color: var(--blue);
  215. --blue: rgb(2, 166, 242);
  216. --light-blue: rgb(163, 224, 255);
  217. --dark-blue: rgb(0, 102, 244);
  218. --teal: rgb(0, 209, 178);
  219. --purple: rgb(143, 40, 140);
  220. --light-purple: rgb(170, 141, 216);
  221. --yellow: rgb(241, 196, 15);
  222. --light-pink: rgb(228, 155, 166);
  223. --dark-pink: rgb(234, 72, 97);
  224. --orange: rgb(255, 94, 0);
  225. --dark-orange: rgb(250, 50, 0);
  226. --green: rgb(68, 189, 50);
  227. --red: rgb(231, 77, 60);
  228. --white: rgb(255, 255, 255);
  229. --black: rgb(0, 0, 0);
  230. --light-grey: rgb(245, 245, 245);
  231. --light-grey-2: rgb(221, 221, 221);
  232. --light-grey-3: rgb(195, 193, 195);
  233. --grey: rgb(107, 107, 107);
  234. --grey-2: rgb(113, 113, 113);
  235. --grey-3: rgb(126, 126, 126);
  236. --dark-grey: rgb(77, 77, 77);
  237. --dark-grey-2: rgb(51, 51, 51);
  238. --dark-grey-3: rgb(34, 34, 34);
  239. --dark-grey-4: rgb(26, 26, 26);
  240. --youtube: rgb(189, 46, 46);
  241. }
  242. .night-mode {
  243. div {
  244. // background-color: var(--black);
  245. color: var(--light-grey-2);
  246. }
  247. #toasts-container .toast {
  248. // color: var(--dark-grey-2);
  249. // background-color: var(--light-grey-3) !important;
  250. // &:last-of-type {
  251. // background-color: var(--light-grey) !important;
  252. // }
  253. }
  254. h1,
  255. h2,
  256. h3,
  257. h4,
  258. h5,
  259. h6 {
  260. color: var(--white) !important;
  261. }
  262. p:not(.help),
  263. label,
  264. .label {
  265. color: var(--light-grey-2) !important;
  266. }
  267. .section,
  268. .content {
  269. background-color: var(--dark-grey-3) !important;
  270. }
  271. .content-box,
  272. .step:not(.selected) {
  273. background-color: var(--dark-grey-3) !important;
  274. }
  275. .tippy-box[data-theme~="songActions"] {
  276. background-color: var(--dark-grey);
  277. }
  278. }
  279. body.night-mode {
  280. background-color: var(--black) !important;
  281. }
  282. #toasts-container {
  283. z-index: 10000 !important;
  284. .toast {
  285. font-weight: 600;
  286. // background-color: var(--dark-grey) !important;
  287. // &:last-of-type {
  288. // background-color: var(--dark-grey-2) !important;
  289. // }
  290. }
  291. }
  292. html {
  293. overflow: auto !important;
  294. height: 100%;
  295. }
  296. body {
  297. background-color: var(--light-grey);
  298. color: var(--dark-grey);
  299. height: 100%;
  300. font-family: "Inter", Helvetica, Arial, sans-serif;
  301. }
  302. h1,
  303. h2,
  304. h3,
  305. h4,
  306. h5,
  307. h6,
  308. .sidebar-title {
  309. font-family: "Inter", Helvetica, Arial, sans-serif;
  310. }
  311. .modal-card-title {
  312. font-weight: 600;
  313. font-family: "Inter", Helvetica, Arial, sans-serif;
  314. }
  315. p,
  316. button,
  317. input,
  318. select,
  319. textarea {
  320. font-family: "Inter", Helvetica, Arial, sans-serif;
  321. }
  322. .upper-container {
  323. height: 100%;
  324. }
  325. .main-container {
  326. height: 100%;
  327. min-height: 100vh;
  328. display: flex;
  329. flex-direction: column;
  330. > .container {
  331. flex: 1 0 auto;
  332. }
  333. }
  334. .main-container.main-container-modal-active {
  335. height: 100% !important;
  336. overflow: hidden;
  337. }
  338. a {
  339. color: var(--primary-color);
  340. text-decoration: none;
  341. }
  342. .modal-card {
  343. margin: 0 !important;
  344. }
  345. .absolute-a {
  346. width: 100%;
  347. height: 100%;
  348. position: absolute;
  349. top: 0;
  350. left: 0;
  351. }
  352. .alert {
  353. padding: 20px;
  354. color: var(--white);
  355. background-color: var(--red);
  356. position: fixed;
  357. top: 50px;
  358. right: 50px;
  359. font-size: 2em;
  360. border-radius: 5px;
  361. z-index: 10000000;
  362. }
  363. .night-mode {
  364. .tippy-box {
  365. border: 1px solid var(--light-grey-3);
  366. box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25),
  367. 0 10px 10px rgba(0, 0, 0, 0.22);
  368. background-color: var(--white);
  369. > .tippy-arrow::before {
  370. border-top-color: var(--white);
  371. }
  372. .tippy-content {
  373. color: var(--black);
  374. }
  375. &[data-theme~="songActions"] {
  376. background-color: var(--dark-grey-2);
  377. border: 0 !important;
  378. i,
  379. a {
  380. color: var(--white);
  381. }
  382. .youtube-icon {
  383. background-color: var(--white);
  384. }
  385. }
  386. &[data-theme~="addToPlaylist"] {
  387. background-color: var(--dark-grey-2);
  388. border: 0 !important;
  389. .nav-dropdown-items {
  390. .nav-item {
  391. background-color: var(--dark-grey);
  392. &:focus {
  393. outline-color: var(--dark-grey);
  394. }
  395. p {
  396. color: var(--white);
  397. }
  398. }
  399. }
  400. }
  401. }
  402. .tippy-box[data-placement^="top"] {
  403. &[data-theme~="songActions"],
  404. &[data-theme~="addToPlaylist"] {
  405. > .tippy-arrow::before {
  406. border-top-color: var(--dark-grey-2);
  407. }
  408. }
  409. }
  410. .tippy-popper[data-placement^="bottom"] {
  411. &[data-theme~="songActions"],
  412. &[data-theme~="addToPlaylist"] {
  413. > .tippy-arrow::before {
  414. border-bottom-color: var(--dark-grey-2);
  415. }
  416. }
  417. }
  418. .tippy-popper[data-placement^="left"] {
  419. &[data-theme~="songActions"],
  420. &[data-theme~="addToPlaylist"] {
  421. > .tippy-arrow::before {
  422. border-left-color: var(--dark-grey-2);
  423. }
  424. }
  425. }
  426. .tippy-box[data-placement^="right"] {
  427. &[data-theme~="songActions"],
  428. &[data-theme~="addToPlaylist"] {
  429. > .tippy-arrow::before {
  430. border-right-color: var(--dark-grey-2);
  431. }
  432. }
  433. }
  434. }
  435. .tippy-box[data-theme~="info"] {
  436. font-size: 12px;
  437. letter-spacing: 1px;
  438. }
  439. .tippy-box[data-theme~="confirm"] {
  440. background-color: var(--red);
  441. .tippy-content {
  442. padding: 0;
  443. }
  444. a {
  445. padding: 15px;
  446. line-height: 25px;
  447. color: var(--white);
  448. border-bottom: 0;
  449. font-size: 15px;
  450. font-weight: 600;
  451. &:hover,
  452. &:focus {
  453. filter: brightness(90%);
  454. }
  455. }
  456. }
  457. .tippy-box[data-theme~="songActions"] {
  458. font-size: 15px;
  459. padding: 5px 10px;
  460. border: 1px solid var(--light-grey-3);
  461. box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
  462. background-color: var(--white);
  463. .button {
  464. width: 146px;
  465. }
  466. .icons-group,
  467. .addToPlaylistDropdown,
  468. .icons-group > div {
  469. display: inline-block;
  470. }
  471. .addToPlaylistDropdown .tippy-popper {
  472. max-width: unset;
  473. }
  474. i,
  475. a {
  476. display: inline-block;
  477. cursor: pointer;
  478. color: var(--dark-grey);
  479. vertical-align: middle;
  480. &:hover,
  481. &:focus {
  482. filter: brightness(90%);
  483. }
  484. &:not(:first) {
  485. margin-left: 5px;
  486. }
  487. }
  488. .play-icon {
  489. color: var(--green);
  490. }
  491. .edit-icon,
  492. .view-icon,
  493. .add-to-playlist-icon,
  494. .add-to-queue-icon {
  495. color: var(--primary-color);
  496. }
  497. .hide-icon {
  498. color: var(--light-grey-3);
  499. }
  500. .stop-icon,
  501. .delete-icon {
  502. color: var(--red);
  503. }
  504. .report-icon {
  505. color: var(--yellow);
  506. }
  507. }
  508. .tippy-box[data-placement^="top"] {
  509. &[data-theme~="songActions"],
  510. &[data-theme~="addToPlaylist"] {
  511. > .tippy-arrow::before {
  512. border-top-color: var(--white);
  513. }
  514. }
  515. &[data-theme~="confirm"] > .tippy-arrow::before {
  516. border-top-color: var(--red);
  517. }
  518. }
  519. .tippy-box[data-placement^="bottom"] {
  520. &[data-theme~="songActions"],
  521. &[data-theme~="addToPlaylist"] {
  522. > .tippy-arrow::before {
  523. border-bottom-color: var(--white);
  524. }
  525. }
  526. &[data-theme~="confirm"] > .tippy-arrow::before {
  527. border-bottom-color: var(--red);
  528. }
  529. }
  530. .tippy-box[data-placement^="left"] {
  531. &[data-theme~="songActions"],
  532. &[data-theme~="addToPlaylist"] {
  533. > .tippy-arrow::before {
  534. border-left-color: var(--white);
  535. }
  536. }
  537. &[data-theme~="confirm"] > .tippy-arrow::before {
  538. border-left-color: var(--red);
  539. }
  540. }
  541. .tippy-box[data-placement^="right"] {
  542. &[data-theme~="songActions"],
  543. &[data-theme~="addToPlaylist"] {
  544. > .tippy-arrow::before {
  545. border-right-color: var(--white);
  546. }
  547. }
  548. &[data-theme~="confirm"] > .tippy-arrow::before {
  549. border-right-color: var(--red);
  550. }
  551. }
  552. .tippy-box[data-theme~="addToPlaylist"] {
  553. font-size: 15px;
  554. padding: 5px;
  555. border: 1px solid var(--light-grey-3);
  556. box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
  557. background-color: var(--white);
  558. color: var(--dark-grey);
  559. .nav-dropdown-items {
  560. .nav-item {
  561. width: 100%;
  562. justify-content: flex-start;
  563. border: 0;
  564. padding: 10px;
  565. font-size: 15.5px;
  566. height: 36px;
  567. background: var(--light-grey);
  568. border-radius: 5px;
  569. cursor: pointer;
  570. .checkbox-control {
  571. display: flex;
  572. flex-direction: row;
  573. align-items: center;
  574. p {
  575. margin-left: 10px;
  576. }
  577. .switch {
  578. position: relative;
  579. display: inline-block;
  580. flex-shrink: 0;
  581. width: 40px;
  582. height: 24px;
  583. }
  584. .switch input {
  585. opacity: 0;
  586. width: 0;
  587. height: 0;
  588. }
  589. .slider {
  590. position: absolute;
  591. cursor: pointer;
  592. top: 0;
  593. left: 0;
  594. right: 0;
  595. bottom: 0;
  596. background-color: #ccc;
  597. transition: 0.2s;
  598. border-radius: 34px;
  599. }
  600. .slider:before {
  601. position: absolute;
  602. content: "";
  603. height: 16px;
  604. width: 16px;
  605. left: 4px;
  606. bottom: 4px;
  607. background-color: white;
  608. transition: 0.2s;
  609. border-radius: 50%;
  610. }
  611. input:checked + .slider {
  612. background-color: var(--primary-color);
  613. }
  614. input:focus + .slider {
  615. box-shadow: 0 0 1px var(--primary-color);
  616. }
  617. input:checked + .slider:before {
  618. transform: translateX(16px);
  619. }
  620. }
  621. &:focus {
  622. outline-color: var(--light-grey-3);
  623. }
  624. &:not(:last-of-type) {
  625. margin-bottom: 5px;
  626. }
  627. }
  628. }
  629. .tippy-content > div {
  630. display: flex;
  631. flex-direction: column;
  632. button {
  633. width: 150px;
  634. &:not(:last-of-type) {
  635. margin-bottom: 10px;
  636. }
  637. }
  638. }
  639. }
  640. .select {
  641. &:after {
  642. border-color: var(--primary-color);
  643. border-width: 1.5px;
  644. margin-top: -3px;
  645. }
  646. select {
  647. height: 36px;
  648. }
  649. }
  650. .button:focus,
  651. .button:active {
  652. border-color: var(--light-grey-2) !important;
  653. }
  654. .input:focus,
  655. .input:active,
  656. .textarea:focus,
  657. .textarea:active,
  658. .select select:focus,
  659. .select select:active {
  660. border-color: var(--primary-color) !important;
  661. }
  662. button.delete:focus {
  663. background-color: rgba(10, 10, 10, 0.3);
  664. }
  665. .tag {
  666. padding-right: 6px !important;
  667. }
  668. .button {
  669. &:hover,
  670. &:focus {
  671. filter: brightness(95%);
  672. }
  673. &.is-success {
  674. background-color: var(--green) !important;
  675. }
  676. &.is-primary {
  677. background-color: var(--primary-color) !important;
  678. }
  679. &.is-danger {
  680. background-color: var(--red) !important;
  681. }
  682. &.is-info {
  683. background-color: var(--primary-color) !important;
  684. }
  685. &.is-warning {
  686. background-color: var(--yellow) !important;
  687. }
  688. }
  689. .input,
  690. .button {
  691. height: 36px;
  692. }
  693. .fadein-helpbox-enter-active {
  694. transition-duration: 0.3s;
  695. transition-timing-function: ease-in;
  696. }
  697. .fadein-helpbox-leave-active {
  698. transition-duration: 0.3s;
  699. transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
  700. }
  701. .fadein-helpbox-enter-to,
  702. .fadein-helpbox-leave {
  703. max-height: 100px;
  704. overflow: hidden;
  705. }
  706. .fadein-helpbox-enter,
  707. .fadein-helpbox-leave-to {
  708. overflow: hidden;
  709. max-height: 0;
  710. }
  711. .control {
  712. margin-bottom: 5px !important;
  713. }
  714. .input-with-button {
  715. .control {
  716. margin-right: 0px !important;
  717. }
  718. input,
  719. select {
  720. width: 100%;
  721. height: 36px;
  722. border-radius: 3px 0 0 3px;
  723. border-right: 0;
  724. border-color: var(--light-grey-3);
  725. }
  726. .button {
  727. height: 36px;
  728. border-radius: 0 3px 3px 0;
  729. }
  730. }
  731. .page-title {
  732. margin: 0 0 50px 0;
  733. }
  734. .material-icons {
  735. user-select: none;
  736. -webkit-user-select: none;
  737. }
  738. .icon-with-button {
  739. margin-right: 3px;
  740. font-size: 18px;
  741. }
  742. .verified-song {
  743. font-size: 17px;
  744. color: var(--primary-color);
  745. }
  746. .section-title,
  747. h4.section-title {
  748. font-size: 26px;
  749. font-weight: 600;
  750. margin: 0px;
  751. }
  752. .section-description {
  753. font-size: 16px;
  754. font-weight: 400;
  755. margin-bottom: 10px !important;
  756. }
  757. .section-horizontal-rule {
  758. margin: 15px 0 30px 0;
  759. }
  760. .section-margin-bottom {
  761. height: 30px;
  762. }
  763. .margin-top-zero {
  764. margin-top: 0 !important;
  765. }
  766. .margin-bottom-zero {
  767. margin-bottom: 0 !important;
  768. }
  769. /** Universial items e.g. playlist items, queue items, activity items */
  770. .item-draggable {
  771. cursor: move;
  772. }
  773. .universal-item {
  774. display: flex;
  775. flex-direction: row;
  776. flex-grow: 1;
  777. align-items: center;
  778. justify-content: space-between;
  779. padding: 7.5px;
  780. border: 1px solid var(--light-grey-3);
  781. border-radius: 3px;
  782. overflow: hidden;
  783. .item-thumbnail {
  784. width: 65px;
  785. height: 65px;
  786. margin: -7.5px;
  787. border-radius: 3px 0 0 3px;
  788. }
  789. .item-title {
  790. font-size: 20px;
  791. overflow: hidden;
  792. text-overflow: ellipsis;
  793. white-space: nowrap;
  794. }
  795. .item-description {
  796. font-size: 14px;
  797. overflow: hidden;
  798. text-overflow: ellipsis;
  799. white-space: nowrap;
  800. }
  801. .universal-item-actions {
  802. display: flex;
  803. flex-direction: row;
  804. margin-left: 10px;
  805. justify-content: center;
  806. @media screen and (max-width: 800px) {
  807. flex-wrap: wrap;
  808. }
  809. .action-dropdown-icon {
  810. display: flex;
  811. color: var(--primary-color);
  812. }
  813. .icons-group {
  814. display: flex;
  815. align-items: center;
  816. a {
  817. padding: 0;
  818. }
  819. }
  820. .button {
  821. width: 146px;
  822. }
  823. i {
  824. cursor: pointer;
  825. color: var(--dark-grey);
  826. &:hover,
  827. &:focus {
  828. filter: brightness(90%);
  829. }
  830. &:not(:first-of-type) {
  831. margin-left: 5px;
  832. }
  833. }
  834. .play-icon {
  835. color: var(--green);
  836. }
  837. .edit-icon,
  838. .view-icon,
  839. .add-to-playlist-icon {
  840. color: var(--primary-color);
  841. }
  842. .hide-icon {
  843. color: var(--light-grey-3);
  844. }
  845. .stop-icon,
  846. .delete-icon {
  847. color: var(--red);
  848. }
  849. .report-icon {
  850. color: var(--yellow);
  851. }
  852. }
  853. }
  854. .save-button-mixin {
  855. min-width: 200px;
  856. &:disabled {
  857. background-color: var(--light-grey) !important;
  858. color: var(--black);
  859. }
  860. }
  861. .save-button-transition-enter-active {
  862. transition: all 0.1s ease;
  863. }
  864. .save-button-transition-enter {
  865. transform: translateX(20px);
  866. opacity: 0;
  867. }
  868. .youtube-icon {
  869. margin-right: 3px;
  870. height: 20px;
  871. width: 20px;
  872. -webkit-mask: url("/assets/social/youtube.svg") no-repeat center;
  873. mask: url("/assets/social/youtube.svg") no-repeat center;
  874. background-color: var(--youtube);
  875. }
  876. #forgot-password {
  877. display: flex;
  878. justify-content: flex-start;
  879. margin: 5px 0;
  880. }
  881. .steps-fade-enter-active,
  882. .steps-fade-leave-active {
  883. transition: all 0.3s ease;
  884. }
  885. .steps-fade-enter,
  886. .steps-fade-leave-to {
  887. opacity: 0;
  888. }
  889. .skip-step {
  890. background-color: var(--grey-3);
  891. color: var(--white);
  892. }
  893. #steps {
  894. display: flex;
  895. align-items: center;
  896. justify-content: center;
  897. height: 50px;
  898. margin-top: 36px;
  899. @media screen and (max-width: 300px) {
  900. display: none;
  901. }
  902. .step {
  903. display: flex;
  904. align-items: center;
  905. justify-content: center;
  906. border-radius: 100%;
  907. border: 1px solid var(--dark-grey);
  908. min-width: 50px;
  909. min-height: 50px;
  910. background-color: var(--white);
  911. font-size: 30px;
  912. cursor: pointer;
  913. &.selected {
  914. background-color: var(--primary-color);
  915. color: var(--white) !important;
  916. border: 0;
  917. }
  918. }
  919. .divider {
  920. display: flex;
  921. justify-content: center;
  922. width: 180px;
  923. height: 1px;
  924. background-color: var(--dark-grey);
  925. }
  926. }
  927. .content-box {
  928. margin-top: 90px;
  929. border-radius: 3px;
  930. background-color: var(--white);
  931. border: 1px solid var(--dark-grey);
  932. max-width: 580px;
  933. padding: 40px;
  934. @media screen and (max-width: 300px) {
  935. margin-top: 30px;
  936. padding: 30px 20px;
  937. }
  938. }
  939. .content-box-optional-helper {
  940. margin-top: 15px;
  941. color: var(--primary-color);
  942. text-decoration: underline;
  943. font-size: 16px;
  944. a {
  945. color: var(--primary-color);
  946. }
  947. }
  948. .content-box-title {
  949. font-size: 25px;
  950. color: var(--black);
  951. }
  952. .content-box-description {
  953. font-size: 14px;
  954. color: var(--dark-grey);
  955. }
  956. .content-box-inputs {
  957. margin-top: 35px;
  958. .input-with-button {
  959. .button {
  960. width: 105px;
  961. }
  962. @media screen and (max-width: 450px) {
  963. flex-direction: column;
  964. }
  965. }
  966. label {
  967. font-size: 11px;
  968. }
  969. #change-password-button {
  970. margin-top: 36px;
  971. width: 175px;
  972. }
  973. }
  974. #password-visibility-container {
  975. display: flex;
  976. align-items: center;
  977. a {
  978. width: 0;
  979. margin-left: -30px;
  980. z-index: 0;
  981. top: 2px;
  982. position: relative;
  983. color: var(--light-grey-1);
  984. }
  985. }
  986. .news-item {
  987. font-family: "Karla";
  988. border-radius: 5px;
  989. padding: 20px;
  990. border: unset !important;
  991. box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1);
  992. * {
  993. font-family: Karla, Arial, sans-serif;
  994. font-size: 16px;
  995. }
  996. h1 {
  997. font-size: 40px;
  998. &:first-of-type {
  999. margin-top: 0;
  1000. }
  1001. }
  1002. h2 {
  1003. font-size: 30px;
  1004. }
  1005. h3 {
  1006. font-size: 25px;
  1007. }
  1008. h4,
  1009. h5,
  1010. h6 {
  1011. font-size: 20px;
  1012. }
  1013. h1,
  1014. h2,
  1015. h3,
  1016. h4,
  1017. h5,
  1018. h6 {
  1019. margin: 10px 0;
  1020. }
  1021. ul {
  1022. list-style: unset;
  1023. }
  1024. li {
  1025. margin-left: 30px;
  1026. }
  1027. blockquote {
  1028. padding: 0px 15px;
  1029. color: #6a737d;
  1030. border-left: 0.25em solid #dfe2e5;
  1031. }
  1032. code {
  1033. font-style: italic;
  1034. }
  1035. }
  1036. .checkbox-control {
  1037. display: flex;
  1038. flex-direction: row;
  1039. align-items: center;
  1040. p {
  1041. margin-left: 10px;
  1042. }
  1043. .switch {
  1044. position: relative;
  1045. display: inline-block;
  1046. flex-shrink: 0;
  1047. width: 40px;
  1048. height: 24px;
  1049. }
  1050. .switch input {
  1051. opacity: 0;
  1052. width: 0;
  1053. height: 0;
  1054. }
  1055. .slider {
  1056. position: absolute;
  1057. cursor: pointer;
  1058. top: 0;
  1059. left: 0;
  1060. right: 0;
  1061. bottom: 0;
  1062. background-color: #ccc;
  1063. transition: 0.2s;
  1064. border-radius: 34px;
  1065. }
  1066. .slider:before {
  1067. position: absolute;
  1068. content: "";
  1069. height: 16px;
  1070. width: 16px;
  1071. left: 4px;
  1072. bottom: 4px;
  1073. background-color: white;
  1074. transition: 0.2s;
  1075. border-radius: 50%;
  1076. }
  1077. input:checked + .slider {
  1078. background-color: var(--primary-color);
  1079. }
  1080. input:focus + .slider {
  1081. box-shadow: 0 0 1px var(--primary-color);
  1082. }
  1083. input:checked + .slider:before {
  1084. transform: translateX(16px);
  1085. }
  1086. }
  1087. </style>