diff --git a/packages/ui-default/components/discussion/comments.page.styl b/packages/ui-default/components/discussion/comments.page.styl
index 8688b7d99..cbabc90ab 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 2ca04b4a0..6917cd2e6 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 000000000..8b1025658
--- /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 000000000..b2bf6ab86
--- /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 1ee960128..1cdb93a76 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 3f928c24e..5957e6448 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 8185ab2cd..ec3fc31e1 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 %}
+