artalk 2.3.0 → 2.3.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.
package/src/artalk.ts CHANGED
@@ -2,9 +2,11 @@ import './style/main.less'
2
2
 
3
3
  import ArtalkConfig from '~/types/artalk-config'
4
4
  import { EventPayloadMap, Handler } from '~/types/event'
5
+ import ArtalkPlug from '~/types/plug'
5
6
  import Context from '~/types/context'
6
7
  import ConcreteContext from './context'
7
8
  import defaults from './defaults'
9
+ import { internal as internalLocales } from './i18n'
8
10
 
9
11
  import CheckerLauncher from './lib/checker'
10
12
  import Editor from './editor'
@@ -12,9 +14,9 @@ import List from './list'
12
14
  import SidebarLayer from './layer/sidebar-layer'
13
15
 
14
16
  import Layer, { GetLayerWrap } from './layer'
15
- import Api from './api'
16
17
  import * as Utils from './lib/utils'
17
18
  import * as Ui from './lib/ui'
19
+ import * as Stat from './lib/stat'
18
20
 
19
21
  /**
20
22
  * Artalk
@@ -24,90 +26,45 @@ import * as Ui from './lib/ui'
24
26
  export default class Artalk {
25
27
  public static readonly defaults: ArtalkConfig = defaults
26
28
 
27
- public ctx!: Context
28
29
  public conf!: ArtalkConfig
30
+ public ctx!: Context
29
31
  public $root!: HTMLElement
30
32
 
31
- public api!: Api
32
33
  public checkerLauncher!: CheckerLauncher
33
34
  public editor!: Editor
34
35
  public list!: List
35
36
  public sidebarLayer!: SidebarLayer
36
37
 
37
- constructor(customConf: Partial<ArtalkConfig>) {
38
- // 配置
39
- this.conf = Utils.mergeDeep(Artalk.defaults, customConf)
40
- this.conf.server = this.conf.server.replace(/\/$/, '').replace(/\/api\/?$/, '')
38
+ protected static Plugins: ArtalkPlug[] = [
39
+ Stat.PvCountWidget
40
+ ]
41
41
 
42
- // 默认 pageKey
43
- if (!this.conf.pageKey) {
44
- // @link http://bl.ocks.org/abernier/3070589
45
- this.conf.pageKey = `${window.location.pathname}`
46
- }
47
-
48
- // 默认 pageTitle
49
- if (!this.conf.pageTitle) {
50
- this.conf.pageTitle = `${document.title}`
51
- }
42
+ constructor(customConf: Partial<ArtalkConfig>) {
43
+ /* 初始化基本配置 */
44
+ this.conf = Artalk.HandelBaseConf(customConf)
45
+ if (this.conf.el instanceof HTMLElement) this.$root = this.conf.el
52
46
 
53
- // 列表显示模式
54
- if (this.conf.nestMax && this.conf.nestMax <= 1) {
55
- this.conf.flatMode = true
56
- }
47
+ /* 初始化 Context */
48
+ this.ctx = new ConcreteContext(this.conf, this.$root)
57
49
 
58
- // 装载元素
59
- this.conf.el = this.conf.el || document.createElement('div') // 允许 this.conf.el 为空
50
+ // @ts-ignore 远程加载引用后端的配置
51
+ if (this.conf.useBackendConf) return this.loadConfRemoteAndInitComponents()
60
52
 
61
- if (this.conf.el instanceof HTMLElement) {
62
- this.$root = this.conf.el
63
- } else {
64
- try {
65
- const $root = document.querySelector<HTMLElement>(this.conf.el)
66
- if (!$root) throw Error(`Target element "${this.conf.el}" was not found.`)
67
- this.$root = $root
68
- } catch (e) {
69
- console.error(e)
70
- throw new Error('Please check your Artalk `el` config.')
71
- }
72
- }
73
-
74
- // Context 初始化
75
- this.ctx = new ConcreteContext(this.$root, this.conf)
76
-
77
- // API 初始化
78
- this.api = new Api(this.ctx)
79
- this.ctx.setApi(this.api)
80
-
81
- // 界面初始化
82
- this.$root.classList.add('artalk')
83
- this.$root.innerHTML = ''
84
-
85
- // 初始化组件
86
- if (this.conf.useBackendConf) {
87
- // 复用后端的配置
88
- // @ts-ignore
89
- return (async () => {
90
- await this.loadConfRemote()
91
- this.initCore()
92
- return this // Promise<Artalk>
93
- })()
94
- }
95
-
96
- this.initCore()
53
+ /* 初始化组件 */
54
+ this.initComponents()
97
55
  }
98
56
 
99
- private initCore() {
100
- /* 组件初始化 */
57
+ /** 组件初始化 */
58
+ private initComponents() {
59
+ this.initLocale()
101
60
  this.initLayer()
102
61
  this.initDarkMode()
62
+ Utils.initMarked(this.ctx)
103
63
 
104
64
  // CheckerLauncher
105
65
  this.checkerLauncher = new CheckerLauncher(this.ctx)
106
66
  this.ctx.setCheckerLauncher(this.checkerLauncher)
107
67
 
108
- // 初始化 marked
109
- Utils.initMarked(this.ctx)
110
-
111
68
  // 编辑器
112
69
  this.editor = new Editor(this.ctx)
113
70
  this.ctx.setEditor(this.editor)
@@ -129,18 +86,55 @@ export default class Artalk {
129
86
  // 事件绑定初始化
130
87
  this.initEventBind()
131
88
 
132
- // 其他
133
- this.initCountAndPV()
134
-
135
89
  // 插件初始化
136
90
  Artalk.Plugins.forEach(plugin => {
137
- if (typeof plugin === 'function') {
91
+ if (typeof plugin === 'function')
138
92
  plugin(this.ctx)
139
- }
140
93
  })
141
94
  }
142
95
 
143
- /** 获取远程配置 */
96
+ /** 基本配置初始化 */
97
+ private static HandelBaseConf(customConf: Partial<ArtalkConfig>): ArtalkConfig {
98
+ // 合并默认配置
99
+ const conf: ArtalkConfig = Utils.mergeDeep(Artalk.defaults, customConf)
100
+
101
+ // 绑定元素
102
+ if (typeof conf.el === 'string' && !!conf.el) {
103
+ try {
104
+ const findEl = document.querySelector<HTMLElement>(conf.el)
105
+ if (!findEl) throw Error(`Target element "${conf.el}" was not found.`)
106
+ conf.el = findEl
107
+ } catch (e) {
108
+ console.error(e)
109
+ throw new Error('Please check your Artalk `el` config.')
110
+ }
111
+ }
112
+
113
+ // 服务器配置
114
+ conf.server = conf.server.replace(/\/$/, '').replace(/\/api\/?$/, '')
115
+
116
+ // 默认 pageKey
117
+ if (!conf.pageKey) {
118
+ // @link http://bl.ocks.org/abernier/3070589
119
+ conf.pageKey = `${window.location.pathname}`
120
+ }
121
+
122
+ // 默认 pageTitle
123
+ if (!conf.pageTitle) {
124
+ conf.pageTitle = `${document.title}`
125
+ }
126
+
127
+ return conf
128
+ }
129
+
130
+ /** 初始化组件根据远程加载的配置 */
131
+ private async loadConfRemoteAndInitComponents() {
132
+ await this.loadConfRemote()
133
+ this.initComponents()
134
+ return this
135
+ }
136
+
137
+ /** 远程加载配置 */
144
138
  private async loadConfRemote() {
145
139
  Ui.showLoading(this.$root)
146
140
  let backendConf = {}
@@ -151,7 +145,7 @@ export default class Artalk {
151
145
  Ui.hideLoading(this.$root)
152
146
  }
153
147
 
154
- /** 事件绑定 · 初始化 */
148
+ /** 事件绑定初始化 */
155
149
  private initEventBind() {
156
150
  // 锚点快速跳转评论
157
151
  window.addEventListener('hashchange', () => {
@@ -166,20 +160,34 @@ export default class Artalk {
166
160
  })
167
161
  }
168
162
 
169
- /** 重新加载 */
170
- public reload() {
171
- this.list.fetchComments(0)
163
+ /** 语言初始化 */
164
+ private initLocale() {
165
+ if (typeof this.conf.locale === 'string') {
166
+ if (this.conf.locale === 'auto') { // 自动切换
167
+ this.conf.locale = ((navigator.languages) ? navigator.languages[0] : navigator.language)
168
+ }
169
+
170
+ this.conf.locale = this.conf.locale.replace(
171
+ /^([a-zA-Z]+)(-[a-zA-Z]+)?$/,
172
+ (_, p1: string, p2: string) => (p1.toLowerCase() + (p2 || '').toUpperCase())
173
+ )
174
+
175
+ if (!internalLocales[this.conf.locale]) { // 语言不存在时,使用 en
176
+ console.log(`Locale "${this.conf.locale}" not found.`)
177
+ this.conf.locale = 'en'
178
+ }
179
+ }
172
180
  }
173
181
 
174
182
  /** Layer 初始化 */
175
- initLayer() {
183
+ private initLayer() {
176
184
  // 记录页面原始 Styles
177
185
  Layer.BodyOrgOverflow = document.body.style.overflow
178
186
  Layer.BodyOrgPaddingRight = document.body.style.paddingRight
179
187
  }
180
188
 
181
- /** 暗黑模式 · 初始化 */
182
- public initDarkMode() {
189
+ /** 暗黑模式初始化 */
190
+ private initDarkMode() {
183
191
  if (this.conf.darkMode === 'auto') {
184
192
  // 自动切换暗黑模式,事件监听
185
193
  const darkModeMedia = window.matchMedia('(prefers-color-scheme: dark)')
@@ -190,7 +198,7 @@ export default class Artalk {
190
198
  }
191
199
  }
192
200
 
193
- /** 暗黑模式 · 设定 */
201
+ /** 设置暗黑模式 */
194
202
  public setDarkMode(darkMode: boolean) {
195
203
  const darkModeClassName = 'atk-dark-mode'
196
204
 
@@ -214,45 +222,6 @@ export default class Artalk {
214
222
  }
215
223
  }
216
224
 
217
- /** 初始化评论数和 PV 数量展示元素 */
218
- public async initCountAndPV() {
219
- // 评论数
220
- const countEl = this.conf.countEl
221
- if (countEl && document.querySelector(countEl)) {
222
- this.handleStatCount({ api: 'page_comment', countEl })
223
- }
224
-
225
- // PV
226
- const curtPagePvNum = await this.ctx.getApi().pv()
227
- const pvEl = this.conf.pvEl
228
- if (pvEl && document.querySelector(pvEl)) {
229
- this.handleStatCount({ api: 'page_pv', countEl: pvEl, curtPageCount: curtPagePvNum })
230
- }
231
- }
232
-
233
- private async handleStatCount(args: { api: 'page_pv'|'page_comment', countEl: string, curtPageCount?: number }) {
234
- let pageCounts: {[key: string]: number} = {}
235
-
236
- // 当前页面的统计数
237
- const curtPageKey = this.ctx.conf.pageKey
238
- if (args.curtPageCount) pageCounts[curtPageKey] = args.curtPageCount
239
-
240
- // 查询其他页面的统计数
241
- let queryPageKeys = Array.from(document.querySelectorAll(args.countEl))
242
- .map(e => e.getAttribute('data-page-key') || curtPageKey)
243
- .filter(pageKey => pageCounts[pageKey] === undefined)
244
- queryPageKeys = [...new Set(queryPageKeys)] // 去重
245
- if (queryPageKeys.length > 0) {
246
- const counts: any = await this.ctx.getApi().stat(args.api, queryPageKeys)
247
- pageCounts = { ...pageCounts, ...counts }
248
- }
249
-
250
- document.querySelectorAll(args.countEl).forEach((el) => {
251
- const pageKey = el.getAttribute('data-page-key') || curtPageKey
252
- el.innerHTML = `${Number(pageCounts[pageKey] || 0)}`
253
- })
254
- }
255
-
256
225
  /** 监听事件 */
257
226
  public on<K extends keyof EventPayloadMap>(name: K, handler: Handler<EventPayloadMap[K]>) {
258
227
  this.ctx.on(name, handler, 'external')
@@ -268,11 +237,20 @@ export default class Artalk {
268
237
  this.ctx.trigger(name, payload, 'external')
269
238
  }
270
239
 
271
- /** Plugins */
272
- protected static Plugins: ((ctx: Context) => void)[] = []
240
+ /** 重新加载 */
241
+ public reload() {
242
+ this.ctx.listReload()
243
+ }
273
244
 
274
- /** Enable Plugin */
275
- public static Use(plugin: ((ctx: Context) => void)) {
245
+ /** Use Plugin */
246
+ public static Use(plugin: ArtalkPlug) {
276
247
  this.Plugins.push(plugin)
277
248
  }
249
+
250
+ /** 装载数量统计元素 */
251
+ public static LoadCountWidget(customConf: Partial<ArtalkConfig>) {
252
+ const conf = this.HandelBaseConf(customConf)
253
+ const ctx = new ConcreteContext(conf)
254
+ Stat.initCountWidget({ ctx, pvAdd: false })
255
+ }
278
256
  }
@@ -1,4 +1,3 @@
1
- import Api from '../api'
2
1
  import Comment from './comment'
3
2
  import ActionBtn from '../components/action-btn'
4
3
 
package/src/context.ts CHANGED
@@ -37,13 +37,17 @@ export default class Context implements ContextApi {
37
37
  /* 订阅者模式 */
38
38
  private eventList: Event[] = []
39
39
 
40
- public constructor($root: HTMLElement, conf: ArtalkConfig) {
40
+ public constructor(conf: ArtalkConfig, $root?: HTMLElement) {
41
41
  this.cid = +new Date()
42
42
  this.conf = conf
43
43
  this.user = new User(this)
44
44
 
45
- this.$root = $root
45
+ this.$root = $root || document.createElement('div')
46
46
  this.$root.setAttribute('atk-run-id', this.cid.toString())
47
+ this.$root.classList.add('artalk')
48
+ this.$root.innerHTML = ''
49
+
50
+ this.api = new Api(this)
47
51
  }
48
52
 
49
53
  /* 设置持有的同事类 */
@@ -5,7 +5,6 @@ import Context from '~/types/context'
5
5
  import Component from '../lib/component'
6
6
  import * as Utils from '../lib/utils'
7
7
  import * as Ui from '../lib/ui'
8
- import Api from '../api'
9
8
 
10
9
  import EditorHTML from './editor.html?raw'
11
10
 
@@ -27,7 +27,7 @@
27
27
  padding: 5px;
28
28
  cursor: pointer;
29
29
  user-select: none;
30
- border-radius: 2px;
30
+ border-radius: (@block-radius / 2);
31
31
  font-size: 16px;
32
32
  min-width: 35px;
33
33
 
@@ -1,4 +1,3 @@
1
- import Api from '@/api'
2
1
  import Editor from '../editor'
3
2
  import EditorPlug from './editor-plug'
4
3
 
@@ -1,5 +1,4 @@
1
1
  import * as Utils from '@/lib/utils'
2
- import Api from '@/api'
3
2
  import Editor from '../editor'
4
3
  import EditorPlug from './editor-plug'
5
4
 
@@ -83,7 +82,7 @@ export default class UploadPlug extends EditorPlug {
83
82
 
84
83
  // 未登录提示
85
84
  if (!this.ctx.user.checkHasBasicUserInfo()) {
86
- this.editor.showNotify('填入你的名字邮箱才能上传哦', 'w')
85
+ this.editor.showNotify(this.ctx.$t('uploadLoginMsg'), 'w')
87
86
  return
88
87
  }
89
88
 
package/src/i18n/en.ts CHANGED
@@ -13,6 +13,7 @@ export default {
13
13
  commentFail: 'Failed to comment',
14
14
  restoredMsg: 'Content has been restored',
15
15
  onlyAdminCanReply: 'Only admin can reply',
16
+ uploadLoginMsg: 'Please fill in your name and email to upload',
16
17
 
17
18
  /* List */
18
19
  counter: '{count} Comments',
package/src/i18n/zh-CN.ts CHANGED
@@ -15,6 +15,7 @@ const zhCN: I18n = {
15
15
  commentFail: '评论失败',
16
16
  restoredMsg: '内容已自动恢复',
17
17
  onlyAdminCanReply: '仅管理员可评论',
18
+ uploadLoginMsg: '填入你的名字邮箱才能上传哦',
18
19
 
19
20
  /* List */
20
21
  counter: '{count} 条评论',
@@ -6,7 +6,6 @@ import * as Utils from '@/lib/utils'
6
6
  import * as Ui from '@/lib/ui'
7
7
  import SidebarHTML from './sidebar-layer.html?raw'
8
8
  import Layer from './layer'
9
- import Api from '../api'
10
9
 
11
10
  export interface SidebarShowPayload {
12
11
  view?: 'comments'|'sites'|'pages'|'transfer'
@@ -1,4 +1,3 @@
1
- import Api from '@/api'
2
1
  import * as Utils from '../utils'
3
2
  import { Checker } from '.'
4
3
 
@@ -1,4 +1,3 @@
1
- import Api from '@/api'
2
1
  import * as Utils from '../utils'
3
2
  import * as Ui from '../ui'
4
3
  import { Checker } from '.'
@@ -0,0 +1,63 @@
1
+ import ContextApi from '~/types/context'
2
+ import ArtalkPlug from '~/types/plug'
3
+
4
+ export interface CountConf {
5
+ ctx: ContextApi
6
+
7
+ /** 是否增加当前页面 PV 数 */
8
+ pvAdd?: boolean
9
+ }
10
+
11
+ export const PvCountWidget: ArtalkPlug = (ctx: ContextApi) => {
12
+ initCountWidget({ ctx, pvAdd: true })
13
+ }
14
+
15
+ /** 初始化评论数和 PV 数量展示元素 */
16
+ export async function initCountWidget(p: CountConf) {
17
+ // 评论数
18
+ const countEl = p.ctx.conf.countEl
19
+ if (countEl && document.querySelector(countEl)) {
20
+ handleStatCount(p, { api: 'page_comment', countEl })
21
+ }
22
+
23
+ // PV
24
+ const curtPagePvNum = p.pvAdd ? await p.ctx.getApi().pv() : undefined
25
+ const pvEl = p.ctx.conf.pvEl
26
+ if (pvEl && document.querySelector(pvEl)) {
27
+ handleStatCount(p, {
28
+ api: 'page_pv',
29
+ countEl: pvEl,
30
+ curtPageCount: curtPagePvNum,
31
+ })
32
+ }
33
+ }
34
+
35
+ export async function handleStatCount(
36
+ p: CountConf,
37
+ args: {
38
+ api: 'page_pv' | 'page_comment'
39
+ countEl: string
40
+ curtPageCount?: number
41
+ }
42
+ ) {
43
+ let pageCounts: { [key: string]: number } = {}
44
+
45
+ // 当前页面的统计数
46
+ const curtPageKey = p.ctx.conf.pageKey
47
+ if (args.curtPageCount) pageCounts[curtPageKey] = args.curtPageCount
48
+
49
+ // 查询其他页面的统计数
50
+ let queryPageKeys = Array.from(document.querySelectorAll(args.countEl))
51
+ .map((e) => e.getAttribute('data-page-key') || curtPageKey)
52
+ .filter((pageKey) => pageCounts[pageKey] === undefined)
53
+ queryPageKeys = [...new Set(queryPageKeys)] // 去重
54
+ if (queryPageKeys.length > 0) {
55
+ const counts: any = await p.ctx.getApi().stat(args.api, queryPageKeys)
56
+ pageCounts = { ...pageCounts, ...counts }
57
+ }
58
+
59
+ document.querySelectorAll(args.countEl).forEach((el) => {
60
+ const pageKey = el.getAttribute('data-page-key') || curtPageKey
61
+ el.innerHTML = `${Number(pageCounts[pageKey] || 0)}`
62
+ })
63
+ }
@@ -3,7 +3,6 @@ import Context from '~/types/context'
3
3
  import Component from '../lib/component'
4
4
  import * as Utils from '../lib/utils'
5
5
  import * as Ui from '../lib/ui'
6
- import Api from '../api'
7
6
  import Comment from '../comment'
8
7
  import Pagination from '../components/pagination'
9
8
  import ReadMoreBtn from '../components/read-more-btn'
package/src/list/list.ts CHANGED
@@ -4,7 +4,6 @@ import { ListData, NotifyData } from '~/types/artalk-data'
4
4
  import Context from '~/types/context'
5
5
  import * as Utils from '../lib/utils'
6
6
  import * as Ui from '../lib/ui'
7
- import Api from '../api'
8
7
  import ListHTML from './list.html?raw'
9
8
  import ListLite from './list-lite'
10
9
 
@@ -26,14 +25,15 @@ export default class List extends ListLite {
26
25
  this.$el = el
27
26
 
28
27
  // 平铺模式
29
- let flatMode = false
30
- if (this.ctx.conf.flatMode === 'auto') {
28
+ if (this.ctx.conf.flatMode === true) {
29
+ this.flatMode = true // 遵循配置总是开启平铺模式
30
+ } else if (this.conf.nestMax && this.conf.nestMax <= 1) {
31
+ this.flatMode = true // 嵌套层数值无效时,强制开启平铺模式
32
+ } else if (this.ctx.conf.flatMode === 'auto') {
33
+ // 自动判断启用平铺模式
31
34
  if (window.matchMedia("(max-width: 768px)").matches)
32
- flatMode = true
33
- } else if (this.ctx.conf.flatMode === true) {
34
- flatMode = true
35
+ this.flatMode = true
35
36
  }
36
- this.flatMode = flatMode
37
37
 
38
38
  // 分页模式
39
39
  this.pageMode = this.conf.pagination.readMore ? 'read-more' : 'pagination'
@@ -1,4 +1,3 @@
1
- @font-family: "Helvetica Neue", "PingFangSC-Light", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif;
2
1
  @font-size: 14px;
3
2
  @line-height: 1.6em;
4
- @block-radius: 4px;
3
+ @block-radius: 6px;
@@ -51,7 +51,7 @@
51
51
  img {
52
52
  width: 50px;
53
53
  height: 50px;
54
- border-radius: 3px;
54
+ border-radius: (@block-radius / 2);
55
55
  }
56
56
  }
57
57
 
@@ -62,7 +62,7 @@
62
62
  & > .atk-header {
63
63
  line-height: 1;
64
64
  font-size: 13px;
65
- margin-bottom: 3px;
65
+ margin-bottom: .5em;
66
66
  overflow: hidden;
67
67
  position: relative;
68
68
  display: flex;
@@ -114,7 +114,7 @@
114
114
  background: var(--at-color-bg-grey);
115
115
  padding: 0px 6px;
116
116
  line-height: 17px;
117
- border-radius: 3px;
117
+ border-radius: (@block-radius / 2);
118
118
 
119
119
  &:not(:last-child) {
120
120
  margin-right: 6px;
@@ -23,7 +23,7 @@
23
23
  font-size: 14px;
24
24
  background: transparent;
25
25
  border: 2px solid transparent;
26
- border-radius: calc(@block-radius / 2);
26
+ border-radius: (@block-radius / 2);
27
27
  padding: 6px 5px;
28
28
  resize: none;
29
29
  outline: none;
@@ -44,7 +44,7 @@
44
44
  font-size: 15px;
45
45
  background-color: var(--at-color-bg);
46
46
  border: 2px solid transparent;
47
- border-radius: calc(@block-radius / 2);
47
+ border-radius: (@block-radius / 2);
48
48
  width: 100%;
49
49
  min-height: 120px;
50
50
  margin-top: 2px;
@@ -61,6 +61,7 @@
61
61
  background-color: var(--at-color-bg);
62
62
  border-top: 1px solid var(--at-color-border);
63
63
  padding: 5px 15px;
64
+ margin-top: 10px;
64
65
  // background: repeating-linear-gradient(145deg, #f2f2f2, #f2f2f2 15px, #fff 0, #fff 30px);
65
66
  }
66
67
 
@@ -68,8 +69,8 @@
68
69
  z-index: 2;
69
70
  position: absolute;
70
71
  right: 7px;
71
- bottom: 8px;
72
- max-width: calc(100% - 20px);
72
+ bottom: 2px;
73
+ max-width: (100% - 20px);
73
74
  height: 30px;
74
75
  line-height: 30px;
75
76
  font-size: 14px;
@@ -79,7 +80,7 @@
79
80
  text-overflow: ellipsis;
80
81
  white-space: nowrap;
81
82
  cursor: pointer;
82
- border-radius: @block-radius;
83
+ border-radius: (@block-radius / 2);
83
84
 
84
85
  .atk-text {
85
86
  }
@@ -125,11 +126,12 @@
125
126
 
126
127
  .atk-plug-btn {
127
128
  padding: 0 8px;
129
+ line-height: 24px;
128
130
  cursor: pointer;
129
131
  color: var(--at-color-grey);
130
132
  font-size: @font-size;
131
133
  user-select: none;
132
- border-radius: @block-radius;
134
+ border-radius: (@block-radius / 2);
133
135
 
134
136
  &:not(:last-child) {
135
137
  margin-right: 2px;
@@ -169,7 +171,7 @@
169
171
  cursor: pointer;
170
172
  transition: opacity 0.3s ease-in-out;
171
173
  outline: none;
172
- border-radius: @block-radius;
174
+ border-radius: (@block-radius / 2);
173
175
 
174
176
  &:active {
175
177
  opacity: 0.9;
@@ -22,7 +22,7 @@
22
22
  border-left: 3px solid transparent;
23
23
  border-right: 3px solid transparent;
24
24
  margin-top: -1px;
25
- margin-left: 0.4rem;
25
+ margin-left: 0.8rem;
26
26
  display: inline-block;
27
27
  }
28
28
 
@@ -46,7 +46,7 @@
46
46
  padding: 0.6rem 0;
47
47
  border: 1px solid var(--at-color-border);
48
48
  text-align: center;
49
- border-radius: 0.25rem;
49
+ border-radius: @block-radius;
50
50
  white-space: nowrap;
51
51
  margin: 0;
52
52
  list-style: none;