From 3ad1daaf8cf2ce6d263aa53995c7644aa3138c14 Mon Sep 17 00:00:00 2001
From: Nicolas Giard <github@ngpixel.com>
Date: Sun, 6 Nov 2022 07:31:13 -0500
Subject: [PATCH] fix: improve chat log rendering (#4686)

---
 .pnp.cjs                                      |  11 ++
 ...mojify-npm-1.0.2-a45d6eb0a7-0044c83b05.zip | Bin 0 -> 17788 bytes
 client/components/ChatLog.vue                 |  70 ++++++++-
 client/shared/colors.scss                     | 139 ++++++++++++++++++
 docker/scripts/app-rsync-extras.sh            |   1 -
 package.json                                  |   1 +
 yarn.lock                                     |   8 +
 7 files changed, 226 insertions(+), 4 deletions(-)
 create mode 100644 .yarn/cache/@twuni-emojify-npm-1.0.2-a45d6eb0a7-0044c83b05.zip
 create mode 100644 client/shared/colors.scss

diff --git a/.pnp.cjs b/.pnp.cjs
index c1a5a3a5e..cd7f836b1 100644
--- a/.pnp.cjs
+++ b/.pnp.cjs
@@ -47,6 +47,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
             ["@percy/cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.1.2"],\
             ["@popperjs/core", "npm:2.11.6"],\
             ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
+            ["@twuni/emojify", "npm:1.0.2"],\
             ["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.1.2"],\
             ["@vue/test-utils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.0"],\
             ["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.2.2"],\
@@ -2226,6 +2227,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
           "linkType": "HARD"\
         }]\
       ]],\
+      ["@twuni/emojify", [\
+        ["npm:1.0.2", {\
+          "packageLocation": "./.yarn/cache/@twuni-emojify-npm-1.0.2-a45d6eb0a7-0044c83b05.zip/node_modules/@twuni/emojify/",\
+          "packageDependencies": [\
+            ["@twuni/emojify", "npm:1.0.2"]\
+          ],\
+          "linkType": "HARD"\
+        }]\
+      ]],\
       ["@types/estree", [\
         ["npm:1.0.0", {\
           "packageLocation": "./.yarn/cache/@types-estree-npm-1.0.0-eddde5b631-910d97fb70.zip/node_modules/@types/estree/",\
@@ -8580,6 +8590,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
             ["@percy/cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.1.2"],\
             ["@popperjs/core", "npm:2.11.6"],\
             ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
+            ["@twuni/emojify", "npm:1.0.2"],\
             ["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.1.2"],\
             ["@vue/test-utils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.0"],\
             ["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.2.2"],\
diff --git a/.yarn/cache/@twuni-emojify-npm-1.0.2-a45d6eb0a7-0044c83b05.zip b/.yarn/cache/@twuni-emojify-npm-1.0.2-a45d6eb0a7-0044c83b05.zip
new file mode 100644
index 0000000000000000000000000000000000000000..4bcf04a90a5b4734d5bb1743005e551d49ad9046
GIT binary patch
literal 17788
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
Hbpr7KS0<Pv

literal 0
HcmV?d00001

diff --git a/client/components/ChatLog.vue b/client/components/ChatLog.vue
index 779734f91..d393b1866 100644
--- a/client/components/ChatLog.vue
+++ b/client/components/ChatLog.vue
@@ -22,6 +22,8 @@
 <script setup>
 import { onMounted, reactive } from 'vue'
 import { DateTime } from 'luxon'
+import { emojify } from '@twuni/emojify'
+import uniq from 'lodash-es/uniq'
 import {
   NTimeline,
   NTimelineItem
@@ -61,9 +63,12 @@ const colors = [
 
 onMounted(() => {
   const authorColors = {}
+
   // Get chat log data from embedded json tag
   const chatLog = JSON.parse(document.getElementById(`${props.componentId}-data`).textContent || '[]')
   if (chatLog.length > 0) {
+    const authorNames = uniq(chatLog.map(l => l.author))
+
     let idx = 1
     let colorIdx = 0
     for (const logItem of chatLog) {
@@ -75,12 +80,22 @@ onMounted(() => {
           colorIdx = 0
         }
       }
+
+      // -> Format text
+      let txt = emojify(logItem.text)
+      if (txt.indexOf('@') >= 0) {
+        for (const authorName of authorNames) {
+          txt = txt.replaceAll(`@${authorName}`, `<span class="user-mention">${authorName}</span>`)
+        }
+      }
+      txt = txt.replaceAll('href="/user_uploads/', 'href="https://zulip.ietf.org/user_uploads/')
+
       // -> Generate log item
       state.items.push({
         id: `logitem-${idx}`,
         color: authorColors[logItem.author],
         author: logItem.author,
-        text: logItem.text,
+        text: txt,
         time: DateTime.fromISO(logItem.time).toFormat('dd LLLL yyyy \'at\' HH:mm:ss a ZZZZ')
       })
       idx++
@@ -90,9 +105,58 @@ onMounted(() => {
 </script>
 
 <style lang="scss">
+@import '../shared/colors.scss';
+
 .chatlog {
-  .n-timeline-item-content__content > div > p {
-    margin-bottom: 0;
+  .n-timeline-item-content__content {
+    > div > p:last-child {
+      margin-bottom: 0;
+    }
+
+    blockquote {
+      background-color: $gray-100;
+      border-radius: 5px;
+      padding: 8px;
+      margin-top: -8px;
+
+      > p:last-child {
+        margin-bottom: 0;
+      }
+    }
+
+    .message_inline_image {
+      display: none;
+    }
+
+    // Manual user mention
+    .user-mention {
+      display: inline-block;
+      padding: 1px 5px;
+      background-color: rgba($purple, .05);
+      color: $purple;
+      font-weight: 500;
+      border-radius: 4px;
+
+      > .user-mention {
+        padding: 0;
+
+        &::before {
+          display: none;
+        }
+      }
+
+      &::before {
+        content: '@';
+      }
+    }
+
+    // User reply mention
+    .user-mention + a {
+      text-decoration: none;
+      color: $purple;
+      font-style: italic;
+      cursor: default;
+    }
   }
 }
 </style>
diff --git a/client/shared/colors.scss b/client/shared/colors.scss
new file mode 100644
index 000000000..e34c459e9
--- /dev/null
+++ b/client/shared/colors.scss
@@ -0,0 +1,139 @@
+// Bootstrap 5 Color Variables
+// Extracted from https://github.com/twbs/bootstrap/blob/main/scss/_variables.scss
+// Copyright (c) 2011-2022 Twitter, Inc.
+// Copyright (c) 2011-2022 The Bootstrap Authors
+
+// Tint a color: mix a color with white
+@function tint-color($color, $weight) {
+  @return mix(white, $color, $weight);
+}
+
+// Shade a color: mix a color with black
+@function shade-color($color, $weight) {
+  @return mix(black, $color, $weight);
+}
+
+// Color system
+
+$white:    #fff !default;
+$gray-100: #f8f9fa !default;
+$gray-200: #e9ecef !default;
+$gray-300: #dee2e6 !default;
+$gray-400: #ced4da !default;
+$gray-500: #adb5bd !default;
+$gray-600: #6c757d !default;
+$gray-700: #495057 !default;
+$gray-800: #343a40 !default;
+$gray-900: #212529 !default;
+$black:    #000 !default;
+
+$blue:    #0d6efd !default;
+$indigo:  #6610f2 !default;
+$purple:  #6f42c1 !default;
+$pink:    #d63384 !default;
+$red:     #dc3545 !default;
+$orange:  #fd7e14 !default;
+$yellow:  #ffc107 !default;
+$green:   #198754 !default;
+$teal:    #20c997 !default;
+$cyan:    #0dcaf0 !default;
+
+$blue-100: tint-color($blue, 80%) !default;
+$blue-200: tint-color($blue, 60%) !default;
+$blue-300: tint-color($blue, 40%) !default;
+$blue-400: tint-color($blue, 20%) !default;
+$blue-500: $blue !default;
+$blue-600: shade-color($blue, 20%) !default;
+$blue-700: shade-color($blue, 40%) !default;
+$blue-800: shade-color($blue, 60%) !default;
+$blue-900: shade-color($blue, 80%) !default;
+
+$indigo-100: tint-color($indigo, 80%) !default;
+$indigo-200: tint-color($indigo, 60%) !default;
+$indigo-300: tint-color($indigo, 40%) !default;
+$indigo-400: tint-color($indigo, 20%) !default;
+$indigo-500: $indigo !default;
+$indigo-600: shade-color($indigo, 20%) !default;
+$indigo-700: shade-color($indigo, 40%) !default;
+$indigo-800: shade-color($indigo, 60%) !default;
+$indigo-900: shade-color($indigo, 80%) !default;
+
+$purple-100: tint-color($purple, 80%) !default;
+$purple-200: tint-color($purple, 60%) !default;
+$purple-300: tint-color($purple, 40%) !default;
+$purple-400: tint-color($purple, 20%) !default;
+$purple-500: $purple !default;
+$purple-600: shade-color($purple, 20%) !default;
+$purple-700: shade-color($purple, 40%) !default;
+$purple-800: shade-color($purple, 60%) !default;
+$purple-900: shade-color($purple, 80%) !default;
+
+$pink-100: tint-color($pink, 80%) !default;
+$pink-200: tint-color($pink, 60%) !default;
+$pink-300: tint-color($pink, 40%) !default;
+$pink-400: tint-color($pink, 20%) !default;
+$pink-500: $pink !default;
+$pink-600: shade-color($pink, 20%) !default;
+$pink-700: shade-color($pink, 40%) !default;
+$pink-800: shade-color($pink, 60%) !default;
+$pink-900: shade-color($pink, 80%) !default;
+
+$red-100: tint-color($red, 80%) !default;
+$red-200: tint-color($red, 60%) !default;
+$red-300: tint-color($red, 40%) !default;
+$red-400: tint-color($red, 20%) !default;
+$red-500: $red !default;
+$red-600: shade-color($red, 20%) !default;
+$red-700: shade-color($red, 40%) !default;
+$red-800: shade-color($red, 60%) !default;
+$red-900: shade-color($red, 80%) !default;
+
+$orange-100: tint-color($orange, 80%) !default;
+$orange-200: tint-color($orange, 60%) !default;
+$orange-300: tint-color($orange, 40%) !default;
+$orange-400: tint-color($orange, 20%) !default;
+$orange-500: $orange !default;
+$orange-600: shade-color($orange, 20%) !default;
+$orange-700: shade-color($orange, 40%) !default;
+$orange-800: shade-color($orange, 60%) !default;
+$orange-900: shade-color($orange, 80%) !default;
+
+$yellow-100: tint-color($yellow, 80%) !default;
+$yellow-200: tint-color($yellow, 60%) !default;
+$yellow-300: tint-color($yellow, 40%) !default;
+$yellow-400: tint-color($yellow, 20%) !default;
+$yellow-500: $yellow !default;
+$yellow-600: shade-color($yellow, 20%) !default;
+$yellow-700: shade-color($yellow, 40%) !default;
+$yellow-800: shade-color($yellow, 60%) !default;
+$yellow-900: shade-color($yellow, 80%) !default;
+
+$green-100: tint-color($green, 80%) !default;
+$green-200: tint-color($green, 60%) !default;
+$green-300: tint-color($green, 40%) !default;
+$green-400: tint-color($green, 20%) !default;
+$green-500: $green !default;
+$green-600: shade-color($green, 20%) !default;
+$green-700: shade-color($green, 40%) !default;
+$green-800: shade-color($green, 60%) !default;
+$green-900: shade-color($green, 80%) !default;
+
+$teal-100: tint-color($teal, 80%) !default;
+$teal-200: tint-color($teal, 60%) !default;
+$teal-300: tint-color($teal, 40%) !default;
+$teal-400: tint-color($teal, 20%) !default;
+$teal-500: $teal !default;
+$teal-600: shade-color($teal, 20%) !default;
+$teal-700: shade-color($teal, 40%) !default;
+$teal-800: shade-color($teal, 60%) !default;
+$teal-900: shade-color($teal, 80%) !default;
+
+$cyan-100: tint-color($cyan, 80%) !default;
+$cyan-200: tint-color($cyan, 60%) !default;
+$cyan-300: tint-color($cyan, 40%) !default;
+$cyan-400: tint-color($cyan, 20%) !default;
+$cyan-500: $cyan !default;
+$cyan-600: shade-color($cyan, 20%) !default;
+$cyan-700: shade-color($cyan, 40%) !default;
+$cyan-800: shade-color($cyan, 60%) !default;
+$cyan-900: shade-color($cyan, 80%) !default;
diff --git a/docker/scripts/app-rsync-extras.sh b/docker/scripts/app-rsync-extras.sh
index ef6966224..b99082b53 100755
--- a/docker/scripts/app-rsync-extras.sh
+++ b/docker/scripts/app-rsync-extras.sh
@@ -43,7 +43,6 @@ cat << EOF > "$EXCLUDE"
 *.doc
 *.exe
 *.html
-*.json
 *.mib
 *.new
 *.p7s
diff --git a/package.json b/package.json
index 98fe90225..d96c37b0a 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
     "@fullcalendar/timegrid": "5.11.3",
     "@fullcalendar/vue3": "5.11.2",
     "@popperjs/core": "2.11.6",
+    "@twuni/emojify": "1.0.2",
     "bootstrap": "5.2.2",
     "bootstrap-icons": "1.9.1",
     "browser-fs-access": "0.31.1",
diff --git a/yarn.lock b/yarn.lock
index 66ed75d83..dda4f64ca 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1719,6 +1719,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@twuni/emojify@npm:1.0.2":
+  version: 1.0.2
+  resolution: "@twuni/emojify@npm:1.0.2"
+  checksum: 0044c83b0589767dae1c1bb933cd56f2e5031a438f0fc993413e4cc229080e29c275cdd836be33ee02ddd59a5d1d6223a718685650f11ecfffc69c881c072152
+  languageName: node
+  linkType: hard
+
 "@types/estree@npm:^1.0.0":
   version: 1.0.0
   resolution: "@types/estree@npm:1.0.0"
@@ -7138,6 +7145,7 @@ browserlist@latest:
     "@percy/cypress": 3.1.2
     "@popperjs/core": 2.11.6
     "@rollup/pluginutils": 5.0.2
+    "@twuni/emojify": 1.0.2
     "@vitejs/plugin-vue": 3.1.2
     "@vue/test-utils": 2.1.0
     bootstrap: 5.2.2