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