WhatIsNew.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. 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 .modal-card .modal-card-foot {
  99. column-gap: 0;
  100. }
  101. </style>
  102. <style lang="scss" scoped>
  103. .night-mode {
  104. .modal-card,
  105. .modal-card-head,
  106. .modal-card-body {
  107. background-color: var(--dark-grey-3);
  108. }
  109. strong,
  110. p {
  111. color: var(--light-grey-2);
  112. }
  113. .section {
  114. background-color: transparent !important;
  115. }
  116. }
  117. .modal-card-head {
  118. border-bottom: none;
  119. background-color: ghostwhite;
  120. padding: 15px;
  121. }
  122. .modal-card-title {
  123. font-size: 14px;
  124. }
  125. .news-item {
  126. box-shadow: unset !important;
  127. }
  128. .delete {
  129. background: transparent;
  130. &:hover {
  131. background: transparent;
  132. }
  133. &:before,
  134. &:after {
  135. background-color: var(--light-grey-3);
  136. }
  137. }
  138. .sect {
  139. div[class^="sect-head"],
  140. div[class*=" sect-head"] {
  141. padding: 12px;
  142. text-transform: uppercase;
  143. font-weight: bold;
  144. color: var(--white);
  145. }
  146. .sect-head-features {
  147. background-color: dodgerblue;
  148. }
  149. .sect-head-improvements {
  150. background-color: seagreen;
  151. }
  152. .sect-head-bugs {
  153. background-color: brown;
  154. }
  155. .sect-head-upcoming {
  156. background-color: mediumpurple;
  157. }
  158. .sect-body {
  159. padding: 15px 25px;
  160. li {
  161. list-style-type: disc;
  162. }
  163. }
  164. }
  165. </style>