From dc7d53b59ce865a3273639458981eb7c8fe3fc14 Mon Sep 17 00:00:00 2001 From: panda Date: Mon, 30 May 2022 14:41:24 +0800 Subject: [PATCH] ui: add discussion reaction (#369) Co-authored-by: undefined --- .../components/discussion/comments.page.styl | 25 ----- .../components/discussion/comments.page.tsx | 80 ---------------- .../components/discussion/reaction.page.styl | 30 ++++++ .../components/discussion/reaction.page.tsx | 92 +++++++++++++++++++ packages/ui-default/package.json | 2 +- .../components/comments_discussion.html | 8 +- .../templates/discussion_detail.html | 10 ++ 7 files changed, 136 insertions(+), 111 deletions(-) create mode 100644 packages/ui-default/components/discussion/reaction.page.styl create mode 100644 packages/ui-default/components/discussion/reaction.page.tsx diff --git a/packages/ui-default/components/discussion/comments.page.styl b/packages/ui-default/components/discussion/comments.page.styl index 8688b7d9..cbabc90a 100644 --- a/packages/ui-default/components/discussion/comments.page.styl +++ b/packages/ui-default/components/discussion/comments.page.styl @@ -27,31 +27,6 @@ $downvote-color = red &:first-child border-top: 0 - - .reactions - .reaction - white-space: nowrap - width: auto - border-radius: 1.75rem - overflow: visible - font-size: rem($font-size-small) - display: inline-block - line-height: rem(22px) - padding: rem(0 10px) - vertical-align: middle - border-radius: rem(12px) - border: 1px solid $supplementary-border-color - cursor: pointer - &.active, &:hover - text-decoration: none - border-color: $primary-color - color: #FFF !important - &.active - background-color: lighten($primary-color, 10%) !important - &:hover - background-color: lighten($primary-color, 30%) !important - .emoji - margin-right: rem(5px) .dczcomments__reply >.media diff --git a/packages/ui-default/components/discussion/comments.page.tsx b/packages/ui-default/components/discussion/comments.page.tsx index 2ca04b4a..6917cd2e 100644 --- a/packages/ui-default/components/discussion/comments.page.tsx +++ b/packages/ui-default/components/discussion/comments.page.tsx @@ -1,8 +1,5 @@ import 'jquery.easing'; -import * as React from 'react'; -import ReactDOM from 'react-dom/client'; -import { Popover } from '@blueprintjs/core'; import { AutoloadPage } from 'vj/misc/Page'; import CommentBox from 'vj/components/discussion/CommentBox'; import { ConfirmDialog } from 'vj/components/dialog'; @@ -12,7 +9,6 @@ import { slideDown, slideUp } from 'vj/utils/slide'; import request from 'vj/utils/request'; import i18n from 'vj/utils/i18n'; import tpl from 'vj/utils/tpl'; -import { chunk } from 'lodash'; const $replyTemplate = $('.commentbox-container').eq(0).clone(); @@ -189,62 +185,6 @@ function onCommentClickDeleteReply(ev) { onCommentClickDelete('reply', ev); } -function renderReactions(reactions, self, rootEle) { - let html = ''; - for (const key in reactions) { - if (!reactions[key]) continue; - html += `
${key} ${reactions[key]}
\n`; - } - rootEle.html(html); -} - -async function handleEmojiClick(payload, emoji, ele) { - const res = await request.post('', { ...payload, emoji }); - renderReactions(res.doc?.react, res.sdoc?.react, ele); -} - -function getRow(count) { - if (count <= 2) return 2; - if (count <= 3) return 3; - if (count <= 4) return 4; - if (count <= 6) return 6; - return 12; -} - -function Reaction({ payload, ele }) { - const emojiList: string[] = (UiContext.emojiList || '👍 👎 😄 😕 ❤️ 🤔 🤣 🌿 🍋 🕊️ 👀 🤣').split(' '); - const elesPerRow = getRow(Math.sqrt(emojiList.length)); - const [focus, updateFocus] = React.useState(false); - const [finish, updateFinish] = React.useState(false); - if (finish) setTimeout(() => updateFinish(false), 1000); - return ( - // eslint-disable-next-line no-nested-ternary - - -
- {chunk(emojiList, elesPerRow).map((line, i) => ( -
- {line.map((emoji) => ( -
handleEmojiClick(payload, emoji, ele).then(() => updateFinish(true))} - > - {emoji} -
- ))} -
- ))} -
-
- updateFocus(true)} onBlur={() => updateFocus(false)}> -
-
-
-
- ); -} - const commentsPage = new AutoloadPage('commentsPage', () => { $(document).on('click', '[name="dczcomments__dummy-box"]', onClickDummyBox); $(document).on('click', '[data-op="reply"][data-type="comment"]', onCommentClickReplyComment); @@ -253,26 +193,6 @@ const commentsPage = new AutoloadPage('commentsPage', () => { $(document).on('click', '[data-op="edit"][data-type="reply"]', onCommentClickEditReply); $(document).on('click', '[data-op="delete"][data-type="comment"]', onCommentClickDeleteComment); $(document).on('click', '[data-op="delete"][data-type="reply"]', onCommentClickDeleteReply); - - const canUseReaction = $('[data-op="react"]').length > 0; - $('[data-op="react"]').each((i, e) => { - ReactDOM.createRoot(e).render(); - }); - $(document).on('click', '.reaction', async (e) => { - if (!canUseReaction) { - (window as any).showSignInDialog(); - return; - } - const target = $(e.currentTarget); - const res = await request.post('', { - operation: 'reaction', - type: 'drid', - id: target.parent().parent().data('drid'), - emoji: target.text().trim().split(' ')[0], - reverse: target.hasClass('active'), - }); - renderReactions(res.doc?.react, res.sdoc?.react, target.parent()); - }); }); export default commentsPage; diff --git a/packages/ui-default/components/discussion/reaction.page.styl b/packages/ui-default/components/discussion/reaction.page.styl new file mode 100644 index 00000000..8b102565 --- /dev/null +++ b/packages/ui-default/components/discussion/reaction.page.styl @@ -0,0 +1,30 @@ +.reactions + display: inline + + .reaction + white-space: nowrap + width: auto + border-radius: 1.75rem + overflow: visible + font-size: rem($font-size-small) + display: inline-block + line-height: rem(22px) + padding: rem(0 10px) + vertical-align: middle + border-radius: rem(12px) + border: 1px solid $supplementary-border-color + cursor: pointer + &.active, &:hover + text-decoration: none + border-color: $primary-color + color: #FFF !important + &.active + background-color: lighten($primary-color, 10%) !important + &:hover + background-color: lighten($primary-color, 30%) !important + .emoji + margin-right: rem(5px) + +.popover-reaction-item + &:hover + background-color: $toolbar-bg-hover \ No newline at end of file diff --git a/packages/ui-default/components/discussion/reaction.page.tsx b/packages/ui-default/components/discussion/reaction.page.tsx new file mode 100644 index 00000000..b2bf6ab8 --- /dev/null +++ b/packages/ui-default/components/discussion/reaction.page.tsx @@ -0,0 +1,92 @@ +import 'jquery.easing'; + +import * as React from 'react'; +import ReactDOM from 'react-dom/client'; +import { Popover } from '@blueprintjs/core'; +import { AutoloadPage } from 'vj/misc/Page'; + +import request from 'vj/utils/request'; +import { chunk } from 'lodash'; + +function renderReactions(reactions, self, rootEle) { + let html = ''; + for (const key in reactions) { + if (!reactions[key]) continue; + html += `
${key} ${reactions[key]}
\n`; + } + rootEle.html(html); +} + +async function handleEmojiClick(payload, emoji, ele) { + const res = await request.post('', { ...payload, emoji }); + if (!res.sdoc) return; + renderReactions(res.doc?.react, res.sdoc.react, ele); +} + +function getRow(count) { + if (count <= 2) return 2; + if (count <= 3) return 3; + if (count <= 4) return 4; + if (count <= 6) return 6; + return 12; +} + +function Reaction({ payload, ele }) { + const emojiList: string[] = (UiContext.emojiList || '👍 👎 😄 😕 ❤️ 🤔 🤣 🌿 🍋 🕊️ 👀 🤣').split(' '); + const elesPerRow = getRow(Math.sqrt(emojiList.length)); + const [focus, updateFocus] = React.useState(false); + const [finish, updateFinish] = React.useState(false); + if (finish) setTimeout(() => updateFinish(false), 1000); + return ( + // eslint-disable-next-line no-nested-ternary + + +
+ {chunk(emojiList, elesPerRow).map((line, i) => ( +
+ {line.map((emoji) => ( +
handleEmojiClick(payload, emoji, ele).then(() => updateFinish(true))} + > + {emoji} +
+ ))} +
+ ))} +
+
+ updateFocus(true)} onBlur={() => updateFocus(false)}> +
+
+
+
+ ); +} + +const reactionPage = new AutoloadPage('reactionPage', () => { + const canUseReaction = $('[data-op="react"]').length > 0; + $('[data-op="react"]').each((i, e) => { + ReactDOM.createRoot(e).render( + , + ); + }); + $(document).on('click', '.reaction', async (e) => { + if (!canUseReaction) { + (window as any).showSignInDialog(); + return; + } + const target = $(e.currentTarget); + const res = await request.post('', { + operation: 'reaction', + type: target.parent().data('type'), + id: target.parent().data(target.parent().data('type')), + emoji: target.text().trim().split(' ')[0], + reverse: target.hasClass('active'), + }); + renderReactions(res.doc?.react, res.sdoc?.react, target.parent()); + }); +}); + +export default reactionPage; diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 1ee96012..1cdb93a7 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.37.13", + "version": "4.37.14", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", diff --git a/packages/ui-default/templates/components/comments_discussion.html b/packages/ui-default/templates/components/comments_discussion.html index 3f928c24..5957e644 100644 --- a/packages/ui-default/templates/components/comments_discussion.html +++ b/packages/ui-default/templates/components/comments_discussion.html @@ -112,11 +112,9 @@
{{ doc['content']|markdown|safe }} -
- {% for key in Object.keys(doc.react or {}) %} - {% if doc.react[key] %} -
{{ key }} {{ doc.react[key] }}
- {% endif %} +
+ {% for e in Object.entries(doc.react or {})|sort(true, false, 1)|selectattr(1) %} +
{{ e[0] }} {{ e[1] }}
{% endfor %}
diff --git a/packages/ui-default/templates/discussion_detail.html b/packages/ui-default/templates/discussion_detail.html index 8185ab2c..ec3fc31e 100644 --- a/packages/ui-default/templates/discussion_detail.html +++ b/packages/ui-default/templates/discussion_detail.html @@ -59,6 +59,16 @@
  • {{ _('Report') }}
  • + {% if handler.user.hasPerm(perm.PERM_ADD_REACTION) %} +
  • + +
  • + {% endif %} +
    + {% for e in Object.entries(ddoc.react or {})|sort(true, false, 1)|selectattr(1) %} +
    {{ e[0] }} {{ e[1] }}
    + {% endfor %} +