@waline/client 2.4.0 → 2.5.0

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 (53) hide show
  1. package/dist/component.esm.js +1 -1
  2. package/dist/component.esm.js.map +1 -1
  3. package/dist/component.js +1 -1
  4. package/dist/component.js.map +1 -1
  5. package/dist/legacy.d.ts +3 -1
  6. package/dist/legacy.js +1 -1
  7. package/dist/legacy.js.map +1 -1
  8. package/dist/pageview.cjs.js +1 -1
  9. package/dist/pageview.esm.js +1 -1
  10. package/dist/pageview.js +1 -1
  11. package/dist/shim.d.ts +3 -1
  12. package/dist/shim.esm.d.ts +3 -1
  13. package/dist/shim.esm.js +1 -1
  14. package/dist/shim.esm.js.map +1 -1
  15. package/dist/shim.js +1 -1
  16. package/dist/shim.js.map +1 -1
  17. package/dist/waline.cjs.d.ts +3 -1
  18. package/dist/waline.cjs.js +1 -1
  19. package/dist/waline.cjs.js.map +1 -1
  20. package/dist/waline.css +1 -1
  21. package/dist/waline.css.map +1 -1
  22. package/dist/waline.d.ts +3 -1
  23. package/dist/waline.esm.d.ts +3 -1
  24. package/dist/waline.esm.js +1 -1
  25. package/dist/waline.esm.js.map +1 -1
  26. package/dist/waline.js +1 -1
  27. package/dist/waline.js.map +1 -1
  28. package/package.json +19 -4
  29. package/src/components/CommentBox.vue +123 -0
  30. package/src/components/CommentCard.vue +26 -23
  31. package/src/components/Icons.ts +20 -0
  32. package/src/components/Waline.vue +34 -12
  33. package/src/composables/index.ts +1 -1
  34. package/src/composables/{likeStorage.ts → like.ts} +4 -1
  35. package/src/composables/userInfo.ts +7 -1
  36. package/src/config/i18n/en.ts +2 -0
  37. package/src/config/i18n/generate.ts +2 -0
  38. package/src/config/i18n/jp.ts +8 -0
  39. package/src/config/i18n/pt-BR.ts +8 -0
  40. package/src/config/i18n/ru.ts +8 -0
  41. package/src/config/i18n/vi-VN.ts +8 -0
  42. package/src/config/i18n/zh-CN.ts +2 -0
  43. package/src/config/i18n/zh-TW.ts +2 -0
  44. package/src/init.ts +7 -2
  45. package/src/styles/card.scss +35 -30
  46. package/src/styles/gif.scss +151 -0
  47. package/src/styles/nomalize.scss +0 -1
  48. package/src/styles/panel.scss +2 -1
  49. package/src/typings/locale.ts +2 -0
  50. package/src/typings/waline.ts +1 -1
  51. package/src/utils/fetchGif.ts +62 -0
  52. package/src/utils/index.ts +2 -0
  53. package/src/utils/throttle.ts +16 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waline/client",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "client for waline comment system",
5
5
  "keywords": [
6
6
  "valine",
@@ -86,12 +86,27 @@
86
86
  "vue": "^3.2.33"
87
87
  },
88
88
  "devDependencies": {
89
+ "@babel/core": "^7.17.10",
90
+ "@babel/preset-env": "^7.17.10",
91
+ "@rollup/plugin-babel": "^5.3.1",
92
+ "@rollup/plugin-commonjs": "^22.0.0",
93
+ "@rollup/plugin-node-resolve": "^13.3.0",
94
+ "@rollup/plugin-replace": "^4.0.0",
89
95
  "@types/autosize": "^4.0.1",
90
96
  "@types/marked": "^4.0.3",
91
- "@vitejs/plugin-vue": "^2.3.2",
92
- "vite": "^2.9.8"
97
+ "@types/node": "^17.0.33",
98
+ "@vitejs/plugin-vue": "^2.3.3",
99
+ "@vue/compiler-sfc": "^3.2.33",
100
+ "@yeger/vue-masonry-wall": "^3.0.31",
101
+ "rimraf": "^3.0.2",
102
+ "rollup": "^2.73.0",
103
+ "rollup-plugin-dts": "^4.2.1",
104
+ "rollup-plugin-terser": "^7.0.2",
105
+ "rollup-plugin-ts": "^2.0.7",
106
+ "typescript": "^4.6.4",
107
+ "vite": "^2.9.9"
93
108
  },
94
109
  "engines": {
95
- "node": ">=12.20.0"
110
+ "node": ">=14"
96
111
  }
97
112
  }
@@ -88,6 +88,16 @@
88
88
  <EmojiIcon />
89
89
  </button>
90
90
 
91
+ <button
92
+ ref="gifButtonRef"
93
+ class="wl-action"
94
+ :class="{ actived: showGif }"
95
+ :title="locale.gif"
96
+ @click="showGif = !showGif"
97
+ >
98
+ <GifIcon />
99
+ </button>
100
+
91
101
  <input
92
102
  ref="imageUploadRef"
93
103
  class="upload"
@@ -152,6 +162,47 @@
152
162
  </button>
153
163
  </div>
154
164
 
165
+ <div
166
+ ref="gifPopupRef"
167
+ class="wl-gif-popup"
168
+ :class="{ display: showGif }"
169
+ >
170
+ <input
171
+ type="text"
172
+ :placeholder="locale.gifSearchPlaceholder"
173
+ ref="gifSearchInputRef"
174
+ @input="onGifSearch"
175
+ />
176
+
177
+ <masonry-wall
178
+ class="wl-gif-waterfall"
179
+ :items="gifData.list"
180
+ :ssr-columns="2"
181
+ :column-width="200"
182
+ :gap="6"
183
+ @scroll="onGifMasonryScroll"
184
+ >
185
+ <template #default="{ item }">
186
+ <img
187
+ @click="insert(`![](${item.media[0].tinygif.url})`)"
188
+ :src="item.media[0].tinygif.url"
189
+ :title="item.title"
190
+ loading="lazy"
191
+ :style="{
192
+ width: '200px',
193
+ height:
194
+ (200 * item.media[0].tinygif.dims[1]) /
195
+ item.media[0].tinygif.dims[0] +
196
+ 'px',
197
+ }"
198
+ />
199
+ </template>
200
+ </masonry-wall>
201
+
202
+ <div v-if="gifData.loading" class="wl-loading">
203
+ <LoadingIcon :size="30" />
204
+ </div>
205
+ </div>
155
206
  <div
156
207
  ref="emojiPopupRef"
157
208
  class="wl-emoji-popup"
@@ -228,6 +279,7 @@ import {
228
279
  MarkdownIcon,
229
280
  PreviewIcon,
230
281
  LoadingIcon,
282
+ GifIcon,
231
283
  } from './Icons';
232
284
  import { useEditor, useUserMeta, useUserInfo } from '../composables';
233
285
  import {
@@ -237,6 +289,9 @@ import {
237
289
  parseEmoji,
238
290
  postComment,
239
291
  getEmojis,
292
+ fetchGif,
293
+ FetchGifResponse,
294
+ throttle,
240
295
  } from '../utils';
241
296
 
242
297
  import type { ComputedRef, DeepReadonly } from 'vue';
@@ -253,6 +308,7 @@ export default defineComponent({
253
308
  MarkdownIcon,
254
309
  PreviewIcon,
255
310
  LoadingIcon,
311
+ GifIcon,
256
312
  },
257
313
 
258
314
  props: {
@@ -286,13 +342,22 @@ export default defineComponent({
286
342
  const imageUploadRef = ref<HTMLInputElement | null>(null);
287
343
  const emojiButtonRef = ref<HTMLDivElement | null>(null);
288
344
  const emojiPopupRef = ref<HTMLDivElement | null>(null);
345
+ const gifButtonRef = ref<HTMLDivElement | null>(null);
346
+ const gifPopupRef = ref<HTMLDivElement | null>(null);
347
+ const gifSearchInputRef = ref<HTMLInputElement | null>(null);
289
348
 
290
349
  const emoji = ref<DeepReadonly<WalineEmojiConfig>>({ tabs: [], map: {} });
291
350
  const emojiTabIndex = ref(0);
292
351
  const showEmoji = ref(false);
352
+ const showGif = ref(false);
293
353
  const showPreview = ref(false);
294
354
  const previewText = ref('');
295
355
  const wordNumber = ref(0);
356
+ const gifData = ref<{
357
+ cursor: string;
358
+ loading: boolean;
359
+ list: FetchGifResponse['results'];
360
+ }>({ cursor: '', loading: true, list: [] });
296
361
 
297
362
  const wordLimit = ref(0);
298
363
  const isWordNumberLegal = ref(false);
@@ -548,6 +613,41 @@ export default defineComponent({
548
613
  !(emojiPopupRef.value as HTMLElement).contains(event.target as Node)
549
614
  )
550
615
  showEmoji.value = false;
616
+
617
+ if (
618
+ !(gifButtonRef.value as HTMLElement).contains(event.target as Node) &&
619
+ !(gifPopupRef.value as HTMLElement).contains(event.target as Node)
620
+ )
621
+ showGif.value = false;
622
+ };
623
+
624
+ const onGifSearch = throttle(async (event: Event) => {
625
+ gifData.value.cursor = '';
626
+ gifData.value.list = [];
627
+ onGifMasonryScroll(event);
628
+ });
629
+
630
+ const onGifMasonryScroll = async (event: Event): Promise<void> => {
631
+ const { scrollTop, clientHeight, scrollHeight } =
632
+ event.target as HTMLDivElement;
633
+ const percent = (clientHeight + scrollTop) / scrollHeight;
634
+ if (percent < 0.9 || gifData.value.loading) {
635
+ return;
636
+ }
637
+
638
+ gifData.value.loading = true;
639
+ const data = await fetchGif({
640
+ keyword: gifSearchInputRef.value?.value || '',
641
+ pos: gifData.value.cursor,
642
+ }).finally(() => {
643
+ gifData.value.loading = false;
644
+ });
645
+
646
+ gifData.value.cursor = data.next;
647
+ gifData.value.list = gifData.value.list.concat(data.results);
648
+ setTimeout(() => {
649
+ (event.target as HTMLDivElement).scrollTop = scrollTop;
650
+ }, 50);
551
651
  };
552
652
 
553
653
  // update wordNumber
@@ -575,6 +675,20 @@ export default defineComponent({
575
675
  { immediate: true }
576
676
  );
577
677
 
678
+ watch([showGif], async ([showGif]) => {
679
+ if (!showGif) {
680
+ return;
681
+ }
682
+
683
+ gifData.value.loading = true;
684
+ const data = await fetchGif({ keyword: '' }).finally(() => {
685
+ gifData.value.loading = false;
686
+ });
687
+
688
+ gifData.value.cursor = data.next;
689
+ gifData.value.list = gifData.value.list.concat(data.results);
690
+ });
691
+
578
692
  onMounted(() => {
579
693
  document.body.addEventListener('click', popupHandler);
580
694
 
@@ -632,6 +746,8 @@ export default defineComponent({
632
746
  onLogout,
633
747
  onProfile,
634
748
  submitComment,
749
+ onGifMasonryScroll,
750
+ onGifSearch,
635
751
 
636
752
  isLogin,
637
753
  userInfo,
@@ -651,6 +767,9 @@ export default defineComponent({
651
767
  emojiTabIndex,
652
768
  showEmoji,
653
769
 
770
+ // gif
771
+ showGif,
772
+
654
773
  // image
655
774
  canUploadImage,
656
775
 
@@ -663,7 +782,11 @@ export default defineComponent({
663
782
  editorRef,
664
783
  emojiButtonRef,
665
784
  emojiPopupRef,
785
+ gifButtonRef,
786
+ gifPopupRef,
666
787
  imageUploadRef,
788
+ gifSearchInputRef,
789
+ gifData,
667
790
  };
668
791
  },
669
792
  });
@@ -31,31 +31,33 @@
31
31
  />
32
32
  <span class="wl-time" v-text="time" />
33
33
 
34
- <button
35
- class="wl-reply"
36
- :class="{ active: isReplyingCurrent }"
37
- :title="isReplyingCurrent ? locale.cancelReply : locale.reply"
38
- @click="$emit('reply', isReplyingCurrent ? null : comment)"
39
- >
40
- <ReplyIcon />
41
- </button>
34
+ <div class="wl-comment-actions">
35
+ <button
36
+ class="wl-delete"
37
+ v-if="isAdmin || isOwner"
38
+ @click="$emit('delete', comment)"
39
+ >
40
+ <DeleteIcon />
41
+ </button>
42
42
 
43
- <button
44
- class="wl-like"
45
- @click="$emit('like', comment)"
46
- :title="like ? locale.cancelLike : locale.like"
47
- >
48
- <LikeIcon :active="like" />
49
- <span v-if="'like' in comment" v-text="comment.like" />
50
- </button>
43
+ <button
44
+ class="wl-like"
45
+ @click="$emit('like', comment)"
46
+ :title="like ? locale.cancelLike : locale.like"
47
+ >
48
+ <LikeIcon :active="like" />
49
+ <span v-if="'like' in comment" v-text="comment.like" />
50
+ </button>
51
51
 
52
- <button
53
- class="wl-delete"
54
- v-if="isAdmin || isOwner"
55
- @click="$emit('delete', comment)"
56
- >
57
- <DeleteIcon />
58
- </button>
52
+ <button
53
+ class="wl-reply"
54
+ :class="{ active: isReplyingCurrent }"
55
+ :title="isReplyingCurrent ? locale.cancelReply : locale.reply"
56
+ @click="$emit('reply', isReplyingCurrent ? null : comment)"
57
+ >
58
+ <ReplyIcon />
59
+ </button>
60
+ </div>
59
61
  </div>
60
62
  <div class="wl-meta" aria-hidden="true">
61
63
  <span v-if="comment.addr" v-text="comment.addr" />
@@ -104,6 +106,7 @@
104
106
  @reply="$emit('reply', $event)"
105
107
  @submit="$emit('submit', $event)"
106
108
  @like="$emit('like', $event)"
109
+ @delete="$emit('delete', $event)"
107
110
  @status="$emit('status', $event)"
108
111
  @sticky="$emit('sticky', $event)"
109
112
  />
@@ -148,3 +148,23 @@ export const LoadingIcon: FunctionalComponent<{ size: number }> = ({ size }) =>
148
148
  })
149
149
  )
150
150
  );
151
+
152
+ export const GifIcon: FunctionalComponent = () =>
153
+ h(
154
+ 'svg',
155
+ {
156
+ width: 24,
157
+ height: 24,
158
+ fill: 'currentcolor',
159
+ viewBox: '0 0 24 24',
160
+ },
161
+ [
162
+ h('path', {
163
+ style: 'transform: translateY(0.5px)',
164
+ d: 'M18.968 10.5H15.968V11.484H17.984V12.984H15.968V15H14.468V9H18.968V10.5V10.5ZM8.984 9C9.26533 9 9.49967 9.09367 9.687 9.281C9.87433 9.46833 9.968 9.70267 9.968 9.984V10.5H6.499V13.5H8.468V12H9.968V14.016C9.968 14.2973 9.87433 14.5317 9.687 14.719C9.49967 14.9063 9.26533 15 8.984 15H5.984C5.70267 15 5.46833 14.9063 5.281 14.719C5.09367 14.5317 5 14.2973 5 14.016V9.985C5 9.70367 5.09367 9.46933 5.281 9.282C5.46833 9.09467 5.70267 9.001 5.984 9.001H8.984V9ZM11.468 9H12.968V15H11.468V9V9Z',
165
+ }),
166
+ h('path', {
167
+ d: 'M18.5 3H5.75C3.6875 3 2 4.6875 2 6.75V18C2 20.0625 3.6875 21.75 5.75 21.75H18.5C20.5625 21.75 22.25 20.0625 22.25 18V6.75C22.25 4.6875 20.5625 3 18.5 3ZM20.75 18C20.75 19.2375 19.7375 20.25 18.5 20.25H5.75C4.5125 20.25 3.5 19.2375 3.5 18V6.75C3.5 5.5125 4.5125 4.5 5.75 4.5H18.5C19.7375 4.5 20.75 5.5125 20.75 6.75V18Z',
168
+ }),
169
+ ]
170
+ );
@@ -312,7 +312,8 @@ export default defineComponent({
312
312
  objectId: comment.objectId,
313
313
  status,
314
314
  });
315
- // todo: render comment list
315
+
316
+ comment.status = status;
316
317
  };
317
318
 
318
319
  const onSticky = async (comment: WalineComment): Promise<void> => {
@@ -327,10 +328,11 @@ export default defineComponent({
327
328
  objectId: comment.objectId,
328
329
  sticky: comment.sticky ? 0 : 1,
329
330
  });
330
- // todo: render comment list
331
+
332
+ comment.sticky = !comment.sticky;
331
333
  };
332
334
 
333
- const onDelete = async (comment: WalineComment): Promise<void> => {
335
+ const onDelete = async ({ objectId }: WalineComment): Promise<void> => {
334
336
  if (!confirm('Are you sure you want to delete this comment?')) return;
335
337
 
336
338
  const { serverURL, lang } = config.value;
@@ -339,30 +341,50 @@ export default defineComponent({
339
341
  serverURL,
340
342
  lang,
341
343
  token: userInfo.value?.token,
342
- objectId: comment.objectId,
344
+ objectId: objectId,
345
+ });
346
+
347
+ // delete comment from data
348
+ data.value.some((item, index) => {
349
+ if (item.objectId === objectId) {
350
+ data.value = data.value.filter((_item, i) => i !== index);
351
+
352
+ return true;
353
+ }
354
+
355
+ return item.children.some((child, childIndex) => {
356
+ if (child.objectId === objectId) {
357
+ data.value[index].children = item.children.filter(
358
+ (_item, i) => i !== childIndex
359
+ );
360
+
361
+ return true;
362
+ }
363
+
364
+ return false;
365
+ });
343
366
  });
344
- // todo render comment list
345
367
  };
346
368
 
347
369
  const onLike = async (comment: WalineComment): Promise<void> => {
348
370
  const { serverURL, lang } = config.value;
349
- const hasLiked = likeStorage.value.includes(comment.objectId);
371
+ const { objectId } = comment;
372
+ const hasLiked = likeStorage.value.includes(objectId);
350
373
 
351
374
  await likeComment({
352
375
  serverURL,
353
376
  lang,
354
- objectId: comment.objectId,
377
+ objectId,
355
378
  like: !hasLiked,
356
379
  });
357
380
 
358
381
  if (hasLiked)
359
- likeStorage.value = likeStorage.value.filter(
360
- (id) => id !== comment.objectId
361
- );
382
+ likeStorage.value = likeStorage.value.filter((id) => id !== objectId);
362
383
  else {
363
- likeStorage.value.push(comment.objectId);
384
+ likeStorage.value = [...likeStorage.value, objectId];
364
385
 
365
- if (likeStorage.value.length > 50) likeStorage.value.slice(-50);
386
+ if (likeStorage.value.length > 50)
387
+ likeStorage.value = likeStorage.value.slice(-50);
366
388
  }
367
389
 
368
390
  comment.like = (comment.like || 0) + (hasLiked ? -1 : 1);
@@ -1,4 +1,4 @@
1
1
  export * from './inputs';
2
2
  export * from './timeAgo';
3
3
  export * from './userInfo';
4
- export * from './likeStorage';
4
+ export * from './like';
@@ -8,4 +8,7 @@ export type LikeID = number | string;
8
8
 
9
9
  export type LikeRef = Ref<LikeID[]>;
10
10
 
11
- export const useLikeStorage = (): LikeRef => useStorage<LikeID[]>(LIKE_KEY, []);
11
+ let likeStorage: LikeRef | null = null;
12
+
13
+ export const useLikeStorage = (): LikeRef =>
14
+ likeStorage || (likeStorage = useStorage<LikeID[]>(LIKE_KEY, []));
@@ -18,5 +18,11 @@ export const USER_KEY = 'WALINE_USER';
18
18
 
19
19
  export type UserInfoRef = Ref<UserInfo | Record<string, never>>;
20
20
 
21
+ let userInfoStorage: UserInfoRef | null = null;
22
+
21
23
  export const useUserInfo = (): UserInfoRef =>
22
- useStorage<UserInfo | Record<string, never>>('USER_KEY', {});
24
+ userInfoStorage ||
25
+ (userInfoStorage = useStorage<UserInfo | Record<string, never>>(
26
+ 'USER_KEY',
27
+ {}
28
+ ));
@@ -39,4 +39,6 @@ export default generateLocale([
39
39
  'Wizards',
40
40
  'Elves',
41
41
  'Maiar',
42
+ 'GIF',
43
+ 'Search GIF',
42
44
  ]);
@@ -39,6 +39,8 @@ const localeKeys = [
39
39
  'level3',
40
40
  'level4',
41
41
  'level5',
42
+ 'gif',
43
+ 'gifSearchPlaceholder',
42
44
  ];
43
45
 
44
46
  export const generateLocale = (locale: string[]): WalineLocale =>
@@ -33,4 +33,12 @@ export default generateLocale([
33
33
  'ワード',
34
34
  'コメントは $0 から $1 ワードの間でなければなりません!\n 現在の単語番号: $2',
35
35
  '匿名',
36
+ 'うえにん',
37
+ 'なかにん',
38
+ 'しもおし',
39
+ '特にしもおし',
40
+ 'かげ',
41
+ 'なぬし',
42
+ 'GIF',
43
+ '探す GIF',
36
44
  ]);
@@ -33,4 +33,12 @@ export default generateLocale([
33
33
  'Palavras',
34
34
  'Favor enviar comentário com $0 a $1 palavras!\n Número de palavras atuais: $2',
35
35
  'Anônimo',
36
+ 'Dwarves',
37
+ 'Hobbits',
38
+ 'Ents',
39
+ 'Wizards',
40
+ 'Elves',
41
+ 'Maiar',
42
+ 'GIF',
43
+ 'Pesquisar GIF',
36
44
  ]);
@@ -33,4 +33,12 @@ export default generateLocale([
33
33
  'Слова',
34
34
  'Пожалуйста, введите комментарии от $0 до $1 слов!\nНомер текущего слова: $2',
35
35
  'Анонимный',
36
+ 'Dwarves',
37
+ 'Hobbits',
38
+ 'Ents',
39
+ 'Wizards',
40
+ 'Elves',
41
+ 'Maiar',
42
+ 'GIF',
43
+ 'Поиск GIF',
36
44
  ]);
@@ -33,4 +33,12 @@ export default generateLocale([
33
33
  'từ',
34
34
  'Please input comments between $0 and $1 words!\n Current word number: $2',
35
35
  'Vô danh',
36
+ 'Dwarves',
37
+ 'Hobbits',
38
+ 'Ents',
39
+ 'Wizards',
40
+ 'Elves',
41
+ 'Maiar',
42
+ 'GIF',
43
+ 'Tìm kiếm GIF',
36
44
  ]);
@@ -39,4 +39,6 @@ export default generateLocale([
39
39
  '活跃',
40
40
  '话痨',
41
41
  '传说',
42
+ '表情包',
43
+ '搜索表情包',
42
44
  ]);
@@ -39,4 +39,6 @@ export default generateLocale([
39
39
  '活躍',
40
40
  '話癆',
41
41
  '傳說',
42
+ '表情包',
43
+ '搜索表情包',
42
44
  ]);
package/src/init.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createApp, h, reactive, watchEffect } from 'vue';
2
+ import MasonryWall from '@yeger/vue-masonry-wall';
2
3
 
3
4
  import Waline from './components/Waline.vue';
4
5
  import { commentCount } from './comment';
@@ -80,8 +81,12 @@ export const init = ({
80
81
  ? createApp(() => h(Waline, { path: state.path, ...props }))
81
82
  : null;
82
83
 
83
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
84
- if (app) app.mount(root!);
84
+ if (app) {
85
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
86
+ app.use(MasonryWall);
87
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
88
+ app.mount(root!);
89
+ }
85
90
 
86
91
  updateCommentCount();
87
92
  updatePageviewCount();
@@ -18,13 +18,13 @@
18
18
  .wl-user {
19
19
  --avatar-size: var(--waline-avatar-size);
20
20
 
21
+ position: relative;
22
+ margin-right: 0.75em;
23
+
21
24
  @media (max-width: 720px) {
22
25
  --avatar-size: var(--waline-m-avatar-size);
23
26
  }
24
27
 
25
- position: relative;
26
- margin-right: 0.75em;
27
-
28
28
  img {
29
29
  width: var(--avatar-size);
30
30
  height: var(--avatar-size);
@@ -101,32 +101,6 @@
101
101
  font-size: 0.75em;
102
102
  }
103
103
 
104
- .wl-delete,
105
- .wl-like,
106
- .wl-reply {
107
- float: right;
108
-
109
- padding: 4px;
110
- border: none;
111
-
112
- background: transparent;
113
- color: var(--waline-color);
114
-
115
- line-height: 1;
116
-
117
- cursor: pointer;
118
-
119
- transition: color 0.2s ease;
120
-
121
- &:hover {
122
- color: var(--waline-theme-color);
123
- }
124
-
125
- &.active {
126
- color: var(--waline-active-color);
127
- }
128
- }
129
-
130
104
  .wl-meta {
131
105
  position: relative;
132
106
  line-height: 1;
@@ -154,6 +128,37 @@
154
128
  }
155
129
  }
156
130
 
131
+ .wl-comment-actions {
132
+ float: right;
133
+ }
134
+
135
+ .wl-delete,
136
+ .wl-like,
137
+ .wl-reply {
138
+ display: inline-flex;
139
+ align-items: center;
140
+
141
+ padding: 4px;
142
+ border: none;
143
+
144
+ background: transparent;
145
+ color: var(--waline-color);
146
+
147
+ line-height: 1;
148
+
149
+ cursor: pointer;
150
+
151
+ transition: color 0.2s ease;
152
+
153
+ &:hover {
154
+ color: var(--waline-theme-color);
155
+ }
156
+
157
+ &.active {
158
+ color: var(--waline-active-color);
159
+ }
160
+ }
161
+
157
162
  .wl-content {
158
163
  position: relative;
159
164
 
@@ -217,8 +222,8 @@
217
222
 
218
223
  .wl-admin-actions {
219
224
  margin: 8px 0;
220
- text-align: right;
221
225
  font-size: 12px;
226
+ text-align: right;
222
227
  }
223
228
 
224
229
  .wl-comment-status {