@ziteh/yangchun-comment-client 0.1.0 → 0.2.0-alpha.1

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.
Files changed (50) hide show
  1. package/README.md +6 -0
  2. package/dist/src/api/apiService.d.ts +22 -0
  3. package/dist/src/api/globalApiService.d.ts +10 -0
  4. package/dist/src/components/comment-admin.d.ts +25 -0
  5. package/dist/src/components/comment-dialog.d.ts +18 -0
  6. package/dist/src/components/comment-info.d.ts +14 -0
  7. package/dist/src/components/comment-input.d.ts +31 -0
  8. package/dist/src/components/list/comment-list-item.d.ts +19 -0
  9. package/dist/src/components/list/comment-list.d.ts +9 -0
  10. package/dist/src/components/yangchun-comment.d.ts +58 -0
  11. package/dist/src/components/yangchun-comment.styles.d.ts +2 -0
  12. package/dist/src/index.d.ts +1 -0
  13. package/dist/src/utils/comment.d.ts +6 -0
  14. package/dist/src/utils/format.d.ts +2 -0
  15. package/dist/src/utils/i18n.d.ts +46 -0
  16. package/dist/src/utils/pow.d.ts +9 -0
  17. package/dist/{utils → src/utils}/pseudonym.d.ts +0 -1
  18. package/dist/src/utils/sanitize.d.ts +1 -0
  19. package/dist/test/sanitize.test.d.ts +1 -0
  20. package/dist/yangchun-comment.js +962 -0
  21. package/dist/yangchun-comment.js.map +1 -0
  22. package/dist/yangchun-comment.umd.cjs +962 -0
  23. package/dist/yangchun-comment.umd.cjs.map +1 -0
  24. package/package.json +17 -13
  25. package/dist/element.d.ts +0 -97
  26. package/dist/element.js +0 -680
  27. package/dist/index.d.ts +0 -9
  28. package/dist/index.js +0 -23
  29. package/dist/types.d.ts +0 -3
  30. package/dist/utils/apiService.d.ts +0 -15
  31. package/dist/utils/apiService.js +0 -118
  32. package/dist/utils/format.d.ts +0 -1
  33. package/dist/utils/format.js +0 -14
  34. package/dist/utils/i18n.d.ts +0 -51
  35. package/dist/utils/i18n.js +0 -98
  36. package/dist/utils/pseudonym.js +0 -34
  37. package/dist/utils/sanitize.d.ts +0 -4
  38. package/dist/utils/sanitize.js +0 -59
  39. package/dist/utils/wordBank.js +0 -692
  40. package/dist/views/comments.d.ts +0 -3
  41. package/dist/views/comments.js +0 -119
  42. package/dist/views/preview.d.ts +0 -3
  43. package/dist/views/preview.js +0 -53
  44. package/dist/yangchun-comment.css +0 -1
  45. package/dist/yangchun-comment.es.js +0 -317
  46. package/dist/yangchun-comment.es.js.map +0 -1
  47. package/dist/yangchun-comment.umd.js +0 -317
  48. package/dist/yangchun-comment.umd.js.map +0 -1
  49. /package/dist/{types.js → src/utils/pow.worker.d.ts} +0 -0
  50. /package/dist/{utils → src/utils}/wordBank.d.ts +0 -0
@@ -1,119 +0,0 @@
1
- import { html } from 'lit';
2
- function getCommentCssClasses(isRoot) {
3
- const prefix = isRoot ? 'comment' : 'reply';
4
- return {
5
- item: prefix,
6
- header: `${prefix}-header ycc-flex ycc-flex-wrap`,
7
- name: `${prefix}-name`,
8
- time: `${prefix}-time`,
9
- content: `${prefix}-content`,
10
- };
11
- }
12
- function createCommentHeader(ctx, comment, css, replyToName, canEdit) {
13
- const isMy = ctx.isMyComment(comment);
14
- const isAdmin = comment.isAdmin;
15
- return html ` <div class="${css.header}">
16
- <span class="${css.name}" title="${comment.id}">
17
- ${ctx.getDisplayName(comment)}
18
- ${isAdmin
19
- ? html `<span class="author-badge">${ctx.i18n$.t('author')}</span>`
20
- : isMy
21
- ? html `<span class="my-comment-badge">Me</span>`
22
- : ''}
23
- </span>
24
- <span
25
- class="${css.time}"
26
- title="${comment.modDate ? ctx.formatDate(comment.pubDate) : undefined}"
27
- >
28
- ${comment.modDate
29
- ? ctx.i18n$.t('modified') + ' ' + ctx.formatDate(comment.modDate)
30
- : ctx.formatDate(comment.pubDate)}
31
- </span>
32
- ${replyToName
33
- ? html `<span class="reply-to"
34
- >${ctx.i18n$.t('replyTo')}<span title="${comment.replyTo ?? ''}"
35
- >${replyToName}</span
36
- ></span
37
- >`
38
- : ''}
39
- ${canEdit
40
- ? html `<span class="comment-controls ycc-flex ycc-gap-xs">
41
- <button
42
- class="edit-button ycc-clickable ycc-transition ycc-transparent-bg ycc-reset-button"
43
- @click=${() => ctx.handleEdit(comment)}
44
- >
45
- ${ctx.i18n$.t('edit')}
46
- </button>
47
- <button
48
- class="delete-button ycc-clickable ycc-transition ycc-transparent-bg ycc-reset-button"
49
- @click=${() => ctx.handleDelete(comment.id)}
50
- >
51
- ${ctx.i18n$.t('delete')}
52
- </button>
53
- </span>`
54
- : ''}
55
- </div>`;
56
- }
57
- function createCommentContent(ctx, comment, contentClass) {
58
- return html `<div class="${contentClass}">${ctx.renderMarkdown(comment.msg)}</div>`;
59
- }
60
- function createCommentActions(ctx, comment) {
61
- return html `<button
62
- class="reply-button ycc-clickable ycc-transition ycc-transparent-bg ycc-reset-button"
63
- @click=${() => ctx.setReplyTo(comment.id)}
64
- >
65
- ${ctx.i18n$.t('reply')}
66
- </button>`;
67
- }
68
- function createCommentItemTemplate(ctx, comment, isRoot = false, replyToName = null, allReplies = null, commentMap = null) {
69
- const css = getCommentCssClasses(isRoot);
70
- const canEdit = ctx.canEditComment(comment.id);
71
- return html ` <div class="${css.item}" ${isRoot ? `data-id="${comment.id}"` : ''}>
72
- ${createCommentHeader(ctx, comment, css, replyToName, canEdit)}
73
- ${createCommentContent(ctx, comment, css.content)} ${createCommentActions(ctx, comment)}
74
- ${isRoot
75
- ? html `<div class="replies">
76
- ${allReplies
77
- ? allReplies.map((reply) => {
78
- const replyToComment = reply.replyTo && commentMap ? commentMap[reply.replyTo] : undefined;
79
- const replyToName = replyToComment ? ctx.getDisplayName(replyToComment) : '';
80
- return createCommentItemTemplate(ctx, reply, false, replyToName);
81
- })
82
- : ''}
83
- </div>`
84
- : ''}
85
- </div>`;
86
- }
87
- function processComments(ctx, data, commentMap) {
88
- const roots = data.filter((c) => !c.replyTo);
89
- const replyMap = {};
90
- data.forEach((c) => {
91
- if (c.replyTo) {
92
- (replyMap[c.replyTo] ||= []).push(c);
93
- }
94
- });
95
- const getAll = (id) => {
96
- const all = [];
97
- const q = [...(replyMap[id] || [])];
98
- while (q.length) {
99
- const r = q.shift();
100
- if (!r)
101
- break;
102
- all.push(r);
103
- const children = replyMap[r.id] || [];
104
- if (children.length)
105
- q.push(...children);
106
- }
107
- return all;
108
- };
109
- return roots.map((root) => createCommentItemTemplate(ctx, root, true, null, getAll(root.id), commentMap));
110
- }
111
- export function createCommentsTemplate(ctx) {
112
- const comments = ctx.comments$;
113
- if (comments.length === 0) {
114
- return html `<div id="comments">
115
- <div class="no-comments-message">${ctx.i18n$.t('noComments')}</div>
116
- </div>`;
117
- }
118
- return html `<div id="comments">${processComments(ctx, comments, ctx.commentMap$)}</div>`;
119
- }
@@ -1,3 +0,0 @@
1
- import { type TemplateResult } from 'lit';
2
- import type { YangchunCommentElement } from '../element';
3
- export declare function createPreviewTemplate(ctx: YangchunCommentElement): TemplateResult;
@@ -1,53 +0,0 @@
1
- import { html } from 'lit';
2
- import { formatDate } from '../utils/format';
3
- export function createPreviewTemplate(ctx) {
4
- const now = Date.now();
5
- const userName = ctx.previewPseudonym$ ?? '';
6
- return html ` <div class="comment-box preview-mode">
7
- <div id="preview">
8
- ${ctx.previewText$
9
- ? html ` <div class="preview-comment">
10
- <div class="comment-header">
11
- <span class="comment-name">${userName || ctx.i18n$.t('anonymous')}</span>
12
- <span class="comment-time">${formatDate(now)}</span>
13
- ${ctx.currentReplyTo$ && ctx.commentMap$[ctx.currentReplyTo$]
14
- ? html `<span class="reply-to"
15
- >${ctx.i18n$.t('replyTo')}<span
16
- >${ctx.getDisplayName(ctx.commentMap$[ctx.currentReplyTo$])}</span
17
- ></span
18
- >`
19
- : ''}
20
- </div>
21
- <div class="comment-content">${ctx.renderMarkdown(ctx.previewText$)}</div>
22
- </div>`
23
- : html `<div class="empty-preview">${ctx.i18n$.t('emptyPreview')}</div>`}
24
- </div>
25
- <div class="comment-footer ycc-flex ycc-gap-xs">
26
- <span style="flex: 1;"></span>
27
- <div class="ycc-flex ycc-gap-xs">
28
- <button
29
- type="button"
30
- class="help-btn ycc-clickable ycc-reset-button"
31
- title="${ctx.i18n$.t('markdownHelp')}"
32
- @click=${() => ctx.toggleMarkdownHelp()}
33
- >
34
- ?
35
- </button>
36
- <button
37
- type="button"
38
- class="preview-btn ycc-clickable ycc-transition ycc-transparent-bg active ycc-reset-button"
39
- @click=${() => ctx.switchTab('write')}
40
- >
41
- ${ctx.i18n$.t('write')}
42
- </button>
43
- <button
44
- type="button"
45
- class="submit-btn ycc-clickable ycc-transition ycc-reset-button"
46
- @click=${() => ctx.handlePreviewSubmit()}
47
- >
48
- ${ctx.editingComment$ ? ctx.i18n$.t('updateComment') : ctx.i18n$.t('submitComment')}
49
- </button>
50
- </div>
51
- </div>
52
- </div>`;
53
- }
@@ -1 +0,0 @@
1
- :root{--ycc-text-color: #333;--ycc-background-color: #fff;--ycc-primary-color: #3b82f6;--ycc-font-family: inherit;--ycc-base-font-size: 14px;--ycc-border-radius: 6px;--ycc-small-border-radius: 4px;--ycc-tiny-border-radius: 2px;--ycc-spacing: 16px;--ycc-small-font-size: .8em;--ycc-transition: all .2s ease;--ycc-reply-indent: 12px;--ycc-hover-opacity: .8;--ycc-light: color-mix(in srgb, var(--ycc-text-color) 60%, var(--ycc-background-color));--ycc-lighter: color-mix(in srgb, var(--ycc-text-color) 40%, var(--ycc-background-color));--ycc-subtle: color-mix(in srgb, var(--ycc-text-color) 20%, var(--ycc-background-color));--ycc-minimal: color-mix(in srgb, var(--ycc-text-color) 5%, var(--ycc-background-color));--ycc-primary-soft: color-mix(in srgb, var(--ycc-primary-color) 90%, var(--ycc-background-color));--ycc-overlay: color-mix(in srgb, var(--ycc-text-color) 50%, transparent)}body.ycc-modal-open{overflow:hidden}.ycc-flex{display:flex}.ycc-flex-center{display:flex;align-items:center}.ycc-flex-wrap{flex-wrap:wrap}.ycc-transparent-bg{background-color:transparent}.ycc-clickable{cursor:pointer}.ycc-transition{transition:var(--ycc-transition)}.ycc-reset-button{border:none;padding:0;margin:0;background:none;font-family:var(--ycc-font-family)}.ycc-reset-form{margin:0;padding:0;border:none;box-shadow:none}.ycc-gap-xs{gap:.5rem}.ycc-gap-sm{gap:.75rem}.ycc-gap-md{gap:1rem}.ycc-container{font-family:var(--ycc-font-family);color:var(--ycc-text-color);font-size:var(--ycc-base-font-size)}.comment-box{border:1px solid var(--ycc-subtle);border-radius:var(--ycc-border-radius);overflow:hidden;background-color:var(--ycc-background-color)}.comment-input{padding:1rem 1rem .25rem}.comment-input textarea{width:100%;border:none;resize:none;font-size:16px;min-height:120px;outline:none;font-family:var(--ycc-font-family);color:var(--ycc-text-color);background-color:var(--ycc-background-color);box-sizing:border-box}.comment-input textarea::placeholder{color:var(--ycc-lighter);opacity:1}.char-count{font-size:12px;color:var(--ycc-light);text-align:right;margin-top:4px}.char-count .over-limit{color:#dc3545;font-weight:700}.name-input-container{flex:1;position:relative}.comment-footer{align-items:center;border-top:1px solid var(--ycc-subtle);padding:.5rem 1rem;background-color:var(--ycc-background-color);position:relative}.comment-footer input[type=text]{width:100%;border:none;font-size:14px;outline:none;font-family:var(--ycc-font-family);color:var(--ycc-text-color);background-color:var(--ycc-background-color);border-radius:var(--ycc-tiny-border-radius)}.comment-footer input[type=text]::placeholder{color:var(--ycc-lighter);opacity:1}.comment-footer button{padding:.3rem .8rem;margin-left:.4rem;font-size:14px;border-radius:var(--ycc-small-border-radius);font-family:var(--ycc-font-family)}.help-btn{font-size:16px;color:var(--ycc-lighter);background:none!important;padding:.2rem .5rem!important}.help-btn:hover,.preview-btn{color:var(--ycc-primary-color)}.preview-btn:hover{background-color:var(--ycc-primary-color);color:var(--ycc-background-color)}.submit-btn{background-color:var(--ycc-primary-color);color:var(--ycc-background-color);border:1px solid var(--ycc-primary-color)}.submit-btn:hover{opacity:var(--ycc-hover-opacity)}.info{max-width:600px;margin:.5rem 0;font-size:13px;color:var(--ycc-lighter);align-items:flex-start}.preview-mode{border:1px solid var(--ycc-subtle);border-radius:var(--ycc-border-radius);background-color:var(--ycc-background-color)}#preview{padding:1rem}.empty-preview{color:var(--ycc-lighter);font-style:italic;padding:2rem 0;text-align:center}#comment-form{box-sizing:border-box;width:100%;background:none}#comments{margin-top:var(--ycc-spacing)}.no-comments-message{text-align:center;color:var(--ycc-lighter);font-style:italic;padding:2rem 1rem;margin:1rem 0}.comment{margin-bottom:12px;padding:4px}.comment-header,.reply-header{margin-bottom:8px;align-items:center;flex-wrap:wrap}.comment-name,.reply-name{font-weight:700}.my-comment-badge{background-color:var(--ycc-light);color:var(--ycc-background-color);border-radius:var(--ycc-small-border-radius);padding:2px 3px;margin-left:2px;font-size:.8em}.author-badge{background-color:var(--ycc-primary-color);color:var(--ycc-background-color);border-radius:var(--ycc-small-border-radius);padding:2px 3px;margin-left:2px;font-size:.8em;font-weight:700}.comment-time,.reply-time,.reply-to{font-size:var(--ycc-small-font-size);color:var(--ycc-light);margin-left:8px}.reply-to{color:var(--ycc-lighter);opacity:0;transition:var(--ycc-transition)}.reply:hover .reply-to{opacity:1}.comment-content,.reply-content,.preview-comment{margin-bottom:6px;line-height:1.5;word-break:break-word}.preview-comment{margin:0;padding:0;border:none;box-shadow:none}.comment-content a,.reply-content a,.preview-comment a{color:var(--ycc-primary-color);text-decoration:none;border-bottom:1px solid var(--ycc-primary-color);padding-bottom:1px}.comment-content img,.reply-content img,.preview-comment img{max-width:75%}.comment-content ul,.reply-content ul,.preview-comment ul{padding-left:20px;margin:8px 0;list-style-type:disc}.comment-content ol,.reply-content ol,.preview-comment ol{padding-left:20px;margin:8px 0;list-style-type:decimal}.comment-content li,.reply-content li,.preview-comment li{margin-bottom:4px}.reply-button,.cancel-link,.edit-button,.delete-button{font-family:var(--ycc-font-family)}.reply-button{color:var(--ycc-text-color);background-color:transparent;font-size:12px;padding:0;text-decoration:underline;text-underline-offset:4px}.cancel-link{color:var(--ycc-primary-color);background-color:transparent;font-size:13px;padding:0}.reply-button:hover,.cancel-link:hover{opacity:var(--ycc-hover-opacity)}.edit-button,.delete-button{color:var(--ycc-light);border-radius:calc(var(--ycc-border-radius) / 2);font-size:calc(var(--ycc-base-font-size) - 2px);padding:2px 6px}.edit-button:hover,.delete-button:hover{background-color:var(--ycc-minimal)}.replies{margin-top:4px}.reply{margin-left:var(--ycc-reply-indent);border-left:4px solid var(--ycc-minimal);padding-left:15px;padding-top:15px}.comment-controls{margin-left:auto}#markdown-help-modal{display:none}#markdown-help-modal.active{display:block;position:fixed;z-index:1000;inset:0}.markdown-help-container{width:100%;height:100%;align-items:center;justify-content:center;position:relative}.markdown-help-backdrop{position:absolute;inset:0;background-color:var(--ycc-overlay)}.markdown-help-content{position:relative;background-color:var(--ycc-background-color);color:var(--ycc-text-color);border-radius:var(--ycc-small-border-radius);padding:1.5rem;max-width:500px;width:90%;max-height:90vh;overflow-y:auto;box-shadow:0 2px 8px var(--ycc-light);z-index:1010}.markdown-help-close{position:absolute;top:10px;right:10px;font-size:1.5rem;color:var(--ycc-light)}.markdown-help-button{align-items:center;justify-content:center;width:26px;height:26px;color:var(--ycc-light);background:none;font-weight:700;margin-right:10px;line-height:1;font-size:var(--ycc-base-font-size)}.markdown-examples{padding:10px 15px;border-radius:var(--ycc-border-radius);background-color:var(--ycc-minimal);overflow-x:auto;margin-bottom:1em}.markdown-help-content a{color:var(--ycc-primary-color);text-decoration:none}.markdown-help-content h4{margin-top:1.5em;margin-bottom:.75em;font-size:1.1rem;color:var(--ycc-primary-color)}.markdown-help-content h4:first-child{margin-top:0}.markdown-help-content p{margin-bottom:1em;font-size:.9rem;line-height:1.5}.markdown-help-content code{font-family:monospace;font-size:.9em}.markdown-help-content pre{margin:0;white-space:pre-wrap;line-height:1.6}.honeypot-field{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important;pointer-events:none!important;opacity:0!important}.comment-box-container{display:flex;flex-direction:column}.form-content{flex:1}.admin-btn-wrapper{display:flex;justify-content:flex-end;padding-right:8px}.admin-btn{font-size:16px;color:var(--ycc-lighter);padding:4px 6px;border-radius:var(--ycc-small-border-radius);opacity:0;transition:var(--ycc-transition)}.comment-box-container:hover .admin-btn{opacity:1}.admin-btn:hover{color:var(--ycc-primary-color);background-color:var(--ycc-subtle)!important}.admin-modal-backdrop{position:fixed;inset:0;background-color:var(--ycc-overlay);display:flex;justify-content:center;align-items:center;z-index:1000}.admin-modal-content{background-color:var(--ycc-background-color);border:1px solid var(--ycc-subtle);border-radius:var(--ycc-border-radius);padding:2rem;max-width:400px;width:90%;position:relative;box-shadow:0 4px 12px #00000026}.admin-modal-close{position:absolute;top:8px;right:12px;font-size:24px;color:var(--ycc-light);background:none!important;padding:0!important;border:none!important;line-height:1}.admin-modal-close:hover{color:var(--ycc-text-color)}.admin-modal-content h3{margin:0 0 1rem;color:var(--ycc-text-color);font-family:var(--ycc-font-family);font-size:1.2em}.admin-form-group{margin-bottom:1rem}.admin-form-group label{display:block;margin-bottom:.5rem;color:var(--ycc-text-color);font-family:var(--ycc-font-family);font-size:var(--ycc-base-font-size)}.admin-form-group input{width:100%;padding:.5rem;border:1px solid var(--ycc-subtle);border-radius:var(--ycc-small-border-radius);font-family:var(--ycc-font-family);font-size:var(--ycc-base-font-size);background-color:var(--ycc-background-color);color:var(--ycc-text-color);box-sizing:border-box}.admin-form-group input:focus{outline:none;border-color:var(--ycc-primary-color)}.admin-login-btn{width:100%;padding:.75rem;background-color:var(--ycc-primary-color);color:var(--ycc-background-color);border:none;border-radius:var(--ycc-small-border-radius);font-family:var(--ycc-font-family);font-size:var(--ycc-base-font-size);font-weight:500;transition:var(--ycc-transition)}.admin-login-btn:hover{opacity:var(--ycc-hover-opacity)}@media (max-width: 576px){.ycc-container,.info{margin:0;max-width:100%}.comment-box{border-radius:var(--ycc-border-radius);margin:0 .5rem;border:1px solid var(--ycc-subtle)}.comment-input{padding:.75rem}.comment-input textarea{min-height:100px;font-size:16px}.comment-footer{flex-direction:column;align-items:stretch;padding:.75rem}.comment-footer input[type=text]{width:100%;min-width:unset;flex:none;margin-bottom:0;padding:.5rem;border:1px solid var(--ycc-subtle);border-radius:var(--ycc-small-border-radius);box-sizing:border-box}.name-input-container{margin-bottom:.75rem}.comment-footer .ycc-flex{justify-content:space-between;align-items:center;width:100%}.help-btn,.preview-btn,.submit-btn{font-size:13px;padding:.4rem .8rem}.comment,.reply{padding:8px}.reply{margin-left:8px;padding-left:10px}.comment-header,.reply-header{flex-direction:column;align-items:flex-start}.comment-time,.reply-time,.reply-to{margin-left:0;margin-top:4px}.reply:hover .reply-to{opacity:1}.comment-controls{margin-left:0;margin-top:8px}.info{flex-direction:column;align-items:flex-start;margin:.5rem 0;padding:0 1rem}.preview-mode .comment-footer{flex-direction:row;justify-content:space-between;align-items:center;padding:.75rem}}