From 39655225592027b7f4a279527292e044d29322a8 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Tue, 2 Apr 2024 18:10:46 +0800 Subject: [PATCH 1/4] chore: change version to release 2.1.0 (#110) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改组件核心包的版本号,准备发布 2.1.0 版本。 > 在此之前,发布插件版本的时候并没有发布组件包,从这个版本开始,将同步推送到 npmjs。 ```release-note None ``` --- packages/comment-widget/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/comment-widget/package.json b/packages/comment-widget/package.json index 70fa85d..30befc9 100644 --- a/packages/comment-widget/package.json +++ b/packages/comment-widget/package.json @@ -1,6 +1,6 @@ { "name": "@halo-dev/comment-widget", - "version": "1.3.0", + "version": "2.1.0", "author": { "name": "Halo", "url": "https://github.com/halo-dev" From ccae3d23588b29fbae4349af21d951dea1417476 Mon Sep 17 00:00:00 2001 From: mashirot Date: Tue, 9 Apr 2024 10:30:08 +0800 Subject: [PATCH 2/4] feat: use gravatar source as comment's avatar (#111) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 后端改动:https://github.com/halo-dev/halo/pull/5642 Fixes https://github.com/halo-dev/plugin-comment-widget/issues/97 Fixes https://github.com/halo-dev/plugin-comment-widget/issues/77 两个不同邮箱,相同头像 效果: ![image](https://github.com/halo-dev/plugin-comment-widget/assets/52254895/3b61eaec-4cca-4425-8735-827d3f06ba72) ```release-note 评论头像支持使用 Gravatar 源 ``` --- .../src/avatar/avatar-policy.ts | 85 +++++++++++++++++++ .../src/avatar/providers/avatar-provider.ts | 23 +++++ .../src/avatar/providers/gravatar.ts | 9 ++ .../src/avatar/providers/index.ts | 24 ++++++ packages/comment-widget/src/comment-item.ts | 11 ++- packages/comment-widget/src/comment-widget.ts | 60 ++++++++++++- packages/comment-widget/src/context/index.ts | 4 + packages/comment-widget/src/reply-item.ts | 11 ++- packages/widget/src/index.ts | 8 ++ .../comment/widget/CommentWidgetPlugin.java | 3 +- .../comment/widget/DefaultCommentWidget.java | 26 +++++- src/main/resources/extensions/settings.yaml | 35 ++++++++ 12 files changed, 291 insertions(+), 8 deletions(-) create mode 100644 packages/comment-widget/src/avatar/avatar-policy.ts create mode 100644 packages/comment-widget/src/avatar/providers/avatar-provider.ts create mode 100644 packages/comment-widget/src/avatar/providers/gravatar.ts create mode 100644 packages/comment-widget/src/avatar/providers/index.ts diff --git a/packages/comment-widget/src/avatar/avatar-policy.ts b/packages/comment-widget/src/avatar/avatar-policy.ts new file mode 100644 index 0000000..1cc4b56 --- /dev/null +++ b/packages/comment-widget/src/avatar/avatar-policy.ts @@ -0,0 +1,85 @@ +import { CommentVo, ReplyVo } from '@halo-dev/api-client'; +import { getAvatarProvider } from './providers'; + +abstract class AvatarPolicy { + abstract applyCommentPolicy(comment: CommentVo | undefined): string | undefined; + abstract applyReplyPolicy(reply: ReplyVo | undefined): string | undefined; +} + +let policyInstance: AvatarPolicy | undefined; +const emailKind = 'Email'; +const emailHash = 'email-hash'; + +class AnonymousUserPolicy extends AvatarPolicy { + applyCommentPolicy(comment: CommentVo | undefined): string | undefined { + const avatarProvider = getAvatarProvider(); + const isAnonymous = comment?.owner.kind === emailKind; + if (isAnonymous) { + return avatarProvider?.getAvatarSrc(comment?.spec.owner.annotations?.[emailHash]); + } + return comment?.owner.avatar; + } + applyReplyPolicy(reply: ReplyVo | undefined): string | undefined { + const avatarProvider = getAvatarProvider(); + const isAnonymous = reply?.owner.kind === emailKind; + if (isAnonymous) { + return avatarProvider?.getAvatarSrc(reply?.spec.owner.annotations?.[emailHash]); + } + return reply?.owner.avatar; + } +} + +class AllUserPolicy extends AvatarPolicy { + applyCommentPolicy(comment: CommentVo | undefined): string | undefined { + const avatarProvider = getAvatarProvider(); + return avatarProvider?.getAvatarSrc(comment?.spec.owner.annotations?.[emailHash]); + } + applyReplyPolicy(reply: ReplyVo | undefined): string | undefined { + const avatarProvider = getAvatarProvider(); + return avatarProvider?.getAvatarSrc(reply?.spec.owner.annotations?.[emailHash]); + } +} + +class NoAvatarUserPolicy extends AvatarPolicy { + applyCommentPolicy(comment: CommentVo | undefined): string | undefined { + const avatarProvider = getAvatarProvider(); + const isAnonymous = comment?.owner.kind === emailKind; + const avatar = comment?.owner.avatar; + if (isAnonymous || !avatar) { + return avatarProvider?.getAvatarSrc(comment?.spec.owner.annotations?.[emailHash]); + } + return avatar; + } + applyReplyPolicy(reply: ReplyVo | undefined): string | undefined { + const avatarProvider = getAvatarProvider(); + const isAnonymous = reply?.owner.kind === emailKind; + const avatar = reply?.owner.avatar; + if (isAnonymous || !avatar) { + return avatarProvider?.getAvatarSrc(reply?.spec.owner.annotations?.[emailHash]); + } + return avatar; + } +} + +enum AvatarPolicyEnum { + ANONYMOUS_USER_POLICY = 'anonymousUser', + ALL_USER_POLICY = 'allUser', + NO_AVATAR_USER_POLICY = 'noAvatarUser', +} + +function setPolicyInstance(nPolicyInstance: AvatarPolicy | undefined) { + policyInstance = nPolicyInstance; +} + +function getPolicyInstance(): AvatarPolicy | undefined { + return policyInstance; +} + +export { + AnonymousUserPolicy, + AllUserPolicy, + NoAvatarUserPolicy, + AvatarPolicyEnum, + setPolicyInstance, + getPolicyInstance, +}; diff --git a/packages/comment-widget/src/avatar/providers/avatar-provider.ts b/packages/comment-widget/src/avatar/providers/avatar-provider.ts new file mode 100644 index 0000000..6b38042 --- /dev/null +++ b/packages/comment-widget/src/avatar/providers/avatar-provider.ts @@ -0,0 +1,23 @@ +export default abstract class AvatarProvider { + private readonly _name: string; + private _url: string; + + constructor(name: string, url: string) { + this._name = name; + this._url = url; + } + + get url(): string { + return this._url; + } + + set url(value: string) { + this._url = value; + } + + get name(): string { + return this._name; + } + + abstract getAvatarSrc(emailHash: string | undefined): string; +} diff --git a/packages/comment-widget/src/avatar/providers/gravatar.ts b/packages/comment-widget/src/avatar/providers/gravatar.ts new file mode 100644 index 0000000..08da722 --- /dev/null +++ b/packages/comment-widget/src/avatar/providers/gravatar.ts @@ -0,0 +1,9 @@ +import AvatarProvider from './avatar-provider'; + +class Gravatar extends AvatarProvider { + override getAvatarSrc(emailHash: string | undefined): string { + return `${this.url}/avatar/${emailHash}`; + } +} + +export default new Gravatar('Gravatar', 'https://gravatar.com'); diff --git a/packages/comment-widget/src/avatar/providers/index.ts b/packages/comment-widget/src/avatar/providers/index.ts new file mode 100644 index 0000000..7723a1c --- /dev/null +++ b/packages/comment-widget/src/avatar/providers/index.ts @@ -0,0 +1,24 @@ +import Gravatar from './gravatar'; +import AvatarProvider from './avatar-provider'; + +let avatarProvider: AvatarProvider | undefined; + +enum AvatarProviderEnum { + GRAVATAR = 'gravatar', +} + +export function setAvatarProvider(provider: string, mirrorUrl?: string) { + switch (provider) { + case AvatarProviderEnum.GRAVATAR: + if (mirrorUrl) { + Gravatar.url = mirrorUrl; + } + avatarProvider = Gravatar; + break; + default: + } +} + +export function getAvatarProvider() { + return avatarProvider; +} diff --git a/packages/comment-widget/src/comment-item.ts b/packages/comment-widget/src/comment-item.ts index 5404505..25edca7 100644 --- a/packages/comment-widget/src/comment-item.ts +++ b/packages/comment-widget/src/comment-item.ts @@ -12,6 +12,7 @@ import { LS_UPVOTED_COMMENTS_KEY } from './constant'; import varStyles from './styles/var'; import { Ref, createRef, ref } from 'lit/directives/ref.js'; import { CommentReplies } from './comment-replies'; +import { getPolicyInstance } from './avatar/avatar-policy'; export class CommentItem extends LitElement { @consume({ context: baseUrlContext }) @@ -103,7 +104,7 @@ export class CommentItem extends LitElement { override render() { return html`(Symbol('name')); export const versionContext = createContext(Symbol('version')); export const replySizeContext = createContext(Symbol('replySize')); export const withRepliesContext = createContext(Symbol('withReplies')); +export const useAvatarProviderContext = createContext(Symbol('useAvatarProvider')); +export const avatarProviderContext = createContext(Symbol('avatarProvider')); +export const avatarProviderMirrorContext = createContext(Symbol('avatarProviderMirror')); +export const avatarPolicyContext = createContext(Symbol('avatarPolicy')); export const allowAnonymousCommentsContext = createContext( Symbol('allowAnonymousComments') diff --git a/packages/comment-widget/src/reply-item.ts b/packages/comment-widget/src/reply-item.ts index ef93c56..dd1b639 100644 --- a/packages/comment-widget/src/reply-item.ts +++ b/packages/comment-widget/src/reply-item.ts @@ -10,6 +10,7 @@ import { LS_UPVOTED_REPLIES_KEY } from './constant'; import { consume } from '@lit/context'; import { baseUrlContext } from './context'; import varStyles from './styles/var'; +import { getPolicyInstance } from './avatar/avatar-policy'; export class ReplyItem extends LitElement { @consume({ context: baseUrlContext }) @@ -106,7 +107,7 @@ export class ReplyItem extends LitElement { override render() { return html` { entries.forEach((entry) => { diff --git a/src/main/java/run/halo/comment/widget/CommentWidgetPlugin.java b/src/main/java/run/halo/comment/widget/CommentWidgetPlugin.java index de7b759..b83d35e 100644 --- a/src/main/java/run/halo/comment/widget/CommentWidgetPlugin.java +++ b/src/main/java/run/halo/comment/widget/CommentWidgetPlugin.java @@ -2,7 +2,6 @@ import org.pf4j.PluginWrapper; import org.springframework.stereotype.Component; -import run.halo.app.extension.SchemeManager; import run.halo.app.plugin.BasePlugin; /** @@ -11,10 +10,10 @@ */ @Component public class CommentWidgetPlugin extends BasePlugin { - public CommentWidgetPlugin(PluginWrapper wrapper) { super(wrapper); } + @Override public void start() { } diff --git a/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java b/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java index 04501e7..9dd7948 100644 --- a/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java +++ b/src/main/java/run/halo/comment/widget/DefaultCommentWidget.java @@ -66,12 +66,19 @@ private String commentHtml(IAttribute groupAttribute, IAttribute kindAttribute, var basicConfig = settingFetcher.fetch(BasicConfig.GROUP, BasicConfig.class) .orElse(new BasicConfig()); - // placeholderHelper only support string, so we need to convert boolean to string properties.setProperty("size", String.valueOf(basicConfig.getSize())); properties.setProperty("replySize", String.valueOf(basicConfig.getReplySize())); properties.setProperty("withReplies", String.valueOf(basicConfig.isWithReplies())); properties.setProperty("withReplySize", String.valueOf(basicConfig.getWithReplySize())); + var avatarConfig = settingFetcher.fetch(AvatarConfig.GROUP, AvatarConfig.class) + .orElse(new AvatarConfig()); + properties.setProperty("useAvatarProvider", String.valueOf(avatarConfig.isEnable())); + properties.setProperty("avatarProvider", String.valueOf(avatarConfig.getProvider())); + properties.setProperty("avatarProviderMirror", String.valueOf(avatarConfig.getProviderMirror())); + properties.setProperty("avatarPolicy", String.valueOf(avatarConfig.getPolicy())); + + // placeholderHelper only support string, so we need to convert boolean to string return PROPERTY_PLACEHOLDER_HELPER.replacePlaceholders("""
@@ -92,7 +103,7 @@ private String commentHtml(IAttribute groupAttribute, IAttribute kindAttribute, } @Data - static class BasicConfig { + private static class BasicConfig { public static final String GROUP = "basic"; private int size; private int replySize; @@ -100,6 +111,15 @@ static class BasicConfig { private int withReplySize; } + @Data + private static class AvatarConfig { + public static final String GROUP = "avatar"; + private boolean enable; + private String provider; + private String providerMirror; + private String policy; + } + private String domIdFrom(String group, String kind, String name) { Assert.notNull(name, "The name must not be null."); Assert.notNull(kind, "The kind must not be null."); diff --git a/src/main/resources/extensions/settings.yaml b/src/main/resources/extensions/settings.yaml index aa4be7a..dd02b5e 100644 --- a/src/main/resources/extensions/settings.yaml +++ b/src/main/resources/extensions/settings.yaml @@ -31,3 +31,38 @@ spec: key: withReplySize validation: required value: 5 + - group: avatar + label: 头像设置 + formSchema: + - $formkit: checkbox + label: 是否启用第三方头像 + name: enable + id: enable + key: enable + value: false + - $formkit: select + label: 头像服务提供者 + if: "$get(enable).value === true" + name: provider + options: + - label: 'Gravatar' + value: 'gravatar' + value: "gravatar" + - $formkit: text + label: 头像服务镜像地址 + if: "$get(enable).value === true" + name: providerMirror + value: "" + help: 使用官方源则留空, 示例:https://gravatar.com + - $formkit: select + label: 头像策略 + if: "$get(enable).value === true" + name: policy + options: + - label: '仅匿名用户' + value: 'anonymousUser' + - label: '所有用户' + value: 'allUser' + - label: '匿名&无头像用户' + value: 'noAvatarUser' + value: "anonymousUser" From 9ef312271ada542ac7186c2b8dcc076e011440f5 Mon Sep 17 00:00:00 2001 From: Anye <53684988+Anyexyz@users.noreply.github.com> Date: Tue, 16 Apr 2024 12:34:09 +0800 Subject: [PATCH 3/4] feat: add aria-label attribute for emoji picker button (#113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为标签按钮添加了aria-label字段,增强无障碍 ```release-note 为标签按钮添加了aria-label字段,增强无障碍 ``` --- packages/comment-widget/src/emoji-button.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/comment-widget/src/emoji-button.ts b/packages/comment-widget/src/emoji-button.ts index 104ea0e..19303cd 100644 --- a/packages/comment-widget/src/emoji-button.ts +++ b/packages/comment-widget/src/emoji-button.ts @@ -83,7 +83,7 @@ export class EmojiButton extends LitElement { } override render() { - return html`