artalk 2.2.2 → 2.2.5

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.
@@ -0,0 +1,222 @@
1
+ const win = (window as any) || {}
2
+ const nav = navigator || {}
3
+
4
+ function Detect (userAgent?: string) {
5
+ const u = String(userAgent || nav.userAgent)
6
+ const dest = {
7
+ os: '',
8
+ osVersion: '',
9
+ engine: '',
10
+ browser: '',
11
+ device: '',
12
+ language: '',
13
+ version: ''
14
+ }
15
+
16
+ // 内核
17
+ const engineMatch = {
18
+ Trident: u.includes('Trident') || u.includes('NET CLR'),
19
+ Presto: u.includes('Presto'),
20
+ WebKit: u.includes('AppleWebKit'),
21
+ Gecko: u.includes('Gecko/')
22
+ }
23
+
24
+ // 浏览器
25
+ const browserMatch = {
26
+ Safari: u.includes('Safari'),
27
+ Chrome: u.includes('Chrome') || u.includes('CriOS'),
28
+ IE: u.includes('MSIE') || u.includes('Trident'),
29
+ Edge: u.includes('Edge') || u.includes('Edg'),
30
+ Firefox: u.includes('Firefox') || u.includes('FxiOS'),
31
+ 'Firefox Focus': u.includes('Focus'),
32
+ Chromium: u.includes('Chromium'),
33
+ Opera: u.includes('Opera') || u.includes('OPR'),
34
+ Vivaldi: u.includes('Vivaldi'),
35
+ Yandex: u.includes('YaBrowser'),
36
+ Kindle: u.includes('Kindle') || u.includes('Silk/'),
37
+ 360: u.includes('360EE') || u.includes('360SE'),
38
+ UC: u.includes('UC') || u.includes(' UBrowser'),
39
+ QQBrowser: u.includes('QQBrowser'),
40
+ QQ: u.includes('QQ/'),
41
+ Baidu: u.includes('Baidu') || u.includes('BIDUBrowser'),
42
+ Maxthon: u.includes('Maxthon'),
43
+ Sogou: u.includes('MetaSr') || u.includes('Sogou'),
44
+ LBBROWSER: u.includes('LBBROWSER'),
45
+ '2345Explorer': u.includes('2345Explorer'),
46
+ TheWorld: u.includes('TheWorld'),
47
+ MIUI: u.includes('MiuiBrowser'),
48
+ Quark: u.includes('Quark'),
49
+ Qiyu: u.includes('Qiyu'),
50
+ Wechat: u.includes('MicroMessenger'),
51
+ Taobao: u.includes('AliApp(TB'),
52
+ Alipay: u.includes('AliApp(AP'),
53
+ Weibo: u.includes('Weibo'),
54
+ Douban: u.includes('com.douban.frodo'),
55
+ Suning: u.includes('SNEBUY-APP'),
56
+ iQiYi: u.includes('IqiyiApp'),
57
+ }
58
+
59
+ // 系统或平台
60
+ const osMatch = {
61
+ Windows: u.includes('Windows'),
62
+ Linux: u.includes('Linux') || u.includes('X11'),
63
+ 'macOS': u.includes('Macintosh'),
64
+ Android: u.includes('Android') || u.includes('Adr'),
65
+ Ubuntu: u.includes('Ubuntu'),
66
+ FreeBSD: u.includes('FreeBSD'),
67
+ Debian: u.includes('Debian'),
68
+ 'Windows Phone': u.includes('IEMobile') || u.includes('Windows Phone'),
69
+ BlackBerry: u.includes('BlackBerry') || u.includes('RIM'),
70
+ MeeGo: u.includes('MeeGo'),
71
+ Symbian: u.includes('Symbian'),
72
+ iOS: u.includes('like Mac OS X'),
73
+ 'Chrome OS': u.includes('CrOS'),
74
+ WebOS: u.includes('hpwOS'),
75
+ }
76
+
77
+ // 设备
78
+ const deviceMatch = {
79
+ Mobile: u.includes('Mobi') || u.includes('iPh') || u.includes('480'),
80
+ Tablet: u.includes('Tablet') || u.includes('Pad') || u.includes('Nexus 7')
81
+ }
82
+
83
+ // 修正
84
+ if (deviceMatch.Mobile) {
85
+ deviceMatch.Mobile = !(u.includes('iPad'))
86
+ } else if (browserMatch.Chrome && u.includes('Edg')) {
87
+ // Chrome 内核的 Edge
88
+ browserMatch.Chrome = false
89
+ browserMatch.Edge = true
90
+ } else if (win.showModalDialog && win.chrome) {
91
+ browserMatch.Chrome = false
92
+ browserMatch['360'] = true
93
+ }
94
+
95
+ // 默认设备
96
+ dest.device = 'PC'
97
+
98
+ // 语言
99
+ dest.language = (() => {
100
+ const g = ((nav as any).browserLanguage || nav.language)
101
+ const arr = g.split('-')
102
+ if (arr[1]) arr[1] = arr[1].toUpperCase()
103
+ return arr.join('_')
104
+ })()
105
+
106
+ // 应用判断数据
107
+ const hash = {
108
+ engine: engineMatch,
109
+ browser: browserMatch,
110
+ os: osMatch,
111
+ device: deviceMatch,
112
+ }
113
+ Object.entries(hash).forEach(([type, match]) => {
114
+ Object.entries(match).forEach(([name, result]) => {
115
+ if (result === true) dest[type] = name
116
+ })
117
+ })
118
+
119
+ // 系统版本信息
120
+ const osVersion = {
121
+ Windows: () => {
122
+ const v = u.replace(/^.*Windows NT ([\d.]+);.*$/, '$1')
123
+ const wvHash = {
124
+ '6.4': '10',
125
+ '6.3': '8.1',
126
+ '6.2': '8',
127
+ '6.1': '7',
128
+ '6.0': 'Vista',
129
+ '5.2': 'XP',
130
+ '5.1': 'XP',
131
+ '5.0': '2000',
132
+ '10.0': '10',
133
+ '11.0': '11' // 自定的,不是微软官方的判断方法
134
+ }
135
+ return wvHash[v] || v
136
+ },
137
+ Android: () => u.replace(/^.*Android ([\d.]+);.*$/, '$1'),
138
+ iOS: () => u.replace(/^.*OS ([\d_]+) like.*$/, '$1').replace(/_/g, '.'),
139
+ Debian: () => u.replace(/^.*Debian\/([\d.]+).*$/, '$1'),
140
+ 'Windows Phone': () => u.replace(/^.*Windows Phone( OS)? ([\d.]+);.*$/, '$2'),
141
+ 'macOS': () => u.replace(/^.*Mac OS X ([\d_]+).*$/, '$1').replace(/_/g, '.'),
142
+ WebOS: () => u.replace(/^.*hpwOS\/([\d.]+);.*$/, '$1')
143
+ }
144
+
145
+ dest.osVersion = ''
146
+ if (osVersion[dest.os]) {
147
+ dest.osVersion = osVersion[dest.os]()
148
+ if (dest.osVersion === u) {
149
+ dest.osVersion = ''
150
+ }
151
+ }
152
+
153
+ // 浏览器版本信息
154
+ const version = {
155
+ Safari: () => u.replace(/^.*Version\/([\d.]+).*$/, '$1'),
156
+ Chrome: () => u.replace(/^.*Chrome\/([\d.]+).*$/, '$1').replace(/^.*CriOS\/([\d.]+).*$/, '$1'),
157
+ IE: () => u.replace(/^.*MSIE ([\d.]+).*$/, '$1').replace(/^.*rv:([\d.]+).*$/, '$1'),
158
+ Edge: () => u.replace(/^.*(Edge|Edg|Edg[A-Z]{1})\/([\d.]+).*$/, '$2'),
159
+ Firefox: () => u.replace(/^.*Firefox\/([\d.]+).*$/, '$1').replace(/^.*FxiOS\/([\d.]+).*$/, '$1'),
160
+ 'Firefox Focus': () => u.replace(/^.*Focus\/([\d.]+).*$/, '$1'),
161
+ Chromium: () => u.replace(/^.*Chromium\/([\d.]+).*$/, '$1'),
162
+ Opera: () => u.replace(/^.*Opera\/([\d.]+).*$/, '$1').replace(/^.*OPR\/([\d.]+).*$/, '$1'),
163
+ Vivaldi: () => u.replace(/^.*Vivaldi\/([\d.]+).*$/, '$1'),
164
+ Yandex: () => u.replace(/^.*YaBrowser\/([\d.]+).*$/, '$1'),
165
+ Kindle: () => u.replace(/^.*Version\/([\d.]+).*$/, '$1'),
166
+ Maxthon: () => u.replace(/^.*Maxthon\/([\d.]+).*$/, '$1'),
167
+ QQBrowser: () => u.replace(/^.*QQBrowser\/([\d.]+).*$/, '$1'),
168
+ QQ: () => u.replace(/^.*QQ\/([\d.]+).*$/, '$1'),
169
+ Baidu: () => u.replace(/^.*BIDUBrowser[\s/]([\d.]+).*$/, '$1'),
170
+ UC: () => u.replace(/^.*UC?Browser\/([\d.]+).*$/, '$1'),
171
+ Sogou: () => u.replace(/^.*SE ([\d.X]+).*$/, '$1').replace(/^.*SogouMobileBrowser\/([\d.]+).*$/, '$1'),
172
+ '2345Explorer': () => u.replace(/^.*2345Explorer\/([\d.]+).*$/, '$1'),
173
+ TheWorld: () => u.replace(/^.*TheWorld ([\d.]+).*$/, '$1'),
174
+ MIUI: () => u.replace(/^.*MiuiBrowser\/([\d.]+).*$/, '$1'),
175
+ Quark: () => u.replace(/^.*Quark\/([\d.]+).*$/, '$1'),
176
+ Qiyu: () => u.replace(/^.*Qiyu\/([\d.]+).*$/, '$1'),
177
+ Wechat: () => u.replace(/^.*MicroMessenger\/([\d.]+).*$/, '$1'),
178
+ Taobao: () => u.replace(/^.*AliApp\(TB\/([\d.]+).*$/, '$1'),
179
+ Alipay: () => u.replace(/^.*AliApp\(AP\/([\d.]+).*$/, '$1'),
180
+ Weibo: () => u.replace(/^.*weibo__([\d.]+).*$/, '$1'),
181
+ Douban: () => u.replace(/^.*com.douban.frodo\/([\d.]+).*$/, '$1'),
182
+ Suning: () => u.replace(/^.*SNEBUY-APP([\d.]+).*$/, '$1'),
183
+ iQiYi: () => u.replace(/^.*IqiyiVersion\/([\d.]+).*$/, '$1'),
184
+ }
185
+
186
+ dest.version = ''
187
+ if (version[dest.browser]) {
188
+ dest.version = version[dest.browser]()
189
+ if (dest.version === u) {
190
+ dest.version = ''
191
+ }
192
+ }
193
+
194
+ // 简化版本号
195
+ /* if (_this.osVersion.indexOf('.')) {
196
+ _this.osVersion = _this.osVersion.substring(0, _this.osVersion.indexOf('.'))
197
+ } */
198
+ if (dest.version.indexOf('.')) {
199
+ dest.version = dest.version.substring(0, dest.version.indexOf('.'))
200
+ }
201
+
202
+ // 修正
203
+ if (dest.os === 'iOS' && u.includes('iPad')) {
204
+ dest.os = 'iPadOS'
205
+ } else if (dest.browser === 'Edge' && !u.includes('Edg')) {
206
+ dest.engine = 'EdgeHTML'
207
+ } else if (dest.browser === 'MIUI') {
208
+ dest.os = 'Android'
209
+ } else if (dest.browser === 'Chrome' && Number(dest.version) > 27) {
210
+ dest.engine = 'Blink'
211
+ } else if (dest.browser === 'Opera' && Number(dest.version) > 12) {
212
+ dest.engine = 'Blink'
213
+ } else if (dest.browser === 'Yandex') {
214
+ dest.engine = 'Blink'
215
+ } else if (dest.browser === undefined) {
216
+ dest.browser = 'Unknow App'
217
+ }
218
+
219
+ return dest
220
+ }
221
+
222
+ export default Detect
package/src/lib/utils.ts CHANGED
@@ -143,32 +143,41 @@ export function versionCompare(a: string, b: string) {
143
143
  /** 初始化 marked */
144
144
  export function initMarked(ctx: Context) {
145
145
  const renderer = new libMarked.Renderer()
146
- const linkRenderer = renderer.link
146
+ const orgLinkRenderer = renderer.link
147
147
  renderer.link = (href, title, text) => {
148
148
  const localLink = href?.startsWith(`${window.location.protocol}//${window.location.hostname}`);
149
- const html = linkRenderer.call(renderer as any, href, title, text);
149
+ const html = orgLinkRenderer.call(renderer as any, href, title, text);
150
150
  return html.replace(/^<a /, `<a target="_blank" ${!localLink ? `rel="noreferrer noopener nofollow"` : ''} `);
151
151
  }
152
152
 
153
+ renderer.code = (block, lang) => {
154
+ // Colorize the block only if the language is known to highlight.js
155
+ const realLang = (!lang ? 'plaintext' : lang)
156
+ let colorized = block
157
+ if ((window as any).hljs) {
158
+ if (realLang && (window as any).hljs.getLanguage(realLang)) {
159
+ colorized = (window as any).hljs.highlight(realLang, block).value
160
+ }
161
+ } else {
162
+ colorized = hanabi(block)
163
+ }
164
+
165
+ return `<pre rel="${realLang}">\n`
166
+ + `<code class="hljs language-${realLang}">${colorized.replace(/&amp;/g, '&')}</code>\n`
167
+ + `</pre>`
168
+ }
169
+
153
170
  // @see https://github.com/markedjs/marked/blob/4afb228d956a415624c4e5554bb8f25d047676fe/src/Tokenizer.js#L329
154
171
  const nMarked = libMarked
155
172
  libMarked.setOptions({
156
173
  renderer,
157
- highlight: (code) => hanabi(code),
158
174
  pedantic: false,
159
175
  gfm: true,
160
176
  breaks: true,
161
177
  smartLists: true,
162
178
  smartypants: true,
163
179
  xhtml: false,
164
- sanitize: true,
165
- sanitizer: (html) => insane(html, {
166
- ...insane.defaults,
167
- allowedAttributes: {
168
- ...insane.defaults.allowedAttributes,
169
- img: ['src', 'atk-emoticon']
170
- },
171
- }),
180
+ sanitize: false,
172
181
  silent: true,
173
182
  })
174
183
 
@@ -177,29 +186,89 @@ export function initMarked(ctx: Context) {
177
186
 
178
187
  /** 解析 markdown */
179
188
  export function marked(ctx: Context, src: string): string {
180
- return ctx.markedInstance.parse(src)
189
+ // @link https://github.com/markedjs/marked/discussions/1232
190
+ // @link https://gist.github.com/lionel-rowe/bb384465ba4e4c81a9c8dada84167225
191
+ let dest = insane(ctx.markedInstance.parse(src), {
192
+ allowedClasses: {},
193
+ allowedSchemes: ['http', 'https', 'mailto'],
194
+ allowedTags: [
195
+ 'a', 'abbr', 'article', 'b', 'blockquote', 'br', 'caption', 'code', 'del', 'details', 'div', 'em',
196
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'main', 'mark',
197
+ 'ol', 'p', 'pre', 'section', 'span', 'strike', 'strong', 'sub', 'summary', 'sup', 'table',
198
+ 'tbody', 'td', 'th', 'thead', 'tr', 'u', 'ul'
199
+ ],
200
+ allowedAttributes: {
201
+ '*': ['title', 'accesskey'],
202
+ a: ['href', 'name', 'target', 'aria-label', 'rel'],
203
+ img: ['src', 'alt', 'title', 'atk-emoticon', 'aria-label'],
204
+ // for code highlight
205
+ code: ['class'],
206
+ span: ['class', 'style'],
207
+ },
208
+ filter: node => {
209
+ // allow hljs style
210
+ const allowed = [
211
+ [ 'code', /^hljs\W+language-(.*)$/ ],
212
+ [ 'span', /^(hljs-.*)$/ ]
213
+ ]
214
+ allowed.forEach(([ tag, reg ]) => {
215
+ if (
216
+ node.tag === tag
217
+ && !!node.attrs.class
218
+ && !(reg as RegExp).test(node.attrs.class)
219
+ ) {
220
+ delete node.attrs.class
221
+ }
222
+ })
223
+
224
+ // allow <span> set color sty
225
+ if (node.tag === 'span' && !!node.attrs.style
226
+ && !/^color:(\W+)?#[0-9a-f]{3,6};?$/i.test(node.attrs.style)) {
227
+ delete node.attrs.style
228
+ }
229
+
230
+ return true
231
+ }
232
+ })
233
+
234
+ // 内容替换器
235
+ ctx.markedReplacers.forEach((replacer) => {
236
+ if (typeof replacer === 'function') dest = replacer(dest)
237
+ })
238
+
239
+ return dest
181
240
  }
182
241
 
183
242
  /** 获取修正后的 UserAgent */
184
243
  export async function getCorrectUserAgent() {
185
244
  const uaRaw = navigator.userAgent
186
- const uaData = (navigator as any).userAgentData // @link https://web.dev/migrate-to-ua-ch/
187
- if (!uaData || !uaData.getHighEntropyValues) {
245
+ if (!(navigator as any).userAgentData || !(navigator as any).userAgentData.getHighEntropyValues) {
188
246
  return uaRaw
189
247
  }
190
248
 
191
- // microsoft f******k you!!!!!
192
- // @link https://docs.microsoft.com/en-us/microsoft-edge/web-platform/how-to-detect-win11
249
+ // @link https://web.dev/migrate-to-ua-ch/
250
+ // @link https://web.dev/user-agent-client-hints/
251
+ const uaData = (navigator as any).userAgentData
193
252
  let uaGot: any = null
194
253
  try {
195
254
  uaGot = await uaData.getHighEntropyValues(["platformVersion"])
196
255
  } catch (err) { console.error(err); return uaRaw }
197
-
198
- if (uaData.platform !== "Windows") { return uaRaw }
199
256
  const majorPlatformVersion = Number(uaGot.platformVersion.split('.')[0])
200
- if (majorPlatformVersion >= 13) {
201
- // Win11 样本:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
202
- return uaRaw.replace(/Windows\W+NT\W+10.0/, 'Windows NT 11.0')
257
+
258
+ if (uaData.platform === "Windows") {
259
+ if (majorPlatformVersion >= 13) { // @link https://docs.microsoft.com/en-us/microsoft-edge/web-platform/how-to-detect-win11
260
+ // @date 2022-4-29
261
+ // Win 11 样本:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36"
262
+ return uaRaw.replace(/Windows NT 10.0/, 'Windows NT 11.0')
263
+ }
264
+ }
265
+ if (uaData.platform === "macOS") {
266
+ if (majorPlatformVersion >= 11) { // 11 => BigSur
267
+ // @date 2022-4-29
268
+ // (Intel Chip) macOS 12.3 样本:"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
269
+ // (Arm Chip) macOS 样本:"Mozilla/5.0 (Macintosh; ARM Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15"
270
+ return uaRaw.replace(/(Mac OS X \d+_\d+_\d+|Mac OS X)/, `Mac OS X ${uaGot.platformVersion.replace(/\./g, '_')}`)
271
+ }
203
272
  }
204
273
 
205
274
  return uaRaw
@@ -167,6 +167,7 @@
167
167
  border-left: 3px solid #eee;
168
168
  margin-bottom: 10px;
169
169
  position: relative;
170
+ margin-top: 10px;
170
171
 
171
172
  .atk-meta {
172
173
  font-size: 15px;
@@ -7,28 +7,48 @@
7
7
  }
8
8
 
9
9
  .artalk, .atk-layer-wrap {
10
+ line-height: @line-height;
11
+ color: var(--at-color-font);
12
+ font-family: @font-family;
13
+ word-wrap: break-word;
14
+ word-break: break-all;
15
+
10
16
  * {
11
17
  box-sizing: border-box;
12
- line-height: @line-height;
18
+ }
19
+
20
+ input, textarea, button, optgroup, select {
21
+ font-family: inherit;
22
+ color: inherit;
23
+ font-size: inherit;
24
+ }
25
+
26
+ @codeFont: source code pro, Consolas, Monaco, Menlo, sans-serif;
27
+
28
+ code {
29
+ font-family: @codeFont;
30
+ margin: 0 .3em;
31
+ padding: .1em .2em;
32
+ background-color: var(--at-color-bg-grey);
13
33
  color: var(--at-color-font);
14
- font-family: @font-family;
15
- word-wrap: break-word;
16
- word-break: break-all;
34
+ border-radius: @block-radius;
17
35
  }
18
36
 
19
37
  pre {
20
- padding: 10px;
38
+ margin: 10px 0 0 0;
39
+ padding: 0;
40
+ line-height: 0;
41
+ }
42
+
43
+ pre code {
44
+ * { font-family: @codeFont; }
21
45
  line-height: @line-height;
46
+ display: block;
47
+ padding: 10px 15px;
48
+ white-space: pre-wrap;
22
49
  background-color: var(--at-color-bg-grey);
23
50
  color: var(--at-color-font);
24
- padding: 10px 15px;
25
- border-radius: @block-radius;
26
51
  margin: 0;
27
- font-family: Source Code Pro,courier new,Input Mono,PT Mono,SFMono-Regular,Consolas,Monaco,Menlo,PingFang SC,Liberation Mono,Microsoft YaHei,Courier,monospace;
28
-
29
- code {
30
- white-space: pre-wrap;
31
- }
32
52
  }
33
53
 
34
54
  a {
@@ -55,6 +75,28 @@
55
75
  img {
56
76
  max-width: 100%;
57
77
  }
78
+
79
+ table {
80
+ width: 100%;
81
+ border-collapse: collapse;
82
+ border-spacing: 0;
83
+ margin-bottom: 1.5em;
84
+ font-size: .96em
85
+ }
86
+
87
+ td, th {
88
+ text-align: left;
89
+ padding: 4px 8px 4px 10px;
90
+ border: 1px solid var(--at-color-border)
91
+ }
92
+
93
+ td {
94
+ vertical-align: top
95
+ }
96
+
97
+ tr:nth-child(even) {
98
+ background-color: var(--at-color-bg-grey);
99
+ }
58
100
  }
59
101
 
60
102
  .atk-hide {
@@ -156,6 +198,9 @@
156
198
  .atk-fade-out {
157
199
  animation: atkFadeOut both .2s;
158
200
  }
201
+ .atk-rotate {
202
+ animation: atkRotate 2s linear infinite;
203
+ }
159
204
 
160
205
  @keyframes atkFadeIn {
161
206
  0% { opacity: 0 }
@@ -167,6 +212,11 @@
167
212
  0% {}
168
213
  }
169
214
 
215
+ @keyframes atkRotate {
216
+ from { transform: rotate(0deg); }
217
+ to { transform: rotate(360deg); }
218
+ }
219
+
170
220
  i.atk-icon {
171
221
  width: 20px;
172
222
  height: 20px;
@@ -175,6 +225,7 @@ i.atk-icon {
175
225
  background-repeat: no-repeat;
176
226
  mask-repeat: no-repeat;
177
227
  mask-position: center;
228
+ mask-size: contain;
178
229
  }
179
230
 
180
231
  .atk-icon-sync {
package/types/event.d.ts CHANGED
@@ -19,7 +19,7 @@ export interface EventPayloadMap {
19
19
  'list-refresh-ui': undefined // 刷新 List UI
20
20
 
21
21
  // Sidebar
22
- 'sidebar-show': undefined // 侧边栏显示
22
+ 'sidebar-show': SidebarShowPayload // 侧边栏显示
23
23
  'sidebar-hide': undefined // 侧边栏隐藏
24
24
 
25
25
  // Editor
@@ -70,6 +70,10 @@ export interface EditorReplyPayload {
70
70
  scroll?: boolean
71
71
  }
72
72
 
73
+ export interface SidebarShowPayload {
74
+ view?: 'comments'|'sites'|'pages'|'transfer'|string
75
+ }
76
+
73
77
  // ============================================
74
78
  export interface Handler<P> {
75
79
  (payload: P): void