WhatIsNew.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. <template>
  2. <div v-if="news !== null">
  3. <modal title="News" class="what-is-news-modal">
  4. <template #body>
  5. <div
  6. class="section news-item"
  7. v-html="sanitize(marked(news.markdown))"
  8. ></div>
  9. </template>
  10. <template #footer>
  11. <span v-if="news.createdBy">
  12. By
  13. <user-id-to-username
  14. :user-id="news.createdBy"
  15. :alt="news.createdBy"
  16. :link="true" /></span
  17. >&nbsp;<span :title="new Date(news.createdAt)">
  18. {{
  19. formatDistance(news.createdAt, new Date(), {
  20. addSuffix: true
  21. })
  22. }}
  23. </span>
  24. </template>
  25. </modal>
  26. </div>
  27. <div v-else></div>
  28. </template>
  29. <script>
  30. import { formatDistance } from "date-fns";
  31. import { marked } from "marked";
  32. import { sanitize } from "dompurify";
  33. import { mapGetters, mapActions } from "vuex";
  34. import ws from "@/ws";
  35. import UserIdToUsername from "@/components/UserIdToUsername.vue";
  36. import Modal from "../Modal.vue";
  37. export default {
  38. components: { Modal, UserIdToUsername },
  39. data() {
  40. return {
  41. isModalActive: false,
  42. news: null
  43. };
  44. },
  45. computed: {
  46. ...mapGetters({
  47. socket: "websockets/getSocket"
  48. })
  49. },
  50. mounted() {
  51. marked.use({
  52. renderer: {
  53. table(header, body) {
  54. return `<table class="table">
  55. <thead>${header}</thead>
  56. <tbody>${body}</tbody>
  57. </table>`;
  58. }
  59. }
  60. });
  61. ws.onConnect(this.init);
  62. },
  63. methods: {
  64. init() {
  65. const newUser = !localStorage.getItem("firstVisited");
  66. this.socket.dispatch("news.newest", newUser, res => {
  67. if (res.status !== "success") return;
  68. const { news } = res.data;
  69. this.news = news;
  70. if (this.news) {
  71. if (newUser) {
  72. this.openModal("whatIsNew");
  73. } else if (localStorage.getItem("whatIsNew")) {
  74. if (
  75. parseInt(localStorage.getItem("whatIsNew")) <
  76. news.createdAt
  77. ) {
  78. this.openModal("whatIsNew");
  79. localStorage.setItem("whatIsNew", news.createdAt);
  80. }
  81. } else {
  82. if (
  83. parseInt(localStorage.getItem("firstVisited")) <
  84. news.createdAt
  85. )
  86. this.openModal("whatIsNew");
  87. localStorage.setItem("whatIsNew", news.createdAt);
  88. }
  89. }
  90. if (!localStorage.getItem("firstVisited"))
  91. localStorage.setItem("firstVisited", Date.now());
  92. });
  93. },
  94. marked,
  95. sanitize,
  96. formatDistance,
  97. ...mapActions("modalVisibility", ["openModal"])
  98. }
  99. };
  100. </script>
  101. <style lang="less">
  102. .what-is-news-modal .modal-card .modal-card-foot {
  103. column-gap: 0;
  104. }
  105. </style>
  106. <style lang="less" scoped>
  107. .night-mode {
  108. .modal-card,
  109. .modal-card-head,
  110. .modal-card-body {
  111. background-color: var(--dark-grey-3);
  112. }
  113. strong,
  114. p {
  115. color: var(--light-grey-2);
  116. }
  117. .section {
  118. background-color: transparent !important;
  119. }
  120. }
  121. .modal-card-head {
  122. border-bottom: none;
  123. background-color: ghostwhite;
  124. padding: 15px;
  125. }
  126. .modal-card-title {
  127. font-size: 14px;
  128. }
  129. .news-item {
  130. box-shadow: unset !important;
  131. }
  132. .delete {
  133. background: transparent;
  134. &:hover {
  135. background: transparent;
  136. }
  137. &:before,
  138. &:after {
  139. background-color: var(--light-grey-3);
  140. }
  141. }
  142. .sect {
  143. div[class^="sect-head"],
  144. div[class*=" sect-head"] {
  145. padding: 12px;
  146. text-transform: uppercase;
  147. font-weight: bold;
  148. color: var(--white);
  149. }
  150. .sect-head-features {
  151. background-color: dodgerblue;
  152. }
  153. .sect-head-improvements {
  154. background-color: seagreen;
  155. }
  156. .sect-head-bugs {
  157. background-color: brown;
  158. }
  159. .sect-head-upcoming {
  160. background-color: mediumpurple;
  161. }
  162. .sect-body {
  163. padding: 15px 25px;
  164. li {
  165. list-style-type: disc;
  166. }
  167. }
  168. }
  169. </style>