WhatIsNew.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. ><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 is-striped">
  55. <thead>${header}</thead>
  56. <tbody>${body}</tbody>
  57. </table>`;
  58. }
  59. }
  60. });
  61. ws.onConnect(this.init);
  62. },
  63. methods: {
  64. init() {
  65. this.socket.dispatch("news.newest", res => {
  66. if (res.status !== "success") return;
  67. const { news } = res.data;
  68. this.news = news;
  69. if (this.news && localStorage.getItem("firstVisited")) {
  70. if (localStorage.getItem("whatIsNew")) {
  71. if (
  72. parseInt(localStorage.getItem("whatIsNew")) <
  73. news.createdAt
  74. ) {
  75. this.openModal("whatIsNew");
  76. localStorage.setItem("whatIsNew", news.createdAt);
  77. }
  78. } else {
  79. if (
  80. parseInt(localStorage.getItem("firstVisited")) <
  81. news.createdAt
  82. )
  83. this.openModal("whatIsNew");
  84. localStorage.setItem("whatIsNew", news.createdAt);
  85. }
  86. } else if (!localStorage.getItem("firstVisited"))
  87. localStorage.setItem("firstVisited", Date.now());
  88. });
  89. },
  90. marked,
  91. sanitize,
  92. formatDistance,
  93. ...mapActions("modalVisibility", ["openModal"])
  94. }
  95. };
  96. </script>
  97. <style lang="scss">
  98. .what-is-news-modal {
  99. .modal-card {
  100. .modal-card-foot {
  101. span:not(:last-child) {
  102. margin-right: 5px !important;
  103. }
  104. }
  105. }
  106. }
  107. </style>
  108. <style lang="scss" scoped>
  109. .night-mode {
  110. .modal-card,
  111. .modal-card-head,
  112. .modal-card-body {
  113. background-color: var(--dark-grey-3);
  114. }
  115. strong,
  116. p {
  117. color: var(--light-grey-2);
  118. }
  119. }
  120. .modal-card-head {
  121. border-bottom: none;
  122. background-color: ghostwhite;
  123. padding: 15px;
  124. }
  125. .modal-card-title {
  126. font-size: 14px;
  127. }
  128. .news-item {
  129. box-shadow: unset !important;
  130. }
  131. .delete {
  132. background: transparent;
  133. &:hover {
  134. background: transparent;
  135. }
  136. &:before,
  137. &:after {
  138. background-color: var(--light-grey-3);
  139. }
  140. }
  141. .sect {
  142. div[class^="sect-head"],
  143. div[class*=" sect-head"] {
  144. padding: 12px;
  145. text-transform: uppercase;
  146. font-weight: bold;
  147. color: var(--white);
  148. }
  149. .sect-head-features {
  150. background-color: dodgerblue;
  151. }
  152. .sect-head-improvements {
  153. background-color: seagreen;
  154. }
  155. .sect-head-bugs {
  156. background-color: brown;
  157. }
  158. .sect-head-upcoming {
  159. background-color: mediumpurple;
  160. }
  161. .sect-body {
  162. padding: 15px 25px;
  163. li {
  164. list-style-type: disc;
  165. }
  166. }
  167. }
  168. </style>