@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
package/dist/element.js DELETED
@@ -1,680 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import snarkdown from 'snarkdown';
8
- import { LitElement, html, nothing } from 'lit';
9
- import { property, state } from 'lit/decorators.js';
10
- import { unsafeHTML } from 'lit/directives/unsafe-html.js';
11
- import { createApiService } from './utils/apiService';
12
- import { createI18n, en, zhHant } from './utils/i18n';
13
- import { generatePseudonymAndHash } from './utils/pseudonym';
14
- import { sanitizeHtml, setupDOMPurifyHooks } from './utils/sanitize';
15
- import { formatDate } from './utils/format';
16
- import { createPreviewTemplate } from './views/preview';
17
- import { createCommentsTemplate as renderCommentsView } from './views/comments';
18
- import './index.css';
19
- export class YangchunCommentElement extends LitElement {
20
- constructor() {
21
- super(...arguments);
22
- this.post = '/blog/my-post';
23
- this.apiUrl = 'http://localhost:8787/';
24
- this.authorName = undefined;
25
- this.language = 'en';
26
- this.apiService = createApiService(this.apiUrl);
27
- this.i18n = createI18n(en);
28
- this.commentMap = {};
29
- this.comments = [];
30
- this.currentReplyTo = null;
31
- this.previewText = '';
32
- this.previewName = '';
33
- this.previewPseudonym = '';
34
- this.editingComment = null;
35
- this.activeTab = 'write';
36
- this.showMarkdownHelp = false;
37
- this.showAdminLogin = false;
38
- }
39
- static { this.MAX_NAME_LENGTH = 25; }
40
- static { this.MAX_MESSAGE_LENGTH = 1000; }
41
- static { this.MY_NAME_HASHES_KEY = 'ycc_my_name_hashes'; }
42
- createRenderRoot() {
43
- return this;
44
- }
45
- connectedCallback() {
46
- super.connectedCallback();
47
- this.syncI18n();
48
- this.apiService = createApiService(this.apiUrl);
49
- setupDOMPurifyHooks();
50
- this.reloadComments();
51
- }
52
- disconnectedCallback() {
53
- document.body.classList.remove('ycc-modal-open');
54
- super.disconnectedCallback();
55
- }
56
- updated(changed) {
57
- if (changed.has('apiUrl'))
58
- this.apiService = createApiService(this.apiUrl);
59
- if (changed.has('language'))
60
- this.syncI18n();
61
- if (changed.has('post'))
62
- this.reloadComments();
63
- }
64
- syncI18n() {
65
- let languageStrings = en;
66
- const lang = this.language;
67
- if (typeof lang === 'string')
68
- languageStrings = lang === 'zh-Hant' ? zhHant : en;
69
- else if (lang && typeof lang === 'object')
70
- languageStrings = lang;
71
- this.i18n = createI18n(languageStrings);
72
- }
73
- renderMarkdown(md) {
74
- return unsafeHTML(sanitizeHtml(snarkdown(md || '')));
75
- }
76
- getDisplayName(comment) {
77
- if (comment?.isAdmin && this.authorName)
78
- return this.authorName;
79
- const cleaned = comment?.pseudonym ?? '';
80
- return cleaned.trim() ? cleaned : this.i18n.t('anonymous');
81
- }
82
- canEditComment(commentId) {
83
- return this.apiService.canEditComment(commentId);
84
- }
85
- saveMyNameHash(nameHash) {
86
- try {
87
- const arr = this.getMyNameHashes();
88
- if (nameHash && !arr.includes(nameHash)) {
89
- arr.push(nameHash);
90
- localStorage.setItem(YangchunCommentElement.MY_NAME_HASHES_KEY, JSON.stringify(arr));
91
- }
92
- }
93
- catch (e) {
94
- console.warn('Failed to save name hash:', e);
95
- }
96
- }
97
- getMyNameHashes() {
98
- try {
99
- const stored = localStorage.getItem(YangchunCommentElement.MY_NAME_HASHES_KEY);
100
- return stored ? JSON.parse(stored) : [];
101
- }
102
- catch (e) {
103
- console.warn('Failed to get name hashes:', e);
104
- return [];
105
- }
106
- }
107
- isMyComment(comment) {
108
- if (!comment.nameHash)
109
- return false;
110
- return this.getMyNameHashes().includes(comment.nameHash);
111
- }
112
- async loadComments() {
113
- return await this.apiService.getComments(this.post);
114
- }
115
- async reloadComments() {
116
- this.comments = await this.loadComments();
117
- this.buildCommentMap();
118
- }
119
- // moved preview template to views/preview.ts
120
- switchTab(tab) {
121
- this.activeTab = tab;
122
- if (tab === 'preview')
123
- this.saveCurrentFormInputs();
124
- }
125
- saveCurrentFormInputs() {
126
- const nameInput = document.querySelector('#comment-form input[name="name"]');
127
- if (nameInput)
128
- this.previewName = nameInput.value;
129
- }
130
- async renderCommentsList() {
131
- if (this.comments.length === 0)
132
- await this.reloadComments();
133
- }
134
- buildCommentMap() {
135
- this.commentMap = {};
136
- this.comments.forEach((c) => {
137
- this.commentMap[c.id] = c;
138
- });
139
- }
140
- createCommentsTemplate() {
141
- return renderCommentsView(this);
142
- }
143
- setReplyTo(commentId) {
144
- if (this.editingComment) {
145
- this.editingComment = null;
146
- this.previewText = '';
147
- this.previewName = '';
148
- this.previewPseudonym = '';
149
- }
150
- this.currentReplyTo = commentId;
151
- const form = this.querySelector('#comment-form-container');
152
- if (form)
153
- form.scrollIntoView({ behavior: 'smooth' });
154
- }
155
- cancelReply() {
156
- this.currentReplyTo = null;
157
- }
158
- handleInputChange(e) {
159
- this.previewText = e.target.value;
160
- }
161
- async handleNameInputChange(e) {
162
- const target = e.target;
163
- this.previewName = target.value;
164
- if (target.value.trim()) {
165
- try {
166
- const { pseudonym } = await generatePseudonymAndHash(target.value);
167
- this.previewPseudonym = pseudonym;
168
- }
169
- catch {
170
- this.previewPseudonym = '';
171
- }
172
- }
173
- else {
174
- this.previewPseudonym = '';
175
- }
176
- }
177
- async handleSubmit(e) {
178
- e.preventDefault();
179
- const fd = new FormData(e.target);
180
- const originalName = fd.get('name');
181
- const message = fd.get('message');
182
- if (originalName && originalName.length > YangchunCommentElement.MAX_NAME_LENGTH) {
183
- alert(`${this.i18n.t('nameTooLong')} (${originalName.length}/${YangchunCommentElement.MAX_NAME_LENGTH})`);
184
- return;
185
- }
186
- if (message.length > YangchunCommentElement.MAX_MESSAGE_LENGTH) {
187
- alert(`${this.i18n.t('messageTooLong')} (${message.length}/${YangchunCommentElement.MAX_MESSAGE_LENGTH})`);
188
- return;
189
- }
190
- let pseudonym;
191
- let hash;
192
- if (this.editingComment) {
193
- pseudonym = this.editingComment.pseudonym || '';
194
- hash = this.editingComment.nameHash || '';
195
- }
196
- else {
197
- const r = await generatePseudonymAndHash(originalName || '');
198
- pseudonym = r.pseudonym;
199
- hash = r.hash;
200
- }
201
- const success = await this.processSubmission(pseudonym, hash, message);
202
- if (success) {
203
- this.resetFormState();
204
- this.comments.length = 0;
205
- await this.renderCommentsList();
206
- }
207
- }
208
- async processSubmission(pseudonym, nameHash, message) {
209
- if (this.editingComment) {
210
- const success = await this.apiService.updateComment(this.post, this.editingComment.id, this.editingComment.pseudonym || '', this.editingComment.nameHash || '', message);
211
- if (!success)
212
- alert(this.i18n.t('editFailed'));
213
- return success;
214
- }
215
- else {
216
- const commentId = await this.apiService.addComment(this.post, pseudonym, nameHash, message, this.currentReplyTo);
217
- if (!commentId) {
218
- alert(this.i18n.t('submitFailed'));
219
- return false;
220
- }
221
- this.saveMyNameHash(nameHash);
222
- return true;
223
- }
224
- }
225
- resetFormState() {
226
- const form = document.querySelector('#comment-form');
227
- if (form)
228
- form.reset();
229
- this.previewText = '';
230
- this.previewName = '';
231
- this.previewPseudonym = '';
232
- this.editingComment = null;
233
- this.currentReplyTo = null;
234
- }
235
- async handlePreviewSubmit() {
236
- if (this.previewName && this.previewName.length > YangchunCommentElement.MAX_NAME_LENGTH) {
237
- alert(`${this.i18n.t('nameTooLong')} (${this.previewName.length}/${YangchunCommentElement.MAX_NAME_LENGTH})`);
238
- return;
239
- }
240
- if (this.previewText.length > YangchunCommentElement.MAX_MESSAGE_LENGTH) {
241
- alert(`${this.i18n.t('messageTooLong')} (${this.previewText.length}/${YangchunCommentElement.MAX_MESSAGE_LENGTH})`);
242
- return;
243
- }
244
- let pseudonym;
245
- let hash;
246
- if (this.editingComment) {
247
- pseudonym = this.editingComment.pseudonym || '';
248
- hash = this.editingComment.nameHash || '';
249
- }
250
- else {
251
- const g = await generatePseudonymAndHash(this.previewName);
252
- pseudonym = g.pseudonym;
253
- hash = g.hash;
254
- }
255
- const success = await this.processSubmission(pseudonym, hash, this.previewText);
256
- if (success) {
257
- this.resetPreviewState();
258
- this.comments.length = 0;
259
- await this.renderCommentsList();
260
- }
261
- }
262
- resetPreviewState() {
263
- this.previewText = '';
264
- this.previewName = '';
265
- this.previewPseudonym = '';
266
- this.editingComment = null;
267
- this.currentReplyTo = null;
268
- this.switchTab('write');
269
- const form = document.querySelector('#comment-form');
270
- if (form)
271
- form.reset();
272
- }
273
- async handleDelete(commentId) {
274
- if (!confirm(this.i18n.t('confirmDelete')))
275
- return;
276
- const success = await this.apiService.deleteComment(this.post, commentId);
277
- if (success) {
278
- this.comments.length = 0;
279
- await this.renderCommentsList();
280
- }
281
- else {
282
- alert(this.i18n.t('deleteFailed'));
283
- }
284
- }
285
- handleEdit(comment) {
286
- this.clearReplyState();
287
- this.setEditingState(comment);
288
- this.populateFormWithComment(comment);
289
- this.scrollToForm();
290
- }
291
- clearReplyState() {
292
- if (this.currentReplyTo)
293
- this.currentReplyTo = null;
294
- }
295
- setEditingState(comment) {
296
- this.editingComment = comment;
297
- this.previewText = comment.msg || '';
298
- this.previewName = comment.pseudonym || '';
299
- this.previewPseudonym = comment.pseudonym || '';
300
- }
301
- populateFormWithComment(comment) {
302
- const nameInput = document.querySelector('#comment-form input[name="name"]');
303
- const messageInput = document.querySelector('#comment-form textarea[name="message"]');
304
- if (nameInput) {
305
- nameInput.value = comment.pseudonym || '';
306
- this.previewName = comment.pseudonym || '';
307
- this.previewPseudonym = comment.pseudonym || '';
308
- }
309
- if (messageInput) {
310
- messageInput.value = comment.msg || '';
311
- this.previewText = comment.msg || '';
312
- }
313
- }
314
- scrollToForm() {
315
- const form = document.querySelector('#comment-form-container');
316
- if (form)
317
- form.scrollIntoView({ behavior: 'smooth' });
318
- }
319
- cancelEdit() {
320
- this.editingComment = null;
321
- this.clearFormAndPreview();
322
- }
323
- clearFormAndPreview() {
324
- const form = document.querySelector('#comment-form');
325
- if (form)
326
- form.reset();
327
- this.previewText = '';
328
- this.previewName = '';
329
- this.previewPseudonym = '';
330
- }
331
- toggleMarkdownHelp() {
332
- this.showMarkdownHelp = !this.showMarkdownHelp;
333
- this.updateBodyScrollLock();
334
- }
335
- createMarkdownHelpTemplate() {
336
- return html ` <div id="markdown-help-modal" class="active">
337
- <div class="markdown-help-container ycc-flex">
338
- <div
339
- class="markdown-help-backdrop ycc-clickable"
340
- @click=${() => this.toggleMarkdownHelp()}
341
- ></div>
342
- <div class="markdown-help-content" role="dialog" aria-modal="true">
343
- <button
344
- class="markdown-help-close ycc-clickable ycc-reset-button"
345
- @click=${() => this.toggleMarkdownHelp()}
346
- aria-label="Close"
347
- >
348
- ×
349
- </button>
350
- <h4>${this.i18n.t('commentSystemTitle')}</h4>
351
- <p>${this.i18n.t('commentSystemDesc')}</p>
352
- <p>${this.i18n.t('commentTimeLimit')}</p>
353
- <p>
354
- Powered by&nbsp;<a
355
- href="https://github.com/ziteh/yangchun-comment"
356
- target="_blank"
357
- rel="noopener noreferrer"
358
- >Yang Chun Comment</a
359
- >
360
- </p>
361
- <h4>${this.i18n.t('markdownSyntax')}</h4>
362
- <p>${this.i18n.t('markdownBasicSupport')}</p>
363
- <div class="markdown-examples">
364
- <code>
365
- <pre>
366
- ${this.i18n.t('markdownLinkExample')}
367
-
368
- ${this.i18n.t('markdownImageExample')}
369
-
370
- ${this.i18n.t('markdownItalicExample')}
371
-
372
- ${this.i18n.t('markdownBoldExample')}
373
-
374
- ${this.i18n.t('markdownListExample')}
375
-
376
- ${this.i18n.t('markdownOrderedListExample')}
377
-
378
- ${this.i18n.t('markdownInlineCodeExample')}
379
-
380
- ${this.i18n.t('markdownCodeBlockExample')}</pre
381
- >
382
- </code>
383
- </div>
384
- </div>
385
- </div>
386
- </div>`;
387
- }
388
- createFormTemplate() {
389
- return html `
390
- ${this.activeTab === 'preview' ? createPreviewTemplate(this) : this.createFormContent()}
391
- ${this.createStatusIndicators()}
392
- ${this.showMarkdownHelp ? this.createMarkdownHelpTemplate() : nothing}
393
- ${this.showAdminLogin ? this.createAdminLoginTemplate() : nothing}
394
- `;
395
- }
396
- createFormContent() {
397
- return html ` <div class="comment-box">
398
- <div id="form-content" class="${this.activeTab === 'write' ? 'active' : ''}">
399
- <form
400
- id="comment-form"
401
- class="ycc-reset-form"
402
- @submit=${(e) => this.handleSubmit(e)}
403
- >
404
- <div class="honeypot-field">
405
- <input type="text" name="website" tabindex="-1" autocomplete="off" aria-hidden="true" />
406
- </div>
407
- ${this.createTextareaSection()} ${this.createFormFooter()}
408
- </form>
409
- </div>
410
- </div>`;
411
- }
412
- createTextareaSection() {
413
- return html ` <div class="comment-input">
414
- <textarea
415
- name="message"
416
- placeholder="${this.i18n.t('messagePlaceholder')}"
417
- maxlength="${YangchunCommentElement.MAX_MESSAGE_LENGTH}"
418
- required
419
- .value=${this.previewText}
420
- @input=${(e) => this.handleInputChange(e)}
421
- ></textarea>
422
- <div class="char-count">
423
- <span
424
- id="message-char-count"
425
- class="${this.previewText.length > YangchunCommentElement.MAX_MESSAGE_LENGTH
426
- ? 'over-limit'
427
- : ''}"
428
- >${this.previewText.length}</span
429
- >/${YangchunCommentElement.MAX_MESSAGE_LENGTH}
430
- </div>
431
- </div>`;
432
- }
433
- createFormFooter() {
434
- return html ` <div class="comment-footer ycc-flex ycc-flex-wrap ycc-gap-xs">
435
- <div class="name-input-container">
436
- <input
437
- type="text"
438
- name="name"
439
- autocomplete="name"
440
- placeholder="${this.i18n.t('namePlaceholder')}"
441
- maxlength="${YangchunCommentElement.MAX_NAME_LENGTH}"
442
- ?disabled=${this.editingComment !== null}
443
- .value=${this.previewName}
444
- @input=${(e) => this.handleNameInputChange(e)}
445
- />
446
- <div class="char-count" style="margin-top: 4px;">
447
- <span
448
- id="name-char-count"
449
- class="${this.previewName.length > YangchunCommentElement.MAX_NAME_LENGTH
450
- ? 'over-limit'
451
- : ''}"
452
- >${this.previewName.length}</span
453
- >/${YangchunCommentElement.MAX_NAME_LENGTH}
454
- </div>
455
- <div class="pseudonym-notice" style="font-size: 0.8em; color: #666; margin-top: 4px;">
456
- ${this.editingComment
457
- ? this.i18n.t('editingPseudonymNotice')
458
- : this.i18n.t('pseudonymNotice')}
459
- </div>
460
- </div>
461
- <div class="ycc-flex ycc-gap-xs">${this.createFormButtons()}</div>
462
- </div>`;
463
- }
464
- createFormButtons() {
465
- return html ` <button
466
- type="button"
467
- class="help-btn ycc-clickable ycc-reset-button"
468
- title="${this.i18n.t('markdownHelp')}"
469
- @click=${() => this.toggleMarkdownHelp()}
470
- >
471
- ?
472
- </button>
473
- <button
474
- type="button"
475
- class="preview-btn ycc-clickable ycc-transition ycc-transparent-bg ycc-reset-button ${this
476
- .activeTab === 'preview'
477
- ? 'active'
478
- : ''}"
479
- @click=${() => this.switchTab(this.activeTab === 'preview' ? 'write' : 'preview')}
480
- >
481
- ${this.activeTab === 'preview' ? this.i18n.t('write') : this.i18n.t('preview')}
482
- </button>
483
- <button type="submit" class="submit-btn ycc-clickable ycc-transition ycc-reset-button">
484
- ${this.editingComment ? this.i18n.t('updateComment') : this.i18n.t('submitComment')}
485
- </button>`;
486
- }
487
- createAdminButton() {
488
- return html `<button
489
- type="button"
490
- class="admin-btn ycc-clickable ycc-reset-button"
491
- title="Admin"
492
- @click=${() => this.showAdminModal()}
493
- >
494
-
495
- </button>`;
496
- }
497
- showAdminModal() {
498
- this.showAdminLogin = true;
499
- this.updateBodyScrollLock();
500
- }
501
- hideAdminModal() {
502
- this.showAdminLogin = false;
503
- this.updateBodyScrollLock();
504
- }
505
- updateBodyScrollLock() {
506
- const lock = this.showMarkdownHelp || this.showAdminLogin;
507
- document.body.classList.toggle('ycc-modal-open', lock);
508
- }
509
- createAdminLoginTemplate() {
510
- return html `<div
511
- class="admin-modal-backdrop ycc-clickable"
512
- @click=${() => this.hideAdminModal()}
513
- >
514
- <div class="admin-modal-content" @click=${(e) => e.stopPropagation()}>
515
- <button
516
- class="admin-modal-close ycc-clickable ycc-reset-button"
517
- @click=${() => this.hideAdminModal()}
518
- >
519
- ×
520
- </button>
521
- <h3>Admin Login</h3>
522
- <form @submit=${(e) => this.handleAdminLogin(e)}>
523
- <div class="admin-form-group">
524
- <label for="admin-username">Username:</label
525
- ><input type="text" id="admin-username" name="username" required autocomplete="off" />
526
- </div>
527
- <div class="admin-form-group">
528
- <label for="admin-password">Password:</label
529
- ><input
530
- type="password"
531
- id="admin-password"
532
- name="password"
533
- required
534
- autocomplete="off"
535
- />
536
- </div>
537
- <button type="submit" class="admin-login-btn ycc-clickable ycc-reset-button">
538
- Login
539
- </button>
540
- </form>
541
- </div>
542
- </div>`;
543
- }
544
- async handleAdminLogin(e) {
545
- e.preventDefault();
546
- const fd = new FormData(e.target);
547
- const username = fd.get('username');
548
- const password = fd.get('password');
549
- try {
550
- const res = await fetch(`${this.apiUrl}admin/login`, {
551
- method: 'POST',
552
- headers: { 'Content-Type': 'application/json' },
553
- body: JSON.stringify({ username, password }),
554
- });
555
- if (res.ok) {
556
- await res.text();
557
- alert('Admin login successful!');
558
- this.hideAdminModal();
559
- }
560
- else {
561
- alert('Admin login failed!');
562
- }
563
- }
564
- catch (err) {
565
- console.error('Admin login error:', err);
566
- alert('Admin login error!');
567
- }
568
- }
569
- createStatusIndicators() {
570
- const replyIndicator = this.createReplyIndicator();
571
- const editIndicator = this.createEditIndicator();
572
- const hasAny = replyIndicator !== '' || editIndicator !== '';
573
- return hasAny ? html `${replyIndicator}${editIndicator}` : nothing;
574
- }
575
- createReplyIndicator() {
576
- return this.currentReplyTo && this.commentMap[this.currentReplyTo]
577
- ? html `<div class="info ycc-flex ycc-gap-md">
578
- ${this.i18n.t('replyingTo')}
579
- ${this.getDisplayName(this.commentMap[this.currentReplyTo])}<button
580
- type="button"
581
- class="cancel-link ycc-clickable ycc-transition ycc-reset-button"
582
- @click=${() => this.cancelReply()}
583
- >
584
- ${this.i18n.t('cancelReply')}
585
- </button>
586
- </div>`
587
- : '';
588
- }
589
- createEditIndicator() {
590
- return this.editingComment
591
- ? html `<div class="info ycc-flex ycc-gap-md">
592
- ${this.i18n.t('editing')} ${this.editingComment.id}<button
593
- type="button"
594
- class="cancel-link ycc-clickable ycc-transition ycc-reset-button"
595
- @click=${() => this.cancelEdit()}
596
- >
597
- ${this.i18n.t('cancelEdit')}
598
- </button>
599
- </div>`
600
- : '';
601
- }
602
- render() {
603
- return html ` <div class="ycc-container">
604
- <div class="comment-box-container">
605
- <div id="comment-form-container" class="form-content">${this.createFormTemplate()}</div>
606
- <!-- <div class="admin-btn-wrapper">${this.createAdminButton()}</div> -->
607
- </div>
608
- <div id="comments-container">${this.createCommentsTemplate()}</div>
609
- </div>`;
610
- }
611
- async refresh() {
612
- await this.reloadComments();
613
- }
614
- get i18n$() {
615
- return this.i18n;
616
- }
617
- get commentMap$() {
618
- return this.commentMap;
619
- }
620
- get currentReplyTo$() {
621
- return this.currentReplyTo;
622
- }
623
- get previewText$() {
624
- return this.previewText;
625
- }
626
- get previewPseudonym$() {
627
- return this.previewPseudonym;
628
- }
629
- get editingComment$() {
630
- return this.editingComment;
631
- }
632
- get comments$() {
633
- return this.comments;
634
- }
635
- formatDate(ts) {
636
- return formatDate(ts);
637
- }
638
- }
639
- __decorate([
640
- property({ type: String })
641
- ], YangchunCommentElement.prototype, "post", void 0);
642
- __decorate([
643
- property({ type: String })
644
- ], YangchunCommentElement.prototype, "apiUrl", void 0);
645
- __decorate([
646
- property({ type: String })
647
- ], YangchunCommentElement.prototype, "authorName", void 0);
648
- __decorate([
649
- property({ attribute: false })
650
- ], YangchunCommentElement.prototype, "language", void 0);
651
- __decorate([
652
- state()
653
- ], YangchunCommentElement.prototype, "commentMap", void 0);
654
- __decorate([
655
- state()
656
- ], YangchunCommentElement.prototype, "comments", void 0);
657
- __decorate([
658
- state()
659
- ], YangchunCommentElement.prototype, "currentReplyTo", void 0);
660
- __decorate([
661
- state()
662
- ], YangchunCommentElement.prototype, "previewText", void 0);
663
- __decorate([
664
- state()
665
- ], YangchunCommentElement.prototype, "previewName", void 0);
666
- __decorate([
667
- state()
668
- ], YangchunCommentElement.prototype, "previewPseudonym", void 0);
669
- __decorate([
670
- state()
671
- ], YangchunCommentElement.prototype, "editingComment", void 0);
672
- __decorate([
673
- state()
674
- ], YangchunCommentElement.prototype, "activeTab", void 0);
675
- __decorate([
676
- state()
677
- ], YangchunCommentElement.prototype, "showMarkdownHelp", void 0);
678
- __decorate([
679
- state()
680
- ], YangchunCommentElement.prototype, "showAdminLogin", void 0);
package/dist/index.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import type { I18nStrings } from './utils/i18n';
2
- import { YangchunCommentElement } from './element';
3
- export declare function initYangchunComment(elementId?: string, options?: {
4
- post?: string;
5
- apiUrl?: string;
6
- language?: 'en' | 'zh-Hant' | I18nStrings;
7
- authorName?: string;
8
- }): YangchunCommentElement;
9
- export default initYangchunComment;