gitalk-react 1.0.0-beta.6 → 1.0.0-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh-CN.md +13 -0
- package/README.md +13 -0
- package/dist/gitalk-dark.css +1 -1
- package/dist/gitalk-light.css +1 -1
- package/dist/gitalk.d.ts +5 -1
- package/dist/gitalk.js +3403 -3291
- package/dist/gitalk.umd.cjs +25 -25
- package/lib/components/comment-textarea.tsx +164 -0
- package/lib/components/comment.tsx +38 -6
- package/lib/components/comments-list.tsx +106 -0
- package/lib/components/meta.tsx +129 -0
- package/lib/constants/index.ts +9 -1
- package/lib/contexts/I18nContext.ts +4 -2
- package/lib/gitalk.tsx +152 -533
- package/lib/interfaces/index.ts +166 -0
- package/lib/services/graphql/comment.ts +1 -2
- package/lib/themes/base.scss +42 -4
- package/lib/themes/gitalk-dark.scss +4 -0
- package/lib/themes/gitalk-light.scss +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { useRequest } from "ahooks";
|
|
2
|
+
import type { Octokit } from "octokit";
|
|
3
|
+
import React, { forwardRef, useContext, useRef, useState } from "react";
|
|
4
|
+
|
|
5
|
+
import Github from "../assets/github.svg?raw";
|
|
6
|
+
import Tip from "../assets/tip.svg?raw";
|
|
7
|
+
import I18nContext from "../contexts/I18nContext";
|
|
8
|
+
import type { User } from "../interfaces";
|
|
9
|
+
import Avatar from "./avatar";
|
|
10
|
+
import Button from "./button";
|
|
11
|
+
import Svg from "./svg";
|
|
12
|
+
|
|
13
|
+
interface CommentTextareaProps
|
|
14
|
+
extends React.DetailedHTMLProps<
|
|
15
|
+
React.TextareaHTMLAttributes<HTMLTextAreaElement>,
|
|
16
|
+
HTMLTextAreaElement
|
|
17
|
+
> {
|
|
18
|
+
value: string;
|
|
19
|
+
octokit: Octokit;
|
|
20
|
+
user?: User;
|
|
21
|
+
onLogin: () => void;
|
|
22
|
+
onCreateComment: (comment: string) => Promise<void>;
|
|
23
|
+
createCommentLoading: boolean;
|
|
24
|
+
onPreviewError: (error: unknown) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const CommentTextarea = forwardRef<HTMLTextAreaElement, CommentTextareaProps>(
|
|
28
|
+
(props, ref) => {
|
|
29
|
+
const {
|
|
30
|
+
value: inputComment,
|
|
31
|
+
octokit,
|
|
32
|
+
user,
|
|
33
|
+
onLogin,
|
|
34
|
+
onCreateComment,
|
|
35
|
+
createCommentLoading,
|
|
36
|
+
onPreviewError,
|
|
37
|
+
...restProps
|
|
38
|
+
} = props;
|
|
39
|
+
|
|
40
|
+
const { polyglot } = useContext(I18nContext);
|
|
41
|
+
|
|
42
|
+
const [isPreviewComment, setIsPreviewComment] = useState<boolean>(false);
|
|
43
|
+
|
|
44
|
+
const prevInputCommentRef = useRef<string>();
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
data: commentHtml = "",
|
|
48
|
+
loading: getCommentHtmlLoading,
|
|
49
|
+
run: runGetCommentHtml,
|
|
50
|
+
} = useRequest(
|
|
51
|
+
async (): Promise<string> => {
|
|
52
|
+
if (prevInputCommentRef.current === inputComment) return commentHtml;
|
|
53
|
+
|
|
54
|
+
const getPreviewedHtmlRes = await octokit.request("POST /markdown", {
|
|
55
|
+
text: inputComment,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (getPreviewedHtmlRes.status === 200) {
|
|
59
|
+
prevInputCommentRef.current = inputComment;
|
|
60
|
+
|
|
61
|
+
const _commentHtml = getPreviewedHtmlRes.data;
|
|
62
|
+
return _commentHtml;
|
|
63
|
+
} else {
|
|
64
|
+
onPreviewError(getPreviewedHtmlRes);
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
manual: true,
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const onCommentInputPreview: React.MouseEventHandler<
|
|
74
|
+
HTMLButtonElement
|
|
75
|
+
> = () => {
|
|
76
|
+
if (isPreviewComment) {
|
|
77
|
+
setIsPreviewComment(false);
|
|
78
|
+
} else {
|
|
79
|
+
setIsPreviewComment(true);
|
|
80
|
+
runGetCommentHtml();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className="gt-header" key="header">
|
|
86
|
+
{user ? (
|
|
87
|
+
<Avatar
|
|
88
|
+
className="gt-header-avatar"
|
|
89
|
+
src={user.avatar_url}
|
|
90
|
+
alt={user.login}
|
|
91
|
+
href={user.html_url}
|
|
92
|
+
/>
|
|
93
|
+
) : (
|
|
94
|
+
<a className="gt-avatar-github" onClick={onLogin}>
|
|
95
|
+
<Svg className="gt-ico-github" icon={Github} />
|
|
96
|
+
</a>
|
|
97
|
+
)}
|
|
98
|
+
<div className="gt-header-comment">
|
|
99
|
+
<textarea
|
|
100
|
+
{...restProps}
|
|
101
|
+
ref={ref}
|
|
102
|
+
value={inputComment}
|
|
103
|
+
className="gt-header-textarea"
|
|
104
|
+
style={{ display: isPreviewComment ? "none" : undefined }}
|
|
105
|
+
/>
|
|
106
|
+
<div
|
|
107
|
+
className="gt-header-preview markdown-body"
|
|
108
|
+
style={{ display: isPreviewComment ? undefined : "none" }}
|
|
109
|
+
dangerouslySetInnerHTML={{
|
|
110
|
+
__html: getCommentHtmlLoading
|
|
111
|
+
? "<span>Loading preview...</span>"
|
|
112
|
+
: commentHtml,
|
|
113
|
+
}}
|
|
114
|
+
/>
|
|
115
|
+
<div className="gt-header-controls">
|
|
116
|
+
<a
|
|
117
|
+
className="gt-header-controls-tip"
|
|
118
|
+
href="https://guides.github.com/features/mastering-markdown/"
|
|
119
|
+
target="_blank"
|
|
120
|
+
rel="noopener noreferrer"
|
|
121
|
+
>
|
|
122
|
+
<Svg
|
|
123
|
+
className="gt-ico-tip"
|
|
124
|
+
icon={Tip}
|
|
125
|
+
text={polyglot.t("support-markdown")}
|
|
126
|
+
/>
|
|
127
|
+
</a>
|
|
128
|
+
|
|
129
|
+
<Button
|
|
130
|
+
className="gt-btn-preview gt-btn--secondary"
|
|
131
|
+
onClick={onCommentInputPreview}
|
|
132
|
+
text={
|
|
133
|
+
isPreviewComment ? polyglot.t("edit") : polyglot.t("preview")
|
|
134
|
+
}
|
|
135
|
+
isLoading={getCommentHtmlLoading}
|
|
136
|
+
disabled={false}
|
|
137
|
+
/>
|
|
138
|
+
|
|
139
|
+
{user ? (
|
|
140
|
+
<Button
|
|
141
|
+
className="gt-btn-public"
|
|
142
|
+
onClick={async () => {
|
|
143
|
+
await onCreateComment(inputComment);
|
|
144
|
+
setIsPreviewComment(false);
|
|
145
|
+
}}
|
|
146
|
+
text={polyglot.t("comment")}
|
|
147
|
+
isLoading={createCommentLoading}
|
|
148
|
+
disabled={createCommentLoading || !inputComment}
|
|
149
|
+
/>
|
|
150
|
+
) : (
|
|
151
|
+
<Button
|
|
152
|
+
className="gt-btn-login"
|
|
153
|
+
onClick={onLogin}
|
|
154
|
+
text={polyglot.t("login-with-github")}
|
|
155
|
+
/>
|
|
156
|
+
)}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
export default CommentTextarea;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { formatDistanceToNow, parseISO } from "date-fns";
|
|
2
|
-
import React, { useContext, useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import React, { useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
|
|
4
|
+
import ArrowDown from "../assets/arrow-down.svg?raw";
|
|
4
5
|
import Edit from "../assets/edit.svg?raw";
|
|
5
6
|
import Heart from "../assets/heart.svg?raw";
|
|
6
7
|
import HeartFilled from "../assets/heart-filled.svg?raw";
|
|
7
8
|
import Reply from "../assets/reply.svg?raw";
|
|
8
9
|
import I18nContext from "../contexts/I18nContext";
|
|
9
|
-
import type { Comment as CommentType } from "../interfaces";
|
|
10
|
+
import type { Comment as CommentType, GitalkProps } from "../interfaces";
|
|
10
11
|
import Avatar from "./avatar";
|
|
11
12
|
import Svg from "./svg";
|
|
12
13
|
|
|
@@ -21,6 +22,7 @@ export interface CommentProps
|
|
|
21
22
|
onReply: (comment: CommentType) => void;
|
|
22
23
|
onLike: (like: boolean, comment: CommentType) => void;
|
|
23
24
|
likeLoading: boolean;
|
|
25
|
+
collapsedHeight?: GitalkProps["collapsedHeight"];
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
const Comment: React.FC<CommentProps> = ({
|
|
@@ -30,11 +32,14 @@ const Comment: React.FC<CommentProps> = ({
|
|
|
30
32
|
onReply,
|
|
31
33
|
onLike,
|
|
32
34
|
likeLoading,
|
|
35
|
+
collapsedHeight,
|
|
33
36
|
className = "",
|
|
34
37
|
...restProps
|
|
35
38
|
}) => {
|
|
36
39
|
const ref = useRef<HTMLDivElement>(null);
|
|
37
40
|
|
|
41
|
+
const [collapsed, setCollapsed] = useState<boolean>(false);
|
|
42
|
+
|
|
38
43
|
const { language, polyglot, dateFnsLocaleMap } = useContext(I18nContext);
|
|
39
44
|
|
|
40
45
|
const { body_html, created_at, user, reactionsHeart, html_url } = comment;
|
|
@@ -72,6 +77,17 @@ const Comment: React.FC<CommentProps> = ({
|
|
|
72
77
|
return () => {};
|
|
73
78
|
}, []);
|
|
74
79
|
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
const commentElement = ref.current;
|
|
82
|
+
|
|
83
|
+
if (commentElement && collapsedHeight) {
|
|
84
|
+
const commentElementHeight = commentElement.clientHeight;
|
|
85
|
+
if (commentElementHeight > collapsedHeight) {
|
|
86
|
+
setCollapsed(true);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}, [collapsedHeight]);
|
|
90
|
+
|
|
75
91
|
return (
|
|
76
92
|
<div
|
|
77
93
|
ref={ref}
|
|
@@ -85,7 +101,12 @@ const Comment: React.FC<CommentProps> = ({
|
|
|
85
101
|
href={user?.html_url}
|
|
86
102
|
/>
|
|
87
103
|
|
|
88
|
-
<div
|
|
104
|
+
<div
|
|
105
|
+
className="gt-comment-content"
|
|
106
|
+
style={
|
|
107
|
+
collapsed ? { maxHeight: collapsedHeight, overflow: "hidden" } : {}
|
|
108
|
+
}
|
|
109
|
+
>
|
|
89
110
|
<div className="gt-comment-header">
|
|
90
111
|
<a
|
|
91
112
|
className="gt-comment-username"
|
|
@@ -96,12 +117,15 @@ const Comment: React.FC<CommentProps> = ({
|
|
|
96
117
|
{user?.login}
|
|
97
118
|
</a>
|
|
98
119
|
<div className="gt-comment-date" title={created_at}>
|
|
99
|
-
|
|
100
|
-
"
|
|
101
|
-
|
|
120
|
+
<span className="gt-comment-date__prefix">
|
|
121
|
+
{polyglot.t("commented")}
|
|
122
|
+
</span>
|
|
123
|
+
<span className="gt-comment-date__time">
|
|
124
|
+
{formatDistanceToNow(parseISO(created_at), {
|
|
102
125
|
addSuffix: true,
|
|
103
126
|
locale: dateFnsLocaleMap[language],
|
|
104
127
|
})}
|
|
128
|
+
</span>
|
|
105
129
|
</div>
|
|
106
130
|
<div className="gt-comment-actions">
|
|
107
131
|
<a
|
|
@@ -145,6 +169,14 @@ const Comment: React.FC<CommentProps> = ({
|
|
|
145
169
|
__html: body_html ?? "",
|
|
146
170
|
}}
|
|
147
171
|
/>
|
|
172
|
+
{collapsed && (
|
|
173
|
+
<div
|
|
174
|
+
className="gt-comment-collapse"
|
|
175
|
+
onClick={() => setCollapsed(false)}
|
|
176
|
+
>
|
|
177
|
+
<Svg className="gt-ico-collapse" icon={ArrowDown} />
|
|
178
|
+
</div>
|
|
179
|
+
)}
|
|
148
180
|
</div>
|
|
149
181
|
</div>
|
|
150
182
|
);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, { forwardRef, useContext } from "react";
|
|
2
|
+
import FlipMove from "react-flip-move";
|
|
3
|
+
|
|
4
|
+
import I18nContext from "../contexts/I18nContext";
|
|
5
|
+
import type { Comment as CommentType, GitalkProps, User } from "../interfaces";
|
|
6
|
+
import Button from "./button";
|
|
7
|
+
import Comment, { type CommentProps } from "./comment";
|
|
8
|
+
|
|
9
|
+
interface CommentWithForwardedRefProps
|
|
10
|
+
extends Pick<
|
|
11
|
+
CommentProps,
|
|
12
|
+
"comment" | "onReply" | "likeLoading" | "collapsedHeight"
|
|
13
|
+
> {
|
|
14
|
+
onLike: (like: boolean, commentId: number, heartReactionId?: number) => void;
|
|
15
|
+
user?: User;
|
|
16
|
+
admin: GitalkProps["admin"];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Why forwardRef? https://www.npmjs.com/package/react-flip-move#usage-with-functional-components
|
|
20
|
+
const CommentWithForwardedRef = forwardRef<
|
|
21
|
+
HTMLDivElement,
|
|
22
|
+
CommentWithForwardedRefProps
|
|
23
|
+
>(({ comment, user, admin, onLike, ...restProps }, ref) => {
|
|
24
|
+
const {
|
|
25
|
+
id: commentId,
|
|
26
|
+
user: commentAuthor,
|
|
27
|
+
reactionsHeart: commentReactionsHeart,
|
|
28
|
+
} = comment;
|
|
29
|
+
|
|
30
|
+
const commentAuthorName = commentAuthor?.login;
|
|
31
|
+
const isAuthor =
|
|
32
|
+
!!user && !!commentAuthorName && user.login === commentAuthorName;
|
|
33
|
+
const isAdmin =
|
|
34
|
+
!!commentAuthorName &&
|
|
35
|
+
!!admin.find(
|
|
36
|
+
(username) => username.toLowerCase() === commentAuthorName.toLowerCase(),
|
|
37
|
+
);
|
|
38
|
+
const heartReactionId = commentReactionsHeart?.nodes.find(
|
|
39
|
+
(node) => node.user.login === user?.login,
|
|
40
|
+
)?.databaseId;
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div ref={ref}>
|
|
44
|
+
<Comment
|
|
45
|
+
{...restProps}
|
|
46
|
+
comment={comment}
|
|
47
|
+
isAuthor={isAuthor}
|
|
48
|
+
isAdmin={isAdmin}
|
|
49
|
+
onLike={(like) => {
|
|
50
|
+
onLike(like, commentId, heartReactionId);
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
interface CommentsListProps
|
|
58
|
+
extends Pick<GitalkProps, "flipMoveOptions">,
|
|
59
|
+
Omit<CommentWithForwardedRefProps, "comment"> {
|
|
60
|
+
comments: CommentType[];
|
|
61
|
+
commentsCount: number;
|
|
62
|
+
onGetComments: () => void;
|
|
63
|
+
getCommentsLoading: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const CommentsList: React.FC<CommentsListProps> = (props) => {
|
|
67
|
+
const {
|
|
68
|
+
comments,
|
|
69
|
+
commentsCount,
|
|
70
|
+
onGetComments,
|
|
71
|
+
getCommentsLoading,
|
|
72
|
+
flipMoveOptions,
|
|
73
|
+
...restCommentProps
|
|
74
|
+
} = props;
|
|
75
|
+
|
|
76
|
+
const { polyglot } = useContext(I18nContext);
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div className="gt-comments" key="comments">
|
|
80
|
+
<FlipMove {...flipMoveOptions}>
|
|
81
|
+
{comments.map((comment) => (
|
|
82
|
+
<CommentWithForwardedRef
|
|
83
|
+
{...restCommentProps}
|
|
84
|
+
key={comment.id}
|
|
85
|
+
comment={comment}
|
|
86
|
+
/>
|
|
87
|
+
))}
|
|
88
|
+
</FlipMove>
|
|
89
|
+
{!commentsCount && (
|
|
90
|
+
<p className="gt-comments-null">{polyglot.t("first-comment-person")}</p>
|
|
91
|
+
)}
|
|
92
|
+
{commentsCount > comments.length ? (
|
|
93
|
+
<div className="gt-comments-controls">
|
|
94
|
+
<Button
|
|
95
|
+
className="gt-btn-loadmore"
|
|
96
|
+
onClick={onGetComments}
|
|
97
|
+
isLoading={getCommentsLoading}
|
|
98
|
+
text={polyglot.t("load-more")}
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
) : null}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export default CommentsList;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import React, { useCallback, useContext, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import ArrowDown from "../assets/arrow-down.svg?raw";
|
|
4
|
+
import { HOMEPAGE, VERSION } from "../constants";
|
|
5
|
+
import I18nContext from "../contexts/I18nContext";
|
|
6
|
+
import type { GitalkProps, Issue, User } from "../interfaces";
|
|
7
|
+
import { hasClassInParent } from "../utils/dom";
|
|
8
|
+
import Action from "./action";
|
|
9
|
+
import Svg from "./svg";
|
|
10
|
+
|
|
11
|
+
interface MetaProps {
|
|
12
|
+
issue?: Issue;
|
|
13
|
+
user?: User;
|
|
14
|
+
commentsCount: number;
|
|
15
|
+
pagerDirection: GitalkProps["pagerDirection"];
|
|
16
|
+
onPagerDirectionChange: (
|
|
17
|
+
direction: NonNullable<GitalkProps["pagerDirection"]>,
|
|
18
|
+
) => void;
|
|
19
|
+
onLogin: () => void;
|
|
20
|
+
onLogout: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const Meta: React.FC<MetaProps> = (props) => {
|
|
24
|
+
const {
|
|
25
|
+
issue,
|
|
26
|
+
user,
|
|
27
|
+
commentsCount,
|
|
28
|
+
pagerDirection,
|
|
29
|
+
onPagerDirectionChange,
|
|
30
|
+
onLogin,
|
|
31
|
+
onLogout,
|
|
32
|
+
} = props;
|
|
33
|
+
|
|
34
|
+
const { polyglot } = useContext(I18nContext);
|
|
35
|
+
|
|
36
|
+
const [showPopup, setShowPopup] = useState<boolean>(false);
|
|
37
|
+
|
|
38
|
+
const hidePopup = useCallback((e: MouseEvent) => {
|
|
39
|
+
const target = e.target as HTMLElement;
|
|
40
|
+
if (target && hasClassInParent(target, "gt-user", "gt-popup")) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
document.removeEventListener("click", hidePopup);
|
|
44
|
+
setShowPopup(false);
|
|
45
|
+
}, []);
|
|
46
|
+
|
|
47
|
+
const onShowOrHidePopup: React.MouseEventHandler<HTMLDivElement> = (e) => {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
|
|
51
|
+
setShowPopup((visible) => {
|
|
52
|
+
if (visible) {
|
|
53
|
+
document.removeEventListener("click", hidePopup);
|
|
54
|
+
} else {
|
|
55
|
+
document.addEventListener("click", hidePopup);
|
|
56
|
+
}
|
|
57
|
+
return !visible;
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div className="gt-meta" key="meta">
|
|
63
|
+
<span
|
|
64
|
+
className="gt-counts"
|
|
65
|
+
dangerouslySetInnerHTML={{
|
|
66
|
+
__html: polyglot.t("counts", {
|
|
67
|
+
counts: `<a class="gt-link gt-link-counts" href="${issue?.html_url}" target="_blank" rel="noopener noreferrer">${commentsCount}</a>`,
|
|
68
|
+
smart_count: commentsCount,
|
|
69
|
+
}),
|
|
70
|
+
}}
|
|
71
|
+
/>
|
|
72
|
+
{showPopup && (
|
|
73
|
+
<div className="gt-popup">
|
|
74
|
+
{user
|
|
75
|
+
? [
|
|
76
|
+
<Action
|
|
77
|
+
key="sort-asc"
|
|
78
|
+
className={`gt-action-sortasc${pagerDirection === "first" ? " is--active" : ""}`}
|
|
79
|
+
onClick={() => onPagerDirectionChange("first")}
|
|
80
|
+
text={polyglot.t("sort-asc")}
|
|
81
|
+
/>,
|
|
82
|
+
<Action
|
|
83
|
+
key="sort-desc"
|
|
84
|
+
className={`gt-action-sortdesc${pagerDirection === "last" ? " is--active" : ""}`}
|
|
85
|
+
onClick={() => onPagerDirectionChange("last")}
|
|
86
|
+
text={polyglot.t("sort-desc")}
|
|
87
|
+
/>,
|
|
88
|
+
]
|
|
89
|
+
: null}
|
|
90
|
+
{user ? (
|
|
91
|
+
<Action
|
|
92
|
+
className="gt-action-logout"
|
|
93
|
+
onClick={onLogout}
|
|
94
|
+
text={polyglot.t("logout")}
|
|
95
|
+
/>
|
|
96
|
+
) : (
|
|
97
|
+
<a className="gt-action gt-action-login" onClick={onLogin}>
|
|
98
|
+
{polyglot.t("login-with-github")}
|
|
99
|
+
</a>
|
|
100
|
+
)}
|
|
101
|
+
<div className="gt-copyright">
|
|
102
|
+
<a
|
|
103
|
+
className="gt-link gt-link-project"
|
|
104
|
+
href={HOMEPAGE}
|
|
105
|
+
target="_blank"
|
|
106
|
+
rel="noopener noreferrer"
|
|
107
|
+
>
|
|
108
|
+
GitalkR
|
|
109
|
+
</a>
|
|
110
|
+
<span className="gt-version">{VERSION}</span>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
)}
|
|
114
|
+
<div className="gt-user">
|
|
115
|
+
<div
|
|
116
|
+
className={`gt-user-inner${showPopup ? " is--poping" : ""}`}
|
|
117
|
+
onClick={onShowOrHidePopup}
|
|
118
|
+
>
|
|
119
|
+
<span className="gt-user-name">
|
|
120
|
+
{user?.login ?? polyglot.t("anonymous")}
|
|
121
|
+
</span>
|
|
122
|
+
<Svg className="gt-ico-arrdown" icon={ArrowDown} />
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export default Meta;
|
package/lib/constants/index.ts
CHANGED
|
@@ -14,14 +14,22 @@ import {
|
|
|
14
14
|
} from "date-fns/locale";
|
|
15
15
|
|
|
16
16
|
import packageJson from "../../package.json";
|
|
17
|
-
import { type GitalkProps } from "../gitalk";
|
|
18
17
|
import { type Lang } from "../i18n";
|
|
18
|
+
import type { GitalkProps } from "../interfaces";
|
|
19
19
|
|
|
20
20
|
export const VERSION = packageJson.version;
|
|
21
21
|
export const HOMEPAGE = packageJson.homepage;
|
|
22
22
|
|
|
23
23
|
export const DEFAULT_LANG: Lang = "en";
|
|
24
24
|
export const DEFAULT_LABELS = ["Gitalk"];
|
|
25
|
+
export const DEFAULT_FLIP_MOVE_OPTIONS: GitalkProps["flipMoveOptions"] = {
|
|
26
|
+
staggerDelayBy: 150,
|
|
27
|
+
appearAnimation: "accordionVertical",
|
|
28
|
+
enterAnimation: "accordionVertical",
|
|
29
|
+
leaveAnimation: "accordionVertical",
|
|
30
|
+
};
|
|
31
|
+
export const DEFAULT_PROXY =
|
|
32
|
+
"https://cors-anywhere.azm.workers.dev/https://github.com/login/oauth/access_token";
|
|
25
33
|
export const DEFAULT_AVATAR =
|
|
26
34
|
"https://cdn.jsdelivr.net/npm/gitalk@1/src/assets/icon/github.svg";
|
|
27
35
|
export const DEFAULT_USER: GitalkProps["defaultUser"] = {
|
|
@@ -5,11 +5,13 @@ import { createContext } from "react";
|
|
|
5
5
|
import { DATE_FNS_LOCALE_MAP, DEFAULT_LANG } from "../constants";
|
|
6
6
|
import i18n, { type Lang } from "../i18n";
|
|
7
7
|
|
|
8
|
-
export
|
|
8
|
+
export interface I18nContextValue {
|
|
9
9
|
language: Lang;
|
|
10
10
|
polyglot: Polyglot;
|
|
11
11
|
dateFnsLocaleMap: Record<string, Locale>;
|
|
12
|
-
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const I18nContext = createContext<I18nContextValue>({
|
|
13
15
|
language: DEFAULT_LANG,
|
|
14
16
|
polyglot: i18n(DEFAULT_LANG),
|
|
15
17
|
dateFnsLocaleMap: DATE_FNS_LOCALE_MAP,
|