From eef368abd0c0dfcd76d2a48bf96394c1e11de01d Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 13 May 2023 20:50:16 +0900 Subject: [PATCH 001/213] Update about-misskey.vue --- packages/frontend/src/pages/about-misskey.vue | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index 9e0594db3c..b487916ff6 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -86,8 +86,13 @@ </FormSection> <FormSection> <template #label>Special thanks</template> - <div style="text-align: center;"> - <a style="display: inline-block;" class="dcadvirth" title="DC Advirth" href="https://www.dotchain.ltd/advirth" target="_blank"><img width="200" src="https://misskey-hub.net/sponsors/dcadvirth.png" alt="DC Advirth"></a> + <div class="_gaps" style="text-align: center;"> + <div> + <a style="display: inline-block;" class="masknetwork" title="Mask Network" href="https://mask.io/" target="_blank"><img width="200" src="https://misskey-hub.net/sponsors/masknetwork.png" alt="Mask Network"></a> + </div> + <div> + <a style="display: inline-block;" class="dcadvirth" title="DC Advirth" href="https://www.dotchain.ltd/advirth" target="_blank"><img width="200" src="https://misskey-hub.net/sponsors/dcadvirth.png" alt="DC Advirth"></a> + </div> </div> </FormSection> </div> From 9166a58c5fa422c0cd5989bdff39ee6c62e382bf Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 13 May 2023 20:50:21 +0900 Subject: [PATCH 002/213] :art: --- packages/frontend/src/components/MkAnimBg.vue | 226 ++++++++++++++++++ .../src/components/MkUserSetupDialog.vue | 3 + 2 files changed, 229 insertions(+) create mode 100644 packages/frontend/src/components/MkAnimBg.vue diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue new file mode 100644 index 0000000000..df0765d494 --- /dev/null +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -0,0 +1,226 @@ +<template> +<canvas ref="canvasEl" style="width: 100%; height: 100%;"></canvas> +</template> + +<script lang="ts" setup> +import { onMounted, onUnmounted, shallowRef } from 'vue'; +import { defaultStore } from '@/store'; + +const canvasEl = shallowRef<HTMLCanvasElement>(); + +function loadShader(gl, type, source) { + const shader = gl.createShader(type); + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + alert( + `falied to compile shader: ${gl.getShaderInfoLog(shader)}`, + ); + gl.deleteShader(shader); + return null; + } + + return shader; +} + +function initShaderProgram(gl, vsSource, fsSource) { + const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); + const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); + + const shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + alert( + `failed to init shader: ${gl.getProgramInfoLog( + shaderProgram, + )}`, + ); + return null; + } + + return shaderProgram; +} + +let handle: ReturnType<typeof window['requestAnimationFrame']> | null = null; + +onMounted(() => { + const canvas = canvasEl.value!; + const gl = canvas.getContext('webgl', { premultipliedAlpha: true }); + + if (gl == null) return; + + gl.clearColor(0.0, 0.0, 0.0, 0.0); + gl.clear(gl.COLOR_BUFFER_BIT); + + const positionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + + const shaderProgram = initShaderProgram(gl, ` + attribute vec2 vertex; + + varying vec2 v_pos; + + void main() { + gl_Position = vec4(vertex, 0.0, 1.0); + v_pos = vertex; + } + `, ` + precision mediump float; + + vec3 mod289(vec3 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + + vec2 mod289(vec2 x) { + return x - floor(x * (1.0 / 289.0)) * 289.0; + } + + vec3 permute(vec3 x) { + return mod289(((x*34.0)+1.0)*x); + } + + float snoise(vec2 v) { + const vec4 C = vec4(0.211324865405187, + 0.366025403784439, + -0.577350269189626, + 0.024390243902439); + + vec2 i = floor(v + dot(v, C.yy) ); + vec2 x0 = v - i + dot(i, C.xx); + + vec2 i1; + i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); + vec4 x12 = x0.xyxy + C.xxzz; + x12.xy -= i1; + + i = mod289(i); + vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + + i.x + vec3(0.0, i1.x, 1.0 )); + + vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); + m = m*m ; + m = m*m ; + + vec3 x = 2.0 * fract(p * C.www) - 1.0; + vec3 h = abs(x) - 0.5; + vec3 ox = floor(x + 0.5); + vec3 a0 = x - ox; + + m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); + + vec3 g; + g.x = a0.x * x0.x + h.x * x0.y; + g.yz = a0.yz * x12.xz + h.yz * x12.yw; + return 130.0 * dot(m, g); + } + + uniform float u_time; + uniform vec2 u_resolution; + uniform float u_spread; + uniform float u_speed; + uniform float u_warp; + uniform float u_focus; + uniform float u_itensity; + + varying vec2 v_pos; + + float circle( in vec2 _pos, in vec2 _origin, in float _radius ) { + float SPREAD = 0.7 * u_spread; + float SPEED = 0.00055 * u_speed; + float WARP = 1.5 * u_warp; + float FOCUS = 1.15 * u_focus; + + vec2 dist = _pos - _origin; + + float distortion = snoise( vec2( + _pos.x * 1.587 * WARP + u_time * SPEED * 0.5, + _pos.y * 1.192 * WARP + u_time * SPEED * 0.3 + ) ) * 0.5 + 0.5; + + float feather = 0.01 + SPREAD * pow( distortion, FOCUS ); + + return 1.0 - smoothstep( + _radius - ( _radius * feather ), + _radius + ( _radius * feather ), + dot( dist, dist ) * 4.0 + ); + } + + void main() { + vec3 green = vec3( 1.0 ) - vec3( 153.0 / 255.0, 211.0 / 255.0, 221.0 / 255.0 ); + vec3 purple = vec3( 1.0 ) - vec3( 195.0 / 255.0, 165.0 / 255.0, 242.0 / 255.0 ); + vec3 orange = vec3( 1.0 ) - vec3( 255.0 / 255.0, 156.0 / 255.0, 136.0 / 255.0 ); + + //float ratio = u_resolution.x / u_resolution.y; + float ratio = 1.0; + + vec2 uv = vec2( v_pos.x, v_pos.y / ratio ) * 0.5 + 0.5; + + vec3 color = vec3( 0.0 ); + + float greenMix = snoise( v_pos * 1.31 + u_time * 0.8 * 0.00017 ) * 0.5 + 0.5; + float purpleMix = snoise( v_pos * 1.26 + u_time * 0.8 * -0.0001 ) * 0.5 + 0.5; + float orangeMix = snoise( v_pos * 1.34 + u_time * 0.8 * 0.00015 ) * 0.5 + 0.5; + + float alphaOne = 0.35 + 0.65 * pow( snoise( vec2( u_time * 0.00012, uv.x ) ) * 0.5 + 0.5, 1.2 ); + float alphaTwo = 0.35 + 0.65 * pow( snoise( vec2( ( u_time + 1561.0 ) * 0.00014, uv.x ) ) * 0.5 + 0.5, 1.2 ); + float alphaThree = 0.35 + 0.65 * pow( snoise( vec2( ( u_time + 3917.0 ) * 0.00013, uv.x ) ) * 0.5 + 0.5, 1.2 ); + + color += vec3( circle( uv, vec2( 0.22 + sin( u_time * 0.000201 ) * 0.06, 0.80 + cos( u_time * 0.000151 ) * 0.06 ), 0.15 ) ) * alphaOne * ( purple * purpleMix + orange * orangeMix ); + color += vec3( circle( uv, vec2( 0.90 + cos( u_time * 0.000166 ) * 0.06, 0.42 + sin( u_time * 0.000138 ) * 0.06 ), 0.18 ) ) * alphaTwo * ( green * greenMix + purple * purpleMix ); + color += vec3( circle( uv, vec2( 0.19 + sin( u_time * 0.000112 ) * 0.06, 0.25 + sin( u_time * 0.000192 ) * 0.06 ), 0.09 ) ) * alphaThree * ( orange * orangeMix ); + + color *= u_itensity + 1.0 * pow( snoise( vec2( v_pos.y + u_time * 0.00013, v_pos.x + u_time * -0.00009 ) ) * 0.5 + 0.5, 2.0 ); + + vec3 inverted = vec3( 1.0 ) - color; + gl_FragColor = vec4( color, max(max(color.x, color.y), color.z) ); + } + `); + + gl.useProgram(shaderProgram); + const u_resolution = gl.getUniformLocation(shaderProgram, 'u_resolution'); + const u_time = gl.getUniformLocation(shaderProgram, 'u_time'); + const u_spread = gl.getUniformLocation(shaderProgram, 'u_spread'); + const u_speed = gl.getUniformLocation(shaderProgram, 'u_speed'); + const u_warp = gl.getUniformLocation(shaderProgram, 'u_warp'); + const u_focus = gl.getUniformLocation(shaderProgram, 'u_focus'); + const u_itensity = gl.getUniformLocation(shaderProgram, 'u_itensity'); + gl.uniform2fv(u_resolution, [canvas.width, canvas.height]); + gl.uniform1f(u_time, 1.0); + gl.uniform1f(u_spread, 1.0); + gl.uniform1f(u_speed, 1.0); + gl.uniform1f(u_warp, 1.0); + gl.uniform1f(u_focus, 1.0); + gl.uniform1f(u_itensity, 0.5); + + const vertex = gl.getAttribLocation(shaderProgram, 'vertex'); + gl.enableVertexAttribArray(vertex); + gl.vertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0); + + const vertices = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW); + + function render(timeStamp) { + gl!.uniform1f(u_time, timeStamp); + gl!.drawArrays(gl!.TRIANGLE_STRIP, 0, 4); + + handle = window.requestAnimationFrame(render); + } + + handle = window.requestAnimationFrame(render); +}); + +onUnmounted(() => { + if (handle) { + window.cancelAnimationFrame(handle); + } +}); +</script> + +<style lang="scss" module> +</style> diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 4e80a5c0fb..3d7497526c 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -27,6 +27,7 @@ > <template v-if="page === 0"> <div :class="$style.centerPage"> + <MkAnimBg style="position: absolute; top: 0;"/> <MkSpacer :margin-min="20" :margin-max="28"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-confetti" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i> @@ -78,6 +79,7 @@ </template> <template v-else-if="page === 5"> <div :class="$style.centerPage"> + <MkAnimBg style="position: absolute; top: 0;"/> <MkSpacer :margin-min="20" :margin-max="28"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i> @@ -106,6 +108,7 @@ import MkButton from '@/components/MkButton.vue'; import XProfile from '@/components/MkUserSetupDialog.Profile.vue'; import XFollow from '@/components/MkUserSetupDialog.Follow.vue'; import XPrivacy from '@/components/MkUserSetupDialog.Privacy.vue'; +import MkAnimBg from '@/components/MkAnimBg.vue'; import { i18n } from '@/i18n'; import { instance } from '@/instance'; import { host } from '@/config'; From 1eaf287b9ce6bc8ff85399edd88b320a4dce1a5c Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 09:44:57 +0900 Subject: [PATCH 003/213] :art: --- packages/frontend/src/components/MkAnimBg.vue | 3 +-- .../frontend/src/components/MkUserSetupDialog.Profile.vue | 4 ++-- packages/frontend/src/components/MkUserSetupDialog.vue | 8 ++++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index df0765d494..a4cc04dde5 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -1,5 +1,5 @@ <template> -<canvas ref="canvasEl" style="width: 100%; height: 100%;"></canvas> +<canvas ref="canvasEl" style="width: 100%; height: 100%; pointer-events: none;"></canvas> </template> <script lang="ts" setup> @@ -191,7 +191,6 @@ onMounted(() => { const u_focus = gl.getUniformLocation(shaderProgram, 'u_focus'); const u_itensity = gl.getUniformLocation(shaderProgram, 'u_itensity'); gl.uniform2fv(u_resolution, [canvas.width, canvas.height]); - gl.uniform1f(u_time, 1.0); gl.uniform1f(u_spread, 1.0); gl.uniform1f(u_speed, 1.0); gl.uniform1f(u_warp, 1.0); diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue index f26ea11214..109d26dfaa 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue @@ -37,8 +37,8 @@ import { chooseFileFromPc } from '@/scripts/select-file'; import * as os from '@/os'; import { $i } from '@/account'; -const name = ref(''); -const description = ref(''); +const name = ref($i.name ?? ''); +const description = ref($i.description ?? ''); watch(name, () => { os.apiWithDialog('i/update', { diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 3d7497526c..07bc561218 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -42,7 +42,9 @@ <div style="height: 100cqh; overflow: auto;"> <MkSpacer :margin-min="20" :margin-max="28"> <XProfile/> - <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + <div class="_buttonsCenter" style="margin-top: 16px;"> + <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + </div> </MkSpacer> </div> </template> @@ -50,7 +52,9 @@ <div style="height: 100cqh; overflow: auto;"> <MkSpacer :margin-min="20" :margin-max="28"> <XPrivacy/> - <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + <div class="_buttonsCenter" style="margin-top: 16px;"> + <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + </div> </MkSpacer> </div> </template> From 89a3195dfd7be1801730e84011f04e50ffb0791f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 09:54:35 +0900 Subject: [PATCH 004/213] :art: --- packages/frontend/src/components/MkFolder.vue | 2 +- .../frontend/src/components/MkUserSetupDialog.Privacy.vue | 4 ++++ packages/frontend/src/components/MkUserSetupDialog.vue | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index 10eee6aab1..8800f31400 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -6,7 +6,7 @@ <div :class="$style.headerIcon"><slot name="icon"></slot></div> <div :class="$style.headerText"> <div :class="$style.headerTextMain"> - <slot name="label"></slot> + <MkCondensedLine :min-scale="2 / 3"><slot name="label"></slot></MkCondensedLine> </div> <div :class="$style.headerTextSub"> <slot name="caption"></slot> diff --git a/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue b/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue index e9f4f68df8..5cea67ccf5 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Privacy.vue @@ -4,6 +4,7 @@ <MkFolder> <template #label>{{ i18n.ts.makeFollowManuallyApprove }}</template> + <template #icon><i class="ti ti-lock"></i></template> <template #suffix>{{ isLocked ? i18n.ts.on : i18n.ts.off }}</template> <MkSwitch v-model="isLocked">{{ i18n.ts.makeFollowManuallyApprove }}<template #caption>{{ i18n.ts.lockedAccountInfo }}</template></MkSwitch> @@ -11,6 +12,7 @@ <MkFolder> <template #label>{{ i18n.ts.hideOnlineStatus }}</template> + <template #icon><i class="ti ti-eye-off"></i></template> <template #suffix>{{ hideOnlineStatus ? i18n.ts.on : i18n.ts.off }}</template> <MkSwitch v-model="hideOnlineStatus">{{ i18n.ts.hideOnlineStatus }}<template #caption>{{ i18n.ts.hideOnlineStatusDescription }}</template></MkSwitch> @@ -18,6 +20,7 @@ <MkFolder> <template #label>{{ i18n.ts.noCrawle }}</template> + <template #icon><i class="ti ti-world-x"></i></template> <template #suffix>{{ noCrawle ? i18n.ts.on : i18n.ts.off }}</template> <MkSwitch v-model="noCrawle">{{ i18n.ts.noCrawle }}<template #caption>{{ i18n.ts.noCrawleDescription }}</template></MkSwitch> @@ -25,6 +28,7 @@ <MkFolder> <template #label>{{ i18n.ts.preventAiLearning }}</template> + <template #icon><i class="ti ti-photo-shield"></i></template> <template #suffix>{{ preventAiLearning ? i18n.ts.on : i18n.ts.off }}</template> <MkSwitch v-model="preventAiLearning">{{ i18n.ts.preventAiLearning }}<template #caption>{{ i18n.ts.preventAiLearningDescription }}</template></MkSwitch> diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 07bc561218..066556a05b 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -7,10 +7,10 @@ @close="close(true)" @closed="emit('closed')" > - <template v-if="page === 1" #header>{{ i18n.ts._initialAccountSetting.profileSetting }}</template> - <template v-else-if="page === 2" #header>{{ i18n.ts._initialAccountSetting.privacySetting }}</template> - <template v-else-if="page === 3" #header>{{ i18n.ts.follow }}</template> - <template v-else-if="page === 4" #header>{{ i18n.ts.pushNotification }}</template> + <template v-if="page === 1" #header><i class="ti ti-user-edit"></i> {{ i18n.ts._initialAccountSetting.profileSetting }}</template> + <template v-else-if="page === 2" #header><i class="ti ti-lock"></i> {{ i18n.ts._initialAccountSetting.privacySetting }}</template> + <template v-else-if="page === 3" #header><i class="ti ti-user-plus"></i> {{ i18n.ts.follow }}</template> + <template v-else-if="page === 4" #header><i class="ti ti-bell-plus"></i> {{ i18n.ts.pushNotification }}</template> <template v-else-if="page === 5" #header>{{ i18n.ts.done }}</template> <template v-else #header>{{ i18n.ts.initialAccountSetting }}</template> From 8c97c54cfacd201e480dffb73db3fd0124532edb Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 10:21:56 +0900 Subject: [PATCH 005/213] refactor(frontend): use css modules --- .../src/components/MkAbuseReportWindow.vue | 6 +- .../frontend/src/components/MkChannelList.vue | 3 - .../frontend/src/components/MkObjectView.vue | 8 +-- .../src/components/MkRetentionLineChart.vue | 4 -- .../src/components/MkRippleEffect.vue | 16 ++--- packages/frontend/src/components/MkSignin.vue | 28 ++++----- .../src/components/MkUrlPreviewPopup.vue | 6 +- .../src/components/page/page.button.vue | 6 +- .../src/components/page/page.counter.vue | 6 +- .../src/components/page/page.note.vue | 14 ++--- .../src/components/page/page.number-input.vue | 6 +- .../src/components/page/page.text-input.vue | 6 +- packages/frontend/src/pages/admin/abuses.vue | 8 +-- .../src/pages/admin/announcements.vue | 8 +-- packages/frontend/src/pages/admin/files.vue | 8 +-- .../frontend/src/pages/admin/overview.pie.vue | 4 -- .../src/pages/admin/overview.queue.chart.vue | 4 -- .../frontend/src/pages/admin/overview.vue | 6 +- .../src/pages/admin/queue.chart.chart.vue | 4 -- .../frontend/src/pages/emoji-edit-dialog.vue | 16 +++-- .../frontend/src/pages/flash/flash-edit.vue | 4 -- packages/frontend/src/pages/gallery/index.vue | 16 ++--- .../frontend/src/pages/my-antennas/create.vue | 4 -- .../frontend/src/pages/my-antennas/edit.vue | 4 -- .../frontend/src/pages/my-antennas/editor.vue | 16 +++-- .../page-editor/els/page-editor.el.image.vue | 12 +--- .../page-editor/els/page-editor.el.text.vue | 38 ++++++------ packages/frontend/src/pages/preview.vue | 8 +-- packages/frontend/src/pages/registry.keys.vue | 3 - .../frontend/src/pages/registry.value.vue | 3 - packages/frontend/src/pages/registry.vue | 3 - .../frontend/src/pages/reset-password.vue | 4 -- .../frontend/src/pages/settings/plugin.vue | 4 -- .../frontend/src/pages/settings/profile.vue | 59 ++++++++++--------- .../frontend/src/pages/settings/reaction.vue | 28 ++++----- packages/frontend/src/pages/share.vue | 4 +- .../frontend/src/pages/signup-complete.vue | 4 -- .../src/widgets/WidgetActivity.chart.vue | 18 +++--- .../frontend/src/widgets/WidgetAichan.vue | 6 +- .../frontend/src/widgets/WidgetButton.vue | 5 -- 40 files changed, 148 insertions(+), 262 deletions(-) diff --git a/packages/frontend/src/components/MkAbuseReportWindow.vue b/packages/frontend/src/components/MkAbuseReportWindow.vue index 9f2bf99338..7a1b7d532e 100644 --- a/packages/frontend/src/components/MkAbuseReportWindow.vue +++ b/packages/frontend/src/components/MkAbuseReportWindow.vue @@ -9,7 +9,7 @@ </I18n> </template> <MkSpacer :margin-min="20" :margin-max="28"> - <div class="dpvffvvy _gaps_m"> + <div class="_gaps_m" :class="$style.root"> <div class=""> <MkTextarea v-model="comment"> <template #label>{{ i18n.ts.details }}</template> @@ -60,8 +60,8 @@ function send() { } </script> -<style lang="scss" scoped> -.dpvffvvy { +<style lang="scss" module> +.root { --root-margin: 16px; } </style> diff --git a/packages/frontend/src/components/MkChannelList.vue b/packages/frontend/src/components/MkChannelList.vue index 408eab7399..4050520eb9 100644 --- a/packages/frontend/src/components/MkChannelList.vue +++ b/packages/frontend/src/components/MkChannelList.vue @@ -26,6 +26,3 @@ const props = withDefaults(defineProps<{ extractor: (item) => item, }); </script> - -<style lang="scss" scoped> -</style> diff --git a/packages/frontend/src/components/MkObjectView.vue b/packages/frontend/src/components/MkObjectView.vue index 55578a37f6..8b1ed74142 100644 --- a/packages/frontend/src/components/MkObjectView.vue +++ b/packages/frontend/src/components/MkObjectView.vue @@ -1,5 +1,5 @@ <template> -<div class="zhyxdalp"> +<div> <XValue :value="value" :collapsed="false"/> </div> </template> @@ -12,9 +12,3 @@ const props = defineProps<{ value: Record<string, unknown>; }>(); </script> - -<style lang="scss" scoped> -.zhyxdalp { - -} -</style> diff --git a/packages/frontend/src/components/MkRetentionLineChart.vue b/packages/frontend/src/components/MkRetentionLineChart.vue index 8bd0279806..9f56189f3e 100644 --- a/packages/frontend/src/components/MkRetentionLineChart.vue +++ b/packages/frontend/src/components/MkRetentionLineChart.vue @@ -124,7 +124,3 @@ onMounted(async () => { }); }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/components/MkRippleEffect.vue b/packages/frontend/src/components/MkRippleEffect.vue index 9d93211d5f..60c3a47385 100644 --- a/packages/frontend/src/components/MkRippleEffect.vue +++ b/packages/frontend/src/components/MkRippleEffect.vue @@ -1,7 +1,7 @@ <template> -<div class="vswabwbm" :style="{ zIndex, top: `${y - 64}px`, left: `${x - 64}px` }"> +<div :class="$style.root" :style="{ zIndex, top: `${y - 64}px`, left: `${x - 64}px` }"> <svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"> - <circle fill="none" cx="64" cy="64"> + <circle fill="none" cx="64" cy="64" style="stroke: var(--accent);"> <animate attributeName="r" begin="0s" dur="0.5s" @@ -22,7 +22,7 @@ /> </circle> <g fill="none" fill-rule="evenodd"> - <circle v-for="(particle, i) in particles" :key="i" :fill="particle.color"> + <circle v-for="(particle, i) in particles" :key="i" :fill="particle.color" style="stroke: var(--accent);"> <animate attributeName="r" begin="0s" dur="0.8s" @@ -100,17 +100,11 @@ onMounted(() => { }); </script> -<style lang="scss" scoped> -.vswabwbm { +<style lang="scss" module> +.root { pointer-events: none; position: fixed; width: 128px; height: 128px; - - > svg { - > circle { - stroke: var(--accent); - } - } } </style> diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index ffc5e82b56..6eae8ecf84 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -1,7 +1,7 @@ <template> -<form class="eppvobhk" :class="{ signing, totpLogin }" @submit.prevent="onSubmit"> - <div class="auth _gaps_m"> - <div v-show="withAvatar" class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null, marginBottom: message ? '1.5em' : null }"></div> +<form :class="{ signing, totpLogin }" @submit.prevent="onSubmit"> + <div class="_gaps_m"> + <div v-show="withAvatar" :class="$style.avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null, marginBottom: message ? '1.5em' : null }"></div> <MkInfo v-if="message"> {{ message }} </MkInfo> @@ -236,18 +236,14 @@ function resetPassword() { } </script> -<style lang="scss" scoped> -.eppvobhk { - > .auth { - > .avatar { - margin: 0 auto 0 auto; - width: 64px; - height: 64px; - background: #ddd; - background-position: center; - background-size: cover; - border-radius: 100%; - } - } +<style lang="scss" module> +.avatar { + margin: 0 auto 0 auto; + width: 64px; + height: 64px; + background: #ddd; + background-position: center; + background-size: cover; + border-radius: 100%; } </style> diff --git a/packages/frontend/src/components/MkUrlPreviewPopup.vue b/packages/frontend/src/components/MkUrlPreviewPopup.vue index e244be3e96..30204b91c1 100644 --- a/packages/frontend/src/components/MkUrlPreviewPopup.vue +++ b/packages/frontend/src/components/MkUrlPreviewPopup.vue @@ -1,5 +1,5 @@ <template> -<div class="fgmtyycl" :style="{ zIndex, top: top + 'px', left: left + 'px' }"> +<div :class="$style.root" :style="{ zIndex, top: top + 'px', left: left + 'px' }"> <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" @after-leave="emit('closed')"> <MkUrlPreview v-if="showing" class="_popup _shadow" :url="url"/> </Transition> @@ -36,8 +36,8 @@ onMounted(() => { }); </script> -<style lang="scss" scoped> -.fgmtyycl { +<style lang="scss" module> +.root { position: absolute; width: 500px; max-width: calc(90vw - 12px); diff --git a/packages/frontend/src/components/page/page.button.vue b/packages/frontend/src/components/page/page.button.vue index 83931021d8..8e89023fd7 100644 --- a/packages/frontend/src/components/page/page.button.vue +++ b/packages/frontend/src/components/page/page.button.vue @@ -1,6 +1,6 @@ <template> <div> - <MkButton class="kudkigyw" :primary="block.primary" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton> + <MkButton :class="$style.button" :primary="block.primary" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton> </div> </template> @@ -56,8 +56,8 @@ export default defineComponent({ }); </script> -<style lang="scss" scoped> -.kudkigyw { +<style lang="scss" module> +.button { display: inline-block; min-width: 200px; max-width: 450px; diff --git a/packages/frontend/src/components/page/page.counter.vue b/packages/frontend/src/components/page/page.counter.vue index 63fde6a120..3f282a2e51 100644 --- a/packages/frontend/src/components/page/page.counter.vue +++ b/packages/frontend/src/components/page/page.counter.vue @@ -1,6 +1,6 @@ <template> <div> - <MkButton class="llumlmnx" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton> + <MkButton :class="$style.button" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton> </div> </template> @@ -41,8 +41,8 @@ export default defineComponent({ }); </script> -<style lang="scss" scoped> -.llumlmnx { +<style lang="scss" module> +.button { display: inline-block; min-width: 300px; max-width: 450px; diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue index 8c65dabf08..7c620184d7 100644 --- a/packages/frontend/src/components/page/page.note.vue +++ b/packages/frontend/src/components/page/page.note.vue @@ -1,5 +1,5 @@ <template> -<div class="voxdxuby"> +<div style="margin: 1em 0;"> <MkNote v-if="note && !block.detailed" :key="note.id + ':normal'" v-model:note="note"/> <MkNoteDetailed v-if="note && block.detailed" :key="note.id + ':detail'" v-model:note="note"/> </div> @@ -28,9 +28,9 @@ export default defineComponent({ onMounted(() => { os.api('notes/show', { noteId: props.block.note }) - .then(result => { - note.value = result; - }); + .then(result => { + note.value = result; + }); }); return { @@ -39,9 +39,3 @@ export default defineComponent({ }, }); </script> - -<style lang="scss" scoped> -.voxdxuby { - margin: 1em 0; -} -</style> diff --git a/packages/frontend/src/components/page/page.number-input.vue b/packages/frontend/src/components/page/page.number-input.vue index 72c1b6deb0..9cac3b4f0d 100644 --- a/packages/frontend/src/components/page/page.number-input.vue +++ b/packages/frontend/src/components/page/page.number-input.vue @@ -1,6 +1,6 @@ <template> <div> - <MkInput class="kudkigyw" :model-value="value" type="number" @update:model-value="updateValue($event)"> + <MkInput :class="$style.input" :model-value="value" type="number" @update:model-value="updateValue($event)"> <template #label>{{ hpml.interpolate(block.text) }}</template> </MkInput> </div> @@ -44,8 +44,8 @@ export default defineComponent({ }); </script> -<style lang="scss" scoped> -.kudkigyw { +<style lang="scss" module> +.input { display: inline-block; min-width: 300px; max-width: 450px; diff --git a/packages/frontend/src/components/page/page.text-input.vue b/packages/frontend/src/components/page/page.text-input.vue index d020a99de8..1df45fefed 100644 --- a/packages/frontend/src/components/page/page.text-input.vue +++ b/packages/frontend/src/components/page/page.text-input.vue @@ -1,6 +1,6 @@ <template> <div> - <MkInput class="kudkigyw" :model-value="value" type="text" @update:model-value="updateValue($event)"> + <MkInput :class="$style.input" :model-value="value" type="text" @update:model-value="updateValue($event)"> <template #label>{{ hpml.interpolate(block.text) }}</template> </MkInput> </div> @@ -44,8 +44,8 @@ export default defineComponent({ }); </script> -<style lang="scss" scoped> -.kudkigyw { +<style lang="scss" module> +.input { display: inline-block; min-width: 300px; max-width: 450px; diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index 9e8af43024..f8200570f9 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :content-max="900"> - <div class="lcixvhis"> + <div> <div class="reports"> <div class=""> <div class="inputs" style="display: flex;"> @@ -87,9 +87,3 @@ definePageMetadata({ icon: 'ti ti-exclamation-circle', }); </script> - -<style lang="scss" scoped> -.lcixvhis { - margin: var(--margin); -} -</style> diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue index b76e4b9114..638b193c11 100644 --- a/packages/frontend/src/pages/admin/announcements.vue +++ b/packages/frontend/src/pages/admin/announcements.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :content-max="900"> - <div class="ztgjmzrw _gaps_m"> + <div class="_gaps_m"> <section v-for="announcement in announcements" class=""> <div class="_panel _gaps_m" style="padding: 24px;"> <MkInput v-model="announcement.title"> @@ -113,9 +113,3 @@ definePageMetadata({ icon: 'ti ti-speakerphone', }); </script> - -<style lang="scss" scoped> -.ztgjmzrw { - margin: var(--margin); -} -</style> diff --git a/packages/frontend/src/pages/admin/files.vue b/packages/frontend/src/pages/admin/files.vue index c189437246..2b13a7c80c 100644 --- a/packages/frontend/src/pages/admin/files.vue +++ b/packages/frontend/src/pages/admin/files.vue @@ -3,7 +3,7 @@ <MkStickyContainer> <template #header><XHeader :actions="headerActions"/></template> <MkSpacer :content-max="900"> - <div class="xrmjdkdw"> + <div> <div> <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap;"> <MkSelect v-model="origin" style="margin: 0; flex: 1;"> @@ -109,9 +109,3 @@ definePageMetadata(computed(() => ({ icon: 'ti ti-cloud', }))); </script> - -<style lang="scss" scoped> -.xrmjdkdw { - margin: var(--margin); -} -</style> diff --git a/packages/frontend/src/pages/admin/overview.pie.vue b/packages/frontend/src/pages/admin/overview.pie.vue index 08a29bf550..af7bc70551 100644 --- a/packages/frontend/src/pages/admin/overview.pie.vue +++ b/packages/frontend/src/pages/admin/overview.pie.vue @@ -67,7 +67,3 @@ onMounted(() => { }); }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/admin/overview.queue.chart.vue b/packages/frontend/src/pages/admin/overview.queue.chart.vue index 6a11e8b768..a3c8659ce5 100644 --- a/packages/frontend/src/pages/admin/overview.queue.chart.vue +++ b/packages/frontend/src/pages/admin/overview.queue.chart.vue @@ -132,7 +132,3 @@ defineExpose({ pushData, }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/admin/overview.vue b/packages/frontend/src/pages/admin/overview.vue index 5c96c07bfb..bdfb200a88 100644 --- a/packages/frontend/src/pages/admin/overview.vue +++ b/packages/frontend/src/pages/admin/overview.vue @@ -1,6 +1,6 @@ <template> <MkSpacer :content-max="1000"> - <div ref="rootEl" class="edbbcaef"> + <div ref="rootEl" :class="$style.root"> <MkFoldableSection class="item"> <template #header>Stats</template> <XStats/> @@ -176,8 +176,8 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.edbbcaef { +<style lang="scss" module> +.root { display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); grid-gap: 16px; diff --git a/packages/frontend/src/pages/admin/queue.chart.chart.vue b/packages/frontend/src/pages/admin/queue.chart.chart.vue index 1a1f6a9db4..9bc0eee212 100644 --- a/packages/frontend/src/pages/admin/queue.chart.chart.vue +++ b/packages/frontend/src/pages/admin/queue.chart.chart.vue @@ -132,7 +132,3 @@ defineExpose({ pushData, }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue index 84bc153b71..3c829d6a8e 100644 --- a/packages/frontend/src/pages/emoji-edit-dialog.vue +++ b/packages/frontend/src/pages/emoji-edit-dialog.vue @@ -10,8 +10,8 @@ <template #header>:{{ emoji.name }}:</template> <MkSpacer :margin-min="20" :margin-max="28"> - <div class="yigymqpb _gaps_m"> - <img :src="`/emoji/${emoji.name}.webp`" class="img"/> + <div class="_gaps_m"> + <img :src="`/emoji/${emoji.name}.webp`" :class="$style.img"/> <MkInput v-model="name"> <template #label>{{ i18n.ts.name }}</template> </MkInput> @@ -99,12 +99,10 @@ async function del() { } </script> -<style lang="scss" scoped> -.yigymqpb { - > .img { - display: block; - height: 64px; - margin: 0 auto; - } +<style lang="scss" module> +.img { + display: block; + height: 64px; + margin: 0 auto; } </style> diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue index 816825e5b6..5e875d195b 100644 --- a/packages/frontend/src/pages/flash/flash-edit.vue +++ b/packages/frontend/src/pages/flash/flash-edit.vue @@ -442,7 +442,3 @@ definePageMetadata(computed(() => flash ? { title: i18n.ts._play.new, })); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/gallery/index.vue b/packages/frontend/src/pages/gallery/index.vue index fc9cc7ae9e..3855a6d9d8 100644 --- a/packages/frontend/src/pages/gallery/index.vue +++ b/packages/frontend/src/pages/gallery/index.vue @@ -7,7 +7,7 @@ <MkFoldableSection class="_margin"> <template #header><i class="ti ti-clock"></i>{{ i18n.ts.recentPosts }}</template> <MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disable-auto-load="true"> - <div class="vfpdbgtk"> + <div :class="$style.items"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> </div> </MkPagination> @@ -15,7 +15,7 @@ <MkFoldableSection class="_margin"> <template #header><i class="ti ti-comet"></i>{{ i18n.ts.popularPosts }}</template> <MkPagination v-slot="{items}" :pagination="popularPostsPagination" :disable-auto-load="true"> - <div class="vfpdbgtk"> + <div :class="$style.items"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> </div> </MkPagination> @@ -23,7 +23,7 @@ </div> <div v-else-if="tab === 'liked'"> <MkPagination v-slot="{items}" :pagination="likedPostsPagination"> - <div class="vfpdbgtk"> + <div :class="$style.items"> <MkGalleryPostPreview v-for="like in items" :key="like.id" :post="like.post" class="post"/> </div> </MkPagination> @@ -31,7 +31,7 @@ <div v-else-if="tab === 'my'"> <MkA to="/gallery/new" class="_link" style="margin: 16px;"><i class="ti ti-plus"></i> {{ i18n.ts.postToGallery }}</MkA> <MkPagination v-slot="{items}" :pagination="myPostsPagination"> - <div class="vfpdbgtk"> + <div :class="$style.items"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> </div> </MkPagination> @@ -119,15 +119,11 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.vfpdbgtk { +<style lang="scss" module> +.items { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); grid-gap: 12px; margin: 0 var(--margin); - - > .post { - - } } </style> diff --git a/packages/frontend/src/pages/my-antennas/create.vue b/packages/frontend/src/pages/my-antennas/create.vue index c35af3e22a..14ab18a3df 100644 --- a/packages/frontend/src/pages/my-antennas/create.vue +++ b/packages/frontend/src/pages/my-antennas/create.vue @@ -38,7 +38,3 @@ definePageMetadata({ icon: 'ti ti-antenna', }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/my-antennas/edit.vue b/packages/frontend/src/pages/my-antennas/edit.vue index 913fbde8e9..da9b2de48f 100644 --- a/packages/frontend/src/pages/my-antennas/edit.vue +++ b/packages/frontend/src/pages/my-antennas/edit.vue @@ -36,7 +36,3 @@ definePageMetadata({ icon: 'ti ti-antenna', }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/my-antennas/editor.vue b/packages/frontend/src/pages/my-antennas/editor.vue index 26b7bcc71b..dd5f3222af 100644 --- a/packages/frontend/src/pages/my-antennas/editor.vue +++ b/packages/frontend/src/pages/my-antennas/editor.vue @@ -1,6 +1,6 @@ <template> <MkSpacer :content-max="700"> - <div class="shaynizk"> + <div> <div class="_gaps_m"> <MkInput v-model="name"> <template #label>{{ i18n.ts.name }}</template> @@ -33,7 +33,7 @@ <MkSwitch v-model="withFile">{{ i18n.ts.withFileAntenna }}</MkSwitch> <MkSwitch v-model="notify">{{ i18n.ts.notifyAntenna }}</MkSwitch> </div> - <div class="actions"> + <div :class="$style.actions"> <MkButton inline primary @click="saveAntenna()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> <MkButton v-if="antenna.id != null" inline danger @click="deleteAntenna()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> </div> @@ -128,12 +128,10 @@ function addUser() { } </script> -<style lang="scss" scoped> -.shaynizk { - > .actions { - margin-top: 16px; - padding: 24px 0; - border-top: solid 0.5px var(--divider); - } +<style lang="scss" module> +.actions { + margin-top: 16px; + padding: 24px 0; + border-top: solid 0.5px var(--divider); } </style> diff --git a/packages/frontend/src/pages/page-editor/els/page-editor.el.image.vue b/packages/frontend/src/pages/page-editor/els/page-editor.el.image.vue index 1b292e8f3c..eca3feda62 100644 --- a/packages/frontend/src/pages/page-editor/els/page-editor.el.image.vue +++ b/packages/frontend/src/pages/page-editor/els/page-editor.el.image.vue @@ -8,8 +8,8 @@ </button> </template> - <section class="oyyftmcf"> - <MkDriveFileThumbnail v-if="file" class="preview" :file="file" fit="contain" @click="choose()"/> + <section> + <MkDriveFileThumbnail v-if="file" style="height: 150px;" :file="file" fit="contain" @click="choose()"/> </section> </XContainer> </template> @@ -54,11 +54,3 @@ onMounted(async () => { } }); </script> - -<style lang="scss" scoped> -.oyyftmcf { - > .preview { - height: 150px; - } -} -</style> diff --git a/packages/frontend/src/pages/page-editor/els/page-editor.el.text.vue b/packages/frontend/src/pages/page-editor/els/page-editor.el.text.vue index bf21ae3c67..3b15c17747 100644 --- a/packages/frontend/src/pages/page-editor/els/page-editor.el.text.vue +++ b/packages/frontend/src/pages/page-editor/els/page-editor.el.text.vue @@ -3,8 +3,8 @@ <XContainer :draggable="true" @remove="() => $emit('remove')"> <template #header><i class="ti ti-align-left"></i> {{ i18n.ts._pages.blocks.text }}</template> - <section class="vckmsadr"> - <textarea v-model="text"></textarea> + <section> + <textarea v-model="text" :class="$style.textarea"></textarea> </section> </XContainer> </template> @@ -33,23 +33,21 @@ watch($$(text), () => { }); </script> -<style lang="scss" scoped> -.vckmsadr { - > textarea { - display: block; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - width: 100%; - min-width: 100%; - min-height: 150px; - border: none; - box-shadow: none; - padding: 16px; - background: transparent; - color: var(--fg); - font-size: 14px; - box-sizing: border-box; - } +<style lang="scss" module> +.textarea { + display: block; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + width: 100%; + min-width: 100%; + min-height: 150px; + border: none; + box-shadow: none; + padding: 16px; + background: transparent; + color: var(--fg); + font-size: 14px; + box-sizing: border-box; } </style> diff --git a/packages/frontend/src/pages/preview.vue b/packages/frontend/src/pages/preview.vue index 354f686e46..952af23a53 100644 --- a/packages/frontend/src/pages/preview.vue +++ b/packages/frontend/src/pages/preview.vue @@ -1,5 +1,5 @@ <template> -<div class="graojtoi"> +<div> <MkSample/> </div> </template> @@ -19,9 +19,3 @@ definePageMetadata(computed(() => ({ icon: 'ti ti-eye', }))); </script> - -<style lang="scss" scoped> -.graojtoi { - padding: var(--margin); -} -</style> diff --git a/packages/frontend/src/pages/registry.keys.vue b/packages/frontend/src/pages/registry.keys.vue index c687b89eab..52b7c256e0 100644 --- a/packages/frontend/src/pages/registry.keys.vue +++ b/packages/frontend/src/pages/registry.keys.vue @@ -93,6 +93,3 @@ definePageMetadata({ icon: 'ti ti-adjustments', }); </script> - -<style lang="scss" scoped> -</style> diff --git a/packages/frontend/src/pages/registry.value.vue b/packages/frontend/src/pages/registry.value.vue index 00e2ca5e03..6ff07e2b77 100644 --- a/packages/frontend/src/pages/registry.value.vue +++ b/packages/frontend/src/pages/registry.value.vue @@ -118,6 +118,3 @@ definePageMetadata({ icon: 'ti ti-adjustments', }); </script> - -<style lang="scss" scoped> -</style> diff --git a/packages/frontend/src/pages/registry.vue b/packages/frontend/src/pages/registry.vue index 5a029cb0c7..016af22815 100644 --- a/packages/frontend/src/pages/registry.vue +++ b/packages/frontend/src/pages/registry.vue @@ -68,6 +68,3 @@ definePageMetadata({ icon: 'ti ti-adjustments', }); </script> - -<style lang="scss" scoped> -</style> diff --git a/packages/frontend/src/pages/reset-password.vue b/packages/frontend/src/pages/reset-password.vue index 38c88cc650..ab7a96a8d0 100644 --- a/packages/frontend/src/pages/reset-password.vue +++ b/packages/frontend/src/pages/reset-password.vue @@ -53,7 +53,3 @@ definePageMetadata({ icon: 'ti ti-lock', }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/settings/plugin.vue b/packages/frontend/src/pages/settings/plugin.vue index 8b57dceefb..f90ca737e9 100644 --- a/packages/frontend/src/pages/settings/plugin.vue +++ b/packages/frontend/src/pages/settings/plugin.vue @@ -94,7 +94,3 @@ definePageMetadata({ icon: 'ti ti-plug', }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 6ffd682610..dd552ed92b 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -1,11 +1,11 @@ <template> <div class="_gaps_m"> - <div class="llvierxe" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }"> - <div class="avatar"> - <MkAvatar class="avatar" :user="$i" @click="changeAvatar"/> - <MkButton primary rounded class="avatarEdit" @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton> + <div :class="$style.avatarAndBanner" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }"> + <div :class="$style.avatarContainer"> + <MkAvatar :class="$style.avatar" :user="$i" @click="changeAvatar"/> + <MkButton primary rounded :class="$style.avatarEdit" @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton> </div> - <MkButton primary rounded class="bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton> + <MkButton primary rounded :class="$style.bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton> </div> <MkInput v-model="profile.name" :max="30" manual-save> @@ -248,36 +248,39 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.llvierxe { +<style lang="scss" module> +.avatarAndBanner { position: relative; background-size: cover; background-position: center; border: solid 1px var(--divider); border-radius: 10px; overflow: clip; - - > .avatar { - display: inline-block; - text-align: center; - padding: 16px; - - > .avatar { - display: inline-block; - width: 72px; - height: 72px; - margin: 0 auto 16px auto; - } - } - - > .bannerEdit { - position: absolute; - top: 16px; - right: 16px; - } } -</style> -<style lang="scss" module> + +.avatarContainer { + display: inline-block; + text-align: center; + padding: 16px; +} + +.avatar { + display: inline-block; + width: 72px; + height: 72px; + margin: 0 auto 16px auto; +} + +.avatarEdit { + +} + +.bannerEdit { + position: absolute; + top: 16px; + right: 16px; +} + .metadataRoot { container-type: inline-size; } diff --git a/packages/frontend/src/pages/settings/reaction.vue b/packages/frontend/src/pages/settings/reaction.vue index ed913731d3..10169ccf18 100644 --- a/packages/frontend/src/pages/settings/reaction.vue +++ b/packages/frontend/src/pages/settings/reaction.vue @@ -3,15 +3,15 @@ <FromSlot> <template #label>{{ i18n.ts.reactionSettingDescription }}</template> <div v-panel style="border-radius: 6px;"> - <Sortable v-model="reactions" class="zoaiodol" :item-key="item => item" :animation="150" :delay="100" :delay-on-touch-only="true"> + <Sortable v-model="reactions" :class="$style.reactions" :item-key="item => item" :animation="150" :delay="100" :delay-on-touch-only="true"> <template #item="{element}"> - <button class="_button item" @click="remove(element, $event)"> + <button class="_button" :class="$style.reactionsItem" @click="remove(element, $event)"> <MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true"/> <MkEmoji v-else :emoji="element" :normal="true"/> </button> </template> <template #footer> - <button class="_button add" @click="chooseEmoji"><i class="ti ti-plus"></i></button> + <button class="_button" :class="$style.reactionsAdd" @click="chooseEmoji"><i class="ti ti-plus"></i></button> </template> </Sortable> </div> @@ -135,20 +135,20 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.zoaiodol { +<style lang="scss" module> +.reactions { padding: 12px; font-size: 1.1em; +} - > .item { - display: inline-block; - padding: 8px; - cursor: move; - } +.reactionsItem { + display: inline-block; + padding: 8px; + cursor: move; +} - > .add { - display: inline-block; - padding: 8px; - } +.reactionsAdd { + display: inline-block; + padding: 8px; } </style> diff --git a/packages/frontend/src/pages/share.vue b/packages/frontend/src/pages/share.vue index 78e0710162..5abb234893 100644 --- a/packages/frontend/src/pages/share.vue +++ b/packages/frontend/src/pages/share.vue @@ -16,7 +16,7 @@ class="_panel" @posted="state = 'posted'" /> - <MkButton v-else-if="state === 'posted'" primary class="close" @click="close()">{{ i18n.ts.close }}</MkButton> + <MkButton v-else-if="state === 'posted'" primary :class="$style.close" @click="close()">{{ i18n.ts.close }}</MkButton> </MkSpacer> </MkStickyContainer> </template> @@ -162,7 +162,7 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> +<style lang="scss" module> .close { margin: 16px auto; } diff --git a/packages/frontend/src/pages/signup-complete.vue b/packages/frontend/src/pages/signup-complete.vue index 5459532310..079cbb3d33 100644 --- a/packages/frontend/src/pages/signup-complete.vue +++ b/packages/frontend/src/pages/signup-complete.vue @@ -35,7 +35,3 @@ definePageMetadata({ icon: 'ti ti-user', }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/widgets/WidgetActivity.chart.vue b/packages/frontend/src/widgets/WidgetActivity.chart.vue index b61e419f94..cc4df65dd2 100644 --- a/packages/frontend/src/widgets/WidgetActivity.chart.vue +++ b/packages/frontend/src/widgets/WidgetActivity.chart.vue @@ -1,26 +1,30 @@ <template> -<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" @mousedown.prevent="onMousedown"> +<svg :viewBox="`0 0 ${ viewBoxX } ${ viewBoxY }`" :class="$style.root" @mousedown.prevent="onMousedown"> <polyline :points="pointsNote" fill="none" stroke-width="1" - stroke="#41ddde"/> + stroke="#41ddde" + /> <polyline :points="pointsReply" fill="none" stroke-width="1" - stroke="#f7796c"/> + stroke="#f7796c" + /> <polyline :points="pointsRenote" fill="none" stroke-width="1" - stroke="#a1de41"/> + stroke="#a1de41" + /> <polyline :points="pointsTotal" fill="none" stroke-width="1" stroke="#555" - stroke-dasharray="2 2"/> + stroke-dasharray="2 2" + /> </svg> </template> @@ -81,8 +85,8 @@ function render() { } </script> -<style lang="scss" scoped> -svg { +<style lang="scss" module> +.root { display: block; padding: 16px; width: 100%; diff --git a/packages/frontend/src/widgets/WidgetAichan.vue b/packages/frontend/src/widgets/WidgetAichan.vue index 37326ee981..0c485441d2 100644 --- a/packages/frontend/src/widgets/WidgetAichan.vue +++ b/packages/frontend/src/widgets/WidgetAichan.vue @@ -1,6 +1,6 @@ <template> <MkContainer :naked="widgetProps.transparent" :show-header="false" data-cy-mkw-aichan class="mkw-aichan"> - <iframe ref="live2d" class="dedjhjmo" src="https://misskey-dev.github.io/mascot-web/?scale=1.5&y=1.1&eyeY=100" @click="touched"></iframe> + <iframe ref="live2d" :class="$style.root" src="https://misskey-dev.github.io/mascot-web/?scale=1.5&y=1.1&eyeY=100" @click="touched"></iframe> </MkContainer> </template> @@ -64,8 +64,8 @@ defineExpose<WidgetComponentExpose>({ }); </script> -<style lang="scss" scoped> -.dedjhjmo { +<style lang="scss" module> +.root { width: 100%; height: 350px; border: none; diff --git a/packages/frontend/src/widgets/WidgetButton.vue b/packages/frontend/src/widgets/WidgetButton.vue index 9eee9680db..98260caeef 100644 --- a/packages/frontend/src/widgets/WidgetButton.vue +++ b/packages/frontend/src/widgets/WidgetButton.vue @@ -101,8 +101,3 @@ defineExpose<WidgetComponentExpose>({ id: props.widget ? props.widget.id : null, }); </script> - -<style lang="scss" scoped> -.mkw-button { -} -</style> From f15f60d5b948d4aff002f16415e8e763d3864594 Mon Sep 17 00:00:00 2001 From: yupix <yupi0982@outlook.jp> Date: Sun, 14 May 2023 01:30:46 +0000 Subject: [PATCH 006/213] =?UTF-8?q?feat:=20=E9=96=8B=E7=99=BA=E8=80=85?= =?UTF-8?q?=E3=83=A2=E3=83=BC=E3=83=89=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ locales/ja-JP.yml | 3 +++ packages/frontend/src/pages/settings/general.vue | 6 +++++- packages/frontend/src/scripts/get-note-menu.ts | 12 +++++++++++- packages/frontend/src/scripts/get-user-menu.ts | 12 +++++++++++- packages/frontend/src/store.ts | 4 ++++ 6 files changed, 40 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8594c42d10..1e907f8c42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ --> +## 13.x.x (unreleased) + +### Client +- 開発者モードを追加 + + ## 13.12.2 ## NOTE diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0b7108fe6d..340698a12b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -52,6 +52,8 @@ addToList: "リストに追加" sendMessage: "メッセージを送信" copyRSS: "RSSをコピー" copyUsername: "ユーザー名をコピー" +copyUserId: "ユーザーIDをコピー" +copyNoteId: "ノートIDをコピー" searchUser: "ユーザーを検索" reply: "返信" loadMore: "もっと見る" @@ -823,6 +825,7 @@ translatedFrom: "{x}から翻訳" accountDeletionInProgress: "アカウントの削除が進行中です" usernameInfo: "サーバー上であなたのアカウントを一意に識別するための名前。アルファベット(a~z, A~Z)、数字(0~9)、およびアンダーバー(_)が使用できます。ユーザー名は後から変更することは出来ません。" aiChanMode: "藍モード" +devMode: "開発者モード" keepCw: "CWを維持する" pubSub: "Pub/Subのアカウント" lastCommunication: "直近の通信" diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index ba0f3274fc..7e70119ec3 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -145,7 +145,10 @@ </FormSection> <FormSection> - <MkSwitch v-model="aiChanMode">{{ i18n.ts.aiChanMode }}</MkSwitch> + <div class="_gaps_s"> + <MkSwitch v-model="aiChanMode">{{ i18n.ts.aiChanMode }}</MkSwitch> + <MkSwitch v-model="devMode">{{ i18n.ts.devMode }}</MkSwitch> + </div> </FormSection> <FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink> @@ -213,6 +216,7 @@ const enableInfiniteScroll = computed(defaultStore.makeGetterSetter('enableInfin const useReactionPickerForContextMenu = computed(defaultStore.makeGetterSetter('useReactionPickerForContextMenu')); const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars')); const aiChanMode = computed(defaultStore.makeGetterSetter('aiChanMode')); +const devMode = computed(defaultStore.makeGetterSetter('devMode')); const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter('mediaListWithOneImageAppearance')); const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index c8a6100253..960f26ca67 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -7,7 +7,7 @@ import { instance } from '@/instance'; import * as os from '@/os'; import copyToClipboard from '@/scripts/copy-to-clipboard'; import { url } from '@/config'; -import { noteActions } from '@/store'; +import { defaultStore, noteActions } from '@/store'; import { miLocalStorage } from '@/local-storage'; import { getUserMenu } from '@/scripts/get-user-menu'; import { clipsCache } from '@/cache'; @@ -396,5 +396,15 @@ export function getNoteMenu(props: { }))]); } + if (defaultStore.state.devMode) { + menu = menu.concat([null, { + icon: 'ti ti-id', + text: i18n.ts.copyNoteId, + action: () => { + copyToClipboard(appearNote.id); + }, + }]); + } + return menu; } diff --git a/packages/frontend/src/scripts/get-user-menu.ts b/packages/frontend/src/scripts/get-user-menu.ts index 6ff9fb63f1..b055d26473 100644 --- a/packages/frontend/src/scripts/get-user-menu.ts +++ b/packages/frontend/src/scripts/get-user-menu.ts @@ -4,7 +4,7 @@ import { i18n } from '@/i18n'; import copyToClipboard from '@/scripts/copy-to-clipboard'; import { host } from '@/config'; import * as os from '@/os'; -import { userActions } from '@/store'; +import { defaultStore, userActions } from '@/store'; import { $i, iAmModerator } from '@/account'; import { mainRouter } from '@/router'; import { Router } from '@/nirax'; @@ -240,6 +240,16 @@ export function getUserMenu(user: misskey.entities.UserDetailed, router: Router }]); } + if (defaultStore.state.devMode) { + menu = menu.concat([null, { + icon: 'ti ti-id', + text: i18n.ts.copyUserId, + action: () => { + copyToClipboard(user.id); + }, + }]); + } + if ($i && meId === user.id) { menu = menu.concat([null, { icon: 'ti ti-pencil', diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 245bcbefe1..61085e5dcf 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -314,6 +314,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, + devMode: { + where: 'device', + default: false, + }, mediaListWithOneImageAppearance: { where: 'device', default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3', From a979fb920774f19edbda0e942706ac229bde5a39 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 10:31:48 +0900 Subject: [PATCH 007/213] =?UTF-8?q?change(frontend):=20=E5=8B=95=E7=9A=84?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AE=E3=82=B3=E3=83=B3=E3=83=9D?= =?UTF-8?q?=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/page/page.block.vue | 13 +- .../src/components/page/page.button.vue | 66 ----------- .../src/components/page/page.canvas.vue | 48 -------- .../src/components/page/page.counter.vue | 51 -------- .../frontend/src/components/page/page.if.vue | 31 ----- .../src/components/page/page.number-input.vue | 54 --------- .../src/components/page/page.post.vue | 111 ------------------ .../src/components/page/page.radio-button.vue | 44 ------- .../src/components/page/page.switch.vue | 54 --------- .../src/components/page/page.text-input.vue | 54 --------- .../components/page/page.textarea-input.vue | 45 ------- .../src/components/page/page.textarea.vue | 39 ------ 12 files changed, 1 insertion(+), 609 deletions(-) delete mode 100644 packages/frontend/src/components/page/page.button.vue delete mode 100644 packages/frontend/src/components/page/page.canvas.vue delete mode 100644 packages/frontend/src/components/page/page.counter.vue delete mode 100644 packages/frontend/src/components/page/page.if.vue delete mode 100644 packages/frontend/src/components/page/page.number-input.vue delete mode 100644 packages/frontend/src/components/page/page.post.vue delete mode 100644 packages/frontend/src/components/page/page.radio-button.vue delete mode 100644 packages/frontend/src/components/page/page.switch.vue delete mode 100644 packages/frontend/src/components/page/page.text-input.vue delete mode 100644 packages/frontend/src/components/page/page.textarea-input.vue delete mode 100644 packages/frontend/src/components/page/page.textarea.vue diff --git a/packages/frontend/src/components/page/page.block.vue b/packages/frontend/src/components/page/page.block.vue index f3e7764604..3f8a5dbc59 100644 --- a/packages/frontend/src/components/page/page.block.vue +++ b/packages/frontend/src/components/page/page.block.vue @@ -7,24 +7,13 @@ import { defineComponent, PropType } from 'vue'; import XText from './page.text.vue'; import XSection from './page.section.vue'; import XImage from './page.image.vue'; -import XButton from './page.button.vue'; -import XNumberInput from './page.number-input.vue'; -import XTextInput from './page.text-input.vue'; -import XTextareaInput from './page.textarea-input.vue'; -import XSwitch from './page.switch.vue'; -import XIf from './page.if.vue'; -import XTextarea from './page.textarea.vue'; -import XPost from './page.post.vue'; -import XCounter from './page.counter.vue'; -import XRadioButton from './page.radio-button.vue'; -import XCanvas from './page.canvas.vue'; import XNote from './page.note.vue'; import { Hpml } from '@/scripts/hpml/evaluator'; import { Block } from '@/scripts/hpml/block'; export default defineComponent({ components: { - XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas, XNote, + XText, XSection, XImage, XNote, }, props: { block: { diff --git a/packages/frontend/src/components/page/page.button.vue b/packages/frontend/src/components/page/page.button.vue deleted file mode 100644 index 8e89023fd7..0000000000 --- a/packages/frontend/src/components/page/page.button.vue +++ /dev/null @@ -1,66 +0,0 @@ -<template> -<div> - <MkButton :class="$style.button" :primary="block.primary" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton> -</div> -</template> - -<script lang="ts"> -import { defineComponent, PropType, unref } from 'vue'; -import MkButton from '../MkButton.vue'; -import * as os from '@/os'; -import { ButtonBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; - -export default defineComponent({ - components: { - MkButton, - }, - props: { - block: { - type: Object as PropType<ButtonBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - methods: { - click() { - if (this.block.action === 'dialog') { - this.hpml.eval(); - os.alert({ - text: this.hpml.interpolate(this.block.content), - }); - } else if (this.block.action === 'resetRandom') { - this.hpml.updateRandomSeed(Math.random()); - this.hpml.eval(); - } else if (this.block.action === 'pushEvent') { - os.api('page-push', { - pageId: this.hpml.page.id, - event: this.block.event, - ...(this.block.var ? { - var: unref(this.hpml.vars)[this.block.var], - } : {}), - }); - - os.alert({ - type: 'success', - text: this.hpml.interpolate(this.block.message), - }); - } else if (this.block.action === 'callAiScript') { - this.hpml.callAiScript(this.block.fn); - } - }, - }, -}); -</script> - -<style lang="scss" module> -.button { - display: inline-block; - min-width: 200px; - max-width: 450px; - margin: 8px 0; -} -</style> diff --git a/packages/frontend/src/components/page/page.canvas.vue b/packages/frontend/src/components/page/page.canvas.vue deleted file mode 100644 index 82ff36ec36..0000000000 --- a/packages/frontend/src/components/page/page.canvas.vue +++ /dev/null @@ -1,48 +0,0 @@ -<template> -<div class="ysrxegms"> - <canvas ref="canvas" :width="block.width" :height="block.height"/> -</div> -</template> - -<script lang="ts"> -import { defineComponent, onMounted, PropType, Ref, ref } from 'vue'; -import { CanvasBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; - -export default defineComponent({ - props: { - block: { - type: Object as PropType<CanvasBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - setup(props, ctx) { - const canvas: Ref<any> = ref(null); - - onMounted(() => { - props.hpml.registerCanvas(props.block.name, canvas.value); - }); - - return { - canvas, - }; - }, -}); -</script> - -<style lang="scss" scoped> -.ysrxegms { - display: inline-block; - vertical-align: bottom; - overflow: auto; - max-width: 100%; - - > canvas { - display: block; - } -} -</style> diff --git a/packages/frontend/src/components/page/page.counter.vue b/packages/frontend/src/components/page/page.counter.vue deleted file mode 100644 index 3f282a2e51..0000000000 --- a/packages/frontend/src/components/page/page.counter.vue +++ /dev/null @@ -1,51 +0,0 @@ -<template> -<div> - <MkButton :class="$style.button" @click="click()">{{ hpml.interpolate(block.text) }}</MkButton> -</div> -</template> - -<script lang="ts"> -import { computed, defineComponent, PropType } from 'vue'; -import MkButton from '../MkButton.vue'; -import { CounterVarBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; - -export default defineComponent({ - components: { - MkButton, - }, - props: { - block: { - type: Object as PropType<CounterVarBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - setup(props, ctx) { - const value = computed(() => { - return props.hpml.vars.value[props.block.name]; - }); - - function click() { - props.hpml.updatePageVar(props.block.name, value.value + (props.block.inc || 1)); - props.hpml.eval(); - } - - return { - click, - }; - }, -}); -</script> - -<style lang="scss" module> -.button { - display: inline-block; - min-width: 300px; - max-width: 450px; - margin: 8px 0; -} -</style> diff --git a/packages/frontend/src/components/page/page.if.vue b/packages/frontend/src/components/page/page.if.vue deleted file mode 100644 index 372a15f0c6..0000000000 --- a/packages/frontend/src/components/page/page.if.vue +++ /dev/null @@ -1,31 +0,0 @@ -<template> -<div v-show="hpml.vars.value[block.var]"> - <XBlock v-for="child in block.children" :key="child.id" :block="child" :hpml="hpml" :h="h"/> -</div> -</template> - -<script lang="ts"> -import { IfBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { defineComponent, defineAsyncComponent, PropType } from 'vue'; - -export default defineComponent({ - components: { - XBlock: defineAsyncComponent(() => import('./page.block.vue')), - }, - props: { - block: { - type: Object as PropType<IfBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - h: { - type: Number, - required: true, - }, - }, -}); -</script> diff --git a/packages/frontend/src/components/page/page.number-input.vue b/packages/frontend/src/components/page/page.number-input.vue deleted file mode 100644 index 9cac3b4f0d..0000000000 --- a/packages/frontend/src/components/page/page.number-input.vue +++ /dev/null @@ -1,54 +0,0 @@ -<template> -<div> - <MkInput :class="$style.input" :model-value="value" type="number" @update:model-value="updateValue($event)"> - <template #label>{{ hpml.interpolate(block.text) }}</template> - </MkInput> -</div> -</template> - -<script lang="ts"> -import { computed, defineComponent, PropType } from 'vue'; -import MkInput from '../MkInput.vue'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { NumberInputVarBlock } from '@/scripts/hpml/block'; - -export default defineComponent({ - components: { - MkInput, - }, - props: { - block: { - type: Object as PropType<NumberInputVarBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - setup(props, ctx) { - const value = computed(() => { - return props.hpml.vars.value[props.block.name]; - }); - - function updateValue(newValue) { - props.hpml.updatePageVar(props.block.name, newValue); - props.hpml.eval(); - } - - return { - value, - updateValue, - }; - }, -}); -</script> - -<style lang="scss" module> -.input { - display: inline-block; - min-width: 300px; - max-width: 450px; - margin: 8px 0; -} -</style> diff --git a/packages/frontend/src/components/page/page.post.vue b/packages/frontend/src/components/page/page.post.vue deleted file mode 100644 index 55da610cb6..0000000000 --- a/packages/frontend/src/components/page/page.post.vue +++ /dev/null @@ -1,111 +0,0 @@ -<template> -<div class="ngbfujlo"> - <MkTextarea :model-value="text" readonly style="margin: 0;"></MkTextarea> - <MkButton class="button" primary :disabled="posting || posted" @click="post()"> - <i v-if="posted" class="ti ti-check"></i> - <i v-else class="ti ti-send"></i> - </MkButton> -</div> -</template> - -<script lang="ts"> -import { defineComponent, PropType } from 'vue'; -import MkTextarea from '../MkTextarea.vue'; -import MkButton from '../MkButton.vue'; -import { apiUrl } from '@/config'; -import * as os from '@/os'; -import { PostBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { defaultStore } from '@/store'; -import { $i } from '@/account'; - -export default defineComponent({ - components: { - MkTextarea, - MkButton, - }, - props: { - block: { - type: Object as PropType<PostBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - data() { - return { - text: this.hpml.interpolate(this.block.text), - posted: false, - posting: false, - }; - }, - watch: { - 'hpml.vars': { - handler() { - this.text = this.hpml.interpolate(this.block.text); - }, - deep: true, - }, - }, - methods: { - upload() { - const promise = new Promise((ok) => { - const canvas = this.hpml.canvases[this.block.canvasId]; - canvas.toBlob(blob => { - const formData = new FormData(); - formData.append('file', blob); - formData.append('i', $i.token); - if (defaultStore.state.uploadFolder) { - formData.append('folderId', defaultStore.state.uploadFolder); - } - - window.fetch(apiUrl + '/drive/files/create', { - method: 'POST', - body: formData, - }) - .then(response => response.json()) - .then(f => { - ok(f); - }); - }); - }); - os.promiseDialog(promise); - return promise; - }, - async post() { - this.posting = true; - const file = this.block.attachCanvasImage ? await this.upload() : null; - os.apiWithDialog('notes/create', { - text: this.text === '' ? null : this.text, - fileIds: file ? [file.id] : undefined, - }).then(() => { - this.posted = true; - }); - }, - }, -}); -</script> - -<style lang="scss" scoped> -.ngbfujlo { - position: relative; - padding: 32px; - border-radius: 6px; - box-shadow: 0 2px 8px var(--shadow); - z-index: 1; - - > .button { - margin-top: 32px; - } - - @media (max-width: 600px) { - padding: 16px; - - > .button { - margin-top: 16px; - } - } -} -</style> diff --git a/packages/frontend/src/components/page/page.radio-button.vue b/packages/frontend/src/components/page/page.radio-button.vue deleted file mode 100644 index ce8f252e44..0000000000 --- a/packages/frontend/src/components/page/page.radio-button.vue +++ /dev/null @@ -1,44 +0,0 @@ -<template> -<div> - <div>{{ hpml.interpolate(block.title) }}</div> - <MkRadio v-for="item in block.values" :key="item" :modelValue="value" :value="item" @update:model-value="updateValue($event)">{{ item }}</MkRadio> -</div> -</template> - -<script lang="ts"> -import { computed, defineComponent, PropType } from 'vue'; -import MkRadio from '../MkRadio.vue'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { RadioButtonVarBlock } from '@/scripts/hpml/block'; - -export default defineComponent({ - components: { - MkRadio, - }, - props: { - block: { - type: Object as PropType<RadioButtonVarBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - setup(props, ctx) { - const value = computed(() => { - return props.hpml.vars.value[props.block.name]; - }); - - function updateValue(newValue: string) { - props.hpml.updatePageVar(props.block.name, newValue); - props.hpml.eval(); - } - - return { - value, - updateValue, - }; - }, -}); -</script> diff --git a/packages/frontend/src/components/page/page.switch.vue b/packages/frontend/src/components/page/page.switch.vue deleted file mode 100644 index b5f3464512..0000000000 --- a/packages/frontend/src/components/page/page.switch.vue +++ /dev/null @@ -1,54 +0,0 @@ -<template> -<div class="hkcxmtwj"> - <MkSwitch :model-value="value" @update:model-value="updateValue($event)">{{ hpml.interpolate(block.text) }}</MkSwitch> -</div> -</template> - -<script lang="ts"> -import { computed, defineComponent, PropType } from 'vue'; -import MkSwitch from '../MkSwitch.vue'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { SwitchVarBlock } from '@/scripts/hpml/block'; - -export default defineComponent({ - components: { - MkSwitch, - }, - props: { - block: { - type: Object as PropType<SwitchVarBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - setup(props, ctx) { - const value = computed(() => { - return props.hpml.vars.value[props.block.name]; - }); - - function updateValue(newValue: boolean) { - props.hpml.updatePageVar(props.block.name, newValue); - props.hpml.eval(); - } - - return { - value, - updateValue, - }; - }, -}); -</script> - -<style lang="scss" scoped> -.hkcxmtwj { - display: inline-block; - margin: 16px auto; - - & + .hkcxmtwj { - margin-left: 16px; - } -} -</style> diff --git a/packages/frontend/src/components/page/page.text-input.vue b/packages/frontend/src/components/page/page.text-input.vue deleted file mode 100644 index 1df45fefed..0000000000 --- a/packages/frontend/src/components/page/page.text-input.vue +++ /dev/null @@ -1,54 +0,0 @@ -<template> -<div> - <MkInput :class="$style.input" :model-value="value" type="text" @update:model-value="updateValue($event)"> - <template #label>{{ hpml.interpolate(block.text) }}</template> - </MkInput> -</div> -</template> - -<script lang="ts"> -import { computed, defineComponent, PropType } from 'vue'; -import MkInput from '../MkInput.vue'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { TextInputVarBlock } from '@/scripts/hpml/block'; - -export default defineComponent({ - components: { - MkInput, - }, - props: { - block: { - type: Object as PropType<TextInputVarBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - setup(props, ctx) { - const value = computed(() => { - return props.hpml.vars.value[props.block.name]; - }); - - function updateValue(newValue) { - props.hpml.updatePageVar(props.block.name, newValue); - props.hpml.eval(); - } - - return { - value, - updateValue, - }; - }, -}); -</script> - -<style lang="scss" module> -.input { - display: inline-block; - min-width: 300px; - max-width: 450px; - margin: 8px 0; -} -</style> diff --git a/packages/frontend/src/components/page/page.textarea-input.vue b/packages/frontend/src/components/page/page.textarea-input.vue deleted file mode 100644 index db3a96dd1b..0000000000 --- a/packages/frontend/src/components/page/page.textarea-input.vue +++ /dev/null @@ -1,45 +0,0 @@ -<template> -<div> - <MkTextarea :model-value="value" @update:model-value="updateValue($event)"> - <template #label>{{ hpml.interpolate(block.text) }}</template> - </MkTextarea> -</div> -</template> - -<script lang="ts"> -import { computed, defineComponent, PropType } from 'vue'; -import MkTextarea from '../MkTextarea.vue'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { TextInputVarBlock } from '@/scripts/hpml/block'; - -export default defineComponent({ - components: { - MkTextarea, - }, - props: { - block: { - type: Object as PropType<TextInputVarBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - setup(props, ctx) { - const value = computed(() => { - return props.hpml.vars.value[props.block.name]; - }); - - function updateValue(newValue) { - props.hpml.updatePageVar(props.block.name, newValue); - props.hpml.eval(); - } - - return { - value, - updateValue, - }; - }, -}); -</script> diff --git a/packages/frontend/src/components/page/page.textarea.vue b/packages/frontend/src/components/page/page.textarea.vue deleted file mode 100644 index 9b82412e8a..0000000000 --- a/packages/frontend/src/components/page/page.textarea.vue +++ /dev/null @@ -1,39 +0,0 @@ -<template> -<MkTextarea :model-value="text" readonly></MkTextarea> -</template> - -<script lang="ts"> -import { TextBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { defineComponent, PropType } from 'vue'; -import MkTextarea from '../MkTextarea.vue'; - -export default defineComponent({ - components: { - MkTextarea, - }, - props: { - block: { - type: Object as PropType<TextBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - data() { - return { - text: this.hpml.interpolate(this.block.text), - }; - }, - watch: { - 'hpml.vars': { - handler() { - this.text = this.hpml.interpolate(this.block.text); - }, - deep: true, - }, - }, -}); -</script> From 238d0fa667c19715135c9d20c06b1359fb0a87be Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 10:50:21 +0900 Subject: [PATCH 008/213] refactor --- .../src/components/page/block.type.ts | 29 +++ .../src/components/page/page.block.vue | 34 +-- .../src/components/page/page.image.vue | 12 +- .../src/components/page/page.note.vue | 40 +-- .../src/components/page/page.section.vue | 35 +-- .../src/components/page/page.text.vue | 56 +--- .../frontend/src/components/page/page.vue | 43 +-- packages/frontend/src/scripts/hpml/block.ts | 109 -------- .../frontend/src/scripts/hpml/evaluator.ts | 171 ------------ packages/frontend/src/scripts/hpml/expr.ts | 79 ------ packages/frontend/src/scripts/hpml/index.ts | 100 ------- packages/frontend/src/scripts/hpml/lib.ts | 245 ------------------ .../frontend/src/scripts/hpml/type-checker.ts | 182 ------------- 13 files changed, 92 insertions(+), 1043 deletions(-) create mode 100644 packages/frontend/src/components/page/block.type.ts delete mode 100644 packages/frontend/src/scripts/hpml/block.ts delete mode 100644 packages/frontend/src/scripts/hpml/evaluator.ts delete mode 100644 packages/frontend/src/scripts/hpml/expr.ts delete mode 100644 packages/frontend/src/scripts/hpml/index.ts delete mode 100644 packages/frontend/src/scripts/hpml/lib.ts delete mode 100644 packages/frontend/src/scripts/hpml/type-checker.ts diff --git a/packages/frontend/src/components/page/block.type.ts b/packages/frontend/src/components/page/block.type.ts new file mode 100644 index 0000000000..71249a8aff --- /dev/null +++ b/packages/frontend/src/components/page/block.type.ts @@ -0,0 +1,29 @@ +export type BlockBase = { + id: string; + type: string; +}; + +export type TextBlock = BlockBase & { + type: 'text'; + text: string; +}; + +export type SectionBlock = BlockBase & { + type: 'section'; + title: string; + children: Block[]; +}; + +export type ImageBlock = BlockBase & { + type: 'image'; + fileId: string | null; +}; + +export type NoteBlock = BlockBase & { + type: 'note'; + detailed: boolean; + note: string | null; +}; + +export type Block = + TextBlock | SectionBlock | ImageBlock | NoteBlock; diff --git a/packages/frontend/src/components/page/page.block.vue b/packages/frontend/src/components/page/page.block.vue index 3f8a5dbc59..dddb9d76bc 100644 --- a/packages/frontend/src/components/page/page.block.vue +++ b/packages/frontend/src/components/page/page.block.vue @@ -1,33 +1,19 @@ <template> -<component :is="'x-' + block.type" :key="block.id" :block="block" :hpml="hpml" :h="h"/> +<component :is="'x-' + block.type" :key="block.id" :page="page" :block="block" :h="h"/> </template> -<script lang="ts"> -import { defineComponent, PropType } from 'vue'; +<script lang="ts" setup> +import { } from 'vue'; +import * as Misskey from 'misskey-js'; import XText from './page.text.vue'; import XSection from './page.section.vue'; import XImage from './page.image.vue'; import XNote from './page.note.vue'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { Block } from '@/scripts/hpml/block'; +import { Block } from './block.type'; -export default defineComponent({ - components: { - XText, XSection, XImage, XNote, - }, - props: { - block: { - type: Object as PropType<Block>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - h: { - type: Number, - required: true, - }, - }, -}); +defineProps<{ + block: Block, + h: number, + page: Misskey.entities.Page, +}>(); </script> diff --git a/packages/frontend/src/components/page/page.image.vue b/packages/frontend/src/components/page/page.image.vue index 6ea81d257f..2edcfb8b1a 100644 --- a/packages/frontend/src/components/page/page.image.vue +++ b/packages/frontend/src/components/page/page.image.vue @@ -5,15 +5,15 @@ </template> <script lang="ts" setup> -import { PropType } from 'vue'; +import { } from 'vue'; +import * as Misskey from 'misskey-js'; +import { ImageBlock } from './block.type'; import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue'; -import { ImageBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; const props = defineProps<{ - block: PropType<ImageBlock>, - hpml: PropType<Hpml>, + block: ImageBlock, + page: Misskey.entities.Page, }>(); -const image = props.hpml.page.attachedFiles.find(x => x.id === props.block.fileId); +const image = props.page.attachedFiles.find(x => x.id === props.block.fileId); </script> diff --git a/packages/frontend/src/components/page/page.note.vue b/packages/frontend/src/components/page/page.note.vue index 7c620184d7..7133a7f5a1 100644 --- a/packages/frontend/src/components/page/page.note.vue +++ b/packages/frontend/src/components/page/page.note.vue @@ -5,37 +5,25 @@ </div> </template> -<script lang="ts"> -import { defineComponent, onMounted, PropType, Ref, ref } from 'vue'; +<script lang="ts" setup> +import { onMounted, Ref, ref } from 'vue'; +import * as Misskey from 'misskey-js'; +import { NoteBlock } from './block.type'; import MkNote from '@/components/MkNote.vue'; import MkNoteDetailed from '@/components/MkNoteDetailed.vue'; import * as os from '@/os'; -import { NoteBlock } from '@/scripts/hpml/block'; -export default defineComponent({ - components: { - MkNote, - MkNoteDetailed, - }, - props: { - block: { - type: Object as PropType<NoteBlock>, - required: true, - }, - }, - setup(props, ctx) { - const note: Ref<Record<string, any> | null> = ref(null); +const props = defineProps<{ + block: NoteBlock, + page: Misskey.entities.Page, +}>(); - onMounted(() => { - os.api('notes/show', { noteId: props.block.note }) - .then(result => { - note.value = result; - }); +const note: Ref<Misskey.entities.Note | null> = ref(null); + +onMounted(() => { + os.api('notes/show', { noteId: props.block.note }) + .then(result => { + note.value = result; }); - - return { - note, - }; - }, }); </script> diff --git a/packages/frontend/src/components/page/page.section.vue b/packages/frontend/src/components/page/page.section.vue index 50181b3905..dc06a231f9 100644 --- a/packages/frontend/src/components/page/page.section.vue +++ b/packages/frontend/src/components/page/page.section.vue @@ -3,34 +3,23 @@ <component :is="'h' + h">{{ block.title }}</component> <div class="children"> - <XBlock v-for="child in block.children" :key="child.id" :block="child" :hpml="hpml" :h="h + 1"/> + <XBlock v-for="child in block.children" :key="child.id" :page="page" :block="child" :h="h + 1"/> </div> </section> </template> -<script lang="ts"> -import { defineComponent, defineAsyncComponent, PropType } from 'vue'; -import { SectionBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; +<script lang="ts" setup> +import { defineAsyncComponent } from 'vue'; +import * as Misskey from 'misskey-js'; +import { SectionBlock } from './block.type'; -export default defineComponent({ - components: { - XBlock: defineAsyncComponent(() => import('./page.block.vue')), - }, - props: { - block: { - type: Object as PropType<SectionBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - h: { - required: true, - }, - }, -}); +const XBlock = defineAsyncComponent(() => import('./page.block.vue')); + +defineProps<{ + block: SectionBlock, + h: number, + page: Misskey.entities.Page, +}>(); </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue index e0e4959efa..c324d55a70 100644 --- a/packages/frontend/src/components/page/page.text.vue +++ b/packages/frontend/src/components/page/page.text.vue @@ -1,56 +1,26 @@ <template> <div class="mrdgzndn"> - <Mfm :key="text" :text="text" :is-note="false" :i="$i"/> + <Mfm :text="block.text" :is-note="false" :i="$i"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" class="url"/> </div> </template> -<script lang="ts"> -import { defineAsyncComponent, defineComponent, PropType } from 'vue'; +<script lang="ts" setup> +import { defineAsyncComponent } from 'vue'; import * as mfm from 'mfm-js'; -import { TextBlock } from '@/scripts/hpml/block'; -import { Hpml } from '@/scripts/hpml/evaluator'; +import * as Misskey from 'misskey-js'; +import { TextBlock } from './block.type'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm'; import { $i } from '@/account'; -export default defineComponent({ - components: { - MkUrlPreview: defineAsyncComponent(() => import('@/components/MkUrlPreview.vue')), - }, - props: { - block: { - type: Object as PropType<TextBlock>, - required: true, - }, - hpml: { - type: Object as PropType<Hpml>, - required: true, - }, - }, - data() { - return { - text: this.hpml.interpolate(this.block.text), - $i, - }; - }, - computed: { - urls(): string[] { - if (this.text) { - return extractUrlFromMfm(mfm.parse(this.text)); - } else { - return []; - } - }, - }, - watch: { - 'hpml.vars': { - handler() { - this.text = this.hpml.interpolate(this.block.text); - }, - deep: true, - }, - }, -}); +const MkUrlPreview = defineAsyncComponent(() => import('@/components/MkUrlPreview.vue')); + +const props = defineProps<{ + block: TextBlock, + page: Misskey.entities.Page, +}>(); + +const urls = props.block.text ? extractUrlFromMfm(mfm.parse(props.block.text)) : []; </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue index 5f1f62581e..f9291c4d2d 100644 --- a/packages/frontend/src/components/page/page.vue +++ b/packages/frontend/src/components/page/page.vue @@ -1,44 +1,17 @@ <template> -<div v-if="hpml" class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }"> - <XBlock v-for="child in page.content" :key="child.id" :block="child" :hpml="hpml" :h="2"/> +<div class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }"> + <XBlock v-for="child in page.content" :key="child.id" :block="child" :h="2"/> </div> </template> -<script lang="ts"> -import { defineComponent, onMounted, nextTick, PropType } from 'vue'; +<script lang="ts" setup> +import { onMounted, nextTick } from 'vue'; +import * as Misskey from 'misskey-js'; import XBlock from './page.block.vue'; -import { Hpml } from '@/scripts/hpml/evaluator'; -import { url } from '@/config'; -import { $i } from '@/account'; -export default defineComponent({ - components: { - XBlock, - }, - props: { - page: { - type: Object as PropType<Record<string, any>>, - required: true, - }, - }, - setup(props, ctx) { - const hpml = new Hpml(props.page, { - randomSeed: Math.random(), - visitor: $i, - url: url, - }); - - onMounted(() => { - nextTick(() => { - hpml.eval(); - }); - }); - - return { - hpml, - }; - }, -}); +defineProps<{ + page: Misskey.entities.Page, +}>(); </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/scripts/hpml/block.ts b/packages/frontend/src/scripts/hpml/block.ts deleted file mode 100644 index 804c5c1124..0000000000 --- a/packages/frontend/src/scripts/hpml/block.ts +++ /dev/null @@ -1,109 +0,0 @@ -// blocks - -export type BlockBase = { - id: string; - type: string; -}; - -export type TextBlock = BlockBase & { - type: 'text'; - text: string; -}; - -export type SectionBlock = BlockBase & { - type: 'section'; - title: string; - children: (Block | VarBlock)[]; -}; - -export type ImageBlock = BlockBase & { - type: 'image'; - fileId: string | null; -}; - -export type ButtonBlock = BlockBase & { - type: 'button'; - text: any; - primary: boolean; - action: string; - content: string; - event: string; - message: string; - var: string; - fn: string; -}; - -export type IfBlock = BlockBase & { - type: 'if'; - var: string; - children: Block[]; -}; - -export type TextareaBlock = BlockBase & { - type: 'textarea'; - text: string; -}; - -export type PostBlock = BlockBase & { - type: 'post'; - text: string; - attachCanvasImage: boolean; - canvasId: string; -}; - -export type CanvasBlock = BlockBase & { - type: 'canvas'; - name: string; // canvas id - width: number; - height: number; -}; - -export type NoteBlock = BlockBase & { - type: 'note'; - detailed: boolean; - note: string | null; -}; - -export type Block = - TextBlock | SectionBlock | ImageBlock | ButtonBlock | IfBlock | TextareaBlock | PostBlock | CanvasBlock | NoteBlock | VarBlock; - -// variable blocks - -export type VarBlockBase = BlockBase & { - name: string; -}; - -export type NumberInputVarBlock = VarBlockBase & { - type: 'numberInput'; - text: string; -}; - -export type TextInputVarBlock = VarBlockBase & { - type: 'textInput'; - text: string; -}; - -export type SwitchVarBlock = VarBlockBase & { - type: 'switch'; - text: string; -}; - -export type RadioButtonVarBlock = VarBlockBase & { - type: 'radioButton'; - title: string; - values: string[]; -}; - -export type CounterVarBlock = VarBlockBase & { - type: 'counter'; - text: string; - inc: number; -}; - -export type VarBlock = - NumberInputVarBlock | TextInputVarBlock | SwitchVarBlock | RadioButtonVarBlock | CounterVarBlock; - -const varBlock = ['numberInput', 'textInput', 'switch', 'radioButton', 'counter']; -export function isVarBlock(block: Block): block is VarBlock { - return varBlock.includes(block.type); -} diff --git a/packages/frontend/src/scripts/hpml/evaluator.ts b/packages/frontend/src/scripts/hpml/evaluator.ts deleted file mode 100644 index 9adfba7f27..0000000000 --- a/packages/frontend/src/scripts/hpml/evaluator.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { ref, Ref, unref } from 'vue'; -import { collectPageVars } from '../collect-page-vars'; -import { initHpmlLib } from './lib'; -import { Expr, isLiteralValue, Variable } from './expr'; -import { PageVar, envVarsDef, Fn, HpmlScope, HpmlError } from '.'; -import { version } from '@/config'; - -/** - * Hpml evaluator - */ -export class Hpml { - private variables: Variable[]; - private pageVars: PageVar[]; - private envVars: Record<keyof typeof envVarsDef, any>; - public pageVarUpdatedCallback?: values.VFn; - public canvases: Record<string, HTMLCanvasElement> = {}; - public vars: Ref<Record<string, any>> = ref({}); - public page: Record<string, any>; - - private opts: { - randomSeed: string; visitor?: any; url?: string; - }; - - constructor(page: Hpml['page'], opts: Hpml['opts']) { - this.page = page; - this.variables = this.page.variables; - this.pageVars = collectPageVars(this.page.content); - this.opts = opts; - - const date = new Date(); - - this.envVars = { - AI: 'kawaii', - VERSION: version, - URL: this.page ? `${opts.url}/@${this.page.user.username}/pages/${this.page.name}` : '', - LOGIN: opts.visitor != null, - NAME: opts.visitor ? opts.visitor.name || opts.visitor.username : '', - USERNAME: opts.visitor ? opts.visitor.username : '', - USERID: opts.visitor ? opts.visitor.id : '', - NOTES_COUNT: opts.visitor ? opts.visitor.notesCount : 0, - FOLLOWERS_COUNT: opts.visitor ? opts.visitor.followersCount : 0, - FOLLOWING_COUNT: opts.visitor ? opts.visitor.followingCount : 0, - IS_CAT: opts.visitor ? opts.visitor.isCat : false, - SEED: opts.randomSeed ? opts.randomSeed : '', - YMD: `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`, - AISCRIPT_DISABLED: true, - NULL: null, - }; - - this.eval(); - } - - public eval() { - try { - this.vars.value = this.evaluateVars(); - } catch (err) { - //this.onError(e); - } - } - - public interpolate(str: string) { - if (str == null) return null; - return str.replace(/{(.+?)}/g, match => { - const v = unref(this.vars)[match.slice(1, -1).trim()]; - return v == null ? 'NULL' : v.toString(); - }); - } - - public registerCanvas(id: string, canvas: any) { - this.canvases[id] = canvas; - } - - public updatePageVar(name: string, value: any) { - const pageVar = this.pageVars.find(v => v.name === name); - if (pageVar !== undefined) { - pageVar.value = value; - } else { - throw new HpmlError(`No such page var '${name}'`); - } - } - - public updateRandomSeed(seed: string) { - this.opts.randomSeed = seed; - this.envVars.SEED = seed; - } - - private _interpolateScope(str: string, scope: HpmlScope) { - return str.replace(/{(.+?)}/g, match => { - const v = scope.getState(match.slice(1, -1).trim()); - return v == null ? 'NULL' : v.toString(); - }); - } - - public evaluateVars(): Record<string, any> { - const values: Record<string, any> = {}; - - for (const [k, v] of Object.entries(this.envVars)) { - values[k] = v; - } - - for (const v of this.pageVars) { - values[v.name] = v.value; - } - - for (const v of this.variables) { - values[v.name] = this.evaluate(v, new HpmlScope([values])); - } - - return values; - } - - private evaluate(expr: Expr, scope: HpmlScope): any { - if (isLiteralValue(expr)) { - if (expr.type === null) { - return null; - } - - if (expr.type === 'number') { - return parseInt((expr.value as any), 10); - } - - if (expr.type === 'text' || expr.type === 'multiLineText') { - return this._interpolateScope(expr.value || '', scope); - } - - if (expr.type === 'textList') { - return this._interpolateScope(expr.value || '', scope).trim().split('\n'); - } - - if (expr.type === 'ref') { - return scope.getState(expr.value); - } - - // Define user function - if (expr.type === 'fn') { - return { - slots: expr.value.slots.map(x => x.name), - exec: (slotArg: Record<string, any>) => { - return this.evaluate(expr.value.expression, scope.createChildScope(slotArg, expr.id)); - }, - } as Fn; - } - return; - } - - // Call user function - if (expr.type.startsWith('fn:')) { - const fnName = expr.type.split(':')[1]; - const fn = scope.getState(fnName); - const args = {} as Record<string, any>; - for (let i = 0; i < fn.slots.length; i++) { - const name = fn.slots[i]; - args[name] = this.evaluate(expr.args[i], scope); - } - return fn.exec(args); - } - - if (expr.args === undefined) return null; - - const funcs = initHpmlLib(expr, scope, this.opts.randomSeed, this.opts.visitor); - - // Call function - const fnName = expr.type; - const fn = (funcs as any)[fnName]; - if (fn == null) { - throw new HpmlError(`No such function '${fnName}'`); - } else { - return fn(...expr.args.map(x => this.evaluate(x, scope))); - } - } -} diff --git a/packages/frontend/src/scripts/hpml/expr.ts b/packages/frontend/src/scripts/hpml/expr.ts deleted file mode 100644 index 18c7c2a14b..0000000000 --- a/packages/frontend/src/scripts/hpml/expr.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { literalDefs, Type } from '.'; - -export type ExprBase = { - id: string; -}; - -// value - -export type EmptyValue = ExprBase & { - type: null; - value: null; -}; - -export type TextValue = ExprBase & { - type: 'text'; - value: string; -}; - -export type MultiLineTextValue = ExprBase & { - type: 'multiLineText'; - value: string; -}; - -export type TextListValue = ExprBase & { - type: 'textList'; - value: string; -}; - -export type NumberValue = ExprBase & { - type: 'number'; - value: number; -}; - -export type RefValue = ExprBase & { - type: 'ref'; - value: string; // value is variable name -}; - -export type AiScriptRefValue = ExprBase & { - type: 'aiScriptVar'; - value: string; // value is variable name -}; - -export type UserFnValue = ExprBase & { - type: 'fn'; - value: UserFnInnerValue; -}; -type UserFnInnerValue = { - slots: { - name: string; - type: Type; - }[]; - expression: Expr; -}; - -export type Value = - EmptyValue | TextValue | MultiLineTextValue | TextListValue | NumberValue | RefValue | AiScriptRefValue | UserFnValue; - -export function isLiteralValue(expr: Expr): expr is Value { - if (expr.type == null) return true; - if (literalDefs[expr.type]) return true; - return false; -} - -// call function - -export type CallFn = ExprBase & { // "fn:hoge" or string - type: string; - args: Expr[]; - value: null; -}; - -// variable -export type Variable = (Value | CallFn) & { - name: string; -}; - -// expression -export type Expr = Variable | Value | CallFn; diff --git a/packages/frontend/src/scripts/hpml/index.ts b/packages/frontend/src/scripts/hpml/index.ts deleted file mode 100644 index 994f286b9f..0000000000 --- a/packages/frontend/src/scripts/hpml/index.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Hpml - */ - -import { Hpml } from './evaluator'; -import { funcDefs } from './lib'; - -export type Fn = { - slots: string[]; - exec: (args: Record<string, any>) => ReturnType<Hpml['evaluate']>; -}; - -export type Type = 'string' | 'number' | 'boolean' | 'stringArray' | null; - -export const literalDefs: Record<string, { out: any; category: string; icon: any; }> = { - text: { out: 'string', category: 'value', icon: 'ti ti-quote' }, - multiLineText: { out: 'string', category: 'value', icon: 'ti ti-align-left' }, - textList: { out: 'stringArray', category: 'value', icon: 'ti ti-list' }, - number: { out: 'number', category: 'value', icon: 'ti ti-list-numbers' }, - ref: { out: null, category: 'value', icon: 'ti ti-wand' }, - aiScriptVar: { out: null, category: 'value', icon: 'ti ti-wand' }, - fn: { out: 'function', category: 'value', icon: 'ti ti-math-function' }, -}; - -export const blockDefs = [ - ...Object.entries(literalDefs).map(([k, v]) => ({ - type: k, out: v.out, category: v.category, icon: v.icon, - })), - ...Object.entries(funcDefs).map(([k, v]) => ({ - type: k, out: v.out, category: v.category, icon: v.icon, - })), -]; - -export type PageVar = { name: string; value: any; type: Type; }; - -export const envVarsDef: Record<string, Type> = { - AI: 'string', - URL: 'string', - VERSION: 'string', - LOGIN: 'boolean', - NAME: 'string', - USERNAME: 'string', - USERID: 'string', - NOTES_COUNT: 'number', - FOLLOWERS_COUNT: 'number', - FOLLOWING_COUNT: 'number', - IS_CAT: 'boolean', - SEED: null, - YMD: 'string', - AISCRIPT_DISABLED: 'boolean', - NULL: null, -}; - -export class HpmlScope { - private layerdStates: Record<string, any>[]; - public name: string; - - constructor(layerdStates: HpmlScope['layerdStates'], name?: HpmlScope['name']) { - this.layerdStates = layerdStates; - this.name = name ?? 'anonymous'; - } - - public createChildScope(states: Record<string, any>, name?: HpmlScope['name']): HpmlScope { - const layer = [states, ...this.layerdStates]; - return new HpmlScope(layer, name); - } - - /** - * 指定した名前の変数の値を取得します - * @param name 変数名 - */ - public getState(name: string): any { - for (const later of this.layerdStates) { - const state = later[name]; - if (state !== undefined) { - return state; - } - } - - throw new HpmlError( - `No such variable '${name}' in scope '${this.name}'`, { - scope: this.layerdStates, - }); - } -} - -export class HpmlError extends Error { - public info?: any; - - constructor(message: string, info?: any) { - super(message); - - this.info = info; - - // Maintains proper stack trace for where our error was thrown (only available on V8) - if (Error.captureStackTrace) { - Error.captureStackTrace(this, HpmlError); - } - } -} diff --git a/packages/frontend/src/scripts/hpml/lib.ts b/packages/frontend/src/scripts/hpml/lib.ts deleted file mode 100644 index 88db82dd27..0000000000 --- a/packages/frontend/src/scripts/hpml/lib.ts +++ /dev/null @@ -1,245 +0,0 @@ -import seedrandom from 'seedrandom'; -import { Hpml } from './evaluator'; -import { Expr } from './expr'; -import { Fn, HpmlScope } from '.'; - -/* TODO: https://www.chartjs.org/docs/latest/configuration/canvas-background.html#color -// https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs -Chart.pluginService.register({ - beforeDraw: (chart, easing) => { - if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) { - const ctx = chart.chart.ctx; - ctx.save(); - ctx.fillStyle = chart.config.options.chartArea.backgroundColor; - ctx.fillRect(0, 0, chart.chart.width, chart.chart.height); - ctx.restore(); - } - } -}); -*/ - -export function initAiLib(hpml: Hpml) { - return { - 'MkPages:updated': values.FN_NATIVE(([callback]) => { - hpml.pageVarUpdatedCallback = (callback as values.VFn); - }), - 'MkPages:get_canvas': values.FN_NATIVE(([id]) => { - utils.assertString(id); - const canvas = hpml.canvases[id.value]; - const ctx = canvas.getContext('2d'); - return values.OBJ(new Map([ - ['clear_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.clearRect(x.value, y.value, width.value, height.value); })], - ['fill_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.fillRect(x.value, y.value, width.value, height.value); })], - ['stroke_rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.strokeRect(x.value, y.value, width.value, height.value); })], - ['fill_text', values.FN_NATIVE(([text, x, y, width]) => { ctx.fillText(text.value, x.value, y.value, width ? width.value : undefined); })], - ['stroke_text', values.FN_NATIVE(([text, x, y, width]) => { ctx.strokeText(text.value, x.value, y.value, width ? width.value : undefined); })], - ['set_line_width', values.FN_NATIVE(([width]) => { ctx.lineWidth = width.value; })], - ['set_font', values.FN_NATIVE(([font]) => { ctx.font = font.value; })], - ['set_fill_style', values.FN_NATIVE(([style]) => { ctx.fillStyle = style.value; })], - ['set_stroke_style', values.FN_NATIVE(([style]) => { ctx.strokeStyle = style.value; })], - ['begin_path', values.FN_NATIVE(() => { ctx.beginPath(); })], - ['close_path', values.FN_NATIVE(() => { ctx.closePath(); })], - ['move_to', values.FN_NATIVE(([x, y]) => { ctx.moveTo(x.value, y.value); })], - ['line_to', values.FN_NATIVE(([x, y]) => { ctx.lineTo(x.value, y.value); })], - ['arc', values.FN_NATIVE(([x, y, radius, startAngle, endAngle]) => { ctx.arc(x.value, y.value, radius.value, startAngle.value, endAngle.value); })], - ['rect', values.FN_NATIVE(([x, y, width, height]) => { ctx.rect(x.value, y.value, width.value, height.value); })], - ['fill', values.FN_NATIVE(() => { ctx.fill(); })], - ['stroke', values.FN_NATIVE(() => { ctx.stroke(); })], - ])); - }), - 'MkPages:chart': values.FN_NATIVE(([id, opts]) => { - /* TODO - utils.assertString(id); - utils.assertObject(opts); - const canvas = hpml.canvases[id.value]; - const color = getComputedStyle(document.documentElement).getPropertyValue('--accent'); - Chart.defaults.color = '#555'; - const chart = new Chart(canvas, { - type: opts.value.get('type').value, - data: { - labels: opts.value.get('labels').value.map(x => x.value), - datasets: opts.value.get('datasets').value.map(x => ({ - label: x.value.has('label') ? x.value.get('label').value : '', - data: x.value.get('data').value.map(x => x.value), - pointRadius: 0, - lineTension: 0, - borderWidth: 2, - borderColor: x.value.has('color') ? x.value.get('color') : color, - backgroundColor: tinycolor(x.value.has('color') ? x.value.get('color') : color).setAlpha(0.1).toRgbString(), - })) - }, - options: { - responsive: false, - devicePixelRatio: 1.5, - title: { - display: opts.value.has('title'), - text: opts.value.has('title') ? opts.value.get('title').value : '', - fontSize: 14, - }, - layout: { - padding: { - left: 32, - right: 32, - top: opts.value.has('title') ? 16 : 32, - bottom: 16 - } - }, - legend: { - display: opts.value.get('datasets').value.filter(x => x.value.has('label') && x.value.get('label').value).length === 0 ? false : true, - position: 'bottom', - labels: { - boxWidth: 16, - } - }, - tooltips: { - enabled: false, - }, - chartArea: { - backgroundColor: '#fff' - }, - ...(opts.value.get('type').value === 'radar' ? { - scale: { - ticks: { - display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : false, - min: opts.value.has('min') ? opts.value.get('min').value : undefined, - max: opts.value.has('max') ? opts.value.get('max').value : undefined, - maxTicksLimit: 8, - }, - pointLabels: { - fontSize: 12 - } - } - } : { - scales: { - yAxes: [{ - ticks: { - display: opts.value.has('show_tick_label') ? opts.value.get('show_tick_label').value : true, - min: opts.value.has('min') ? opts.value.get('min').value : undefined, - max: opts.value.has('max') ? opts.value.get('max').value : undefined, - } - }] - } - }) - } - }); - */ - }), - }; -} - -export const funcDefs: Record<string, { in: any[]; out: any; category: string; icon: any; }> = { - if: { in: ['boolean', 0, 0], out: 0, category: 'flow', icon: 'ti ti-share' }, - for: { in: ['number', 'function'], out: null, category: 'flow', icon: 'ti ti-recycle' }, - not: { in: ['boolean'], out: 'boolean', category: 'logical', icon: 'ti ti-flag' }, - or: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: 'ti ti-flag' }, - and: { in: ['boolean', 'boolean'], out: 'boolean', category: 'logical', icon: 'ti ti-flag' }, - add: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'ti ti-plus' }, - subtract: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'ti ti-minus' }, - multiply: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'ti ti-x' }, - divide: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'ti ti-divide' }, - mod: { in: ['number', 'number'], out: 'number', category: 'operation', icon: 'ti ti-divide' }, - round: { in: ['number'], out: 'number', category: 'operation', icon: 'ti ti-calculator' }, - eq: { in: [0, 0], out: 'boolean', category: 'comparison', icon: 'ti ti-equal' }, - notEq: { in: [0, 0], out: 'boolean', category: 'comparison', icon: 'ti ti-equal-not' }, - gt: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'ti ti-math-greater' }, - lt: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'ti ti-math-lower' }, - gtEq: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'ti ti-math-equal-greater' }, - ltEq: { in: ['number', 'number'], out: 'boolean', category: 'comparison', icon: 'ti ti-math-equal-lower' }, - strLen: { in: ['string'], out: 'number', category: 'text', icon: 'ti ti-quote' }, - strPick: { in: ['string', 'number'], out: 'string', category: 'text', icon: 'ti ti-quote' }, - strReplace: { in: ['string', 'string', 'string'], out: 'string', category: 'text', icon: 'ti ti-quote' }, - strReverse: { in: ['string'], out: 'string', category: 'text', icon: 'ti ti-quote' }, - join: { in: ['stringArray', 'string'], out: 'string', category: 'text', icon: 'ti ti-quote' }, - stringToNumber: { in: ['string'], out: 'number', category: 'convert', icon: 'ti ti-arrows-right-left' }, - numberToString: { in: ['number'], out: 'string', category: 'convert', icon: 'ti ti-arrows-right-left' }, - splitStrByLine: { in: ['string'], out: 'stringArray', category: 'convert', icon: 'ti ti-arrows-right-left' }, - pick: { in: [null, 'number'], out: null, category: 'list', icon: 'ti ti-indent-increase' }, - listLen: { in: [null], out: 'number', category: 'list', icon: 'ti ti-indent-increase' }, - rannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: 'ti ti-dice' }, - dailyRannum: { in: ['number', 'number'], out: 'number', category: 'random', icon: 'ti ti-dice' }, - seedRannum: { in: [null, 'number', 'number'], out: 'number', category: 'random', icon: 'ti ti-dice' }, - random: { in: ['number'], out: 'boolean', category: 'random', icon: 'ti ti-dice' }, - dailyRandom: { in: ['number'], out: 'boolean', category: 'random', icon: 'ti ti-dice' }, - seedRandom: { in: [null, 'number'], out: 'boolean', category: 'random', icon: 'ti ti-dice' }, - randomPick: { in: [0], out: 0, category: 'random', icon: 'ti ti-dice' }, - dailyRandomPick: { in: [0], out: 0, category: 'random', icon: 'ti ti-dice' }, - seedRandomPick: { in: [null, 0], out: 0, category: 'random', icon: 'ti ti-dice' }, - DRPWPM: { in: ['stringArray'], out: 'string', category: 'random', icon: 'ti ti-dice' }, // dailyRandomPickWithProbabilityMapping -}; - -export function initHpmlLib(expr: Expr, scope: HpmlScope, randomSeed: string, visitor?: any) { - const date = new Date(); - const day = `${visitor ? visitor.id : ''} ${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`; - - // SHOULD be fine to ignore since it's intended + function shape isn't defined - // eslint-disable-next-line @typescript-eslint/ban-types - const funcs: Record<string, Function> = { - not: (a: boolean) => !a, - or: (a: boolean, b: boolean) => a || b, - and: (a: boolean, b: boolean) => a && b, - eq: (a: any, b: any) => a === b, - notEq: (a: any, b: any) => a !== b, - gt: (a: number, b: number) => a > b, - lt: (a: number, b: number) => a < b, - gtEq: (a: number, b: number) => a >= b, - ltEq: (a: number, b: number) => a <= b, - if: (bool: boolean, a: any, b: any) => bool ? a : b, - for: (times: number, fn: Fn) => { - const result: any[] = []; - for (let i = 0; i < times; i++) { - result.push(fn.exec({ - [fn.slots[0]]: i + 1, - })); - } - return result; - }, - add: (a: number, b: number) => a + b, - subtract: (a: number, b: number) => a - b, - multiply: (a: number, b: number) => a * b, - divide: (a: number, b: number) => a / b, - mod: (a: number, b: number) => a % b, - round: (a: number) => Math.round(a), - strLen: (a: string) => a.length, - strPick: (a: string, b: number) => a[b - 1], - strReplace: (a: string, b: string, c: string) => a.split(b).join(c), - strReverse: (a: string) => a.split('').reverse().join(''), - join: (texts: string[], separator: string) => texts.join(separator || ''), - stringToNumber: (a: string) => parseInt(a), - numberToString: (a: number) => a.toString(), - splitStrByLine: (a: string) => a.split('\n'), - pick: (list: any[], i: number) => list[i - 1], - listLen: (list: any[]) => list.length, - random: (probability: number) => Math.floor(seedrandom(`${randomSeed}:${expr.id}`)() * 100) < probability, - rannum: (min: number, max: number) => min + Math.floor(seedrandom(`${randomSeed}:${expr.id}`)() * (max - min + 1)), - randomPick: (list: any[]) => list[Math.floor(seedrandom(`${randomSeed}:${expr.id}`)() * list.length)], - dailyRandom: (probability: number) => Math.floor(seedrandom(`${day}:${expr.id}`)() * 100) < probability, - dailyRannum: (min: number, max: number) => min + Math.floor(seedrandom(`${day}:${expr.id}`)() * (max - min + 1)), - dailyRandomPick: (list: any[]) => list[Math.floor(seedrandom(`${day}:${expr.id}`)() * list.length)], - seedRandom: (seed: any, probability: number) => Math.floor(seedrandom(seed)() * 100) < probability, - seedRannum: (seed: any, min: number, max: number) => min + Math.floor(seedrandom(seed)() * (max - min + 1)), - seedRandomPick: (seed: any, list: any[]) => list[Math.floor(seedrandom(seed)() * list.length)], - DRPWPM: (list: string[]) => { - const xs: any[] = []; - let totalFactor = 0; - for (const x of list) { - const parts = x.split(' '); - const factor = parseInt(parts.pop()!, 10); - const text = parts.join(' '); - totalFactor += factor; - xs.push({ factor, text }); - } - const r = seedrandom(`${day}:${expr.id}`)() * totalFactor; - let stackedFactor = 0; - for (const x of xs) { - if (r >= stackedFactor && r <= stackedFactor + x.factor) { - return x.text; - } else { - stackedFactor += x.factor; - } - } - return xs[0].text; - }, - }; - - return funcs; -} diff --git a/packages/frontend/src/scripts/hpml/type-checker.ts b/packages/frontend/src/scripts/hpml/type-checker.ts deleted file mode 100644 index ea8133f297..0000000000 --- a/packages/frontend/src/scripts/hpml/type-checker.ts +++ /dev/null @@ -1,182 +0,0 @@ -import { isLiteralValue } from './expr'; -import { funcDefs } from './lib'; -import { envVarsDef } from '.'; -import type { Type, PageVar } from '.'; -import type { Expr, Variable } from './expr'; - -type TypeError = { - arg: number; - expect: Type; - actual: Type; -}; - -/** - * Hpml type checker - */ -export class HpmlTypeChecker { - public variables: Variable[]; - public pageVars: PageVar[]; - - constructor(variables: HpmlTypeChecker['variables'] = [], pageVars: HpmlTypeChecker['pageVars'] = []) { - this.variables = variables; - this.pageVars = pageVars; - } - - public typeCheck(v: Expr): TypeError | null { - if (isLiteralValue(v)) return null; - - const def = funcDefs[v.type || '']; - if (def == null) { - throw new Error('Unknown type: ' + v.type); - } - - const generic: Type[] = []; - - for (let i = 0; i < def.in.length; i++) { - const arg = def.in[i]; - const type = this.infer(v.args[i]); - if (type === null) continue; - - if (typeof arg === 'number') { - if (generic[arg] === undefined) { - generic[arg] = type; - } else if (type !== generic[arg]) { - return { - arg: i, - expect: generic[arg], - actual: type, - }; - } - } else if (type !== arg) { - return { - arg: i, - expect: arg, - actual: type, - }; - } - } - - return null; - } - - public getExpectedType(v: Expr, slot: number): Type { - const def = funcDefs[v.type ?? '']; - if (def == null) { - throw new Error('Unknown type: ' + v.type); - } - - const generic: Type[] = []; - - for (let i = 0; i < def.in.length; i++) { - const arg = def.in[i]; - const type = this.infer(v.args[i]); - if (type === null) continue; - - if (typeof arg === 'number') { - if (generic[arg] === undefined) { - generic[arg] = type; - } - } - } - - if (typeof def.in[slot] === 'number') { - return generic[def.in[slot]] ?? null; - } else { - return def.in[slot]; - } - } - - public infer(v: Expr): Type { - if (v.type === null) return null; - if (v.type === 'text') return 'string'; - if (v.type === 'multiLineText') return 'string'; - if (v.type === 'textList') return 'stringArray'; - if (v.type === 'number') return 'number'; - if (v.type === 'ref') { - const variable = this.variables.find(va => va.name === v.value); - if (variable) { - return this.infer(variable); - } - - const pageVar = this.pageVars.find(va => va.name === v.value); - if (pageVar) { - return pageVar.type; - } - - const envVar = envVarsDef[v.value ?? '']; - if (envVar !== undefined) { - return envVar; - } - - return null; - } - if (v.type === 'aiScriptVar') return null; - if (v.type === 'fn') return null; // todo - if (v.type.startsWith('fn:')) return null; // todo - - const generic: Type[] = []; - - const def = funcDefs[v.type]; - - for (let i = 0; i < def.in.length; i++) { - const arg = def.in[i]; - if (typeof arg === 'number') { - const type = this.infer(v.args[i]); - - if (generic[arg] === undefined) { - generic[arg] = type; - } else { - if (type !== generic[arg]) { - generic[arg] = null; - } - } - } - } - - if (typeof def.out === 'number') { - return generic[def.out]; - } else { - return def.out; - } - } - - public getVarByName(name: string): Variable { - const v = this.variables.find(x => x.name === name); - if (v !== undefined) { - return v; - } else { - throw new Error(`No such variable '${name}'`); - } - } - - public getVarsByType(type: Type): Variable[] { - if (type == null) return this.variables; - return this.variables.filter(x => (this.infer(x) === null) || (this.infer(x) === type)); - } - - public getEnvVarsByType(type: Type): string[] { - if (type == null) return Object.keys(envVarsDef); - return Object.entries(envVarsDef).filter(([k, v]) => v === null || type === v).map(([k, v]) => k); - } - - public getPageVarsByType(type: Type): string[] { - if (type == null) return this.pageVars.map(v => v.name); - return this.pageVars.filter(v => type === v.type).map(v => v.name); - } - - public isUsedName(name: string) { - if (this.variables.some(v => v.name === name)) { - return true; - } - - if (this.pageVars.some(v => v.name === name)) { - return true; - } - - if (envVarsDef[name]) { - return true; - } - - return false; - } -} From 3d4a90b08a284f416564fc950a9216936c1a8e99 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 11:43:56 +0900 Subject: [PATCH 009/213] refactor(frontend): use composition api --- packages/frontend/src/components/MkSample.vue | 118 ----------- .../frontend/src/components/MkSuperMenu.vue | 21 +- .../frontend/src/components/MkTextarea.vue | 199 ++++++------------ .../pages/page-editor/page-editor.blocks.vue | 60 +++--- .../page-editor/page-editor.container.vue | 84 +++----- packages/frontend/src/pages/preview.vue | 21 -- packages/frontend/src/router.ts | 3 - 7 files changed, 125 insertions(+), 381 deletions(-) delete mode 100644 packages/frontend/src/components/MkSample.vue delete mode 100644 packages/frontend/src/pages/preview.vue diff --git a/packages/frontend/src/components/MkSample.vue b/packages/frontend/src/components/MkSample.vue deleted file mode 100644 index 922b862b47..0000000000 --- a/packages/frontend/src/components/MkSample.vue +++ /dev/null @@ -1,118 +0,0 @@ -<template> -<div class=""> - <div class=""> - <MkInput v-model="text"> - <template #label>Text</template> - </MkInput> - <MkSwitch v-model="flag"> - <span>Switch is now {{ flag ? 'on' : 'off' }}</span> - </MkSwitch> - <div style="margin: 32px 0;"> - <MkRadio v-model="radio" value="misskey">Misskey</MkRadio> - <MkRadio v-model="radio" value="mastodon">Mastodon</MkRadio> - <MkRadio v-model="radio" value="pleroma">Pleroma</MkRadio> - </div> - <MkButton inline>This is</MkButton> - <MkButton inline primary>the button</MkButton> - </div> - <div class="" style="pointer-events: none;"> - <Mfm :text="mfm"/> - </div> - <div class=""> - <MkButton inline primary @click="openMenu">Open menu</MkButton> - <MkButton inline primary @click="openDialog">Open dialog</MkButton> - <MkButton inline primary @click="openForm">Open form</MkButton> - <MkButton inline primary @click="openDrive">Open drive</MkButton> - </div> -</div> -</template> - -<script lang="ts"> -import { defineComponent } from 'vue'; -import MkButton from '@/components/MkButton.vue'; -import MkInput from '@/components/MkInput.vue'; -import MkSwitch from '@/components/MkSwitch.vue'; -import MkTextarea from '@/components/MkTextarea.vue'; -import MkRadio from '@/components/MkRadio.vue'; -import * as os from '@/os'; -import * as config from '@/config'; -import { $i } from '@/account'; - -export default defineComponent({ - components: { - MkButton, - MkInput, - MkSwitch, - MkTextarea, - MkRadio, - }, - - data() { - return { - text: '', - flag: true, - radio: 'misskey', - $i, - mfm: `Hello world! This is an @example mention. BTW you are @${this.$i ? this.$i.username : 'guest'}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.`, - }; - }, - - methods: { - async openDialog() { - os.alert({ - type: 'warning', - title: 'Oh my Aichan', - text: 'Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - }); - }, - - async openForm() { - os.form('Example form', { - foo: { - type: 'boolean', - default: true, - label: 'This is a boolean property', - }, - bar: { - type: 'number', - default: 300, - label: 'This is a number property', - }, - baz: { - type: 'string', - default: 'Misskey makes you happy.', - label: 'This is a string property', - }, - }); - }, - - async openDrive() { - os.selectDriveFile(false); - }, - - async selectUser() { - os.selectUser(); - }, - - async openMenu(ev) { - os.popupMenu([{ - type: 'label', - text: 'Fruits', - }, { - text: 'Create some apples', - action: () => {}, - }, { - text: 'Read some oranges', - action: () => {}, - }, { - text: 'Update some melons', - action: () => {}, - }, null, { - text: 'Delete some bananas', - danger: true, - action: () => {}, - }], ev.currentTarget ?? ev.target); - }, - }, -}); -</script> diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue index 2a8e43c570..72b70416d9 100644 --- a/packages/frontend/src/components/MkSuperMenu.vue +++ b/packages/frontend/src/components/MkSuperMenu.vue @@ -23,22 +23,13 @@ </div> </template> -<script lang="ts"> -import { defineComponent } from 'vue'; +<script lang="ts" setup> +import { } from 'vue'; -export default defineComponent({ - props: { - def: { - type: Array, - required: true, - }, - grid: { - type: Boolean, - required: false, - default: false, - }, - }, -}); +defineProps<{ + def: any[]; + grid?: boolean; +}>(); </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/MkTextarea.vue b/packages/frontend/src/components/MkTextarea.vue index 82b631edda..e8f10ab048 100644 --- a/packages/frontend/src/components/MkTextarea.vue +++ b/packages/frontend/src/components/MkTextarea.vue @@ -26,153 +26,88 @@ </div> </template> -<script lang="ts"> -import { defineComponent, onMounted, nextTick, ref, watch, computed, toRefs } from 'vue'; +<script lang="ts" setup> +import { onMounted, nextTick, ref, watch, computed, toRefs, shallowRef } from 'vue'; import { debounce } from 'throttle-debounce'; import MkButton from '@/components/MkButton.vue'; import { i18n } from '@/i18n'; -export default defineComponent({ - components: { - MkButton, - }, +const props = defineProps<{ + modelValue: string | null; + required?: boolean; + readonly?: boolean; + disabled?: boolean; + pattern?: string; + placeholder?: string; + autofocus?: boolean; + autocomplete?: string; + spellcheck?: boolean; + debounce?: boolean; + manualSave?: boolean; + code?: boolean; + tall?: boolean; + pre?: boolean; +}>(); - props: { - modelValue: { - required: true, - }, - type: { - type: String, - required: false, - }, - required: { - type: Boolean, - required: false, - }, - readonly: { - type: Boolean, - required: false, - }, - disabled: { - type: Boolean, - required: false, - }, - pattern: { - type: String, - required: false, - }, - placeholder: { - type: String, - required: false, - }, - autofocus: { - type: Boolean, - required: false, - default: false, - }, - autocomplete: { - required: false, - }, - spellcheck: { - required: false, - }, - code: { - type: Boolean, - required: false, - }, - tall: { - type: Boolean, - required: false, - default: false, - }, - pre: { - type: Boolean, - required: false, - default: false, - }, - debounce: { - type: Boolean, - required: false, - default: false, - }, - manualSave: { - type: Boolean, - required: false, - default: false, - }, - }, +const emit = defineEmits<{ + (ev: 'change', _ev: KeyboardEvent): void; + (ev: 'keydown', _ev: KeyboardEvent): void; + (ev: 'enter'): void; + (ev: 'update:modelValue', value: string): void; +}>(); - emits: ['change', 'keydown', 'enter', 'update:modelValue'], +const { modelValue, autofocus } = toRefs(props); +const v = ref<string>(modelValue.value ?? ''); +const focused = ref(false); +const changed = ref(false); +const invalid = ref(false); +const filled = computed(() => v.value !== '' && v.value != null); +const inputEl = shallowRef<HTMLTextAreaElement>(); - setup(props, context) { - const { modelValue, autofocus } = toRefs(props); - const v = ref(modelValue.value); - const focused = ref(false); - const changed = ref(false); - const invalid = ref(false); - const filled = computed(() => v.value !== '' && v.value != null); - const inputEl = ref(null); +const focus = () => inputEl.value.focus(); +const onInput = (ev) => { + changed.value = true; + emit('change', ev); +}; +const onKeydown = (ev: KeyboardEvent) => { + if (ev.isComposing || ev.key === 'Process' || ev.keyCode === 229) return; - const focus = () => inputEl.value.focus(); - const onInput = (ev) => { - changed.value = true; - context.emit('change', ev); - }; - const onKeydown = (ev: KeyboardEvent) => { - if (ev.isComposing || ev.key === 'Process' || ev.keyCode === 229) return; + emit('keydown', ev); - context.emit('keydown', ev); + if (ev.code === 'Enter') { + emit('enter'); + } +}; - if (ev.code === 'Enter') { - context.emit('enter'); - } - }; +const updated = () => { + changed.value = false; + emit('update:modelValue', v.value ?? ''); +}; - const updated = () => { - changed.value = false; - context.emit('update:modelValue', v.value); - }; +const debouncedUpdated = debounce(1000, updated); - const debouncedUpdated = debounce(1000, updated); +watch(modelValue, newValue => { + v.value = newValue; +}); - watch(modelValue, newValue => { - v.value = newValue; - }); +watch(v, newValue => { + if (!props.manualSave) { + if (props.debounce) { + debouncedUpdated(); + } else { + updated(); + } + } - watch(v, newValue => { - if (!props.manualSave) { - if (props.debounce) { - debouncedUpdated(); - } else { - updated(); - } - } + invalid.value = inputEl.value.validity.badInput; +}); - invalid.value = inputEl.value.validity.badInput; - }); - - onMounted(() => { - nextTick(() => { - if (autofocus.value) { - focus(); - } - }); - }); - - return { - v, - focused, - invalid, - changed, - filled, - inputEl, - focus, - onInput, - onKeydown, - updated, - i18n, - }; - }, +onMounted(() => { + nextTick(() => { + if (autofocus.value) { + focus(); + } + }); }); </script> diff --git a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue index 97bdcfe80f..2c3d59256c 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue @@ -9,49 +9,41 @@ </Sortable> </template> -<script lang="ts"> -import { defineComponent, defineAsyncComponent } from 'vue'; +<script lang="ts" setup> +import { defineAsyncComponent } from 'vue'; import XSection from './els/page-editor.el.section.vue'; import XText from './els/page-editor.el.text.vue'; import XImage from './els/page-editor.el.image.vue'; import XNote from './els/page-editor.el.note.vue'; -export default defineComponent({ - components: { - Sortable: defineAsyncComponent(() => import('vuedraggable').then(x => x.default)), - XSection, XText, XImage, XNote, - }, +const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default)); - props: { - modelValue: { - type: Array, - required: true, - }, - }, +const props = defineProps<{ + modelValue: any[]; +}>(); - emits: ['update:modelValue'], +const emit = defineEmits<{ + (ev: 'update:modelValue', value: any[]): void; +}>(); - methods: { - updateItem(v) { - const i = this.modelValue.findIndex(x => x.id === v.id); - const newValue = [ - ...this.modelValue.slice(0, i), - v, - ...this.modelValue.slice(i + 1), - ]; - this.$emit('update:modelValue', newValue); - }, +function updateItem(v) { + const i = props.modelValue.findIndex(x => x.id === v.id); + const newValue = [ + ...props.modelValue.slice(0, i), + v, + ...props.modelValue.slice(i + 1), + ]; + emit('update:modelValue', newValue); +} - removeItem(el) { - const i = this.modelValue.findIndex(x => x.id === el.id); - const newValue = [ - ...this.modelValue.slice(0, i), - ...this.modelValue.slice(i + 1), - ]; - this.$emit('update:modelValue', newValue); - }, - }, -}); +function removeItem(el) { + const i = props.modelValue.findIndex(x => x.id === el.id); + const newValue = [ + ...props.modelValue.slice(0, i), + ...props.modelValue.slice(i + 1), + ]; + emit('update:modelValue', newValue); +} </script> <style lang="scss" module> diff --git a/packages/frontend/src/pages/page-editor/page-editor.container.vue b/packages/frontend/src/pages/page-editor/page-editor.container.vue index dd733403af..0842b4fd26 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.container.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.container.vue @@ -1,5 +1,5 @@ <template> -<div class="cpjygsrt" :class="{ error: error != null, warn: warn != null }"> +<div class="cpjygsrt"> <header> <div class="title"><slot name="header"></slot></div> <div class="buttons"> @@ -16,58 +16,40 @@ </button> </div> </header> - <p v-show="showBody" v-if="error != null" class="error">{{ i18n.t('_pages.script.typeError', { slot: error.arg + 1, expect: i18n.t(`script.types.${error.expect}`), actual: i18n.t(`script.types.${error.actual}`) }) }}</p> - <p v-show="showBody" v-if="warn != null" class="warn">{{ i18n.t('_pages.script.thereIsEmptySlot', { slot: warn.slot + 1 }) }}</p> <div v-show="showBody" class="body"> <slot></slot> </div> </div> </template> -<script lang="ts"> -import { defineComponent } from 'vue'; +<script lang="ts" setup> +import { ref } from 'vue'; import { i18n } from '@/i18n'; -export default defineComponent({ - props: { - expanded: { - type: Boolean, - default: true, - }, - removable: { - type: Boolean, - default: true, - }, - draggable: { - type: Boolean, - default: false, - }, - error: { - required: false, - default: null, - }, - warn: { - required: false, - default: null, - }, - }, - emits: ['toggle', 'remove'], - data() { - return { - showBody: this.expanded, - i18n, - }; - }, - methods: { - toggleContent(show: boolean) { - this.showBody = show; - this.$emit('toggle', show); - }, - remove() { - this.$emit('remove'); - }, - }, +const props = withDefaults(defineProps<{ + expanded?: boolean; + removable?: boolean; + draggable?: boolean; +}>(), { + expanded: true, + removable: true, }); + +const emit = defineEmits<{ + (ev: 'toggle', show: boolean): void; + (ev: 'remove'): void; +}>(); + +const showBody = ref(props.expanded); + +function toggleContent(show: boolean) { + showBody.value = show; + emit('toggle', show); +} + +function remove() { + emit('remove'); +} </script> <style lang="scss" scoped> @@ -128,20 +110,6 @@ export default defineComponent({ } } - > .warn { - color: #b19e49; - margin: 0; - padding: 16px 16px 0 16px; - font-size: 14px; - } - - > .error { - color: #f00; - margin: 0; - padding: 16px 16px 0 16px; - font-size: 14px; - } - > .body { ::v-deep(.juejbjww), ::v-deep(.eiipwacr) { &:not(.inline):first-child { diff --git a/packages/frontend/src/pages/preview.vue b/packages/frontend/src/pages/preview.vue deleted file mode 100644 index 952af23a53..0000000000 --- a/packages/frontend/src/pages/preview.vue +++ /dev/null @@ -1,21 +0,0 @@ -<template> -<div> - <MkSample/> -</div> -</template> - -<script lang="ts" setup> -import { computed } from 'vue'; -import MkSample from '@/components/MkSample.vue'; -import { i18n } from '@/i18n'; -import { definePageMetadata } from '@/scripts/page-metadata'; - -const headerActions = $computed(() => []); - -const headerTabs = $computed(() => []); - -definePageMetadata(computed(() => ({ - title: i18n.ts.preview, - icon: 'ti ti-eye', -}))); -</script> diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index e46c1eeb77..add4bd9217 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -242,9 +242,6 @@ export const routes = [{ }, { path: '/scratchpad', component: page(() => import('./pages/scratchpad.vue')), -}, { - path: '/preview', - component: page(() => import('./pages/preview.vue')), }, { path: '/auth/:token', component: page(() => import('./pages/auth.vue')), From 0717afc3124a5d7434af3df31dfa54cbf420f109 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 12:23:39 +0900 Subject: [PATCH 010/213] refactor(frontend): use composition api --- .../src/components/MkFoldableSection.vue | 123 ++-- .../frontend/src/components/MkFormDialog.vue | 80 +-- .../src/components/MkObjectView.value.vue | 64 +- packages/frontend/src/components/MkRadios.vue | 36 +- packages/frontend/src/components/MkTab.vue | 12 +- .../frontend/src/components/form/suspense.vue | 91 +-- .../frontend/src/components/global/i18n.ts | 58 +- packages/frontend/src/components/mfm.ts | 652 +++++++++--------- 8 files changed, 495 insertions(+), 621 deletions(-) diff --git a/packages/frontend/src/components/MkFoldableSection.vue b/packages/frontend/src/components/MkFoldableSection.vue index 475e01c8d4..f52c66a8be 100644 --- a/packages/frontend/src/components/MkFoldableSection.vue +++ b/packages/frontend/src/components/MkFoldableSection.vue @@ -1,5 +1,5 @@ <template> -<div class="ssazuxis"> +<div ref="el" class="ssazuxis"> <header class="_button" :style="{ background: bg }" @click="showBody = !showBody"> <div class="title"><div><slot name="header"></slot></div></div> <div class="divider"></div> @@ -22,80 +22,67 @@ </div> </template> -<script lang="ts"> -import { defineComponent } from 'vue'; +<script lang="ts" setup> +import { onMounted, ref, shallowRef, watch } from 'vue'; import tinycolor from 'tinycolor2'; import { miLocalStorage } from '@/local-storage'; import { defaultStore } from '@/store'; const miLocalStoragePrefix = 'ui:folder:' as const; -export default defineComponent({ - props: { - expanded: { - type: Boolean, - required: false, - default: true, - }, - persistKey: { - type: String, - required: false, - default: null, - }, - }, - data() { - return { - defaultStore, - bg: null, - showBody: (this.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`) === 't') : this.expanded, - }; - }, - watch: { - showBody() { - if (this.persistKey) { - miLocalStorage.setItem(`${miLocalStoragePrefix}${this.persistKey}`, this.showBody ? 't' : 'f'); - } - }, - }, - mounted() { - function getParentBg(el: Element | null): string { - if (el == null || el.tagName === 'BODY') return 'var(--bg)'; - const bg = el.style.background || el.style.backgroundColor; - if (bg) { - return bg; - } else { - return getParentBg(el.parentElement); - } - } - const rawBg = getParentBg(this.$el); - const bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); - bg.setAlpha(0.85); - this.bg = bg.toRgbString(); - }, - methods: { - toggleContent(show: boolean) { - this.showBody = show; - }, +const props = withDefaults(defineProps<{ + expanded?: boolean; + persistKey?: string; +}>(), { + expanded: true, +}); - enter(el) { - const elementHeight = el.getBoundingClientRect().height; - el.style.height = 0; - el.offsetHeight; // reflow - el.style.height = elementHeight + 'px'; - }, - afterEnter(el) { - el.style.height = null; - }, - leave(el) { - const elementHeight = el.getBoundingClientRect().height; - el.style.height = elementHeight + 'px'; - el.offsetHeight; // reflow - el.style.height = 0; - }, - afterLeave(el) { - el.style.height = null; - }, - }, +const el = shallowRef<HTMLDivElement>(); +const bg = ref<string | null>(null); +const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded); + +watch(showBody, () => { + if (props.persistKey) { + miLocalStorage.setItem(`${miLocalStoragePrefix}${props.persistKey}`, showBody.value ? 't' : 'f'); + } +}); + +function enter(el: Element) { + const elementHeight = el.getBoundingClientRect().height; + el.style.height = 0; + el.offsetHeight; // reflow + el.style.height = elementHeight + 'px'; +} + +function afterEnter(el: Element) { + el.style.height = null; +} + +function leave(el: Element) { + const elementHeight = el.getBoundingClientRect().height; + el.style.height = elementHeight + 'px'; + el.offsetHeight; // reflow + el.style.height = 0; +} + +function afterLeave(el: Element) { + el.style.height = null; +} + +onMounted(() => { + function getParentBg(el: HTMLElement | null): string { + if (el == null || el.tagName === 'BODY') return 'var(--bg)'; + const bg = el.style.background || el.style.backgroundColor; + if (bg) { + return bg; + } else { + return getParentBg(el.parentElement); + } + } + const rawBg = getParentBg(el.value); + const _bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); + _bg.setAlpha(0.85); + bg.value = _bg.toRgbString(); }); </script> diff --git a/packages/frontend/src/components/MkFormDialog.vue b/packages/frontend/src/components/MkFormDialog.vue index 979df2e7c1..b4ef54aecd 100644 --- a/packages/frontend/src/components/MkFormDialog.vue +++ b/packages/frontend/src/components/MkFormDialog.vue @@ -54,8 +54,8 @@ </MkModalWindow> </template> -<script lang="ts"> -import { defineComponent } from 'vue'; +<script lang="ts" setup> +import { reactive, shallowRef } from 'vue'; import MkInput from './MkInput.vue'; import MkTextarea from './MkTextarea.vue'; import MkSwitch from './MkSwitch.vue'; @@ -66,58 +66,36 @@ import MkRadios from './MkRadios.vue'; import MkModalWindow from '@/components/MkModalWindow.vue'; import { i18n } from '@/i18n'; -export default defineComponent({ - components: { - MkModalWindow, - MkInput, - MkTextarea, - MkSwitch, - MkSelect, - MkRange, - MkButton, - MkRadios, - }, +const props = defineProps<{ + title: string; + form: any; +}>(); - props: { - title: { - type: String, - required: true, - }, - form: { - type: Object, - required: true, - }, - }, +const emit = defineEmits<{ + (ev: 'done', v: { + canceled?: boolean; + result?: any; + }): void; +}>(); - emits: ['done'], +const dialog = shallowRef<InstanceType<typeof MkModalWindow>>(); +const values = reactive({}); - data() { - return { - values: {}, - i18n, - }; - }, +for (const item in props.form) { + values[item] = props.form[item].default ?? null; +} - created() { - for (const item in this.form) { - this.values[item] = this.form[item].default ?? null; - } - }, +function ok() { + emit('done', { + result: values, + }); + dialog.value.close(); +} - methods: { - ok() { - this.$emit('done', { - result: this.values, - }); - this.$refs.dialog.close(); - }, - - cancel() { - this.$emit('done', { - canceled: true, - }); - this.$refs.dialog.close(); - }, - }, -}); +function cancel() { + emit('done', { + canceled: true, + }); + dialog.value.close(); +} </script> diff --git a/packages/frontend/src/components/MkObjectView.value.vue b/packages/frontend/src/components/MkObjectView.value.vue index e7fc73bce3..d48e7886eb 100644 --- a/packages/frontend/src/components/MkObjectView.value.vue +++ b/packages/frontend/src/components/MkObjectView.value.vue @@ -28,54 +28,38 @@ </div> </template> -<script lang="ts"> -import { defineComponent, reactive } from 'vue'; +<script lang="ts" setup> +import { reactive } from 'vue'; import number from '@/filters/number'; +import XValue from '@/components/MkObjectView.value.vue'; -export default defineComponent({ - name: 'XValue', +const props = defineProps<{ + value: any; +}>(); - props: { - value: { - required: true, - }, - }, +const collapsed = reactive({}); - setup(props) { - const collapsed = reactive({}); +if (isObject(props.value)) { + for (const key in props.value) { + collapsed[key] = collapsable(props.value[key]); + } +} - if (isObject(props.value)) { - for (const key in props.value) { - collapsed[key] = collapsable(props.value[key]); - } - } +function isObject(v): boolean { + return typeof v === 'object' && !Array.isArray(v) && v !== null; +} - function isObject(v): boolean { - return typeof v === 'object' && !Array.isArray(v) && v !== null; - } +function isArray(v): boolean { + return Array.isArray(v); +} - function isArray(v): boolean { - return Array.isArray(v); - } +function isEmpty(v): boolean { + return (isArray(v) && v.length === 0) || (isObject(v) && Object.keys(v).length === 0); +} - function isEmpty(v): boolean { - return (isArray(v) && v.length === 0) || (isObject(v) && Object.keys(v).length === 0); - } - - function collapsable(v): boolean { - return (isObject(v) || isArray(v)) && !isEmpty(v); - } - - return { - number, - collapsed, - isObject, - isArray, - isEmpty, - collapsable, - }; - }, -}); +function collapsable(v): boolean { + return (isObject(v) || isArray(v)) && !isEmpty(v); +} </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/MkRadios.vue b/packages/frontend/src/components/MkRadios.vue index e2240fb4e1..84be10078a 100644 --- a/packages/frontend/src/components/MkRadios.vue +++ b/packages/frontend/src/components/MkRadios.vue @@ -1,37 +1,27 @@ <script lang="ts"> -import { VNode, defineComponent, h } from 'vue'; +import { VNode, defineComponent, h, ref, watch } from 'vue'; import MkRadio from './MkRadio.vue'; export default defineComponent({ - components: { - MkRadio, - }, props: { modelValue: { required: false, }, }, - data() { - return { - value: this.modelValue, - }; - }, - watch: { - value() { - this.$emit('update:modelValue', this.value); - }, - }, - render() { - console.log(this.$slots, this.$slots.label && this.$slots.label()); - if (!this.$slots.default) return null; - let options = this.$slots.default(); - const label = this.$slots.label && this.$slots.label(); - const caption = this.$slots.caption && this.$slots.caption(); + setup(props, context) { + const value = ref(props.modelValue); + watch(value, () => { + context.emit('update:modelValue', value.value); + }); + if (!context.slots.default) return null; + let options = context.slots.default(); + const label = context.slots.label && context.slots.label(); + const caption = context.slots.caption && context.slots.caption(); // なぜかFragmentになることがあるため if (options.length === 1 && options[0].props == null) options = options[0].children as VNode[]; - return h('div', { + return () => h('div', { class: 'novjtcto', }, [ ...(label ? [h('div', { @@ -42,8 +32,8 @@ export default defineComponent({ }, options.map(option => h(MkRadio, { key: option.key, value: option.props?.value, - modelValue: this.value, - 'onUpdate:modelValue': value => this.value = value, + modelValue: value.value, + 'onUpdate:modelValue': _v => value.value = _v, }, () => option.children)), ), ...(caption ? [h('div', { diff --git a/packages/frontend/src/components/MkTab.vue b/packages/frontend/src/components/MkTab.vue index 6f819bbbd7..7274f9b310 100644 --- a/packages/frontend/src/components/MkTab.vue +++ b/packages/frontend/src/components/MkTab.vue @@ -7,17 +7,17 @@ export default defineComponent({ required: true, }, }, - render() { - const options = this.$slots.default(); + setup(props, { emit, slots }) { + const options = slots.default(); - return h('div', { + return () => h('div', { class: 'pxhvhrfw', }, options.map(option => withDirectives(h('button', { - class: ['_button', { active: this.modelValue === option.props.value }], + class: ['_button', { active: props.modelValue === option.props.value }], key: option.key, - disabled: this.modelValue === option.props.value, + disabled: props.modelValue === option.props.value, onClick: () => { - this.$emit('update:modelValue', option.props.value); + emit('update:modelValue', option.props.value); }, }, option.children), [ [resolveDirective('click-anime')], diff --git a/packages/frontend/src/components/form/suspense.vue b/packages/frontend/src/components/form/suspense.vue index 3a44c3da3d..9b39858ca1 100644 --- a/packages/frontend/src/components/form/suspense.vue +++ b/packages/frontend/src/components/form/suspense.vue @@ -15,70 +15,49 @@ </Transition> </template> -<script lang="ts"> -import { defineComponent, PropType, ref, watch } from 'vue'; +<script lang="ts" setup> +import { ref, watch } from 'vue'; import MkButton from '@/components/MkButton.vue'; import { defaultStore } from '@/store'; import { i18n } from '@/i18n'; -export default defineComponent({ - components: { - MkButton, - }, +const props = defineProps<{ + p: () => Promise<any>; +}>(); - props: { - p: { - type: Function as PropType<() => Promise<any>>, - required: true, - }, - }, +const pending = ref(true); +const resolved = ref(false); +const rejected = ref(false); +const result = ref(null); - setup(props, context) { - const pending = ref(true); - const resolved = ref(false); - const rejected = ref(false); - const result = ref(null); +const process = () => { + if (props.p == null) { + return; + } + const promise = props.p(); + pending.value = true; + resolved.value = false; + rejected.value = false; + promise.then((_result) => { + pending.value = false; + resolved.value = true; + result.value = _result; + }); + promise.catch(() => { + pending.value = false; + rejected.value = true; + }); +}; - const process = () => { - if (props.p == null) { - return; - } - const promise = props.p(); - pending.value = true; - resolved.value = false; - rejected.value = false; - promise.then((_result) => { - pending.value = false; - resolved.value = true; - result.value = _result; - }); - promise.catch(() => { - pending.value = false; - rejected.value = true; - }); - }; - - watch(() => props.p, () => { - process(); - }, { - immediate: true, - }); - - const retry = () => { - process(); - }; - - return { - pending, - resolved, - rejected, - result, - retry, - defaultStore, - i18n, - }; - }, +watch(() => props.p, () => { + process(); +}, { + immediate: true, }); + +const retry = () => { + process(); +}; </script> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/global/i18n.ts b/packages/frontend/src/components/global/i18n.ts index 1fd293ba10..2708b759aa 100644 --- a/packages/frontend/src/components/global/i18n.ts +++ b/packages/frontend/src/components/global/i18n.ts @@ -1,42 +1,24 @@ -import { h, defineComponent } from 'vue'; +import { h } from 'vue'; -export default defineComponent({ - props: { - src: { - type: String, - required: true, - }, - tag: { - type: String, - required: false, - default: 'span', - }, - textTag: { - type: String, - required: false, - default: null, - }, - }, - render() { - let str = this.src; - const parsed = [] as (string | { arg: string; })[]; - while (true) { - const nextBracketOpen = str.indexOf('{'); - const nextBracketClose = str.indexOf('}'); +export default function(props: { src: string; tag?: string; textTag?: string; }, { slots }) { + let str = props.src; + const parsed = [] as (string | { arg: string; })[]; + while (true) { + const nextBracketOpen = str.indexOf('{'); + const nextBracketClose = str.indexOf('}'); - if (nextBracketOpen === -1) { - parsed.push(str); - break; - } else { - if (nextBracketOpen > 0) parsed.push(str.substr(0, nextBracketOpen)); - parsed.push({ - arg: str.substring(nextBracketOpen + 1, nextBracketClose), - }); - } - - str = str.substr(nextBracketClose + 1); + if (nextBracketOpen === -1) { + parsed.push(str); + break; + } else { + if (nextBracketOpen > 0) parsed.push(str.substr(0, nextBracketOpen)); + parsed.push({ + arg: str.substring(nextBracketOpen + 1, nextBracketClose), + }); } - return h(this.tag, parsed.map(x => typeof x === 'string' ? (this.textTag ? h(this.textTag, x) : x) : this.$slots[x.arg]())); - }, -}); + str = str.substr(nextBracketClose + 1); + } + + return h(props.tag ?? 'span', parsed.map(x => typeof x === 'string' ? (props.textTag ? h(props.textTag, x) : x) : slots[x.arg]())); +} diff --git a/packages/frontend/src/components/mfm.ts b/packages/frontend/src/components/mfm.ts index c3c07b5834..042dad7809 100644 --- a/packages/frontend/src/components/mfm.ts +++ b/packages/frontend/src/components/mfm.ts @@ -1,5 +1,6 @@ -import { VNode, defineComponent, h } from 'vue'; +import { VNode, h } from 'vue'; import * as mfm from 'mfm-js'; +import * as Misskey from 'misskey-js'; import MkUrl from '@/components/global/MkUrl.vue'; import MkLink from '@/components/MkLink.vue'; import MkMention from '@/components/MkMention.vue'; @@ -21,370 +22,343 @@ border-left: solid 3px var(--fg); opacity: 0.7; `.split('\n').join(' '); -export default defineComponent({ - props: { - text: { - type: String, - required: true, - }, - plain: { - type: Boolean, - default: false, - }, - nowrap: { - type: Boolean, - default: false, - }, - author: { - type: Object, - default: null, - }, - i: { - type: Object, - default: null, - }, - isNote: { - type: Boolean, - default: true, - }, - emojiUrls: { - type: Object, - default: null, - }, - rootScale: { - type: Number, - default: 1, - } - }, +export default function(props: { + text: string; + plain?: boolean; + nowrap?: boolean; + author?: Misskey.entities.UserLite; + i?: Misskey.entities.UserLite; + isNote?: boolean; + emojiUrls?: string[]; + rootScale?: number; +}) { + const isNote = props.isNote !== undefined ? props.isNote : true; - render() { - if (this.text == null || this.text === '') return; + if (props.text == null || props.text === '') return; - const ast = (this.plain ? mfm.parseSimple : mfm.parse)(this.text); + const ast = (props.plain ? mfm.parseSimple : mfm.parse)(props.text); - const validTime = (t: string | null | undefined) => { - if (t == null) return null; - return t.match(/^[0-9.]+s$/) ? t : null; - }; + const validTime = (t: string | null | undefined) => { + if (t == null) return null; + return t.match(/^[0-9.]+s$/) ? t : null; + }; - const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm; + const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm; - /** - * Gen Vue Elements from MFM AST - * @param ast MFM AST - * @param scale How times large the text is - */ - const genEl = (ast: mfm.MfmNode[], scale: number) => ast.map((token): VNode | string | (VNode | string)[] => { - switch (token.type) { - case 'text': { - const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n'); + /** + * Gen Vue Elements from MFM AST + * @param ast MFM AST + * @param scale How times large the text is + */ + const genEl = (ast: mfm.MfmNode[], scale: number) => ast.map((token): VNode | string | (VNode | string)[] => { + switch (token.type) { + case 'text': { + const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n'); - if (!this.plain) { - const res: (VNode | string)[] = []; - for (const t of text.split('\n')) { - res.push(h('br')); - res.push(t); - } - res.shift(); - return res; - } else { - return [text.replace(/\n/g, ' ')]; + if (!props.plain) { + const res: (VNode | string)[] = []; + for (const t of text.split('\n')) { + res.push(h('br')); + res.push(t); } + res.shift(); + return res; + } else { + return [text.replace(/\n/g, ' ')]; } + } - case 'bold': { - return [h('b', genEl(token.children, scale))]; - } + case 'bold': { + return [h('b', genEl(token.children, scale))]; + } - case 'strike': { - return [h('del', genEl(token.children, scale))]; - } + case 'strike': { + return [h('del', genEl(token.children, scale))]; + } - case 'italic': { - return h('i', { - style: 'font-style: oblique;', - }, genEl(token.children, scale)); - } + case 'italic': { + return h('i', { + style: 'font-style: oblique;', + }, genEl(token.children, scale)); + } - case 'fn': { - // TODO: CSSを文字列で組み立てていくと token.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる - let style; - switch (token.props.name) { - case 'tada': { - const speed = validTime(token.props.args.speed) ?? '1s'; - style = 'font-size: 150%;' + (useAnim ? `animation: tada ${speed} linear infinite both;` : ''); - break; - } - case 'jelly': { - const speed = validTime(token.props.args.speed) ?? '1s'; - style = (useAnim ? `animation: mfm-rubberBand ${speed} linear infinite both;` : ''); - break; - } - case 'twitch': { - const speed = validTime(token.props.args.speed) ?? '0.5s'; - style = useAnim ? `animation: mfm-twitch ${speed} ease infinite;` : ''; - break; - } - case 'shake': { - const speed = validTime(token.props.args.speed) ?? '0.5s'; - style = useAnim ? `animation: mfm-shake ${speed} ease infinite;` : ''; - break; - } - case 'spin': { - const direction = - token.props.args.left ? 'reverse' : - token.props.args.alternate ? 'alternate' : - 'normal'; - const anime = - token.props.args.x ? 'mfm-spinX' : - token.props.args.y ? 'mfm-spinY' : - 'mfm-spin'; - const speed = validTime(token.props.args.speed) ?? '1.5s'; - style = useAnim ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : ''; - break; - } - case 'jump': { - const speed = validTime(token.props.args.speed) ?? '0.75s'; - style = useAnim ? `animation: mfm-jump ${speed} linear infinite;` : ''; - break; - } - case 'bounce': { - const speed = validTime(token.props.args.speed) ?? '0.75s'; - style = useAnim ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom;` : ''; - break; - } - case 'flip': { - const transform = - (token.props.args.h && token.props.args.v) ? 'scale(-1, -1)' : - token.props.args.v ? 'scaleY(-1)' : - 'scaleX(-1)'; - style = `transform: ${transform};`; - break; - } - case 'x2': { - return h('span', { - class: defaultStore.state.advancedMfm ? 'mfm-x2' : '', - }, genEl(token.children, scale * 2)); - } - case 'x3': { - return h('span', { - class: defaultStore.state.advancedMfm ? 'mfm-x3' : '', - }, genEl(token.children, scale * 3)); - } - case 'x4': { - return h('span', { - class: defaultStore.state.advancedMfm ? 'mfm-x4' : '', - }, genEl(token.children, scale * 4)); - } - case 'font': { - const family = - token.props.args.serif ? 'serif' : - token.props.args.monospace ? 'monospace' : - token.props.args.cursive ? 'cursive' : - token.props.args.fantasy ? 'fantasy' : - token.props.args.emoji ? 'emoji' : - token.props.args.math ? 'math' : - null; - if (family) style = `font-family: ${family};`; - break; - } - case 'blur': { - return h('span', { - class: '_mfm_blur_', - }, genEl(token.children, scale)); - } - case 'rainbow': { - const speed = validTime(token.props.args.speed) ?? '1s'; - style = useAnim ? `animation: mfm-rainbow ${speed} linear infinite;` : ''; - break; - } - case 'sparkle': { - if (!useAnim) { - return genEl(token.children, scale); - } - return h(MkSparkle, {}, genEl(token.children, scale)); - } - case 'rotate': { - const degrees = parseFloat(token.props.args.deg ?? '90'); - style = `transform: rotate(${degrees}deg); transform-origin: center center;`; - break; - } - case 'position': { - if (!defaultStore.state.advancedMfm) break; - const x = parseFloat(token.props.args.x ?? '0'); - const y = parseFloat(token.props.args.y ?? '0'); - style = `transform: translateX(${x}em) translateY(${y}em);`; - break; - } - case 'scale': { - if (!defaultStore.state.advancedMfm) { - style = ''; - break; - } - const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5); - const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5); - style = `transform: scale(${x}, ${y});`; - scale = scale * Math.max(x, y); - break; - } - case 'fg': { - let color = token.props.args.color; - if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; - style = `color: #${color};`; - break; - } - case 'bg': { - let color = token.props.args.color; - if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; - style = `background-color: #${color};`; - break; - } + case 'fn': { + // TODO: CSSを文字列で組み立てていくと token.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる + let style; + switch (token.props.name) { + case 'tada': { + const speed = validTime(token.props.args.speed) ?? '1s'; + style = 'font-size: 150%;' + (useAnim ? `animation: tada ${speed} linear infinite both;` : ''); + break; } - if (style == null) { - return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children, scale), ']']); - } else { + case 'jelly': { + const speed = validTime(token.props.args.speed) ?? '1s'; + style = (useAnim ? `animation: mfm-rubberBand ${speed} linear infinite both;` : ''); + break; + } + case 'twitch': { + const speed = validTime(token.props.args.speed) ?? '0.5s'; + style = useAnim ? `animation: mfm-twitch ${speed} ease infinite;` : ''; + break; + } + case 'shake': { + const speed = validTime(token.props.args.speed) ?? '0.5s'; + style = useAnim ? `animation: mfm-shake ${speed} ease infinite;` : ''; + break; + } + case 'spin': { + const direction = + token.props.args.left ? 'reverse' : + token.props.args.alternate ? 'alternate' : + 'normal'; + const anime = + token.props.args.x ? 'mfm-spinX' : + token.props.args.y ? 'mfm-spinY' : + 'mfm-spin'; + const speed = validTime(token.props.args.speed) ?? '1.5s'; + style = useAnim ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : ''; + break; + } + case 'jump': { + const speed = validTime(token.props.args.speed) ?? '0.75s'; + style = useAnim ? `animation: mfm-jump ${speed} linear infinite;` : ''; + break; + } + case 'bounce': { + const speed = validTime(token.props.args.speed) ?? '0.75s'; + style = useAnim ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom;` : ''; + break; + } + case 'flip': { + const transform = + (token.props.args.h && token.props.args.v) ? 'scale(-1, -1)' : + token.props.args.v ? 'scaleY(-1)' : + 'scaleX(-1)'; + style = `transform: ${transform};`; + break; + } + case 'x2': { return h('span', { - style: 'display: inline-block; ' + style, + class: defaultStore.state.advancedMfm ? 'mfm-x2' : '', + }, genEl(token.children, scale * 2)); + } + case 'x3': { + return h('span', { + class: defaultStore.state.advancedMfm ? 'mfm-x3' : '', + }, genEl(token.children, scale * 3)); + } + case 'x4': { + return h('span', { + class: defaultStore.state.advancedMfm ? 'mfm-x4' : '', + }, genEl(token.children, scale * 4)); + } + case 'font': { + const family = + token.props.args.serif ? 'serif' : + token.props.args.monospace ? 'monospace' : + token.props.args.cursive ? 'cursive' : + token.props.args.fantasy ? 'fantasy' : + token.props.args.emoji ? 'emoji' : + token.props.args.math ? 'math' : + null; + if (family) style = `font-family: ${family};`; + break; + } + case 'blur': { + return h('span', { + class: '_mfm_blur_', }, genEl(token.children, scale)); } - } - - case 'small': { - return [h('small', { - style: 'opacity: 0.7;', - }, genEl(token.children, scale))]; - } - - case 'center': { - return [h('div', { - style: 'text-align:center;', - }, genEl(token.children, scale))]; - } - - case 'url': { - return [h(MkUrl, { - key: Math.random(), - url: token.props.url, - rel: 'nofollow noopener', - })]; - } - - case 'link': { - return [h(MkLink, { - key: Math.random(), - url: token.props.url, - rel: 'nofollow noopener', - }, genEl(token.children, scale))]; - } - - case 'mention': { - return [h(MkMention, { - key: Math.random(), - host: (token.props.host == null && this.author && this.author.host != null ? this.author.host : token.props.host) || host, - username: token.props.username, - })]; - } - - case 'hashtag': { - return [h(MkA, { - key: Math.random(), - to: this.isNote ? `/tags/${encodeURIComponent(token.props.hashtag)}` : `/user-tags/${encodeURIComponent(token.props.hashtag)}`, - style: 'color:var(--hashtag);', - }, `#${token.props.hashtag}`)]; - } - - case 'blockCode': { - return [h(MkCode, { - key: Math.random(), - code: token.props.code, - lang: token.props.lang, - })]; - } - - case 'inlineCode': { - return [h(MkCode, { - key: Math.random(), - code: token.props.code, - inline: true, - })]; - } - - case 'quote': { - if (!this.nowrap) { - return [h('div', { - style: QUOTE_STYLE, - }, genEl(token.children, scale))]; - } else { - return [h('span', { - style: QUOTE_STYLE, - }, genEl(token.children, scale))]; + case 'rainbow': { + const speed = validTime(token.props.args.speed) ?? '1s'; + style = useAnim ? `animation: mfm-rainbow ${speed} linear infinite;` : ''; + break; + } + case 'sparkle': { + if (!useAnim) { + return genEl(token.children, scale); + } + return h(MkSparkle, {}, genEl(token.children, scale)); + } + case 'rotate': { + const degrees = parseFloat(token.props.args.deg ?? '90'); + style = `transform: rotate(${degrees}deg); transform-origin: center center;`; + break; + } + case 'position': { + if (!defaultStore.state.advancedMfm) break; + const x = parseFloat(token.props.args.x ?? '0'); + const y = parseFloat(token.props.args.y ?? '0'); + style = `transform: translateX(${x}em) translateY(${y}em);`; + break; + } + case 'scale': { + if (!defaultStore.state.advancedMfm) { + style = ''; + break; + } + const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5); + const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5); + style = `transform: scale(${x}, ${y});`; + scale = scale * Math.max(x, y); + break; + } + case 'fg': { + let color = token.props.args.color; + if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; + style = `color: #${color};`; + break; + } + case 'bg': { + let color = token.props.args.color; + if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00'; + style = `background-color: #${color};`; + break; } } + if (style == null) { + return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children, scale), ']']); + } else { + return h('span', { + style: 'display: inline-block; ' + style, + }, genEl(token.children, scale)); + } + } - case 'emojiCode': { + case 'small': { + return [h('small', { + style: 'opacity: 0.7;', + }, genEl(token.children, scale))]; + } + + case 'center': { + return [h('div', { + style: 'text-align:center;', + }, genEl(token.children, scale))]; + } + + case 'url': { + return [h(MkUrl, { + key: Math.random(), + url: token.props.url, + rel: 'nofollow noopener', + })]; + } + + case 'link': { + return [h(MkLink, { + key: Math.random(), + url: token.props.url, + rel: 'nofollow noopener', + }, genEl(token.children, scale))]; + } + + case 'mention': { + return [h(MkMention, { + key: Math.random(), + host: (token.props.host == null && props.author && props.author.host != null ? props.author.host : token.props.host) || host, + username: token.props.username, + })]; + } + + case 'hashtag': { + return [h(MkA, { + key: Math.random(), + to: isNote ? `/tags/${encodeURIComponent(token.props.hashtag)}` : `/user-tags/${encodeURIComponent(token.props.hashtag)}`, + style: 'color:var(--hashtag);', + }, `#${token.props.hashtag}`)]; + } + + case 'blockCode': { + return [h(MkCode, { + key: Math.random(), + code: token.props.code, + lang: token.props.lang, + })]; + } + + case 'inlineCode': { + return [h(MkCode, { + key: Math.random(), + code: token.props.code, + inline: true, + })]; + } + + case 'quote': { + if (!props.nowrap) { + return [h('div', { + style: QUOTE_STYLE, + }, genEl(token.children, scale))]; + } else { + return [h('span', { + style: QUOTE_STYLE, + }, genEl(token.children, scale))]; + } + } + + case 'emojiCode': { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (props.author?.host == null) { + return [h(MkCustomEmoji, { + key: Math.random(), + name: token.props.name, + normal: props.plain, + host: null, + useOriginalSize: scale >= 2.5, + })]; + } else { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (this.author?.host == null) { + if (props.emojiUrls && (props.emojiUrls[token.props.name] == null)) { + return [h('span', `:${token.props.name}:`)]; + } else { return [h(MkCustomEmoji, { key: Math.random(), name: token.props.name, - normal: this.plain, - host: null, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + url: props.emojiUrls ? props.emojiUrls[token.props.name] : null, + normal: props.plain, + host: props.author.host, useOriginalSize: scale >= 2.5, })]; - } else { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (this.emojiUrls && (this.emojiUrls[token.props.name] == null)) { - return [h('span', `:${token.props.name}:`)]; - } else { - return [h(MkCustomEmoji, { - key: Math.random(), - name: token.props.name, - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - url: this.emojiUrls ? this.emojiUrls[token.props.name] : null, - normal: this.plain, - host: this.author.host, - useOriginalSize: scale >= 2.5, - })]; - } } } - - case 'unicodeEmoji': { - return [h(MkEmoji, { - key: Math.random(), - emoji: token.props.emoji, - })]; - } - - case 'mathInline': { - return [h('code', token.props.formula)]; - } - - case 'mathBlock': { - return [h('code', token.props.formula)]; - } - - case 'search': { - return [h(MkGoogle, { - key: Math.random(), - q: token.props.query, - })]; - } - - case 'plain': { - return [h('span', genEl(token.children, scale))]; - } - - default: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - console.error('unrecognized ast type:', (token as any).type); - - return []; - } } - }).flat(Infinity) as (VNode | string)[]; - // Parse ast to DOM - return h('span', genEl(ast, this.rootScale)); - }, -}); + case 'unicodeEmoji': { + return [h(MkEmoji, { + key: Math.random(), + emoji: token.props.emoji, + })]; + } + + case 'mathInline': { + return [h('code', token.props.formula)]; + } + + case 'mathBlock': { + return [h('code', token.props.formula)]; + } + + case 'search': { + return [h(MkGoogle, { + key: Math.random(), + q: token.props.query, + })]; + } + + case 'plain': { + return [h('span', genEl(token.children, scale))]; + } + + default: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + console.error('unrecognized ast type:', (token as any).type); + + return []; + } + } + }).flat(Infinity) as (VNode | string)[]; + + return h('span', genEl(ast, props.rootScale ?? 1)); +} From 636428c72e26d83ef0dc179424caf2dd45d8b539 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 12:24:21 +0900 Subject: [PATCH 011/213] make __VUE_OPTIONS_API__ false --- packages/frontend/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index fad0dd0177..e552329af3 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -99,7 +99,7 @@ export function getConfig(): UserConfig { _DATA_TRANSFER_DRIVE_FILE_: JSON.stringify('mk_drive_file'), _DATA_TRANSFER_DRIVE_FOLDER_: JSON.stringify('mk_drive_folder'), _DATA_TRANSFER_DECK_COLUMN_: JSON.stringify('mk_deck_column'), - __VUE_OPTIONS_API__: true, + __VUE_OPTIONS_API__: false, __VUE_PROD_DEVTOOLS__: false, }, From 38391010af2491562d1c58f126ac26bbbc1da0f5 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 13:23:25 +0900 Subject: [PATCH 012/213] Revert "make __VUE_OPTIONS_API__ false" This reverts commit 636428c72e26d83ef0dc179424caf2dd45d8b539. --- packages/frontend/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index e552329af3..fad0dd0177 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -99,7 +99,7 @@ export function getConfig(): UserConfig { _DATA_TRANSFER_DRIVE_FILE_: JSON.stringify('mk_drive_file'), _DATA_TRANSFER_DRIVE_FOLDER_: JSON.stringify('mk_drive_folder'), _DATA_TRANSFER_DECK_COLUMN_: JSON.stringify('mk_deck_column'), - __VUE_OPTIONS_API__: false, + __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false, }, From 9ff088a830c78403c7e6fb1d243c42ce0f1058ea Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 17:55:39 +0900 Subject: [PATCH 013/213] :v: --- packages/frontend/src/init.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/frontend/src/init.ts b/packages/frontend/src/init.ts index 49e7bb4008..13fbd08c56 100644 --- a/packages/frontend/src/init.ts +++ b/packages/frontend/src/init.ts @@ -344,13 +344,7 @@ if ($i) { hotkeys['p|n'] = post; if (defaultStore.state.accountSetupWizard !== -1) { - // このウィザードが実装される前に登録したユーザーには表示させないため - // TODO: そのうち消す - if (Date.now() - new Date($i.createdAt).getTime() < 1000 * 60 * 60 * 24) { - popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); - } else { - defaultStore.set('accountSetupWizard', -1); - } + popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); } if ($i.isDeleted) { From 93629fb29d7f4789511c8b0de61749b8ceefc417 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 20:08:32 +0900 Subject: [PATCH 014/213] upgrade aiscript to 0.13.3 --- CHANGELOG.md | 2 +- packages/frontend/package.json | 2 +- packages/frontend/src/pages/flash/flash-edit.vue | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e907f8c42..7087d73b9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ ### Client - 開発者モードを追加 - +- AiScriptを0.13.3に更新 ## 13.12.2 diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 5b4004d8e3..e03dc51824 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -19,7 +19,7 @@ "@rollup/plugin-json": "6.0.0", "@rollup/plugin-replace": "5.0.2", "@rollup/pluginutils": "5.0.2", - "@syuilo/aiscript": "0.13.2", + "@syuilo/aiscript": "0.13.3", "@tabler/icons-webfont": "2.17.0", "@vitejs/plugin-vue": "4.2.2", "@vue-macros/reactivity-transform": "0.3.6", diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue index 5e875d195b..a3daa8ea46 100644 --- a/packages/frontend/src/pages/flash/flash-edit.vue +++ b/packages/frontend/src/pages/flash/flash-edit.vue @@ -33,7 +33,7 @@ import MkTextarea from '@/components/MkTextarea.vue'; import MkInput from '@/components/MkInput.vue'; import { useRouter } from '@/router'; -const PRESET_DEFAULT = `/// @ 0.13.2 +const PRESET_DEFAULT = `/// @ 0.13.3 var name = "" @@ -51,7 +51,7 @@ Ui:render([ ]) `; -const PRESET_OMIKUJI = `/// @ 0.13.2 +const PRESET_OMIKUJI = `/// @ 0.13.3 // ユーザーごとに日替わりのおみくじのプリセット // 選択肢 @@ -94,7 +94,7 @@ Ui:render([ ]) `; -const PRESET_SHUFFLE = `/// @ 0.13.2 +const PRESET_SHUFFLE = `/// @ 0.13.3 // 巻き戻し可能な文字シャッフルのプリセット let string = "ペペロンチーノ" @@ -173,7 +173,7 @@ var cursor = 0 do() `; -const PRESET_QUIZ = `/// @ 0.13.2 +const PRESET_QUIZ = `/// @ 0.13.3 let title = '地理クイズ' let qas = [{ @@ -286,7 +286,7 @@ qaEls.push(Ui:C:container({ Ui:render(qaEls) `; -const PRESET_TIMELINE = `/// @ 0.13.2 +const PRESET_TIMELINE = `/// @ 0.13.3 // APIリクエストを行いローカルタイムラインを表示するプリセット @fetch() { From d36e44bc5770a821d8b83a014485f77f68b5d188 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 20:22:27 +0900 Subject: [PATCH 015/213] Update pnpm-lock.yaml --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74a7e89857..04675a7da7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -640,8 +640,8 @@ importers: specifier: 5.0.2 version: 5.0.2(rollup@3.21.6) '@syuilo/aiscript': - specifier: 0.13.2 - version: 0.13.2 + specifier: 0.13.3 + version: 0.13.3 '@tabler/icons-webfont': specifier: 2.17.0 version: 2.17.0 @@ -6126,8 +6126,8 @@ packages: dev: false optional: true - /@syuilo/aiscript@0.13.2: - resolution: {integrity: sha512-1aqQSH6U+vV01UDUotXUEjIwJKcZZPASJyIJ9msxXRpSInPGJJ/q1kGkZMgSpVhzYFT7/QBxo0UC1ZVEOsrDTw==} + /@syuilo/aiscript@0.13.3: + resolution: {integrity: sha512-0YFlWA+7YhyRRsp+9Nl72SoSUg5ghskthjCdLvj4qdGyLedeyanKZWJlH2A9d47Nes03UYY8CRDsMHHv64IWcg==} dependencies: autobind-decorator: 2.4.0 seedrandom: 3.0.5 From 86f952e659005099330e648ee133a408f29c87cc Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 14 May 2023 20:32:08 +0900 Subject: [PATCH 016/213] fix #10850 ? --- packages/frontend/src/init.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/init.ts b/packages/frontend/src/init.ts index 13fbd08c56..17ebb6bdd7 100644 --- a/packages/frontend/src/init.ts +++ b/packages/frontend/src/init.ts @@ -343,9 +343,11 @@ if ($i) { // only add post shortcuts if logged in hotkeys['p|n'] = post; - if (defaultStore.state.accountSetupWizard !== -1) { - popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); - } + defaultStore.ready.then(() => { + if (defaultStore.state.accountSetupWizard !== -1) { + popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); + } + }); if ($i.isDeleted) { alert({ From c066013c5723587ecadb20ff1bfd9397af85647a Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 15 May 2023 11:03:18 +0900 Subject: [PATCH 017/213] fix #10850 ? --- packages/frontend/src/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/init.ts b/packages/frontend/src/init.ts index 17ebb6bdd7..763b6d44b0 100644 --- a/packages/frontend/src/init.ts +++ b/packages/frontend/src/init.ts @@ -343,7 +343,7 @@ if ($i) { // only add post shortcuts if logged in hotkeys['p|n'] = post; - defaultStore.ready.then(() => { + defaultStore.loaded.then(() => { if (defaultStore.state.accountSetupWizard !== -1) { popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); } From f4e6d73a8afa5b9b024bae22e787c6fab58694ca Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 15 May 2023 13:57:36 +0900 Subject: [PATCH 018/213] refactor --- packages/frontend/src/components/MkTooltip.vue | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkTooltip.vue b/packages/frontend/src/components/MkTooltip.vue index 2d34b090ed..6104b8df72 100644 --- a/packages/frontend/src/components/MkTooltip.vue +++ b/packages/frontend/src/components/MkTooltip.vue @@ -66,10 +66,8 @@ onMounted(() => { setPosition(); const loop = () => { - loopHandler = window.requestAnimationFrame(() => { - setPosition(); - loop(); - }); + setPosition(); + loopHandler = window.requestAnimationFrame(loop); }; loop(); From 60f504bbe2dc0ccf2e6cc11e9db1de9f087a2e86 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 15 May 2023 14:29:35 +0900 Subject: [PATCH 019/213] =?UTF-8?q?fix(frontend):=20=E3=83=84=E3=83=BC?= =?UTF-8?q?=E3=83=AB=E3=83=81=E3=83=83=E3=83=97=E3=81=8C=E6=B0=B8=E4=B9=85?= =?UTF-8?q?=E3=81=ABDOM=E3=81=AB=E6=AE=8B=E3=82=8B=E3=81=93=E3=81=A8?= =?UTF-8?q?=E3=81=8C=E3=81=82=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #10805 --- packages/frontend/src/components/MkTooltip.vue | 3 +++ packages/frontend/src/directives/tooltip.ts | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkTooltip.vue b/packages/frontend/src/components/MkTooltip.vue index 6104b8df72..ea39198706 100644 --- a/packages/frontend/src/components/MkTooltip.vue +++ b/packages/frontend/src/components/MkTooltip.vue @@ -41,6 +41,9 @@ const emit = defineEmits<{ (ev: 'closed'): void; }>(); +// タイミングによっては最初から showing = false な場合があり、その場合に closed 扱いにしないと永久にDOMに残ることになる +if (!props.showing) emit('closed'); + const el = shallowRef<HTMLElement>(); const zIndex = os.claimZIndex('high'); diff --git a/packages/frontend/src/directives/tooltip.ts b/packages/frontend/src/directives/tooltip.ts index 5d13497b5f..373141fa35 100644 --- a/packages/frontend/src/directives/tooltip.ts +++ b/packages/frontend/src/directives/tooltip.ts @@ -5,7 +5,7 @@ import { defineAsyncComponent, Directive, ref } from 'vue'; import { isTouchUsing } from '@/scripts/touch'; import { popup, alert } from '@/os'; -const start = isTouchUsing ? 'touchstart' : 'mouseover'; +const start = isTouchUsing ? 'touchstart' : 'mouseenter'; const end = isTouchUsing ? 'touchend' : 'mouseleave'; export default { @@ -63,16 +63,24 @@ export default { ev.preventDefault(); }); - el.addEventListener(start, () => { + el.addEventListener(start, (ev) => { window.clearTimeout(self.showTimer); window.clearTimeout(self.hideTimer); - self.showTimer = window.setTimeout(self.show, delay); + if (delay === 0) { + self.show(); + } else { + self.showTimer = window.setTimeout(self.show, delay); + } }, { passive: true }); el.addEventListener(end, () => { window.clearTimeout(self.showTimer); window.clearTimeout(self.hideTimer); - self.hideTimer = window.setTimeout(self.close, delay); + if (delay === 0) { + self.close(); + } else { + self.hideTimer = window.setTimeout(self.close, delay); + } }, { passive: true }); el.addEventListener('click', () => { From d867fc00b6e6d844e146a748e0a3034541892bda Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 15 May 2023 16:25:44 +0900 Subject: [PATCH 020/213] clean up --- packages/frontend/src/components/MkPageWindow.vue | 4 ++-- packages/frontend/src/ui/classic.vue | 2 +- packages/frontend/src/ui/universal.vue | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index 02ce58451d..bd842c486a 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -12,12 +12,12 @@ > <template #header> <template v-if="pageMetadata?.value"> - <i v-if="pageMetadata.value.icon" class="icon" :class="pageMetadata.value.icon" style="margin-right: 0.5em;"></i> + <i v-if="pageMetadata.value.icon" :class="pageMetadata.value.icon" style="margin-right: 0.5em;"></i> <span>{{ pageMetadata.value.title }}</span> </template> </template> - <div :class="$style.root" :style="{ background: pageMetadata?.value?.bg }" style="container-type: inline-size;"> + <div :class="$style.root" style="container-type: inline-size;"> <RouterView :key="reloadCount" :router="router"/> </div> </MkWindow> diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index 792c1ccc5e..c17450f6ed 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -10,7 +10,7 @@ <XWidgets place="left" :margin-top="'var(--margin)'" @mounted="attachSticky(widgetsLeft)"/> </div> - <main class="main" :style="{ background: pageMetadata?.value?.bg }" @contextmenu.stop="onContextmenu"> + <main class="main" @contextmenu.stop="onContextmenu"> <div class="content" style="container-type: inline-size;"> <RouterView/> </div> diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 27d0c26ac4..f755dda627 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -4,7 +4,7 @@ <MkStickyContainer :class="$style.contents"> <template #header><XStatusBars :class="$style.statusbars"/></template> - <main style="min-width: 0;" :style="{ background: pageMetadata?.value?.bg }" @contextmenu.stop="onContextmenu"> + <main style="min-width: 0;" @contextmenu.stop="onContextmenu"> <div :class="$style.content" style="container-type: inline-size;"> <RouterView/> </div> From a7ee4aabcbd280d488fbd6b0d5079ee8c1c2058b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 15 May 2023 16:40:19 +0900 Subject: [PATCH 021/213] =?UTF-8?q?chore(frontend):=20=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E7=94=BB=E9=9D=A2=E3=82=92=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/pages/settings/general.vue | 15 +++++---------- packages/frontend/src/pages/settings/other.vue | 12 ++++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 7e70119ec3..ec2bc3623c 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -145,15 +145,13 @@ </FormSection> <FormSection> - <div class="_gaps_s"> - <MkSwitch v-model="aiChanMode">{{ i18n.ts.aiChanMode }}</MkSwitch> - <MkSwitch v-model="devMode">{{ i18n.ts.devMode }}</MkSwitch> + <template #label>{{ i18n.ts.other }}</template> + + <div class="_gaps"> + <FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink> + <FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink> </div> </FormSection> - - <FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink> - - <FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink> </div> </template> @@ -215,8 +213,6 @@ const instanceTicker = computed(defaultStore.makeGetterSetter('instanceTicker')) const enableInfiniteScroll = computed(defaultStore.makeGetterSetter('enableInfiniteScroll')); const useReactionPickerForContextMenu = computed(defaultStore.makeGetterSetter('useReactionPickerForContextMenu')); const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars')); -const aiChanMode = computed(defaultStore.makeGetterSetter('aiChanMode')); -const devMode = computed(defaultStore.makeGetterSetter('devMode')); const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter('mediaListWithOneImageAppearance')); const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); @@ -248,7 +244,6 @@ watch([ useSystemFont, enableInfiniteScroll, squareAvatars, - aiChanMode, showNoteActionsOnlyHover, showGapBetweenNotesInTimeline, instanceTicker, diff --git a/packages/frontend/src/pages/settings/other.vue b/packages/frontend/src/pages/settings/other.vue index 776305d723..0b73780a8b 100644 --- a/packages/frontend/src/pages/settings/other.vue +++ b/packages/frontend/src/pages/settings/other.vue @@ -53,6 +53,17 @@ </MkSwitch> </div> </MkFolder> + + <MkFolder> + <template #icon><i class="ti ti-code"></i></template> + <template #label>{{ i18n.ts.developer }}</template> + + <div class="_gaps_m"> + <MkSwitch v-model="devMode"> + <template #label>{{ i18n.ts.devMode }}</template> + </MkSwitch> + </div> + </MkFolder> </div> </FormSection> @@ -80,6 +91,7 @@ import FormSection from '@/components/form/section.vue'; const reportError = computed(defaultStore.makeGetterSetter('reportError')); const enableCondensedLineForAcct = computed(defaultStore.makeGetterSetter('enableCondensedLineForAcct')); +const devMode = computed(defaultStore.makeGetterSetter('devMode')); function onChangeInjectFeaturedNote(v) { os.api('i/update', { From 23f106a0c1d16e821a712d39be1c90d17cd6c901 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 15 May 2023 19:08:46 +0900 Subject: [PATCH 022/213] =?UTF-8?q?refactor(frontend):=20boot=E5=88=86?= =?UTF-8?q?=E5=89=B2=E3=81=97=E3=81=9F=E3=82=8A=E5=89=AF=E4=BD=9C=E7=94=A8?= =?UTF-8?q?=E6=B8=9B=E3=82=89=E3=81=97=E3=81=9F=E3=82=8A=E3=81=A8=E3=81=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #10838 --- packages/backend/src/config.ts | 4 +- packages/frontend/src/_boot_.ts | 12 + packages/frontend/src/boot/common.ts | 263 +++++++++ packages/frontend/src/boot/main-boot.ts | 254 +++++++++ packages/frontend/src/boot/sub-boot.ts | 8 + packages/frontend/src/components/MkDrive.vue | 4 +- .../src/components/MkFollowButton.vue | 4 +- .../src/components/MkNotifications.vue | 6 +- .../frontend/src/components/MkTimeline.vue | 4 +- packages/frontend/src/custom-emojis.ts | 13 +- packages/frontend/src/init.ts | 523 ------------------ .../src/pages/admin/overview.queue.vue | 4 +- .../frontend/src/pages/admin/overview.vue | 4 +- .../frontend/src/pages/admin/queue.chart.vue | 4 +- .../pages/settings/preferences-backups.vue | 4 +- packages/frontend/src/pizzax.ts | 8 +- packages/frontend/src/scripts/select-file.ts | 4 +- .../frontend/src/scripts/use-note-capture.ts | 4 +- packages/frontend/src/stream.ts | 14 +- packages/frontend/src/ui/_common_/common.vue | 6 +- .../src/ui/_common_/stream-indicator.vue | 6 +- packages/frontend/src/ui/minimum.vue | 34 ++ .../frontend/src/widgets/WidgetJobQueue.vue | 4 +- .../frontend/src/widgets/WidgetPhotos.vue | 4 +- .../src/widgets/server-metric/index.vue | 4 +- packages/frontend/vite.config.ts | 2 +- 26 files changed, 628 insertions(+), 573 deletions(-) create mode 100644 packages/frontend/src/_boot_.ts create mode 100644 packages/frontend/src/boot/common.ts create mode 100644 packages/frontend/src/boot/main-boot.ts create mode 100644 packages/frontend/src/boot/sub-boot.ts delete mode 100644 packages/frontend/src/init.ts create mode 100644 packages/frontend/src/ui/minimum.vue diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index c6e1075389..744f999596 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -144,7 +144,7 @@ export function loadConfig() { const clientManifestExists = fs.existsSync(_dirname + '/../../../built/_vite_/manifest.json'); const clientManifest = clientManifestExists ? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_vite_/manifest.json`, 'utf-8')) - : { 'src/init.ts': { file: 'src/init.ts' } }; + : { 'src/_boot_.ts': { file: 'src/_boot_.ts' } }; const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source; const mixin = {} as Mixin; @@ -165,7 +165,7 @@ export function loadConfig() { mixin.authUrl = `${mixin.scheme}://${mixin.host}/auth`; mixin.driveUrl = `${mixin.scheme}://${mixin.host}/files`; mixin.userAgent = `Misskey/${meta.version} (${config.url})`; - mixin.clientEntry = clientManifest['src/init.ts']; + mixin.clientEntry = clientManifest['src/_boot_.ts']; mixin.clientManifestExists = clientManifestExists; const externalMediaProxy = config.mediaProxy ? diff --git a/packages/frontend/src/_boot_.ts b/packages/frontend/src/_boot_.ts new file mode 100644 index 0000000000..a8efafca61 --- /dev/null +++ b/packages/frontend/src/_boot_.ts @@ -0,0 +1,12 @@ +// https://vitejs.dev/config/build-options.html#build-modulepreload +import 'vite/modulepreload-polyfill'; + +import '@/style.scss'; +import { mainBoot } from './boot/main-boot'; +import { subBoot } from './boot/sub-boot'; + +if (['/share', '/auth', '/miauth'].includes(location.pathname)) { + subBoot(); +} else { + mainBoot(); +} diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts new file mode 100644 index 0000000000..e9d6586f85 --- /dev/null +++ b/packages/frontend/src/boot/common.ts @@ -0,0 +1,263 @@ +import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent, App } from 'vue'; +import { compareVersions } from 'compare-versions'; +import JSON5 from 'json5'; +import widgets from '@/widgets'; +import directives from '@/directives'; +import components from '@/components'; +import { version, ui, lang, updateLocale } from '@/config'; +import { applyTheme } from '@/scripts/theme'; +import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; +import { i18n, updateI18n } from '@/i18n'; +import { confirm, alert, post, popup, toast } from '@/os'; +import { $i, refreshAccount, login, updateAccount, signout } from '@/account'; +import { defaultStore, ColdDeviceStorage } from '@/store'; +import { fetchInstance, instance } from '@/instance'; +import { deviceKind } from '@/scripts/device-kind'; +import { reloadChannel } from '@/scripts/unison-reload'; +import { reactionPicker } from '@/scripts/reaction-picker'; +import { getUrlWithoutLoginId } from '@/scripts/login-id'; +import { getAccountFromId } from '@/scripts/get-account-from-id'; +import { deckStore } from '@/ui/deck/deck-store'; +import { miLocalStorage } from '@/local-storage'; +import { fetchCustomEmojis } from '@/custom-emojis'; +import { mainRouter } from '@/router'; + +export async function common(createVue: () => App<Element>) { + console.info(`Misskey v${version}`); + + if (_DEV_) { + console.warn('Development mode!!!'); + + console.info(`vue ${vueVersion}`); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (window as any).$i = $i; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (window as any).$store = defaultStore; + + window.addEventListener('error', event => { + console.error(event); + /* + alert({ + type: 'error', + title: 'DEV: Unhandled error', + text: event.message + }); + */ + }); + + window.addEventListener('unhandledrejection', event => { + console.error(event); + /* + alert({ + type: 'error', + title: 'DEV: Unhandled promise rejection', + text: event.reason + }); + */ + }); + } + + const splash = document.getElementById('splash'); + // 念のためnullチェック(HTMLが古い場合があるため(そのうち消す)) + if (splash) splash.addEventListener('transitionend', () => { + splash.remove(); + }); + + let isClientUpdated = false; + + //#region クライアントが更新されたかチェック + const lastVersion = miLocalStorage.getItem('lastVersion'); + if (lastVersion !== version) { + miLocalStorage.setItem('lastVersion', version); + + // テーマリビルドするため + miLocalStorage.removeItem('theme'); + + try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため + if (lastVersion != null && compareVersions(version, lastVersion) === 1) { + isClientUpdated = true; + } + } catch (err) { /* empty */ } + } + //#endregion + + //#region Detect language & fetch translations + const localeVersion = miLocalStorage.getItem('localeVersion'); + const localeOutdated = (localeVersion == null || localeVersion !== version); + if (localeOutdated) { + const res = await window.fetch(`/assets/locales/${lang}.${version}.json`); + if (res.status === 200) { + const newLocale = await res.text(); + const parsedNewLocale = JSON.parse(newLocale); + miLocalStorage.setItem('locale', newLocale); + miLocalStorage.setItem('localeVersion', version); + updateLocale(parsedNewLocale); + updateI18n(parsedNewLocale); + } + } + //#endregion + + // タッチデバイスでCSSの:hoverを機能させる + document.addEventListener('touchend', () => {}, { passive: true }); + + // 一斉リロード + reloadChannel.addEventListener('message', path => { + if (path !== null) location.href = path; + else location.reload(); + }); + + // If mobile, insert the viewport meta tag + if (['smartphone', 'tablet'].includes(deviceKind)) { + const viewport = document.getElementsByName('viewport').item(0); + viewport.setAttribute('content', + `${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`); + } + + //#region Set lang attr + const html = document.documentElement; + html.setAttribute('lang', lang); + //#endregion + + await defaultStore.ready; + await deckStore.ready; + + const fetchInstanceMetaPromise = fetchInstance(); + + fetchInstanceMetaPromise.then(() => { + miLocalStorage.setItem('v', instance.version); + }); + + //#region loginId + const params = new URLSearchParams(location.search); + const loginId = params.get('loginId'); + + if (loginId) { + const target = getUrlWithoutLoginId(location.href); + + if (!$i || $i.id !== loginId) { + const account = await getAccountFromId(loginId); + if (account) { + await login(account.token, target); + } + } + + history.replaceState({ misskey: 'loginId' }, '', target); + } + //#endregion + + // NOTE: この処理は必ずクライアント更新チェック処理より後に来ること(テーマ再構築のため) + watch(defaultStore.reactiveState.darkMode, (darkMode) => { + applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); + }, { immediate: miLocalStorage.getItem('theme') == null }); + + const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); + const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); + + watch(darkTheme, (theme) => { + if (defaultStore.state.darkMode) { + applyTheme(theme); + } + }); + + watch(lightTheme, (theme) => { + if (!defaultStore.state.darkMode) { + applyTheme(theme); + } + }); + + //#region Sync dark mode + if (ColdDeviceStorage.get('syncDeviceDarkMode')) { + defaultStore.set('darkMode', isDeviceDarkmode()); + } + + window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { + if (ColdDeviceStorage.get('syncDeviceDarkMode')) { + defaultStore.set('darkMode', mql.matches); + } + }); + //#endregion + + fetchInstanceMetaPromise.then(() => { + if (defaultStore.state.themeInitial) { + if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON5.parse(instance.defaultLightTheme)); + if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON5.parse(instance.defaultDarkTheme)); + defaultStore.set('themeInitial', false); + } + }); + + watch(defaultStore.reactiveState.useBlurEffectForModal, v => { + document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none'); + }, { immediate: true }); + + watch(defaultStore.reactiveState.useBlurEffect, v => { + if (v) { + document.documentElement.style.removeProperty('--blur'); + } else { + document.documentElement.style.setProperty('--blur', 'none'); + } + }, { immediate: true }); + + //#region Fetch user + if ($i && $i.token) { + if (_DEV_) { + console.log('account cache found. refreshing...'); + } + + refreshAccount(); + } + //#endregion + + try { + await fetchCustomEmojis(); + } catch (err) { /* empty */ } + + const app = createVue(); + + if (_DEV_) { + app.config.performance = true; + } + + widgets(app); + directives(app); + components(app); + + // https://github.com/misskey-dev/misskey/pull/8575#issuecomment-1114239210 + // なぜか2回実行されることがあるため、mountするdivを1つに制限する + const rootEl = ((): HTMLElement => { + const MISSKEY_MOUNT_DIV_ID = 'misskey_app'; + + const currentRoot = document.getElementById(MISSKEY_MOUNT_DIV_ID); + + if (currentRoot) { + console.warn('multiple import detected'); + return currentRoot; + } + + const root = document.createElement('div'); + root.id = MISSKEY_MOUNT_DIV_ID; + document.body.appendChild(root); + return root; + })(); + + app.mount(rootEl); + + // boot.jsのやつを解除 + window.onerror = null; + window.onunhandledrejection = null; + + removeSplash(); + + return { + isClientUpdated, + app, + }; +} + +function removeSplash() { + const splash = document.getElementById('splash'); + if (splash) { + splash.style.opacity = '0'; + splash.style.pointerEvents = 'none'; + } +} diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts new file mode 100644 index 0000000000..c0bfa4603e --- /dev/null +++ b/packages/frontend/src/boot/main-boot.ts @@ -0,0 +1,254 @@ +import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent } from 'vue'; +import { common } from './common'; +import { version, ui, lang, updateLocale } from '@/config'; +import { i18n, updateI18n } from '@/i18n'; +import { confirm, alert, post, popup, toast } from '@/os'; +import { useStream } from '@/stream'; +import * as sound from '@/scripts/sound'; +import { $i, refreshAccount, login, updateAccount, signout } from '@/account'; +import { defaultStore, ColdDeviceStorage } from '@/store'; +import { makeHotkey } from '@/scripts/hotkey'; +import { reactionPicker } from '@/scripts/reaction-picker'; +import { miLocalStorage } from '@/local-storage'; +import { claimAchievement, claimedAchievements } from '@/scripts/achievements'; +import { mainRouter } from '@/router'; +import { initializeSw } from '@/scripts/initialize-sw'; + +export async function mainBoot() { + const { isClientUpdated } = await common(() => createApp( + new URLSearchParams(window.location.search).has('zen') ? defineAsyncComponent(() => import('@/ui/zen.vue')) : + !$i ? defineAsyncComponent(() => import('@/ui/visitor.vue')) : + ui === 'deck' ? defineAsyncComponent(() => import('@/ui/deck.vue')) : + ui === 'classic' ? defineAsyncComponent(() => import('@/ui/classic.vue')) : + defineAsyncComponent(() => import('@/ui/universal.vue')), + )); + + reactionPicker.init(); + + if (isClientUpdated && $i) { + popup(defineAsyncComponent(() => import('@/components/MkUpdated.vue')), {}, {}, 'closed'); + } + + const stream = useStream(); + + let reloadDialogShowing = false; + stream.on('_disconnected_', async () => { + if (defaultStore.state.serverDisconnectedBehavior === 'reload') { + location.reload(); + } else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { + if (reloadDialogShowing) return; + reloadDialogShowing = true; + const { canceled } = await confirm({ + type: 'warning', + title: i18n.ts.disconnectedFromServer, + text: i18n.ts.reloadConfirm, + }); + reloadDialogShowing = false; + if (!canceled) { + location.reload(); + } + } + }); + + for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) { + import('../plugin').then(async ({ install }) => { + // Workaround for https://bugs.webkit.org/show_bug.cgi?id=242740 + await new Promise(r => setTimeout(r, 0)); + install(plugin); + }); + } + + const hotkeys = { + 'd': (): void => { + defaultStore.set('darkMode', !defaultStore.state.darkMode); + }, + 's': (): void => { + mainRouter.push('/search'); + }, + }; + + if ($i) { + // only add post shortcuts if logged in + hotkeys['p|n'] = post; + + defaultStore.loaded.then(() => { + if (defaultStore.state.accountSetupWizard !== -1) { + popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); + } + }); + + if ($i.isDeleted) { + alert({ + type: 'warning', + text: i18n.ts.accountDeletionInProgress, + }); + } + + const now = new Date(); + const m = now.getMonth() + 1; + const d = now.getDate(); + + if ($i.birthday) { + const bm = parseInt($i.birthday.split('-')[1]); + const bd = parseInt($i.birthday.split('-')[2]); + if (m === bm && d === bd) { + claimAchievement('loggedInOnBirthday'); + } + } + + if (m === 1 && d === 1) { + claimAchievement('loggedInOnNewYearsDay'); + } + + if ($i.loggedInDays >= 3) claimAchievement('login3'); + if ($i.loggedInDays >= 7) claimAchievement('login7'); + if ($i.loggedInDays >= 15) claimAchievement('login15'); + if ($i.loggedInDays >= 30) claimAchievement('login30'); + if ($i.loggedInDays >= 60) claimAchievement('login60'); + if ($i.loggedInDays >= 100) claimAchievement('login100'); + if ($i.loggedInDays >= 200) claimAchievement('login200'); + if ($i.loggedInDays >= 300) claimAchievement('login300'); + if ($i.loggedInDays >= 400) claimAchievement('login400'); + if ($i.loggedInDays >= 500) claimAchievement('login500'); + if ($i.loggedInDays >= 600) claimAchievement('login600'); + if ($i.loggedInDays >= 700) claimAchievement('login700'); + if ($i.loggedInDays >= 800) claimAchievement('login800'); + if ($i.loggedInDays >= 900) claimAchievement('login900'); + if ($i.loggedInDays >= 1000) claimAchievement('login1000'); + + if ($i.notesCount > 0) claimAchievement('notes1'); + if ($i.notesCount >= 10) claimAchievement('notes10'); + if ($i.notesCount >= 100) claimAchievement('notes100'); + if ($i.notesCount >= 500) claimAchievement('notes500'); + if ($i.notesCount >= 1000) claimAchievement('notes1000'); + if ($i.notesCount >= 5000) claimAchievement('notes5000'); + if ($i.notesCount >= 10000) claimAchievement('notes10000'); + if ($i.notesCount >= 20000) claimAchievement('notes20000'); + if ($i.notesCount >= 30000) claimAchievement('notes30000'); + if ($i.notesCount >= 40000) claimAchievement('notes40000'); + if ($i.notesCount >= 50000) claimAchievement('notes50000'); + if ($i.notesCount >= 60000) claimAchievement('notes60000'); + if ($i.notesCount >= 70000) claimAchievement('notes70000'); + if ($i.notesCount >= 80000) claimAchievement('notes80000'); + if ($i.notesCount >= 90000) claimAchievement('notes90000'); + if ($i.notesCount >= 100000) claimAchievement('notes100000'); + + if ($i.followersCount > 0) claimAchievement('followers1'); + if ($i.followersCount >= 10) claimAchievement('followers10'); + if ($i.followersCount >= 50) claimAchievement('followers50'); + if ($i.followersCount >= 100) claimAchievement('followers100'); + if ($i.followersCount >= 300) claimAchievement('followers300'); + if ($i.followersCount >= 500) claimAchievement('followers500'); + if ($i.followersCount >= 1000) claimAchievement('followers1000'); + + if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365) { + claimAchievement('passedSinceAccountCreated1'); + } + if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365 * 2) { + claimAchievement('passedSinceAccountCreated2'); + } + if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365 * 3) { + claimAchievement('passedSinceAccountCreated3'); + } + + if (claimedAchievements.length >= 30) { + claimAchievement('collectAchievements30'); + } + + window.setInterval(() => { + if (Math.floor(Math.random() * 20000) === 0) { + claimAchievement('justPlainLucky'); + } + }, 1000 * 10); + + window.setTimeout(() => { + claimAchievement('client30min'); + }, 1000 * 60 * 30); + + window.setTimeout(() => { + claimAchievement('client60min'); + }, 1000 * 60 * 60); + + const lastUsed = miLocalStorage.getItem('lastUsed'); + if (lastUsed) { + const lastUsedDate = parseInt(lastUsed, 10); + // 二時間以上前なら + if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { + toast(i18n.t('welcomeBackWithName', { + name: $i.name || $i.username, + })); + } + } + miLocalStorage.setItem('lastUsed', Date.now().toString()); + + const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt'); + const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo'); + if (neverShowDonationInfo !== 'true' && (new Date($i.createdAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) { + if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) { + popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {}, 'closed'); + } + } + + if ('Notification' in window) { + // 許可を得ていなかったらリクエスト + if (Notification.permission === 'default') { + Notification.requestPermission(); + } + } + + const main = markRaw(stream.useChannel('main', null, 'System')); + + // 自分の情報が更新されたとき + main.on('meUpdated', i => { + updateAccount(i); + }); + + main.on('readAllNotifications', () => { + updateAccount({ hasUnreadNotification: false }); + }); + + main.on('unreadNotification', () => { + updateAccount({ hasUnreadNotification: true }); + }); + + main.on('unreadMention', () => { + updateAccount({ hasUnreadMentions: true }); + }); + + main.on('readAllUnreadMentions', () => { + updateAccount({ hasUnreadMentions: false }); + }); + + main.on('unreadSpecifiedNote', () => { + updateAccount({ hasUnreadSpecifiedNotes: true }); + }); + + main.on('readAllUnreadSpecifiedNotes', () => { + updateAccount({ hasUnreadSpecifiedNotes: false }); + }); + + main.on('readAllAntennas', () => { + updateAccount({ hasUnreadAntenna: false }); + }); + + main.on('unreadAntenna', () => { + updateAccount({ hasUnreadAntenna: true }); + sound.play('antenna'); + }); + + main.on('readAllAnnouncements', () => { + updateAccount({ hasUnreadAnnouncement: false }); + }); + + // トークンが再生成されたとき + // このままではMisskeyが利用できないので強制的にサインアウトさせる + main.on('myTokenRegenerated', () => { + signout(); + }); + } + + // shortcut + document.addEventListener('keydown', makeHotkey(hotkeys)); + + initializeSw(); +} diff --git a/packages/frontend/src/boot/sub-boot.ts b/packages/frontend/src/boot/sub-boot.ts new file mode 100644 index 0000000000..c2664f6c1d --- /dev/null +++ b/packages/frontend/src/boot/sub-boot.ts @@ -0,0 +1,8 @@ +import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent } from 'vue'; +import { common } from './common'; + +export async function subBoot() { + const { isClientUpdated } = await common(() => createApp( + defineAsyncComponent(() => import('@/ui/minimum.vue')), + )); +} diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index bfec57d6a0..edeaabfba4 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -95,7 +95,7 @@ import XNavFolder from '@/components/MkDrive.navFolder.vue'; import XFolder from '@/components/MkDrive.folder.vue'; import XFile from '@/components/MkDrive.file.vue'; import * as os from '@/os'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { defaultStore } from '@/store'; import { i18n } from '@/i18n'; import { uploadFile, uploads } from '@/scripts/upload'; @@ -131,7 +131,7 @@ const hierarchyFolders = ref<Misskey.entities.DriveFolder[]>([]); const selectedFiles = ref<Misskey.entities.DriveFile[]>([]); const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]); const uploadings = uploads; -const connection = stream.useChannel('drive'); +const connection = useStream().useChannel('drive'); const keepOriginal = ref<boolean>(defaultStore.state.keepOriginalUploading); // 外部渡しが多いので$refは使わないほうがよい // ドロップされようとしているか diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index beee21c647..7d066fd033 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -33,7 +33,7 @@ import { onBeforeUnmount, onMounted } from 'vue'; import * as Misskey from 'misskey-js'; import * as os from '@/os'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { i18n } from '@/i18n'; import { claimAchievement } from '@/scripts/achievements'; import { $i } from '@/account'; @@ -50,7 +50,7 @@ const props = withDefaults(defineProps<{ let isFollowing = $ref(props.user.isFollowing); let hasPendingFollowRequestFromYou = $ref(props.user.hasPendingFollowRequestFromYou); let wait = $ref(false); -const connection = stream.useChannel('main'); +const connection = useStream().useChannel('main'); if (props.user.isFollowing == null) { os.api('users/show', { diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index 1aea95fe0e..8cb1b064ba 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -22,7 +22,7 @@ import MkPagination, { Paging } from '@/components/MkPagination.vue'; import XNotification from '@/components/MkNotification.vue'; import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue'; import MkNote from '@/components/MkNote.vue'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { $i } from '@/account'; import { i18n } from '@/i18n'; import { notificationTypes } from '@/const'; @@ -45,7 +45,7 @@ const pagination: Paging = { const onNotification = (notification) => { const isMuted = props.includeTypes ? !props.includeTypes.includes(notification.type) : $i.mutingNotificationTypes.includes(notification.type); if (isMuted || document.visibilityState === 'visible') { - stream.send('readNotification'); + useStream().send('readNotification'); } if (!isMuted) { @@ -56,7 +56,7 @@ const onNotification = (notification) => { let connection; onMounted(() => { - connection = stream.useChannel('main'); + connection = useStream().useChannel('main'); connection.on('notification', onNotification); }); diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index fb0a3a4b67..00a0cb760d 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -5,7 +5,7 @@ <script lang="ts" setup> import { computed, provide, onUnmounted } from 'vue'; import MkNotes from '@/components/MkNotes.vue'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import * as sound from '@/scripts/sound'; import { $i } from '@/account'; import { defaultStore } from '@/store'; @@ -57,6 +57,8 @@ let query; let connection; let connection2; +const stream = useStream(); + if (props.src === 'antenna') { endpoint = 'antennas/notes'; query = { diff --git a/packages/frontend/src/custom-emojis.ts b/packages/frontend/src/custom-emojis.ts index a89a420d77..de1b5b8a63 100644 --- a/packages/frontend/src/custom-emojis.ts +++ b/packages/frontend/src/custom-emojis.ts @@ -1,8 +1,7 @@ import { shallowRef, computed, markRaw } from 'vue'; import * as Misskey from 'misskey-js'; import { api, apiGet } from './os'; -import { miLocalStorage } from './local-storage'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { get, set } from '@/scripts/idb-proxy'; const storageCache = await get('emojis'); @@ -17,6 +16,9 @@ export const customEmojiCategories = computed<[ ...string[], null ]>(() => { return markRaw([...Array.from(categories), null]); }); +// TODO: ここら辺副作用なのでいい感じにする +const stream = useStream(); + stream.on('emojiAdded', emojiData => { customEmojis.value = [emojiData.emoji, ...customEmojis.value]; set('emojis', customEmojis.value); @@ -34,10 +36,9 @@ stream.on('emojiDeleted', emojiData => { export async function fetchCustomEmojis(force = false) { const now = Date.now(); - const needsMigration = miLocalStorage.getItem('emojis') != null; let res; - if (force || needsMigration) { + if (force) { res = await api('emojis', {}); } else { const lastFetchedAt = await get('lastEmojisFetchedAt'); @@ -48,10 +49,6 @@ export async function fetchCustomEmojis(force = false) { customEmojis.value = res.emojis; set('emojis', res.emojis); set('lastEmojisFetchedAt', now); - if (needsMigration) { - miLocalStorage.removeItem('emojis'); - miLocalStorage.removeItem('lastEmojisFetchedAt'); - } } let cachedTags; diff --git a/packages/frontend/src/init.ts b/packages/frontend/src/init.ts deleted file mode 100644 index 763b6d44b0..0000000000 --- a/packages/frontend/src/init.ts +++ /dev/null @@ -1,523 +0,0 @@ -/** - * Client entry point - */ -// https://vitejs.dev/config/build-options.html#build-modulepreload -import 'vite/modulepreload-polyfill'; - -import '@/style.scss'; - -import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent } from 'vue'; -import { compareVersions } from 'compare-versions'; -import JSON5 from 'json5'; - -import widgets from '@/widgets'; -import directives from '@/directives'; -import components from '@/components'; -import { version, ui, lang, updateLocale } from '@/config'; -import { applyTheme } from '@/scripts/theme'; -import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; -import { i18n, updateI18n } from '@/i18n'; -import { confirm, alert, post, popup, toast } from '@/os'; -import { stream } from '@/stream'; -import * as sound from '@/scripts/sound'; -import { $i, refreshAccount, login, updateAccount, signout } from '@/account'; -import { defaultStore, ColdDeviceStorage } from '@/store'; -import { fetchInstance, instance } from '@/instance'; -import { makeHotkey } from '@/scripts/hotkey'; -import { deviceKind } from '@/scripts/device-kind'; -import { initializeSw } from '@/scripts/initialize-sw'; -import { reloadChannel } from '@/scripts/unison-reload'; -import { reactionPicker } from '@/scripts/reaction-picker'; -import { getUrlWithoutLoginId } from '@/scripts/login-id'; -import { getAccountFromId } from '@/scripts/get-account-from-id'; -import { deckStore } from '@/ui/deck/deck-store'; -import { miLocalStorage } from '@/local-storage'; -import { claimAchievement, claimedAchievements } from '@/scripts/achievements'; -import { fetchCustomEmojis } from '@/custom-emojis'; -import { mainRouter } from '@/router'; - -console.info(`Misskey v${version}`); - -if (_DEV_) { - console.warn('Development mode!!!'); - - console.info(`vue ${vueVersion}`); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (window as any).$i = $i; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (window as any).$store = defaultStore; - - window.addEventListener('error', event => { - console.error(event); - /* - alert({ - type: 'error', - title: 'DEV: Unhandled error', - text: event.message - }); - */ - }); - - window.addEventListener('unhandledrejection', event => { - console.error(event); - /* - alert({ - type: 'error', - title: 'DEV: Unhandled promise rejection', - text: event.reason - }); - */ - }); -} - -//#region Detect language & fetch translations -const localeVersion = miLocalStorage.getItem('localeVersion'); -const localeOutdated = (localeVersion == null || localeVersion !== version); -if (localeOutdated) { - const res = await window.fetch(`/assets/locales/${lang}.${version}.json`); - if (res.status === 200) { - const newLocale = await res.text(); - const parsedNewLocale = JSON.parse(newLocale); - miLocalStorage.setItem('locale', newLocale); - miLocalStorage.setItem('localeVersion', version); - updateLocale(parsedNewLocale); - updateI18n(parsedNewLocale); - } -} -//#endregion - -// タッチデバイスでCSSの:hoverを機能させる -document.addEventListener('touchend', () => {}, { passive: true }); - -// 一斉リロード -reloadChannel.addEventListener('message', path => { - if (path !== null) location.href = path; - else location.reload(); -}); - -// If mobile, insert the viewport meta tag -if (['smartphone', 'tablet'].includes(deviceKind)) { - const viewport = document.getElementsByName('viewport').item(0); - viewport.setAttribute('content', - `${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`); -} - -//#region Set lang attr -const html = document.documentElement; -html.setAttribute('lang', lang); -//#endregion - -//#region loginId -const params = new URLSearchParams(location.search); -const loginId = params.get('loginId'); - -if (loginId) { - const target = getUrlWithoutLoginId(location.href); - - if (!$i || $i.id !== loginId) { - const account = await getAccountFromId(loginId); - if (account) { - await login(account.token, target); - } - } - - history.replaceState({ misskey: 'loginId' }, '', target); -} - -//#endregion - -//#region Fetch user -if ($i && $i.token) { - if (_DEV_) { - console.log('account cache found. refreshing...'); - } - - refreshAccount(); -} else { - if (_DEV_) { - console.log('no account cache found.'); - } - - // 連携ログインの場合用にCookieを参照する - const i = (document.cookie.match(/igi=(\w+)/) ?? [null, null])[1]; - - if (i != null && i !== 'null') { - if (_DEV_) { - console.log('signing...'); - } - - try { - document.body.innerHTML = '<div>Please wait...</div>'; - await login(i); - } catch (err) { - // Render the error screen - // TODO: ちゃんとしたコンポーネントをレンダリングする(v10とかのトラブルシューティングゲーム付きのやつみたいな) - document.body.innerHTML = '<div id="err">Oops!</div>'; - } - } else { - if (_DEV_) { - console.log('not signed in'); - } - } -} -//#endregion - -const fetchInstanceMetaPromise = fetchInstance(); - -fetchInstanceMetaPromise.then(() => { - miLocalStorage.setItem('v', instance.version); - - // Init service worker - initializeSw(); -}); - -try { - await fetchCustomEmojis(); -} catch (err) { /* empty */ } - -const app = createApp( - new URLSearchParams(window.location.search).has('zen') ? defineAsyncComponent(() => import('@/ui/zen.vue')) : - !$i ? defineAsyncComponent(() => import('@/ui/visitor.vue')) : - ui === 'deck' ? defineAsyncComponent(() => import('@/ui/deck.vue')) : - ui === 'classic' ? defineAsyncComponent(() => import('@/ui/classic.vue')) : - defineAsyncComponent(() => import('@/ui/universal.vue')), -); - -if (_DEV_) { - app.config.performance = true; -} - -widgets(app); -directives(app); -components(app); - -const splash = document.getElementById('splash'); -// 念のためnullチェック(HTMLが古い場合があるため(そのうち消す)) -if (splash) splash.addEventListener('transitionend', () => { - splash.remove(); -}); - -await deckStore.ready; - -// https://github.com/misskey-dev/misskey/pull/8575#issuecomment-1114239210 -// なぜかinit.tsの内容が2回実行されることがあるため、mountするdivを1つに制限する -const rootEl = ((): HTMLElement => { - const MISSKEY_MOUNT_DIV_ID = 'misskey_app'; - - const currentRoot = document.getElementById(MISSKEY_MOUNT_DIV_ID); - - if (currentRoot) { - console.warn('multiple import detected'); - return currentRoot; - } - - const root = document.createElement('div'); - root.id = MISSKEY_MOUNT_DIV_ID; - document.body.appendChild(root); - return root; -})(); - -app.mount(rootEl); - -// boot.jsのやつを解除 -window.onerror = null; -window.onunhandledrejection = null; - -reactionPicker.init(); - -if (splash) { - splash.style.opacity = '0'; - splash.style.pointerEvents = 'none'; -} - -// クライアントが更新されたか? -const lastVersion = miLocalStorage.getItem('lastVersion'); -if (lastVersion !== version) { - miLocalStorage.setItem('lastVersion', version); - - // テーマリビルドするため - miLocalStorage.removeItem('theme'); - - try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため - if (lastVersion != null && compareVersions(version, lastVersion) === 1) { - // ログインしてる場合だけ - if ($i) { - popup(defineAsyncComponent(() => import('@/components/MkUpdated.vue')), {}, {}, 'closed'); - } - } - } catch (err) { /* empty */ } -} - -await defaultStore.ready; - -// NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため) -watch(defaultStore.reactiveState.darkMode, (darkMode) => { - applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); -}, { immediate: miLocalStorage.getItem('theme') == null }); - -const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); -const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); - -watch(darkTheme, (theme) => { - if (defaultStore.state.darkMode) { - applyTheme(theme); - } -}); - -watch(lightTheme, (theme) => { - if (!defaultStore.state.darkMode) { - applyTheme(theme); - } -}); - -//#region Sync dark mode -if (ColdDeviceStorage.get('syncDeviceDarkMode')) { - defaultStore.set('darkMode', isDeviceDarkmode()); -} - -window.matchMedia('(prefers-color-scheme: dark)').addListener(mql => { - if (ColdDeviceStorage.get('syncDeviceDarkMode')) { - defaultStore.set('darkMode', mql.matches); - } -}); -//#endregion - -fetchInstanceMetaPromise.then(() => { - if (defaultStore.state.themeInitial) { - if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON5.parse(instance.defaultLightTheme)); - if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON5.parse(instance.defaultDarkTheme)); - defaultStore.set('themeInitial', false); - } -}); - -watch(defaultStore.reactiveState.useBlurEffectForModal, v => { - document.documentElement.style.setProperty('--modalBgFilter', v ? 'blur(4px)' : 'none'); -}, { immediate: true }); - -watch(defaultStore.reactiveState.useBlurEffect, v => { - if (v) { - document.documentElement.style.removeProperty('--blur'); - } else { - document.documentElement.style.setProperty('--blur', 'none'); - } -}, { immediate: true }); - -let reloadDialogShowing = false; -stream.on('_disconnected_', async () => { - if (defaultStore.state.serverDisconnectedBehavior === 'reload') { - location.reload(); - } else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { - if (reloadDialogShowing) return; - reloadDialogShowing = true; - const { canceled } = await confirm({ - type: 'warning', - title: i18n.ts.disconnectedFromServer, - text: i18n.ts.reloadConfirm, - }); - reloadDialogShowing = false; - if (!canceled) { - location.reload(); - } - } -}); - -for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) { - import('./plugin').then(async ({ install }) => { - // Workaround for https://bugs.webkit.org/show_bug.cgi?id=242740 - await new Promise(r => setTimeout(r, 0)); - install(plugin); - }); -} - -const hotkeys = { - 'd': (): void => { - defaultStore.set('darkMode', !defaultStore.state.darkMode); - }, - 's': (): void => { - mainRouter.push('/search'); - }, -}; - -if ($i) { - // only add post shortcuts if logged in - hotkeys['p|n'] = post; - - defaultStore.loaded.then(() => { - if (defaultStore.state.accountSetupWizard !== -1) { - popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {}, 'closed'); - } - }); - - if ($i.isDeleted) { - alert({ - type: 'warning', - text: i18n.ts.accountDeletionInProgress, - }); - } - - const now = new Date(); - const m = now.getMonth() + 1; - const d = now.getDate(); - - if ($i.birthday) { - const bm = parseInt($i.birthday.split('-')[1]); - const bd = parseInt($i.birthday.split('-')[2]); - if (m === bm && d === bd) { - claimAchievement('loggedInOnBirthday'); - } - } - - if (m === 1 && d === 1) { - claimAchievement('loggedInOnNewYearsDay'); - } - - if ($i.loggedInDays >= 3) claimAchievement('login3'); - if ($i.loggedInDays >= 7) claimAchievement('login7'); - if ($i.loggedInDays >= 15) claimAchievement('login15'); - if ($i.loggedInDays >= 30) claimAchievement('login30'); - if ($i.loggedInDays >= 60) claimAchievement('login60'); - if ($i.loggedInDays >= 100) claimAchievement('login100'); - if ($i.loggedInDays >= 200) claimAchievement('login200'); - if ($i.loggedInDays >= 300) claimAchievement('login300'); - if ($i.loggedInDays >= 400) claimAchievement('login400'); - if ($i.loggedInDays >= 500) claimAchievement('login500'); - if ($i.loggedInDays >= 600) claimAchievement('login600'); - if ($i.loggedInDays >= 700) claimAchievement('login700'); - if ($i.loggedInDays >= 800) claimAchievement('login800'); - if ($i.loggedInDays >= 900) claimAchievement('login900'); - if ($i.loggedInDays >= 1000) claimAchievement('login1000'); - - if ($i.notesCount > 0) claimAchievement('notes1'); - if ($i.notesCount >= 10) claimAchievement('notes10'); - if ($i.notesCount >= 100) claimAchievement('notes100'); - if ($i.notesCount >= 500) claimAchievement('notes500'); - if ($i.notesCount >= 1000) claimAchievement('notes1000'); - if ($i.notesCount >= 5000) claimAchievement('notes5000'); - if ($i.notesCount >= 10000) claimAchievement('notes10000'); - if ($i.notesCount >= 20000) claimAchievement('notes20000'); - if ($i.notesCount >= 30000) claimAchievement('notes30000'); - if ($i.notesCount >= 40000) claimAchievement('notes40000'); - if ($i.notesCount >= 50000) claimAchievement('notes50000'); - if ($i.notesCount >= 60000) claimAchievement('notes60000'); - if ($i.notesCount >= 70000) claimAchievement('notes70000'); - if ($i.notesCount >= 80000) claimAchievement('notes80000'); - if ($i.notesCount >= 90000) claimAchievement('notes90000'); - if ($i.notesCount >= 100000) claimAchievement('notes100000'); - - if ($i.followersCount > 0) claimAchievement('followers1'); - if ($i.followersCount >= 10) claimAchievement('followers10'); - if ($i.followersCount >= 50) claimAchievement('followers50'); - if ($i.followersCount >= 100) claimAchievement('followers100'); - if ($i.followersCount >= 300) claimAchievement('followers300'); - if ($i.followersCount >= 500) claimAchievement('followers500'); - if ($i.followersCount >= 1000) claimAchievement('followers1000'); - - if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365) { - claimAchievement('passedSinceAccountCreated1'); - } - if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365 * 2) { - claimAchievement('passedSinceAccountCreated2'); - } - if (Date.now() - new Date($i.createdAt).getTime() > 1000 * 60 * 60 * 24 * 365 * 3) { - claimAchievement('passedSinceAccountCreated3'); - } - - if (claimedAchievements.length >= 30) { - claimAchievement('collectAchievements30'); - } - - window.setInterval(() => { - if (Math.floor(Math.random() * 20000) === 0) { - claimAchievement('justPlainLucky'); - } - }, 1000 * 10); - - window.setTimeout(() => { - claimAchievement('client30min'); - }, 1000 * 60 * 30); - - window.setTimeout(() => { - claimAchievement('client60min'); - }, 1000 * 60 * 60); - - const lastUsed = miLocalStorage.getItem('lastUsed'); - if (lastUsed) { - const lastUsedDate = parseInt(lastUsed, 10); - // 二時間以上前なら - if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) { - toast(i18n.t('welcomeBackWithName', { - name: $i.name || $i.username, - })); - } - } - miLocalStorage.setItem('lastUsed', Date.now().toString()); - - const latestDonationInfoShownAt = miLocalStorage.getItem('latestDonationInfoShownAt'); - const neverShowDonationInfo = miLocalStorage.getItem('neverShowDonationInfo'); - if (neverShowDonationInfo !== 'true' && (new Date($i.createdAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 3))) && !location.pathname.startsWith('/miauth')) { - if (latestDonationInfoShownAt == null || (new Date(latestDonationInfoShownAt).getTime() < (Date.now() - (1000 * 60 * 60 * 24 * 30)))) { - popup(defineAsyncComponent(() => import('@/components/MkDonation.vue')), {}, {}, 'closed'); - } - } - - if ('Notification' in window) { - // 許可を得ていなかったらリクエスト - if (Notification.permission === 'default') { - Notification.requestPermission(); - } - } - - const main = markRaw(stream.useChannel('main', null, 'System')); - - // 自分の情報が更新されたとき - main.on('meUpdated', i => { - updateAccount(i); - }); - - main.on('readAllNotifications', () => { - updateAccount({ hasUnreadNotification: false }); - }); - - main.on('unreadNotification', () => { - updateAccount({ hasUnreadNotification: true }); - }); - - main.on('unreadMention', () => { - updateAccount({ hasUnreadMentions: true }); - }); - - main.on('readAllUnreadMentions', () => { - updateAccount({ hasUnreadMentions: false }); - }); - - main.on('unreadSpecifiedNote', () => { - updateAccount({ hasUnreadSpecifiedNotes: true }); - }); - - main.on('readAllUnreadSpecifiedNotes', () => { - updateAccount({ hasUnreadSpecifiedNotes: false }); - }); - - main.on('readAllAntennas', () => { - updateAccount({ hasUnreadAntenna: false }); - }); - - main.on('unreadAntenna', () => { - updateAccount({ hasUnreadAntenna: true }); - sound.play('antenna'); - }); - - main.on('readAllAnnouncements', () => { - updateAccount({ hasUnreadAnnouncement: false }); - }); - - // トークンが再生成されたとき - // このままではMisskeyが利用できないので強制的にサインアウトさせる - main.on('myTokenRegenerated', () => { - signout(); - }); -} - -// shortcut -document.addEventListener('keydown', makeHotkey(hotkeys)); diff --git a/packages/frontend/src/pages/admin/overview.queue.vue b/packages/frontend/src/pages/admin/overview.queue.vue index 1f56a2826a..69ca89e226 100644 --- a/packages/frontend/src/pages/admin/overview.queue.vue +++ b/packages/frontend/src/pages/admin/overview.queue.vue @@ -33,9 +33,9 @@ import { markRaw, onMounted, onUnmounted, ref } from 'vue'; import XChart from './overview.queue.chart.vue'; import number from '@/filters/number'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; -const connection = markRaw(stream.useChannel('queueStats')); +const connection = markRaw(useStream().useChannel('queueStats')); const activeSincePrevTick = ref(0); const active = ref(0); diff --git a/packages/frontend/src/pages/admin/overview.vue b/packages/frontend/src/pages/admin/overview.vue index bdfb200a88..46a93ac5d8 100644 --- a/packages/frontend/src/pages/admin/overview.vue +++ b/packages/frontend/src/pages/admin/overview.vue @@ -72,7 +72,7 @@ import XRetention from './overview.retention.vue'; import XModerators from './overview.moderators.vue'; import XHeatmap from './overview.heatmap.vue'; import * as os from '@/os'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; @@ -87,7 +87,7 @@ let federationSubActive = $ref<number | null>(null); let federationSubActiveDiff = $ref<number | null>(null); let newUsers = $ref(null); let activeInstances = $shallowRef(null); -const queueStatsConnection = markRaw(stream.useChannel('queueStats')); +const queueStatsConnection = markRaw(useStream().useChannel('queueStats')); const now = new Date(); const filesPagination = { endpoint: 'admin/drive/files' as const, diff --git a/packages/frontend/src/pages/admin/queue.chart.vue b/packages/frontend/src/pages/admin/queue.chart.vue index 100d1ea545..728f3b2c80 100644 --- a/packages/frontend/src/pages/admin/queue.chart.vue +++ b/packages/frontend/src/pages/admin/queue.chart.vue @@ -47,11 +47,11 @@ import { markRaw, onMounted, onUnmounted, ref } from 'vue'; import XChart from './queue.chart.chart.vue'; import number from '@/filters/number'; import * as os from '@/os'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { i18n } from '@/i18n'; import MkFolder from '@/components/MkFolder.vue'; -const connection = markRaw(stream.useChannel('queueStats')); +const connection = markRaw(useStream().useChannel('queueStats')); const activeSincePrevTick = ref(0); const active = ref(0); diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 6613ce4c1d..86f633c445 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -40,7 +40,7 @@ import MkInfo from '@/components/MkInfo.vue'; import * as os from '@/os'; import { ColdDeviceStorage, defaultStore } from '@/store'; import { unisonReload } from '@/scripts/unison-reload'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { $i } from '@/account'; import { i18n } from '@/i18n'; import { version, host } from '@/config'; @@ -125,7 +125,7 @@ type Profile = { }; }; -const connection = $i && stream.useChannel('main'); +const connection = $i && useStream().useChannel('main'); let profiles = $ref<Record<string, Profile> | null>(null); diff --git a/packages/frontend/src/pizzax.ts b/packages/frontend/src/pizzax.ts index 2616a8a1d5..d97bd4be62 100644 --- a/packages/frontend/src/pizzax.ts +++ b/packages/frontend/src/pizzax.ts @@ -6,7 +6,7 @@ import { $i } from './account'; import { api } from './os'; import { get, set } from './scripts/idb-proxy'; import { defaultStore } from './store'; -import { stream } from './stream'; +import { useStream } from './stream'; import { deepClone } from './scripts/clone'; type StateDef = Record<string, { @@ -26,8 +26,6 @@ type PizzaxChannelMessage<T extends StateDef> = { userId?: string; }; -const connection = $i && stream.useChannel('main'); - export class Storage<T extends StateDef> { public readonly ready: Promise<void>; public readonly loaded: Promise<void>; @@ -105,8 +103,10 @@ export class Storage<T extends StateDef> { }); if ($i) { + const connection = useStream().useChannel('main'); + // streamingのuser storage updateイベントを監視して更新 - connection?.on('registryUpdated', ({ scope, key, value }: { scope?: string[], key: keyof T, value: T[typeof key]['default'] }) => { + connection.on('registryUpdated', ({ scope, key, value }: { scope?: string[], key: keyof T, value: T[typeof key]['default'] }) => { if (!scope || scope.length !== 2 || scope[0] !== 'client' || scope[1] !== this.key || this.state[key] === value) return; this.reactiveState[key].value = this.state[key] = value; diff --git a/packages/frontend/src/scripts/select-file.ts b/packages/frontend/src/scripts/select-file.ts index fe9f0a2447..44a58d6c7d 100644 --- a/packages/frontend/src/scripts/select-file.ts +++ b/packages/frontend/src/scripts/select-file.ts @@ -1,7 +1,7 @@ import { ref } from 'vue'; import { DriveFile } from 'misskey-js/built/entities'; import * as os from '@/os'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; import { uploadFile } from '@/scripts/upload'; @@ -51,7 +51,7 @@ export function chooseFileFromUrl(): Promise<DriveFile> { const marker = Math.random().toString(); // TODO: UUIDとか使う - const connection = stream.useChannel('main'); + const connection = useStream().useChannel('main'); connection.on('urlUploadFinished', urlResponse => { if (urlResponse.marker === marker) { res(urlResponse.file); diff --git a/packages/frontend/src/scripts/use-note-capture.ts b/packages/frontend/src/scripts/use-note-capture.ts index ffe33cccc0..22a01e066a 100644 --- a/packages/frontend/src/scripts/use-note-capture.ts +++ b/packages/frontend/src/scripts/use-note-capture.ts @@ -1,6 +1,6 @@ import { onUnmounted, Ref } from 'vue'; import * as misskey from 'misskey-js'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { $i } from '@/account'; export function useNoteCapture(props: { @@ -9,7 +9,7 @@ export function useNoteCapture(props: { isDeletedRef: Ref<boolean>; }) { const note = props.note; - const connection = $i ? stream : null; + const connection = $i ? useStream() : null; function onStreamNoteUpdated(noteData): void { const { type, id, body } = noteData; diff --git a/packages/frontend/src/stream.ts b/packages/frontend/src/stream.ts index dea3459b86..9cae58a26a 100644 --- a/packages/frontend/src/stream.ts +++ b/packages/frontend/src/stream.ts @@ -3,6 +3,14 @@ import { markRaw } from 'vue'; import { $i } from '@/account'; import { url } from '@/config'; -export const stream = markRaw(new Misskey.Stream(url, $i ? { - token: $i.token, -} : null)); +let stream: Misskey.Stream | null = null; + +export function useStream(): Misskey.Stream { + if (stream) return stream; + + stream = markRaw(new Misskey.Stream(url, $i ? { + token: $i.token, + } : null)); + + return stream; +} diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue index 71a4285e9d..2beebb0390 100644 --- a/packages/frontend/src/ui/_common_/common.vue +++ b/packages/frontend/src/ui/_common_/common.vue @@ -40,7 +40,7 @@ import { popups, pendingApiRequestsCount } from '@/os'; import { uploads } from '@/scripts/upload'; import * as sound from '@/scripts/sound'; import { $i } from '@/account'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; @@ -55,7 +55,7 @@ function onNotification(notification) { if ($i.mutingNotificationTypes.includes(notification.type)) return; if (document.visibilityState === 'visible') { - stream.send('readNotification'); + useStream().send('readNotification'); notifications.unshift(notification); window.setTimeout(() => { @@ -71,7 +71,7 @@ function onNotification(notification) { } if ($i) { - const connection = stream.useChannel('main', null, 'UI'); + const connection = useStream().useChannel('main', null, 'UI'); connection.on('notification', onNotification); //#region Listen message from SW diff --git a/packages/frontend/src/ui/_common_/stream-indicator.vue b/packages/frontend/src/ui/_common_/stream-indicator.vue index 2a856e2a45..3e97df7ee5 100644 --- a/packages/frontend/src/ui/_common_/stream-indicator.vue +++ b/packages/frontend/src/ui/_common_/stream-indicator.vue @@ -10,7 +10,7 @@ <script lang="ts" setup> import { onUnmounted } from 'vue'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { i18n } from '@/i18n'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os'; @@ -32,10 +32,10 @@ function reload() { location.reload(); } -stream.on('_disconnected_', onDisconnected); +useStream().on('_disconnected_', onDisconnected); onUnmounted(() => { - stream.off('_disconnected_', onDisconnected); + useStream().off('_disconnected_', onDisconnected); }); </script> diff --git a/packages/frontend/src/ui/minimum.vue b/packages/frontend/src/ui/minimum.vue new file mode 100644 index 0000000000..628390e3f7 --- /dev/null +++ b/packages/frontend/src/ui/minimum.vue @@ -0,0 +1,34 @@ +<template> +<div class="mk-app" style="container-type: inline-size;"> + <RouterView/> + + <XCommon/> +</div> +</template> + +<script lang="ts" setup> +import { provide, ComputedRef } from 'vue'; +import XCommon from './_common_/common.vue'; +import { mainRouter } from '@/router'; +import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; +import { instanceName } from '@/config'; + +let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); + +provide('router', mainRouter); +provideMetadataReceiver((info) => { + pageMetadata = info; + if (pageMetadata.value) { + document.title = `${pageMetadata.value.title} | ${instanceName}`; + } +}); + +document.documentElement.style.overflowY = 'scroll'; +</script> + +<style lang="scss" scoped> +.mk-app { + min-height: 100dvh; + box-sizing: border-box; +} +</style> diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue index 84043cf13f..73a4802595 100644 --- a/packages/frontend/src/widgets/WidgetJobQueue.vue +++ b/packages/frontend/src/widgets/WidgetJobQueue.vue @@ -49,7 +49,7 @@ import { onUnmounted, reactive } from 'vue'; import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; import { GetFormResultType } from '@/scripts/form'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import number from '@/filters/number'; import * as sound from '@/scripts/sound'; import { deepClone } from '@/scripts/clone'; @@ -81,7 +81,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); -const connection = stream.useChannel('queueStats'); +const connection = useStream().useChannel('queueStats'); const current = reactive({ inbox: { activeSincePrevTick: 0, diff --git a/packages/frontend/src/widgets/WidgetPhotos.vue b/packages/frontend/src/widgets/WidgetPhotos.vue index 716bbb4274..1484aa1941 100644 --- a/packages/frontend/src/widgets/WidgetPhotos.vue +++ b/packages/frontend/src/widgets/WidgetPhotos.vue @@ -20,7 +20,7 @@ import { onUnmounted, ref } from 'vue'; import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; import { GetFormResultType } from '@/scripts/form'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { getStaticImageUrl } from '@/scripts/media-proxy'; import * as os from '@/os'; import MkContainer from '@/components/MkContainer.vue'; @@ -54,7 +54,7 @@ const { widgetProps, configure } = useWidgetPropsManager(name, emit, ); -const connection = stream.useChannel('main'); +const connection = useStream().useChannel('main'); const images = ref([]); const fetching = ref(true); diff --git a/packages/frontend/src/widgets/server-metric/index.vue b/packages/frontend/src/widgets/server-metric/index.vue index 357d0ab78b..df8de10f63 100644 --- a/packages/frontend/src/widgets/server-metric/index.vue +++ b/packages/frontend/src/widgets/server-metric/index.vue @@ -25,7 +25,7 @@ import XDisk from './disk.vue'; import MkContainer from '@/components/MkContainer.vue'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; -import { stream } from '@/stream'; +import { useStream } from '@/stream'; import { i18n } from '@/i18n'; const name = 'serverMetric'; @@ -75,7 +75,7 @@ const toggleView = () => { save(); }; -const connection = stream.useChannel('serverStats'); +const connection = useStream().useChannel('serverStats'); onUnmounted(() => { connection.dispose(); }); diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index fad0dd0177..339761e78c 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -117,7 +117,7 @@ export function getConfig(): UserConfig { manifest: 'manifest.json', rollupOptions: { input: { - app: './src/init.ts', + app: './src/_boot_.ts', }, output: { manualChunks: { From d10d5a8d53fd214ca75613f73bb7149632ec9cf9 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 16 May 2023 12:16:37 +0900 Subject: [PATCH 023/213] =?UTF-8?q?enhance:=20=E3=82=BF=E3=82=A4=E3=83=A0?= =?UTF-8?q?=E3=83=A9=E3=82=A4=E3=83=B3=E3=81=AB=E3=83=95=E3=82=A9=E3=83=AD?= =?UTF-8?q?=E3=82=A4=E3=83=BC=E3=81=AE=E8=A1=8C=E3=81=A3=E3=81=9F=E4=BB=96?= =?UTF-8?q?=E4=BA=BA=E3=81=B8=E3=81=AE=E3=83=AA=E3=83=97=E3=83=A9=E3=82=A4?= =?UTF-8?q?=E3=82=92=E5=90=AB=E3=82=81=E3=82=8B=E3=81=8B=E3=81=A9=E3=81=86?= =?UTF-8?q?=E3=81=8B=E3=81=AE=E8=A8=AD=E5=AE=9A=E3=82=92=E3=82=A2=E3=82=AB?= =?UTF-8?q?=E3=82=A6=E3=83=B3=E3=83=88=E3=81=AB=E4=BF=9D=E5=AD=98=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=81=AE=E3=82=92=E3=82=84=E3=82=81=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve #10646 --- CHANGELOG.md | 4 +++ ...684206886988-remove-showTimelineReplies.js | 11 ++++++++ packages/backend/src/core/QueryService.ts | 4 +-- .../activitypub/models/ApPersonService.ts | 7 ++--- .../src/core/entities/UserEntityService.ts | 1 - packages/backend/src/models/entities/User.ts | 6 ---- .../src/server/api/endpoints/i/update.ts | 2 -- .../api/endpoints/notes/global-timeline.ts | 9 ++---- .../api/endpoints/notes/hybrid-timeline.ts | 9 ++---- .../api/endpoints/notes/local-timeline.ts | 9 ++---- .../server/api/endpoints/notes/timeline.ts | 9 ++---- .../api/stream/channels/global-timeline.ts | 5 +++- .../api/stream/channels/home-timeline.ts | 5 +++- .../api/stream/channels/hybrid-timeline.ts | 5 +++- .../api/stream/channels/local-timeline.ts | 5 +++- packages/backend/test/e2e/users.ts | 5 ---- .../frontend/src/components/MkTimeline.vue | 28 ++++++++++++++++--- .../frontend/src/pages/settings/general.vue | 2 ++ .../frontend/src/pages/settings/profile.vue | 2 -- packages/frontend/src/store.ts | 4 +++ 20 files changed, 78 insertions(+), 54 deletions(-) create mode 100644 packages/backend/migration/1684206886988-remove-showTimelineReplies.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 7087d73b9a..a20120b483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ ## 13.x.x (unreleased) +### General +- タイムラインにフォロイーの行った他人へのリプライを含めるかどうかの設定をアカウントに保存するのをやめるように + - 今後はAPI呼び出し時およびストリーミング接続時に設定するようになります + ### Client - 開発者モードを追加 - AiScriptを0.13.3に更新 diff --git a/packages/backend/migration/1684206886988-remove-showTimelineReplies.js b/packages/backend/migration/1684206886988-remove-showTimelineReplies.js new file mode 100644 index 0000000000..690653bd7c --- /dev/null +++ b/packages/backend/migration/1684206886988-remove-showTimelineReplies.js @@ -0,0 +1,11 @@ +export class RemoveShowTimelineReplies1684206886988 { + name = 'RemoveShowTimelineReplies1684206886988' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "showTimelineReplies"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "showTimelineReplies" boolean NOT NULL DEFAULT false`); + } +} diff --git a/packages/backend/src/core/QueryService.ts b/packages/backend/src/core/QueryService.ts index 0cee2076bf..bf50a1cded 100644 --- a/packages/backend/src/core/QueryService.ts +++ b/packages/backend/src/core/QueryService.ts @@ -208,7 +208,7 @@ export class QueryService { } @bindThis - public generateRepliesQuery(q: SelectQueryBuilder<any>, me?: Pick<User, 'id' | 'showTimelineReplies'> | null): void { + public generateRepliesQuery(q: SelectQueryBuilder<any>, withReplies: boolean, me?: Pick<User, 'id'> | null): void { if (me == null) { q.andWhere(new Brackets(qb => { qb .where('note.replyId IS NULL') // 返信ではない @@ -217,7 +217,7 @@ export class QueryService { .andWhere('note.replyUserId = note.userId'); })); })); - } else if (!me.showTimelineReplies) { + } else if (!withReplies) { q.andWhere(new Brackets(qb => { qb .where('note.replyId IS NULL') // 返信ではない .orWhere('note.replyUserId = :meId', { meId: me.id }) // 返信だけど自分のノートへの返信 diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index eea1d1b848..f52ebed107 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -32,6 +32,8 @@ import type { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import { MetaService } from '@/core/MetaService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; +import type { AccountMoveService } from '@/core/AccountMoveService.js'; +import { checkHttps } from '@/misc/check-https.js'; import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js'; import { extractApHashtags } from './tag.js'; import type { OnModuleInit } from '@nestjs/common'; @@ -42,8 +44,6 @@ import type { ApLoggerService } from '../ApLoggerService.js'; // eslint-disable-next-line @typescript-eslint/consistent-type-imports import type { ApImageService } from './ApImageService.js'; import type { IActor, IObject } from '../type.js'; -import type { AccountMoveService } from '@/core/AccountMoveService.js'; -import { checkHttps } from '@/misc/check-https.js'; const nameLength = 128; const summaryLength = 2048; @@ -306,7 +306,6 @@ export class ApPersonService implements OnModuleInit { tags, isBot, isCat: (person as any).isCat === true, - showTimelineReplies: false, })) as RemoteUser; await transactionalEntityManager.save(new UserProfile({ @@ -696,7 +695,7 @@ export class ApPersonService implements OnModuleInit { if (!dst.alsoKnownAs || dst.alsoKnownAs.length === 0) { return 'skip: dst.alsoKnownAs is empty'; } - if (!dst.alsoKnownAs?.includes(src.uri)) { + if (!dst.alsoKnownAs.includes(src.uri)) { return 'skip: alsoKnownAs does not include from.uri'; } diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 7f61e1d6f3..bfd506ea86 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -466,7 +466,6 @@ export class UserEntityService implements OnModuleInit { mutedInstances: profile!.mutedInstances, mutingNotificationTypes: profile!.mutingNotificationTypes, emailNotificationTypes: profile!.emailNotificationTypes, - showTimelineReplies: user.showTimelineReplies ?? falsy, achievements: profile!.achievements, loggedInDays: profile!.loggedInDates.length, policies: this.roleService.getUserPolicies(user.id), diff --git a/packages/backend/src/models/entities/User.ts b/packages/backend/src/models/entities/User.ts index 8e10f999b6..6669890cf6 100644 --- a/packages/backend/src/models/entities/User.ts +++ b/packages/backend/src/models/entities/User.ts @@ -232,12 +232,6 @@ export class User { }) public followersUri: string | null; - @Column('boolean', { - default: false, - comment: 'Whether to show users replying to other users in the timeline.', - }) - public showTimelineReplies: boolean; - @Index({ unique: true }) @Column('char', { length: 16, nullable: true, unique: true, diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 74be00a8b8..d10f690a32 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -141,7 +141,6 @@ export const paramDef = { preventAiLearning: { type: 'boolean' }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, - showTimelineReplies: { type: 'boolean' }, injectFeaturedNote: { type: 'boolean' }, receiveAnnouncementEmail: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' }, @@ -239,7 +238,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { if (typeof ps.hideOnlineStatus === 'boolean') updates.hideOnlineStatus = ps.hideOnlineStatus; if (typeof ps.publicReactions === 'boolean') profileUpdates.publicReactions = ps.publicReactions; if (typeof ps.isBot === 'boolean') updates.isBot = ps.isBot; - if (typeof ps.showTimelineReplies === 'boolean') updates.showTimelineReplies = ps.showTimelineReplies; if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot; if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index c11c1eac40..88c1ca7f58 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -34,11 +34,8 @@ export const meta = { export const paramDef = { type: 'object', properties: { - withFiles: { - type: 'boolean', - default: false, - description: 'Only show notes that have attached files.', - }, + withFiles: { type: 'boolean', default: false }, + withReplies: { type: 'boolean', default: false }, limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, @@ -78,7 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { .leftJoinAndSelect('reply.user', 'replyUser') .leftJoinAndSelect('renote.user', 'renoteUser'); - this.queryService.generateRepliesQuery(query, me); + this.queryService.generateRepliesQuery(query, ps.withReplies, me); if (me) { this.queryService.generateMutedUserQuery(query, me); this.queryService.generateMutedNoteQuery(query, me); diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 89abd91c7e..7a3581e6e4 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -46,11 +46,8 @@ export const paramDef = { includeMyRenotes: { type: 'boolean', default: true }, includeRenotedMyNotes: { type: 'boolean', default: true }, includeLocalRenotes: { type: 'boolean', default: true }, - withFiles: { - type: 'boolean', - default: false, - description: 'Only show notes that have attached files.', - }, + withFiles: { type: 'boolean', default: false }, + withReplies: { type: 'boolean', default: false }, }, required: [], } as const; @@ -98,7 +95,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { .setParameters(followingQuery.getParameters()); this.queryService.generateChannelQuery(query, me); - this.queryService.generateRepliesQuery(query, me); + this.queryService.generateRepliesQuery(query, ps.withReplies, me); this.queryService.generateVisibilityQuery(query, me); this.queryService.generateMutedUserQuery(query, me); this.queryService.generateMutedNoteQuery(query, me); diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index afdafc7c55..2ee549232c 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -36,11 +36,8 @@ export const meta = { export const paramDef = { type: 'object', properties: { - withFiles: { - type: 'boolean', - default: false, - description: 'Only show notes that have attached files.', - }, + withFiles: { type: 'boolean', default: false }, + withReplies: { type: 'boolean', default: false }, fileType: { type: 'array', items: { type: 'string', } }, @@ -86,7 +83,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateChannelQuery(query, me); - this.queryService.generateRepliesQuery(query, me); + this.queryService.generateRepliesQuery(query, ps.withReplies, me); this.queryService.generateVisibilityQuery(query, me); if (me) this.queryService.generateMutedUserQuery(query, me); if (me) this.queryService.generateMutedNoteQuery(query, me); diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index c6ee1e5c2b..e1f286439b 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -35,11 +35,8 @@ export const paramDef = { includeMyRenotes: { type: 'boolean', default: true }, includeRenotedMyNotes: { type: 'boolean', default: true }, includeLocalRenotes: { type: 'boolean', default: true }, - withFiles: { - type: 'boolean', - default: false, - description: 'Only show notes that have attached files.', - }, + withFiles: { type: 'boolean', default: false }, + withReplies: { type: 'boolean', default: false }, }, required: [], } as const; @@ -84,7 +81,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { } this.queryService.generateChannelQuery(query, me); - this.queryService.generateRepliesQuery(query, me); + this.queryService.generateRepliesQuery(query, ps.withReplies, me); this.queryService.generateVisibilityQuery(query, me); this.queryService.generateMutedUserQuery(query, me); this.queryService.generateMutedNoteQuery(query, me); diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 5454836fe1..d3339072c1 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -13,6 +13,7 @@ class GlobalTimelineChannel extends Channel { public readonly chName = 'globalTimeline'; public static shouldShare = true; public static requireCredential = false; + private withReplies: boolean; constructor( private metaService: MetaService, @@ -31,6 +32,8 @@ class GlobalTimelineChannel extends Channel { const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null); if (!policies.gtlAvailable) return; + this.withReplies = params.withReplies as boolean; + // Subscribe events this.subscriber.on('notesStream', this.onNote); } @@ -54,7 +57,7 @@ class GlobalTimelineChannel extends Channel { } // 関係ない返信は除外 - if (note.reply && !this.user!.showTimelineReplies) { + if (note.reply && !this.withReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index ee874ad81e..1755aa94cf 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -11,6 +11,7 @@ class HomeTimelineChannel extends Channel { public readonly chName = 'homeTimeline'; public static shouldShare = true; public static requireCredential = true; + private withReplies: boolean; constructor( private noteEntityService: NoteEntityService, @@ -24,6 +25,8 @@ class HomeTimelineChannel extends Channel { @bindThis public async init(params: any) { + this.withReplies = params.withReplies as boolean; + this.subscriber.on('notesStream', this.onNote); } @@ -63,7 +66,7 @@ class HomeTimelineChannel extends Channel { } // 関係ない返信は除外 - if (note.reply && !this.user!.showTimelineReplies) { + if (note.reply && !this.withReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index 4f7b4e78b6..5a33e13cf5 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -13,6 +13,7 @@ class HybridTimelineChannel extends Channel { public readonly chName = 'hybridTimeline'; public static shouldShare = true; public static requireCredential = true; + private withReplies: boolean; constructor( private metaService: MetaService, @@ -31,6 +32,8 @@ class HybridTimelineChannel extends Channel { const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null); if (!policies.ltlAvailable) return; + this.withReplies = params.withReplies as boolean; + // Subscribe events this.subscriber.on('notesStream', this.onNote); } @@ -75,7 +78,7 @@ class HybridTimelineChannel extends Channel { if (isInstanceMuted(note, new Set<string>(this.userProfile!.mutedInstances ?? []))) return; // 関係ない返信は除外 - if (note.reply && !this.user!.showTimelineReplies) { + if (note.reply && !this.withReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 09b0005ac1..9ca4db8ced 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -12,6 +12,7 @@ class LocalTimelineChannel extends Channel { public readonly chName = 'localTimeline'; public static shouldShare = true; public static requireCredential = false; + private withReplies: boolean; constructor( private metaService: MetaService, @@ -30,6 +31,8 @@ class LocalTimelineChannel extends Channel { const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null); if (!policies.ltlAvailable) return; + this.withReplies = params.withReplies as boolean; + // Subscribe events this.subscriber.on('notesStream', this.onNote); } @@ -54,7 +57,7 @@ class LocalTimelineChannel extends Channel { } // 関係ない返信は除外 - if (note.reply && this.user && !this.user.showTimelineReplies) { + if (note.reply && this.user && !this.withReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 if (reply.userId !== this.user.id && note.userId !== this.user.id && reply.userId !== note.userId) return; diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index a7f8210c8e..02684c93b8 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -43,7 +43,6 @@ describe('ユーザー', () => { type MeDetailed = UserDetailedNotMe & misskey.entities.MeDetailed & { - showTimelineReplies: boolean, achievements: object[], loggedInDays: number, policies: object, @@ -160,7 +159,6 @@ describe('ユーザー', () => { mutedInstances: user.mutedInstances, mutingNotificationTypes: user.mutingNotificationTypes, emailNotificationTypes: user.emailNotificationTypes, - showTimelineReplies: user.showTimelineReplies, achievements: user.achievements, loggedInDays: user.loggedInDays, policies: user.policies, @@ -406,7 +404,6 @@ describe('ユーザー', () => { assert.deepStrictEqual(response.mutedInstances, []); assert.deepStrictEqual(response.mutingNotificationTypes, []); assert.deepStrictEqual(response.emailNotificationTypes, ['follow', 'receiveFollowRequest']); - assert.strictEqual(response.showTimelineReplies, false); assert.deepStrictEqual(response.achievements, []); assert.deepStrictEqual(response.loggedInDays, 0); assert.deepStrictEqual(response.policies, DEFAULT_POLICIES); @@ -470,8 +467,6 @@ describe('ユーザー', () => { { parameters: (): object => ({ isBot: false }) }, { parameters: (): object => ({ isCat: true }) }, { parameters: (): object => ({ isCat: false }) }, - { parameters: (): object => ({ showTimelineReplies: true }) }, - { parameters: (): object => ({ showTimelineReplies: false }) }, { parameters: (): object => ({ injectFeaturedNote: true }) }, { parameters: (): object => ({ injectFeaturedNote: false }) }, { parameters: (): object => ({ receiveAnnouncementEmail: true }) }, diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index 00a0cb760d..25d813e39f 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -70,7 +70,12 @@ if (props.src === 'antenna') { connection.on('note', prepend); } else if (props.src === 'home') { endpoint = 'notes/timeline'; - connection = stream.useChannel('homeTimeline'); + query = { + withReplies: defaultStore.state.showTimelineReplies, + }; + connection = stream.useChannel('homeTimeline', { + withReplies: defaultStore.state.showTimelineReplies, + }); connection.on('note', prepend); connection2 = stream.useChannel('main'); @@ -78,15 +83,30 @@ if (props.src === 'antenna') { connection2.on('unfollow', onChangeFollowing); } else if (props.src === 'local') { endpoint = 'notes/local-timeline'; - connection = stream.useChannel('localTimeline'); + query = { + withReplies: defaultStore.state.showTimelineReplies, + }; + connection = stream.useChannel('localTimeline', { + withReplies: defaultStore.state.showTimelineReplies, + }); connection.on('note', prepend); } else if (props.src === 'social') { endpoint = 'notes/hybrid-timeline'; - connection = stream.useChannel('hybridTimeline'); + query = { + withReplies: defaultStore.state.showTimelineReplies, + }; + connection = stream.useChannel('hybridTimeline', { + withReplies: defaultStore.state.showTimelineReplies, + }); connection.on('note', prepend); } else if (props.src === 'global') { endpoint = 'notes/global-timeline'; - connection = stream.useChannel('globalTimeline'); + query = { + withReplies: defaultStore.state.showTimelineReplies, + }; + connection = stream.useChannel('globalTimeline', { + withReplies: defaultStore.state.showTimelineReplies, + }); connection.on('note', prepend); } else if (props.src === 'mentions') { endpoint = 'notes/mentions'; diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index ec2bc3623c..0dfc847049 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -148,6 +148,7 @@ <template #label>{{ i18n.ts.other }}</template> <div class="_gaps"> + <MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> <FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink> <FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink> </div> @@ -216,6 +217,7 @@ const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars')); const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter('mediaListWithOneImageAppearance')); const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); +const showTimelineReplies = computed(defaultStore.makeGetterSetter('showTimelineReplies')); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index dd552ed92b..35af43d789 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -91,8 +91,6 @@ <option value="likeOnly">{{ i18n.ts.likeOnly }}</option> <option value="likeOnlyForRemote">{{ i18n.ts.likeOnlyForRemote }}</option> </MkSelect> - - <MkSwitch v-model="profile.showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> </div> </template> diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 61085e5dcf..0af4b5c021 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -102,6 +102,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'account', default: [] as string[], }, + showTimelineReplies: { + where: 'account', + default: false, + }, menu: { where: 'deviceAccount', From 0d8e1c5421c6c495b72bf52621bb0ebf0a4ead86 Mon Sep 17 00:00:00 2001 From: nenohi <kimutipartylove@gmail.com> Date: Tue, 16 May 2023 12:28:59 +0900 Subject: [PATCH 024/213] =?UTF-8?q?channel=20favorite=E3=81=AE=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=E4=BF=AE=E6=AD=A3=20(#10855)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/pages/channel.vue | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 9aa564a7da..2c0483aa06 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -5,6 +5,8 @@ <div v-if="channel && tab === 'overview'" class="_gaps"> <div class="_panel" :class="$style.bannerContainer"> <XChannelFollowButton :channel="channel" :full="true" :class="$style.subscribe"/> + <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" as-like class="button" rounded primary :class="$style.favorite" @click="unfavorite()"><i class="ti ti-star"></i></MkButton> + <MkButton v-else v-tooltip="i18n.ts.favorite" as-like class="button" rounded :class="$style.favorite" @click="favorite()"><i class="ti ti-star"></i></MkButton> <div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" :class="$style.banner"> <div :class="$style.bannerStatus"> <div><i class="ti ti-users ti-fw"></i><I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> @@ -17,9 +19,6 @@ </div> </div> - <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" as-like class="button" rounded primary @click="unfavorite()"><i class="ti ti-star"></i></MkButton> - <MkButton v-else v-tooltip="i18n.ts.favorite" as-like class="button" rounded @click="favorite()"><i class="ti ti-star"></i></MkButton> - <MkFoldableSection> <template #header><i class="ti ti-pin ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.pinnedNotes }}</template> <div v-if="channel.pinnedNotes.length > 0" class="_gaps"> @@ -229,6 +228,13 @@ definePageMetadata(computed(() => channel ? { left: 16px; } +.favorite { + position: absolute; + z-index: 1; + top: 16px; + right: 16px; +} + .banner { position: relative; height: 200px; From 153eed7d71e5071e63a2bc0eda1889f66b75ef9b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 16 May 2023 18:41:34 +0900 Subject: [PATCH 025/213] =?UTF-8?q?fix(frontend/test):=20MkAnimBg=E3=81=A7?= =?UTF-8?q?=E6=AF=8E=E5=9B=9EChromatic=E3=81=AE=E5=B7=AE=E5=88=86=E3=81=8C?= =?UTF-8?q?=E7=94=9F=E6=88=90=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkAnimBg.vue | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index a4cc04dde5..5a5c427cf1 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -4,7 +4,7 @@ <script lang="ts" setup> import { onMounted, onUnmounted, shallowRef } from 'vue'; -import { defaultStore } from '@/store'; +import isChromatic from 'chromatic/isChromatic'; const canvasEl = shallowRef<HTMLCanvasElement>(); @@ -204,14 +204,19 @@ onMounted(() => { const vertices = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW); - function render(timeStamp) { - gl!.uniform1f(u_time, timeStamp); + if (isChromatic()) { + gl!.uniform1f(u_time, 0); gl!.drawArrays(gl!.TRIANGLE_STRIP, 0, 4); + } else { + function render(timeStamp) { + gl!.uniform1f(u_time, timeStamp); + gl!.drawArrays(gl!.TRIANGLE_STRIP, 0, 4); + + handle = window.requestAnimationFrame(render); + } handle = window.requestAnimationFrame(render); } - - handle = window.requestAnimationFrame(render); }); onUnmounted(() => { From a35f0d43e40d7178616b91bd62a9948ed3984ae1 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 16 May 2023 19:24:10 +0900 Subject: [PATCH 026/213] refactor: define _IS_CHROMATIC_ --- packages/frontend/.eslintrc.js | 1 + packages/frontend/.storybook/main.ts | 3 +++ packages/frontend/@types/global.d.ts | 1 + packages/frontend/src/components/MkAnimBg.vue | 3 +-- packages/frontend/vite.config.ts | 1 + 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/frontend/.eslintrc.js b/packages/frontend/.eslintrc.js index e8e0e57d2a..0b7750c9f6 100644 --- a/packages/frontend/.eslintrc.js +++ b/packages/frontend/.eslintrc.js @@ -82,6 +82,7 @@ module.exports = { '_LANGS_': false, '_VERSION_': false, '_ENV_': false, + '_IS_CHROMATIC_': false, '_PERF_PREFIX_': false, '_DATA_TRANSFER_DRIVE_FILE_': false, '_DATA_TRANSFER_DRIVE_FOLDER_': false, diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts index 1d0ce5ab63..80628d9bc6 100644 --- a/packages/frontend/.storybook/main.ts +++ b/packages/frontend/.storybook/main.ts @@ -32,6 +32,9 @@ const config = { rootDir: config.root ?? process.cwd(), }), ], + define: { + _IS_CHROMATIC_: true, + }, build: { target: [ 'chrome108', diff --git a/packages/frontend/@types/global.d.ts b/packages/frontend/@types/global.d.ts index c757482900..e91d341be7 100644 --- a/packages/frontend/@types/global.d.ts +++ b/packages/frontend/@types/global.d.ts @@ -4,6 +4,7 @@ declare const _LANGS_: string[][]; declare const _VERSION_: string; declare const _ENV_: string; declare const _DEV_: boolean; +declare const _IS_CHROMATIC_: boolean; declare const _PERF_PREFIX_: string; declare const _DATA_TRANSFER_DRIVE_FILE_: string; declare const _DATA_TRANSFER_DRIVE_FOLDER_: string; diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index 5a5c427cf1..6b42c158cb 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -4,7 +4,6 @@ <script lang="ts" setup> import { onMounted, onUnmounted, shallowRef } from 'vue'; -import isChromatic from 'chromatic/isChromatic'; const canvasEl = shallowRef<HTMLCanvasElement>(); @@ -204,7 +203,7 @@ onMounted(() => { const vertices = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW); - if (isChromatic()) { + if (_IS_CHROMATIC_) { gl!.uniform1f(u_time, 0); gl!.drawArrays(gl!.TRIANGLE_STRIP, 0, 4); } else { diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 339761e78c..a2a9bb3f56 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -95,6 +95,7 @@ export function getConfig(): UserConfig { _LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])), _ENV_: JSON.stringify(process.env.NODE_ENV), _DEV_: process.env.NODE_ENV !== 'production', + _IS_CHROMATIC_: false, _PERF_PREFIX_: JSON.stringify('Misskey:'), _DATA_TRANSFER_DRIVE_FILE_: JSON.stringify('mk_drive_file'), _DATA_TRANSFER_DRIVE_FOLDER_: JSON.stringify('mk_drive_folder'), From ed3c1375438425b0cb27361ba7f7098fb25159f8 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 16 May 2023 19:37:15 +0900 Subject: [PATCH 027/213] Revert "refactor: define _IS_CHROMATIC_" This reverts commit a35f0d43e40d7178616b91bd62a9948ed3984ae1. --- packages/frontend/.eslintrc.js | 1 - packages/frontend/.storybook/main.ts | 3 --- packages/frontend/@types/global.d.ts | 1 - packages/frontend/src/components/MkAnimBg.vue | 3 ++- packages/frontend/vite.config.ts | 1 - 5 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/frontend/.eslintrc.js b/packages/frontend/.eslintrc.js index 0b7750c9f6..e8e0e57d2a 100644 --- a/packages/frontend/.eslintrc.js +++ b/packages/frontend/.eslintrc.js @@ -82,7 +82,6 @@ module.exports = { '_LANGS_': false, '_VERSION_': false, '_ENV_': false, - '_IS_CHROMATIC_': false, '_PERF_PREFIX_': false, '_DATA_TRANSFER_DRIVE_FILE_': false, '_DATA_TRANSFER_DRIVE_FOLDER_': false, diff --git a/packages/frontend/.storybook/main.ts b/packages/frontend/.storybook/main.ts index 80628d9bc6..1d0ce5ab63 100644 --- a/packages/frontend/.storybook/main.ts +++ b/packages/frontend/.storybook/main.ts @@ -32,9 +32,6 @@ const config = { rootDir: config.root ?? process.cwd(), }), ], - define: { - _IS_CHROMATIC_: true, - }, build: { target: [ 'chrome108', diff --git a/packages/frontend/@types/global.d.ts b/packages/frontend/@types/global.d.ts index e91d341be7..c757482900 100644 --- a/packages/frontend/@types/global.d.ts +++ b/packages/frontend/@types/global.d.ts @@ -4,7 +4,6 @@ declare const _LANGS_: string[][]; declare const _VERSION_: string; declare const _ENV_: string; declare const _DEV_: boolean; -declare const _IS_CHROMATIC_: boolean; declare const _PERF_PREFIX_: string; declare const _DATA_TRANSFER_DRIVE_FILE_: string; declare const _DATA_TRANSFER_DRIVE_FOLDER_: string; diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index 6b42c158cb..5a5c427cf1 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -4,6 +4,7 @@ <script lang="ts" setup> import { onMounted, onUnmounted, shallowRef } from 'vue'; +import isChromatic from 'chromatic/isChromatic'; const canvasEl = shallowRef<HTMLCanvasElement>(); @@ -203,7 +204,7 @@ onMounted(() => { const vertices = [1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.DYNAMIC_DRAW); - if (_IS_CHROMATIC_) { + if (isChromatic()) { gl!.uniform1f(u_time, 0); gl!.drawArrays(gl!.TRIANGLE_STRIP, 0, 4); } else { diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index a2a9bb3f56..339761e78c 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -95,7 +95,6 @@ export function getConfig(): UserConfig { _LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]) => [k, v._lang_])), _ENV_: JSON.stringify(process.env.NODE_ENV), _DEV_: process.env.NODE_ENV !== 'production', - _IS_CHROMATIC_: false, _PERF_PREFIX_: JSON.stringify('Misskey:'), _DATA_TRANSFER_DRIVE_FILE_: JSON.stringify('mk_drive_file'), _DATA_TRANSFER_DRIVE_FOLDER_: JSON.stringify('mk_drive_folder'), From 5d22e113b2617eb7807136405132d5ca2e60488e Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 17 May 2023 10:52:22 +0900 Subject: [PATCH 028/213] :art: --- packages/frontend/src/components/MkAnimBg.vue | 7 +- packages/frontend/src/pages/welcome.setup.vue | 66 ++++++++++++------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index 5a5c427cf1..010bfb6fee 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -50,8 +50,10 @@ let handle: ReturnType<typeof window['requestAnimationFrame']> | null = null; onMounted(() => { const canvas = canvasEl.value!; - const gl = canvas.getContext('webgl', { premultipliedAlpha: true }); + canvas.width = canvas.offsetWidth; + canvas.height = canvas.offsetHeight; + const gl = canvas.getContext('webgl', { premultipliedAlpha: true }); if (gl == null) return; gl.clearColor(0.0, 0.0, 0.0, 0.0); @@ -156,8 +158,7 @@ onMounted(() => { vec3 purple = vec3( 1.0 ) - vec3( 195.0 / 255.0, 165.0 / 255.0, 242.0 / 255.0 ); vec3 orange = vec3( 1.0 ) - vec3( 255.0 / 255.0, 156.0 / 255.0, 136.0 / 255.0 ); - //float ratio = u_resolution.x / u_resolution.y; - float ratio = 1.0; + float ratio = u_resolution.x / u_resolution.y; vec2 uv = vec2( v_pos.x, v_pos.y / ratio ) * 0.5 + 0.5; diff --git a/packages/frontend/src/pages/welcome.setup.vue b/packages/frontend/src/pages/welcome.setup.vue index 7728d97a65..5a68292b1b 100644 --- a/packages/frontend/src/pages/welcome.setup.vue +++ b/packages/frontend/src/pages/welcome.setup.vue @@ -1,27 +1,32 @@ <template> -<form :class="$style.root" class="_panel" @submit.prevent="submit()"> - <div :class="$style.title"> - <div>Welcome to Misskey!</div> - <div :class="$style.version">v{{ version }}</div> +<div :class="$style.root"> + <MkAnimBg style="position: fixed; top: 0;"/> + <div :class="$style.formContainer"> + <form :class="$style.form" class="_panel" @submit.prevent="submit()"> + <div :class="$style.title"> + <div>Welcome to Misskey!</div> + <div :class="$style.version">v{{ version }}</div> + </div> + <div class="_gaps_m" style="padding: 32px;"> + <div>{{ i18n.ts.intro }}</div> + <MkInput v-model="username" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" required data-cy-admin-username> + <template #label>{{ i18n.ts.username }}</template> + <template #prefix>@</template> + <template #suffix>@{{ host }}</template> + </MkInput> + <MkInput v-model="password" type="password" data-cy-admin-password> + <template #label>{{ i18n.ts.password }}</template> + <template #prefix><i class="ti ti-lock"></i></template> + </MkInput> + <div> + <MkButton gradate large rounded type="submit" :disabled="submitting" data-cy-admin-ok style="margin: 0 auto;"> + {{ submitting ? i18n.ts.processing : i18n.ts.done }}<MkEllipsis v-if="submitting"/> + </MkButton> + </div> + </div> + </form> </div> - <div class="_gaps_m" style="padding: 32px;"> - <div>{{ i18n.ts.intro }}</div> - <MkInput v-model="username" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" required data-cy-admin-username> - <template #label>{{ i18n.ts.username }}</template> - <template #prefix>@</template> - <template #suffix>@{{ host }}</template> - </MkInput> - <MkInput v-model="password" type="password" data-cy-admin-password> - <template #label>{{ i18n.ts.password }}</template> - <template #prefix><i class="ti ti-lock"></i></template> - </MkInput> - <div> - <MkButton gradate large rounded type="submit" :disabled="submitting" data-cy-admin-ok style="margin: 0 auto;"> - {{ submitting ? i18n.ts.processing : i18n.ts.done }}<MkEllipsis v-if="submitting"/> - </MkButton> - </div> - </div> -</form> +</div> </template> <script lang="ts" setup> @@ -32,6 +37,7 @@ import { host, version } from '@/config'; import * as os from '@/os'; import { login } from '@/account'; import { i18n } from '@/i18n'; +import MkAnimBg from '@/components/MkAnimBg.vue'; let username = $ref(''); let password = $ref(''); @@ -59,11 +65,23 @@ function submit() { <style lang="scss" module> .root { +} + +.formContainer { + min-height: 100svh; + padding: 32px 32px 64px 32px; + box-sizing: border-box; +display: grid; +place-content: center; +} + +.form { + position: relative; + z-index: 10; border-radius: var(--radius); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); - overflow: hidden; + overflow: clip; max-width: 500px; - margin: 32px auto; } .title { From ca2ed0a59bca26243d4f2f0d75546110cc439268 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 17 May 2023 11:08:46 +0900 Subject: [PATCH 029/213] :art: --- packages/frontend/src/components/MkAnimBg.vue | 16 ++++++++++++++-- .../src/components/MkUserSetupDialog.vue | 4 ++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index 010bfb6fee..575ea7c5e3 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -8,6 +8,14 @@ import isChromatic from 'chromatic/isChromatic'; const canvasEl = shallowRef<HTMLCanvasElement>(); +const props = withDefaults(defineProps<{ + scale?: number; + focus?: number; +}>(), { + scale: 1.0, + focus: 1.0, +}); + function loadShader(gl, type, source) { const shader = gl.createShader(type); @@ -65,11 +73,13 @@ onMounted(() => { const shaderProgram = initShaderProgram(gl, ` attribute vec2 vertex; + uniform vec2 u_scale; + varying vec2 v_pos; void main() { gl_Position = vec4(vertex, 0.0, 1.0); - v_pos = vertex; + v_pos = vertex / u_scale; } `, ` precision mediump float; @@ -191,12 +201,14 @@ onMounted(() => { const u_warp = gl.getUniformLocation(shaderProgram, 'u_warp'); const u_focus = gl.getUniformLocation(shaderProgram, 'u_focus'); const u_itensity = gl.getUniformLocation(shaderProgram, 'u_itensity'); + const u_scale = gl.getUniformLocation(shaderProgram, 'u_scale'); gl.uniform2fv(u_resolution, [canvas.width, canvas.height]); gl.uniform1f(u_spread, 1.0); gl.uniform1f(u_speed, 1.0); gl.uniform1f(u_warp, 1.0); - gl.uniform1f(u_focus, 1.0); + gl.uniform1f(u_focus, props.focus); gl.uniform1f(u_itensity, 0.5); + gl.uniform2fv(u_scale, [props.scale, props.scale]); const vertex = gl.getAttribLocation(shaderProgram, 'vertex'); gl.enableVertexAttribArray(vertex); diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 066556a05b..5c04faadca 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -27,7 +27,7 @@ > <template v-if="page === 0"> <div :class="$style.centerPage"> - <MkAnimBg style="position: absolute; top: 0;"/> + <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> <MkSpacer :margin-min="20" :margin-max="28"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-confetti" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i> @@ -83,7 +83,7 @@ </template> <template v-else-if="page === 5"> <div :class="$style.centerPage"> - <MkAnimBg style="position: absolute; top: 0;"/> + <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> <MkSpacer :margin-min="20" :margin-max="28"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i> From cbca48846c2bedf0e99ac8dec332500748b9798f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 17 May 2023 11:10:31 +0900 Subject: [PATCH 030/213] fix streamin error --- packages/backend/src/server/api/stream/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/stream/index.ts b/packages/backend/src/server/api/stream/index.ts index a6f9145952..fee56e3668 100644 --- a/packages/backend/src/server/api/stream/index.ts +++ b/packages/backend/src/server/api/stream/index.ts @@ -246,7 +246,7 @@ export default class Connection { const ch: Channel = channelService.create(id, this); this.channels.push(ch); - ch.init(params); + ch.init(params ?? {}); if (pong) { this.sendMessageToWs('connected', { From e126083e10c49e4d9b6466749a40e44ca3d1b321 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 17 May 2023 11:42:50 +0900 Subject: [PATCH 031/213] =?UTF-8?q?fix(frontend):=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=81=AEprop?= =?UTF-8?q?=E3=82=92=E9=9D=9ElowerCamelCase=E3=81=A7=E6=B8=A1=E3=81=99?= =?UTF-8?q?=E3=81=A8=E6=A9=9F=E8=83=BD=E3=81=97=E3=81=AA=E3=81=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/.eslintrc.js | 1 + .../src/components/global/MkMisskeyFlavoredMarkdown.vue | 2 +- packages/frontend/src/components/page/page.text.vue | 2 +- packages/frontend/src/pages/channel.vue | 2 +- packages/frontend/src/pages/clip.vue | 2 +- packages/frontend/src/pages/user/home.vue | 2 +- packages/frontend/src/widgets/WidgetOnlineUsers.vue | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/frontend/.eslintrc.js b/packages/frontend/.eslintrc.js index e8e0e57d2a..a1e1f57e10 100644 --- a/packages/frontend/.eslintrc.js +++ b/packages/frontend/.eslintrc.js @@ -64,6 +64,7 @@ module.exports = { 'vue/singleline-html-element-content-newline': 'off', // (vue/vue3-recommended disabled the autofix for Vue 2 compatibility) 'vue/v-on-event-hyphenation': ['warn', 'always', { autofix: true }], + 'vue/attribute-hyphenation': ['warn', 'never'], }, globals: { // Node.js diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue index 28a0d1c986..aadee75044 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue @@ -1,5 +1,5 @@ <template> -<MfmCore :text="text" :plain="plain" :nowrap="nowrap" :author="author" :is-note="isNote" :class="[$style.root, { [$style.nowrap]: nowrap }]"/> +<MfmCore :text="text" :plain="plain" :nowrap="nowrap" :author="author" :isNote="isNote" :class="[$style.root, { [$style.nowrap]: nowrap }]"/> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue index c324d55a70..308948b45c 100644 --- a/packages/frontend/src/components/page/page.text.vue +++ b/packages/frontend/src/components/page/page.text.vue @@ -1,6 +1,6 @@ <template> <div class="mrdgzndn"> - <Mfm :text="block.text" :is-note="false" :i="$i"/> + <Mfm :text="block.text" :isNote="false" :i="$i"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" class="url"/> </div> </template> diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 2c0483aa06..59ca6c83bd 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -15,7 +15,7 @@ <div :class="$style.bannerFade"></div> </div> <div v-if="channel.description" :class="$style.description"> - <Mfm :text="channel.description" :is-note="false" :i="$i"/> + <Mfm :text="channel.description" :isNote="false" :i="$i"/> </div> </div> diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue index e3ac3f4c9b..9207a9fa9b 100644 --- a/packages/frontend/src/pages/clip.vue +++ b/packages/frontend/src/pages/clip.vue @@ -5,7 +5,7 @@ <div v-if="clip"> <div class="okzinsic _panel"> <div v-if="clip.description" class="description"> - <Mfm :text="clip.description" :is-note="false" :i="$i"/> + <Mfm :text="clip.description" :isNote="false" :i="$i"/> </div> <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" as-like class="button" rounded primary @click="unfavorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> <MkButton v-else v-tooltip="i18n.ts.favorite" as-like class="button" rounded @click="favorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index 9c133346d5..a39f206863 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -69,7 +69,7 @@ </div> <div class="description"> <MkOmit> - <Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i"/> + <Mfm v-if="user.description" :text="user.description" :isNote="false" :author="user" :i="$i"/> <p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p> </MkOmit> </div> diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue index 44e073545d..19195d6fde 100644 --- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue +++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue @@ -1,6 +1,6 @@ <template> <div data-cy-mkw-onlineUsers class="mkw-onlineUsers" :class="{ _panel: !widgetProps.transparent, pad: !widgetProps.transparent }"> - <I18n v-if="onlineUsersCount" :src="i18n.ts.onlineUsersCount" text-tag="span" class="text"> + <I18n v-if="onlineUsersCount" :src="i18n.ts.onlineUsersCount" textTag="span" class="text"> <template #n><b>{{ number(onlineUsersCount) }}</b></template> </I18n> </div> From 7b012967d9e47d8fef9487c27fcf1247a8869913 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 17 May 2023 11:50:37 +0900 Subject: [PATCH 032/213] =?UTF-8?q?refactor(frontend):=20MFM=E3=82=B3?= =?UTF-8?q?=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=8D=E3=83=B3=E3=83=88=E3=81=AE?= =?UTF-8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF=20&=20=E3=83=91?= =?UTF-8?q?=E3=83=95=E3=82=A9=E3=83=BC=E3=83=9E=E3=83=B3=E3=82=B9=E3=82=92?= =?UTF-8?q?=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MkMisskeyFlavoredMarkdown.stories.impl.ts | 2 +- .../MkMisskeyFlavoredMarkdown.ts} | 5 +- .../global/MkMisskeyFlavoredMarkdown.vue | 171 ------------------ packages/frontend/src/components/index.ts | 2 +- packages/frontend/src/style.scss | 137 ++++++++++++++ 5 files changed, 143 insertions(+), 174 deletions(-) rename packages/frontend/src/components/{mfm.ts => global/MkMisskeyFlavoredMarkdown.ts} (97%) delete mode 100644 packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts index f6811b6747..685b3b8b8e 100644 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.stories.impl.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; -import MkMisskeyFlavoredMarkdown from './MkMisskeyFlavoredMarkdown.vue'; import { within } from '@storybook/testing-library'; import { expect } from '@storybook/jest'; +import MkMisskeyFlavoredMarkdown from './MkMisskeyFlavoredMarkdown.ts'; export const Default = { render(args) { return { diff --git a/packages/frontend/src/components/mfm.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts similarity index 97% rename from packages/frontend/src/components/mfm.ts rename to packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts index 042dad7809..2a50a34390 100644 --- a/packages/frontend/src/components/mfm.ts +++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts @@ -360,5 +360,8 @@ export default function(props: { } }).flat(Infinity) as (VNode | string)[]; - return h('span', genEl(ast, props.rootScale ?? 1)); + return h('span', { + // https://codeday.me/jp/qa/20190424/690106.html + style: props.nowrap ? 'white-space: pre; word-wrap: normal; overflow: hidden; text-overflow: ellipsis;' : 'white-space: pre-wrap;', + }, genEl(ast, props.rootScale ?? 1)); } diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue deleted file mode 100644 index aadee75044..0000000000 --- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.vue +++ /dev/null @@ -1,171 +0,0 @@ -<template> -<MfmCore :text="text" :plain="plain" :nowrap="nowrap" :author="author" :isNote="isNote" :class="[$style.root, { [$style.nowrap]: nowrap }]"/> -</template> - -<script lang="ts" setup> -import { } from 'vue'; -import MfmCore from '@/components/mfm'; - -const props = withDefaults(defineProps<{ - text: string; - plain?: boolean; - nowrap?: boolean; - author?: any; - isNote?: boolean; -}>(), { - plain: false, - nowrap: false, - author: null, - isNote: true, -}); -</script> - -<style lang="scss"> -._mfm_blur_ { - filter: blur(6px); - transition: filter 0.3s; - - &:hover { - filter: blur(0px); - } -} - -.mfm-x2 { - --mfm-zoom-size: 200%; -} - -.mfm-x3 { - --mfm-zoom-size: 400%; -} - -.mfm-x4 { - --mfm-zoom-size: 600%; -} - -.mfm-x2, .mfm-x3, .mfm-x4 { - font-size: var(--mfm-zoom-size); - - .mfm-x2, .mfm-x3, .mfm-x4 { - /* only half effective */ - font-size: calc(var(--mfm-zoom-size) / 2 + 50%); - - .mfm-x2, .mfm-x3, .mfm-x4 { - /* disabled */ - font-size: 100%; - } - } -} - -@keyframes mfm-spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -@keyframes mfm-spinX { - 0% { transform: perspective(128px) rotateX(0deg); } - 100% { transform: perspective(128px) rotateX(360deg); } -} - -@keyframes mfm-spinY { - 0% { transform: perspective(128px) rotateY(0deg); } - 100% { transform: perspective(128px) rotateY(360deg); } -} - -@keyframes mfm-jump { - 0% { transform: translateY(0); } - 25% { transform: translateY(-16px); } - 50% { transform: translateY(0); } - 75% { transform: translateY(-8px); } - 100% { transform: translateY(0); } -} - -@keyframes mfm-bounce { - 0% { transform: translateY(0) scale(1, 1); } - 25% { transform: translateY(-16px) scale(1, 1); } - 50% { transform: translateY(0) scale(1, 1); } - 75% { transform: translateY(0) scale(1.5, 0.75); } - 100% { transform: translateY(0) scale(1, 1); } -} - -// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`; -// let css = ''; -// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } -@keyframes mfm-twitch { - 0% { transform: translate(7px, -2px) } - 5% { transform: translate(-3px, 1px) } - 10% { transform: translate(-7px, -1px) } - 15% { transform: translate(0px, -1px) } - 20% { transform: translate(-8px, 6px) } - 25% { transform: translate(-4px, -3px) } - 30% { transform: translate(-4px, -6px) } - 35% { transform: translate(-8px, -8px) } - 40% { transform: translate(4px, 6px) } - 45% { transform: translate(-3px, 1px) } - 50% { transform: translate(2px, -10px) } - 55% { transform: translate(-7px, 0px) } - 60% { transform: translate(-2px, 4px) } - 65% { transform: translate(3px, -8px) } - 70% { transform: translate(6px, 7px) } - 75% { transform: translate(-7px, -2px) } - 80% { transform: translate(-7px, -8px) } - 85% { transform: translate(9px, 3px) } - 90% { transform: translate(-3px, -2px) } - 95% { transform: translate(-10px, 2px) } - 100% { transform: translate(-2px, -6px) } -} - -// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`; -// let css = ''; -// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } -@keyframes mfm-shake { - 0% { transform: translate(-3px, -1px) rotate(-8deg) } - 5% { transform: translate(0px, -1px) rotate(-10deg) } - 10% { transform: translate(1px, -3px) rotate(0deg) } - 15% { transform: translate(1px, 1px) rotate(11deg) } - 20% { transform: translate(-2px, 1px) rotate(1deg) } - 25% { transform: translate(-1px, -2px) rotate(-2deg) } - 30% { transform: translate(-1px, 2px) rotate(-3deg) } - 35% { transform: translate(2px, 1px) rotate(6deg) } - 40% { transform: translate(-2px, -3px) rotate(-9deg) } - 45% { transform: translate(0px, -1px) rotate(-12deg) } - 50% { transform: translate(1px, 2px) rotate(10deg) } - 55% { transform: translate(0px, -3px) rotate(8deg) } - 60% { transform: translate(1px, -1px) rotate(8deg) } - 65% { transform: translate(0px, -1px) rotate(-7deg) } - 70% { transform: translate(-1px, -3px) rotate(6deg) } - 75% { transform: translate(0px, -2px) rotate(4deg) } - 80% { transform: translate(-2px, -1px) rotate(3deg) } - 85% { transform: translate(1px, -3px) rotate(-10deg) } - 90% { transform: translate(1px, 0px) rotate(3deg) } - 95% { transform: translate(-2px, 0px) rotate(-3deg) } - 100% { transform: translate(2px, 1px) rotate(2deg) } -} - -@keyframes mfm-rubberBand { - from { transform: scale3d(1, 1, 1); } - 30% { transform: scale3d(1.25, 0.75, 1); } - 40% { transform: scale3d(0.75, 1.25, 1); } - 50% { transform: scale3d(1.15, 0.85, 1); } - 65% { transform: scale3d(0.95, 1.05, 1); } - 75% { transform: scale3d(1.05, 0.95, 1); } - to { transform: scale3d(1, 1, 1); } -} - -@keyframes mfm-rainbow { - 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); } - 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); } -} -</style> - -<style lang="scss" module> -.root { - white-space: pre-wrap; - - &.nowrap { - white-space: pre; - word-wrap: normal; // https://codeday.me/jp/qa/20190424/690106.html - overflow: hidden; - text-overflow: ellipsis; - } -} -</style> diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index 4ef8111da9..ee2a2bc7bd 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -1,6 +1,6 @@ import { App } from 'vue'; -import Mfm from './global/MkMisskeyFlavoredMarkdown.vue'; +import Mfm from './global/MkMisskeyFlavoredMarkdown.ts'; import MkA from './global/MkA.vue'; import MkAcct from './global/MkAcct.vue'; import MkAvatar from './global/MkAvatar.vue'; diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 20254d335e..689cb6ed82 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -483,3 +483,140 @@ hr { transform: scaleX(1.00) scaleY(1.00) ; } } + +// MFM ----------------------------- + +._mfm_blur_ { + filter: blur(6px); + transition: filter 0.3s; + + &:hover { + filter: blur(0px); + } +} + +.mfm-x2 { + --mfm-zoom-size: 200%; +} + +.mfm-x3 { + --mfm-zoom-size: 400%; +} + +.mfm-x4 { + --mfm-zoom-size: 600%; +} + +.mfm-x2, .mfm-x3, .mfm-x4 { + font-size: var(--mfm-zoom-size); + + .mfm-x2, .mfm-x3, .mfm-x4 { + /* only half effective */ + font-size: calc(var(--mfm-zoom-size) / 2 + 50%); + + .mfm-x2, .mfm-x3, .mfm-x4 { + /* disabled */ + font-size: 100%; + } + } +} + +@keyframes mfm-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +@keyframes mfm-spinX { + 0% { transform: perspective(128px) rotateX(0deg); } + 100% { transform: perspective(128px) rotateX(360deg); } +} + +@keyframes mfm-spinY { + 0% { transform: perspective(128px) rotateY(0deg); } + 100% { transform: perspective(128px) rotateY(360deg); } +} + +@keyframes mfm-jump { + 0% { transform: translateY(0); } + 25% { transform: translateY(-16px); } + 50% { transform: translateY(0); } + 75% { transform: translateY(-8px); } + 100% { transform: translateY(0); } +} + +@keyframes mfm-bounce { + 0% { transform: translateY(0) scale(1, 1); } + 25% { transform: translateY(-16px) scale(1, 1); } + 50% { transform: translateY(0) scale(1, 1); } + 75% { transform: translateY(0) scale(1.5, 0.75); } + 100% { transform: translateY(0) scale(1, 1); } +} + +// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`; +// let css = ''; +// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } +@keyframes mfm-twitch { + 0% { transform: translate(7px, -2px) } + 5% { transform: translate(-3px, 1px) } + 10% { transform: translate(-7px, -1px) } + 15% { transform: translate(0px, -1px) } + 20% { transform: translate(-8px, 6px) } + 25% { transform: translate(-4px, -3px) } + 30% { transform: translate(-4px, -6px) } + 35% { transform: translate(-8px, -8px) } + 40% { transform: translate(4px, 6px) } + 45% { transform: translate(-3px, 1px) } + 50% { transform: translate(2px, -10px) } + 55% { transform: translate(-7px, 0px) } + 60% { transform: translate(-2px, 4px) } + 65% { transform: translate(3px, -8px) } + 70% { transform: translate(6px, 7px) } + 75% { transform: translate(-7px, -2px) } + 80% { transform: translate(-7px, -8px) } + 85% { transform: translate(9px, 3px) } + 90% { transform: translate(-3px, -2px) } + 95% { transform: translate(-10px, 2px) } + 100% { transform: translate(-2px, -6px) } +} + +// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`; +// let css = ''; +// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } +@keyframes mfm-shake { + 0% { transform: translate(-3px, -1px) rotate(-8deg) } + 5% { transform: translate(0px, -1px) rotate(-10deg) } + 10% { transform: translate(1px, -3px) rotate(0deg) } + 15% { transform: translate(1px, 1px) rotate(11deg) } + 20% { transform: translate(-2px, 1px) rotate(1deg) } + 25% { transform: translate(-1px, -2px) rotate(-2deg) } + 30% { transform: translate(-1px, 2px) rotate(-3deg) } + 35% { transform: translate(2px, 1px) rotate(6deg) } + 40% { transform: translate(-2px, -3px) rotate(-9deg) } + 45% { transform: translate(0px, -1px) rotate(-12deg) } + 50% { transform: translate(1px, 2px) rotate(10deg) } + 55% { transform: translate(0px, -3px) rotate(8deg) } + 60% { transform: translate(1px, -1px) rotate(8deg) } + 65% { transform: translate(0px, -1px) rotate(-7deg) } + 70% { transform: translate(-1px, -3px) rotate(6deg) } + 75% { transform: translate(0px, -2px) rotate(4deg) } + 80% { transform: translate(-2px, -1px) rotate(3deg) } + 85% { transform: translate(1px, -3px) rotate(-10deg) } + 90% { transform: translate(1px, 0px) rotate(3deg) } + 95% { transform: translate(-2px, 0px) rotate(-3deg) } + 100% { transform: translate(2px, 1px) rotate(2deg) } +} + +@keyframes mfm-rubberBand { + from { transform: scale3d(1, 1, 1); } + 30% { transform: scale3d(1.25, 0.75, 1); } + 40% { transform: scale3d(0.75, 1.25, 1); } + 50% { transform: scale3d(1.15, 0.85, 1); } + 65% { transform: scale3d(0.95, 1.05, 1); } + 75% { transform: scale3d(1.05, 0.95, 1); } + to { transform: scale3d(1, 1, 1); } +} + +@keyframes mfm-rainbow { + 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); } + 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); } +} From e707aadbcc47f1fd7cefb6071a37169503066752 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 17 May 2023 14:11:32 +0900 Subject: [PATCH 033/213] update deps --- packages/frontend/package.json | 60 +- pnpm-lock.yaml | 1176 +++++++++++++++++--------------- 2 files changed, 647 insertions(+), 589 deletions(-) diff --git a/packages/frontend/package.json b/packages/frontend/package.json index e03dc51824..7e6c1442b1 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -21,10 +21,10 @@ "@rollup/pluginutils": "5.0.2", "@syuilo/aiscript": "0.13.3", "@tabler/icons-webfont": "2.17.0", - "@vitejs/plugin-vue": "4.2.2", - "@vue-macros/reactivity-transform": "0.3.6", - "@vue/compiler-sfc": "3.3.1", - "autosize": "5.0.2", + "@vitejs/plugin-vue": "4.2.3", + "@vue-macros/reactivity-transform": "0.3.7", + "@vue/compiler-sfc": "3.3.2", + "autosize": "6.0.1", "blurhash": "2.0.5", "broadcast-channel": "4.20.2", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", @@ -53,7 +53,7 @@ "punycode": "2.3.0", "querystring": "0.2.1", "rndstr": "1.0.0", - "rollup": "3.21.6", + "rollup": "3.22.0", "s-age": "1.1.2", "sanitize-html": "2.10.0", "sass": "1.62.1", @@ -70,31 +70,31 @@ "typescript": "5.0.4", "uuid": "9.0.0", "vanilla-tilt": "1.8.0", - "vite": "4.3.5", - "vue": "3.3.1", + "vite": "4.3.7", + "vue": "3.3.2", "vue-plyr": "7.0.0", "vue-prism-editor": "2.0.0-alpha.2", "vuedraggable": "next" }, "devDependencies": { - "@storybook/addon-actions": "7.0.10", - "@storybook/addon-essentials": "7.0.10", - "@storybook/addon-interactions": "7.0.10", - "@storybook/addon-links": "7.0.10", - "@storybook/addon-storysource": "7.0.10", - "@storybook/addons": "7.0.10", - "@storybook/blocks": "7.0.10", - "@storybook/core-events": "7.0.10", + "@storybook/addon-actions": "7.0.12", + "@storybook/addon-essentials": "7.0.12", + "@storybook/addon-interactions": "7.0.12", + "@storybook/addon-links": "7.0.12", + "@storybook/addon-storysource": "7.0.12", + "@storybook/addons": "7.0.12", + "@storybook/blocks": "7.0.12", + "@storybook/core-events": "7.0.12", "@storybook/jest": "0.1.0", - "@storybook/manager-api": "7.0.10", - "@storybook/preview-api": "7.0.10", - "@storybook/react": "7.0.10", - "@storybook/react-vite": "7.0.10", + "@storybook/manager-api": "7.0.12", + "@storybook/preview-api": "7.0.12", + "@storybook/react": "7.0.12", + "@storybook/react-vite": "7.0.12", "@storybook/testing-library": "0.1.0", - "@storybook/theming": "7.0.10", - "@storybook/types": "7.0.10", - "@storybook/vue3": "7.0.10", - "@storybook/vue3-vite": "7.0.10", + "@storybook/theming": "7.0.12", + "@storybook/types": "7.0.12", + "@storybook/vue3": "7.0.12", + "@storybook/vue3-vite": "7.0.12", "@testing-library/jest-dom": "5.16.5", "@testing-library/vue": "7.0.0", "@types/escape-regexp": "0.0.1", @@ -103,7 +103,7 @@ "@types/gulp-rename": "2.0.2", "@types/matter-js": "0.18.3", "@types/micromatch": "4.0.2", - "@types/node": "20.1.3", + "@types/node": "20.1.7", "@types/punycode": "2.1.0", "@types/sanitize-html": "2.9.0", "@types/seedrandom": "3.0.5", @@ -116,16 +116,16 @@ "@typescript-eslint/eslint-plugin": "5.59.5", "@typescript-eslint/parser": "5.59.5", "@vitest/coverage-c8": "0.31.0", - "@vue/runtime-core": "3.3.1", + "@vue/runtime-core": "3.3.2", "astring": "1.8.4", "chokidar-cli": "3.0.0", "cross-env": "7.0.3", "cypress": "12.12.0", "eslint": "8.40.0", "eslint-plugin-import": "2.27.5", - "eslint-plugin-vue": "9.12.0", + "eslint-plugin-vue": "9.13.0", "fast-glob": "3.2.12", - "happy-dom": "9.16.0", + "happy-dom": "9.18.3", "micromatch": "3.1.10", "msw": "1.2.1", "msw-storybook-addon": "1.8.0", @@ -133,13 +133,13 @@ "react": "18.2.0", "react-dom": "18.2.0", "start-server-and-test": "2.0.0", - "storybook": "7.0.10", + "storybook": "7.0.12", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "summaly": "github:misskey-dev/summaly", "vite-plugin-turbosnap": "1.0.2", "vitest": "0.31.0", "vitest-fetch-mock": "0.2.2", - "vue-eslint-parser": "9.2.1", - "vue-tsc": "1.6.4" + "vue-eslint-parser": "9.3.0", + "vue-tsc": "1.6.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 04675a7da7..f98ed0f654 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -629,16 +629,16 @@ importers: version: 14.1.2 '@rollup/plugin-alias': specifier: 5.0.0 - version: 5.0.0(rollup@3.21.6) + version: 5.0.0(rollup@3.22.0) '@rollup/plugin-json': specifier: 6.0.0 - version: 6.0.0(rollup@3.21.6) + version: 6.0.0(rollup@3.22.0) '@rollup/plugin-replace': specifier: 5.0.2 - version: 5.0.2(rollup@3.21.6) + version: 5.0.2(rollup@3.22.0) '@rollup/pluginutils': specifier: 5.0.2 - version: 5.0.2(rollup@3.21.6) + version: 5.0.2(rollup@3.22.0) '@syuilo/aiscript': specifier: 0.13.3 version: 0.13.3 @@ -646,17 +646,17 @@ importers: specifier: 2.17.0 version: 2.17.0 '@vitejs/plugin-vue': - specifier: 4.2.2 - version: 4.2.2(vite@4.3.5)(vue@3.3.1) + specifier: 4.2.3 + version: 4.2.3(vite@4.3.7)(vue@3.3.2) '@vue-macros/reactivity-transform': - specifier: 0.3.6 - version: 0.3.6(rollup@3.21.6)(vue@3.3.1) + specifier: 0.3.7 + version: 0.3.7(rollup@3.22.0)(vue@3.3.2) '@vue/compiler-sfc': - specifier: 3.3.1 - version: 3.3.1 + specifier: 3.3.2 + version: 3.3.2 autosize: - specifier: 5.0.2 - version: 5.0.2 + specifier: 6.0.1 + version: 6.0.1 blurhash: specifier: 2.0.5 version: 2.0.5 @@ -742,8 +742,8 @@ importers: specifier: 1.0.0 version: 1.0.0 rollup: - specifier: 3.21.6 - version: 3.21.6 + specifier: 3.22.0 + version: 3.22.0 s-age: specifier: 1.1.2 version: 1.1.2 @@ -793,81 +793,81 @@ importers: specifier: 1.8.0 version: 1.8.0 vite: - specifier: 4.3.5 - version: 4.3.5(@types/node@20.1.3)(sass@1.62.1) + specifier: 4.3.7 + version: 4.3.7(@types/node@20.1.7)(sass@1.62.1) vue: - specifier: 3.3.1 - version: 3.3.1 + specifier: 3.3.2 + version: 3.3.2 vue-plyr: specifier: 7.0.0 version: 7.0.0 vue-prism-editor: specifier: 2.0.0-alpha.2 - version: 2.0.0-alpha.2(vue@3.3.1) + version: 2.0.0-alpha.2(vue@3.3.2) vuedraggable: specifier: next - version: 4.1.0(vue@3.3.1) + version: 4.1.0(vue@3.3.2) devDependencies: '@storybook/addon-actions': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-essentials': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-interactions': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-links': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-storysource': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/addons': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/blocks': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/core-events': - specifier: 7.0.10 - version: 7.0.10 + specifier: 7.0.12 + version: 7.0.12 '@storybook/jest': specifier: 0.1.0 version: 0.1.0 '@storybook/manager-api': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/preview-api': - specifier: 7.0.10 - version: 7.0.10 + specifier: 7.0.12 + version: 7.0.12 '@storybook/react': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) '@storybook/react-vite': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.5) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7) '@storybook/testing-library': specifier: 0.1.0 version: 0.1.0 '@storybook/theming': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0) '@storybook/types': - specifier: 7.0.10 - version: 7.0.10 + specifier: 7.0.12 + version: 7.0.12 '@storybook/vue3': - specifier: 7.0.10 - version: 7.0.10(vue@3.3.1) + specifier: 7.0.12 + version: 7.0.12(vue@3.3.2) '@storybook/vue3-vite': - specifier: 7.0.10 - version: 7.0.10(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.5)(vue@3.3.1) + specifier: 7.0.12 + version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7)(vue@3.3.2) '@testing-library/jest-dom': specifier: 5.16.5 version: 5.16.5 '@testing-library/vue': specifier: 7.0.0 - version: 7.0.0(@vue/compiler-sfc@3.3.1)(vue@3.3.1) + version: 7.0.0(@vue/compiler-sfc@3.3.2)(vue@3.3.2) '@types/escape-regexp': specifier: 0.0.1 version: 0.0.1 @@ -887,8 +887,8 @@ importers: specifier: 4.0.2 version: 4.0.2 '@types/node': - specifier: 20.1.3 - version: 20.1.3 + specifier: 20.1.7 + version: 20.1.7 '@types/punycode': specifier: 2.1.0 version: 2.1.0 @@ -926,8 +926,8 @@ importers: specifier: 0.31.0 version: 0.31.0(vitest@0.31.0) '@vue/runtime-core': - specifier: 3.3.1 - version: 3.3.1 + specifier: 3.3.2 + version: 3.3.2 astring: specifier: 1.8.4 version: 1.8.4 @@ -947,14 +947,14 @@ importers: specifier: 2.27.5 version: 2.27.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0) eslint-plugin-vue: - specifier: 9.12.0 - version: 9.12.0(eslint@8.40.0) + specifier: 9.13.0 + version: 9.13.0(eslint@8.40.0) fast-glob: specifier: 3.2.12 version: 3.2.12 happy-dom: - specifier: 9.16.0 - version: 9.16.0 + specifier: 9.18.3 + version: 9.18.3 micromatch: specifier: 3.1.10 version: 3.1.10 @@ -977,11 +977,11 @@ importers: specifier: 2.0.0 version: 2.0.0 storybook: - specifier: 7.0.10 - version: 7.0.10 + specifier: 7.0.12 + version: 7.0.12 storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.10)(@storybook/components@7.0.10)(@storybook/core-events@7.0.10)(@storybook/manager-api@7.0.10)(@storybook/preview-api@7.0.10)(@storybook/theming@7.0.10)(@storybook/types@7.0.10)(react-dom@18.2.0)(react@18.2.0) + version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.12)(@storybook/components@7.0.12)(@storybook/core-events@7.0.12)(@storybook/manager-api@7.0.12)(@storybook/preview-api@7.0.12)(@storybook/theming@7.0.12)(@storybook/types@7.0.12)(react-dom@18.2.0)(react@18.2.0) summaly: specifier: github:misskey-dev/summaly version: github.com/misskey-dev/summaly/77dd5654bb82280b38c1f50e51a771c33f3df503 @@ -990,16 +990,16 @@ importers: version: 1.0.2 vitest: specifier: 0.31.0 - version: 0.31.0(happy-dom@9.16.0)(sass@1.62.1) + version: 0.31.0(happy-dom@9.18.3)(sass@1.62.1) vitest-fetch-mock: specifier: 0.2.2 version: 0.2.2(vitest@0.31.0) vue-eslint-parser: - specifier: 9.2.1 - version: 9.2.1(eslint@8.40.0) + specifier: 9.3.0 + version: 9.3.0(eslint@8.40.0) vue-tsc: - specifier: 1.6.4 - version: 1.6.4(typescript@5.0.4) + specifier: 1.6.5 + version: 1.6.5(typescript@5.0.4) packages/misskey-js: dependencies: @@ -2316,10 +2316,6 @@ packages: '@babel/types': 7.21.5 dev: true - /@babel/helper-string-parser@7.19.4: - resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} - engines: {node: '>=6.9.0'} - /@babel/helper-string-parser@7.21.5: resolution: {integrity: sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==} engines: {node: '>=6.9.0'} @@ -2365,19 +2361,12 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser@7.21.4: - resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.21.4 - /@babel/parser@7.21.8: resolution: {integrity: sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} @@ -3379,9 +3368,10 @@ packages: resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.19.4 + '@babel/helper-string-parser': 7.21.5 '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 + dev: true /@babel/types@7.21.5: resolution: {integrity: sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==} @@ -3987,7 +3977,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 chalk: 4.1.2 jest-message-util: 29.5.0 jest-util: 29.5.0 @@ -4008,14 +3998,14 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.5.0 - jest-config: 29.5.0(@types/node@20.1.3) + jest-config: 29.5.0(@types/node@20.1.7) jest-haste-map: 29.5.0 jest-message-util: 29.5.0 jest-regex-util: 29.4.3 @@ -4049,7 +4039,7 @@ packages: dependencies: '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 jest-mock: 29.5.0 dev: true @@ -4076,7 +4066,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@sinonjs/fake-timers': 10.0.2 - '@types/node': 20.1.3 + '@types/node': 20.1.7 jest-message-util: 29.5.0 jest-mock: 29.5.0 jest-util: 29.5.0 @@ -4109,7 +4099,7 @@ packages: '@jest/transform': 29.5.0 '@jest/types': 29.5.0 '@jridgewell/trace-mapping': 0.3.17 - '@types/node': 20.1.3 + '@types/node': 20.1.7 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -4203,7 +4193,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: true @@ -4215,12 +4205,12 @@ packages: '@jest/schemas': 29.4.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@types/yargs': 17.0.19 chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.0.4)(vite@4.3.5): + /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.0.4)(vite@4.3.7): resolution: {integrity: sha512-ou4ZJSXMMWHqGS4g8uNRbC5TiTWxAgQZiVucoUrOCWuPrTbkpJbmVyIi9jU72SBry7gQtuMEDp4YR8EEXAg7VQ==} peerDependencies: typescript: '>= 4.3.x' @@ -4234,7 +4224,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.0.4) typescript: 5.0.4 - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) dev: true /@jridgewell/gen-mapping@0.1.1: @@ -4653,7 +4643,7 @@ packages: '@redis/client': 1.4.2 dev: true - /@rollup/plugin-alias@5.0.0(rollup@3.21.6): + /@rollup/plugin-alias@5.0.0(rollup@3.22.0): resolution: {integrity: sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4662,11 +4652,11 @@ packages: rollup: optional: true dependencies: - rollup: 3.21.6 + rollup: 3.22.0 slash: 4.0.0 dev: false - /@rollup/plugin-json@6.0.0(rollup@3.21.6): + /@rollup/plugin-json@6.0.0(rollup@3.22.0): resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4675,11 +4665,11 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.21.6) - rollup: 3.21.6 + '@rollup/pluginutils': 5.0.2(rollup@3.22.0) + rollup: 3.22.0 dev: false - /@rollup/plugin-replace@5.0.2(rollup@3.21.6): + /@rollup/plugin-replace@5.0.2(rollup@3.22.0): resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4688,9 +4678,9 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.21.6) + '@rollup/pluginutils': 5.0.2(rollup@3.22.0) magic-string: 0.27.0 - rollup: 3.21.6 + rollup: 3.22.0 dev: false /@rollup/pluginutils@4.2.1: @@ -4701,7 +4691,7 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/pluginutils@5.0.2(rollup@3.21.6): + /@rollup/pluginutils@5.0.2(rollup@3.22.0): resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4713,7 +4703,7 @@ packages: '@types/estree': 1.0.1 estree-walker: 2.0.2 picomatch: 2.3.1 - rollup: 3.21.6 + rollup: 3.22.0 dev: false /@rushstack/node-core-library@3.58.0(@types/node@18.16.3): @@ -4864,8 +4854,8 @@ packages: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} dev: false - /@storybook/addon-actions@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-U8c7n918/mOjXnc1Iu/sglbK+ryC4xoyjWE5SG/68h0+sHb1rioNq7leAi24mCP6jNwNI5Q7TWtuvflOGxQDKQ==} + /@storybook/addon-actions@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-f07Mc3qwcG9heGsuUUTIJbWF2nw/Ite3mvyIZY2VbgwhMUMVHj4knY4fh/LojwcUmmmc7CNZu3sJN/wIqpaHCQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4875,14 +4865,14 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 dequal: 2.0.3 lodash: 4.17.21 polished: 4.2.2 @@ -4895,8 +4885,8 @@ packages: uuid: 9.0.0 dev: true - /@storybook/addon-backgrounds@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-QtOxXO9hKtwBjjdLXWYKp4HpcpNOrLfc71dn78XbMKyCkQRlYtVe8GNk/++70UQtFfKCEJIB0hTHrPmSjDJE5A==} + /@storybook/addon-backgrounds@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sAZSxsbj3CcabowALKTafpdnqXMBZB8C42s4Uxv11FCP50GqrP8jp2TqsIiDZxUbeXwI094W/gHnw41MSphG8Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4906,22 +4896,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-controls@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-j5UiPH8ZJx0ieUoIeV3iENlsIRDuQCeg3gTlLD668sebx8KHOCSJygh0Zvg1sTUUGSIbenhWaPlqfaW6ShKFWQ==} + /@storybook/addon-controls@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-/+yBhswN1N7ttR1NGN94HE/25VELm4YuBtrkh+LJeKP/eQ5CZpLjexASN2GZcfmdnkwIYZAEH0X/AImLaCJAWA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4931,15 +4921,15 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.10 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.0.10 - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/blocks': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.12 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.0.12 + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 lodash: 4.17.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4948,8 +4938,8 @@ packages: - supports-color dev: true - /@storybook/addon-docs@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-1tUsJ+fuBqk4oTOBLabyPQeQYiRKs9I6+soY7dG8jN15Bxe/Ey2giNpqUkA3xAIuqS75ydRVKmsfQvILu2nLjg==} + /@storybook/addon-docs@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-zgg4sq34Zz8TN74+kSogxRHsIZ5gsIazJpa0osZp91nJQvsKUEfldjBtQWbBWzjVCrWmzOhW5/RLCnmCNm9y/w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4958,19 +4948,19 @@ packages: '@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.21.3) '@jest/transform': 29.5.0 '@mdx-js/react': 2.3.0(react@18.2.0) - '@storybook/blocks': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/csf-plugin': 7.0.10 - '@storybook/csf-tools': 7.0.10 + '@storybook/blocks': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/csf-plugin': 7.0.12 + '@storybook/csf-tools': 7.0.12 '@storybook/global': 5.0.0 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.0.10 - '@storybook/postinstall': 7.0.10 - '@storybook/preview-api': 7.0.10 - '@storybook/react-dom-shim': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/node-logger': 7.0.12 + '@storybook/postinstall': 7.0.12 + '@storybook/preview-api': 7.0.12 + '@storybook/react-dom-shim': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 fs-extra: 11.1.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4981,25 +4971,25 @@ packages: - supports-color dev: true - /@storybook/addon-essentials@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-nOeUtNbfLXOlgGqqqlsYC9gcYSrAxABBo8jHYiZg3xaEB9+cnKjCKK8VxrqJiR002AG5JZvi+uHeAauM94fkkQ==} + /@storybook/addon-essentials@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Js2cxvauAf8fkA5D0QrqPPe/FvpY1DbJp61VNGh82Xu0zZrczCGYP3jkWG79vl0zllJNs7hnkV8W6xY1JWgLoA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/addon-actions': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-backgrounds': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-controls': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-docs': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-highlight': 7.0.10 - '@storybook/addon-measure': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-outline': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-toolbars': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-viewport': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.10 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.0.10 - '@storybook/preview-api': 7.0.10 + '@storybook/addon-actions': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-backgrounds': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-controls': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-docs': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-highlight': 7.0.12 + '@storybook/addon-measure': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-outline': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-toolbars': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-viewport': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.12 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.0.12 + '@storybook/preview-api': 7.0.12 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 @@ -5007,16 +4997,16 @@ packages: - supports-color dev: true - /@storybook/addon-highlight@7.0.10: - resolution: {integrity: sha512-TohDxElSu7JrSvhLRZAwtNk/7Ot626wvlODwklocE4kbtn1fulFoUlRta7NImBGX554LITDFRy0m4R1rRQ9OfQ==} + /@storybook/addon-highlight@7.0.12: + resolution: {integrity: sha512-ccIsBVjUlZ7cM1adSSFTqqWXiELPdDqfZLz4dWfDbiLyG3InC953ugtvoUWCIZpC2OOnjVLpF7Rbshq2O/QoMw==} dependencies: - '@storybook/core-events': 7.0.10 + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.10 + '@storybook/preview-api': 7.0.12 dev: true - /@storybook/addon-interactions@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-7hdFgoetQblwysYwRlmC5fbMVDb6lIM6le1pVEmRci6X44Gr2Xe5w2s6h5bTp4tMpNS1CFKjru9kF/TqfK46wA==} + /@storybook/addon-interactions@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Rb1mv1RQrTd3sA/WwNTdv00rW+7APfvZEeZks6+8+kS1C4EFMDmLnVBZlPllFdo1BOnTCyer4GZZ5ncVkWNLyQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5026,16 +5016,16 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.10 - '@storybook/core-events': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.12 + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 7.0.10 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/instrumenter': 7.0.12 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 jest-mock: 27.5.1 polished: 4.2.2 react: 18.2.0 @@ -5045,8 +5035,8 @@ packages: - supports-color dev: true - /@storybook/addon-links@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Odhe0eICqW9X2yyIjtOVb23cKXJ2WRxPHBm5oYf6hBBoXXK7EJicwyQSJLxJyHK7r1PeAnFxSGlNrO3w7JULjg==} + /@storybook/addon-links@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-6kGClsIpX9dRKc5bUAPNcp/4wlgPIxMrieUV+6k1dTsRQqbaEfxih/Fq259D5+yVBDNi3YAnvRjMiIibl8fa5A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5056,22 +5046,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/core-events': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/core-events': 7.0.12 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/router': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/router': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-measure@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-70BQT8PM6r3qjXDgXuN5mx9CBq9dYTdEgR1tlZ8FbMi8B8tB1oZJD0o6tfGM3r8WjdI0sTwX70ic5pv9Ma/MiA==} + /@storybook/addon-measure@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Uq9cj9QmN7WKBQ6wqeneFmTqo1UQKXIc4CpGBEtJtfsYNLsERrVzOs/tRUf66Zl3lWgfFZxs1B5Ij6RDsYEjRw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5081,19 +5071,19 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/types': 7.0.12 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addon-outline@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Aakoc+II7orfgUDmjgMbnSp5HZS/47z0NeRAfh+FP4fxL0lFd9vmaeIXWYo1DjJqdEFfvlSLd8aS9Ltb+souMw==} + /@storybook/addon-outline@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-eZPkm3mECdqx1EDJ0S6DAzZ9WZLPIsZH7fRy6vdJJuAgvnOSzkt7AEpA0hlgiNyXcFpE1Cav6/g12FUf4Zo82g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5103,20 +5093,20 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/types': 7.0.12 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-storysource@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-5anwqnBOcHDI/EB3F2q3Vs/JN+vCBRr8UVqnKS8NqN3BrpJ4q7jUeQ2cA0Q2/aAmdHJn9FLh/Cgx7aTO+6iC2w==} + /@storybook/addon-storysource@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-drWG7mY76eL8BwkD5KFMSxnErqF6iOZCk3bpUFGqT5uzx6oVkjmOimZHTEuHtHEi6TtK8QN5KTUi6vXzsGSGpA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5126,13 +5116,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/router': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/source-loader': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/router': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/source-loader': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) estraverse: 5.3.0 prop-types: 15.8.1 react: 18.2.0 @@ -5140,8 +5130,8 @@ packages: react-syntax-highlighter: 15.5.0(react@18.2.0) dev: true - /@storybook/addon-toolbars@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-U4a45CDw4SZzrgboYVMgxyiD7Ejud1kSz2lyS+J3fGTZGXq2+tmJS/2oNrLJlSH7v8629lVUbKnFxsP0HbfShg==} + /@storybook/addon-toolbars@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7xRxk+999NVdEwzn2z1O9Tg5iuUSEXQ5jo+hiyK934VvuyqUsZnflKbSvwVEHb2W+DroaaXu8bdHWxGSH+6moQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5151,17 +5141,17 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addon-viewport@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Ck9sdCg3T8ChXoxYL5IEi+ZUOwdH6Je5XeK4kRVq+Ar+Ytm5CFTGJCCZjI6biroTnuJCUefaV2K5NUZoHkZI+A==} + /@storybook/addon-viewport@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-pMgqtDQF8e9AErnRKbbSK9m1lcKn1dFSOkk0PgSBwIIjmha6q+GeT45EHQrQGtkLdtWT0iTktC8ivzIiGKmHkg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5171,49 +5161,49 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) memoizerific: 1.11.3 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addons@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-RRtozbB0JovZdLgTgC03kOjNh/5sAN77VHZFC5aK/Y9Hz2A0C6V4w/SqTt0382skSllcGMcrHjB1k06BlxlZ8A==} + /@storybook/addons@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-yVADbWCFdb12cSpspeb+/6lfTNarPtZZLql49Bhu6E7PxECw/Q3kfHu0LXBLcSnU7f4QqQvQjp88ultt01ABBQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/types': 7.0.12 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/blocks@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-OqXuN1x2TjXgrOqGSaD0Vz8iCqmLjiPkrQpWMD7bToFpHH0dpmcrzzRhLhxgJLN2CAzyr98IYIkUgXX9Da1neA==} + /@storybook/blocks@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-MbJKjuTJ7xVbkUVwkEwb6vTYGrkRk4+Xtx1UGo+512o91ubqFs8hXwCHP+x/49RCIIQs5zl93Ig8fTtm+MejWw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.0.10 - '@storybook/client-logger': 7.0.10 - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.10 + '@storybook/channels': 7.0.12 + '@storybook/client-logger': 7.0.12 + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.12 '@storybook/csf': 0.1.0 - '@storybook/docs-tools': 7.0.10 + '@storybook/docs-tools': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 '@types/lodash': 4.14.191 color-convert: 2.0.1 dequal: 2.0.3 @@ -5231,13 +5221,13 @@ packages: - supports-color dev: true - /@storybook/builder-manager@7.0.10: - resolution: {integrity: sha512-izCVE4JEbDVN5DPkX/Ym1PifAJKlheBvXKmGXGklnJQ2l+TEuvesPbOmVFNuu7ptJAFw4JO5n2KAo9+a5FRwiw==} + /@storybook/builder-manager@7.0.12: + resolution: {integrity: sha512-bkZPSDH38/dUSsO087oQ8+goyaEDP/xD0/O61QcQ8EbaVeT6s6Qt7mMhqsLrtmEZHvPMQwKeIXhOJlRNNXB+SA==} dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 7.0.10 - '@storybook/manager': 7.0.10 - '@storybook/node-logger': 7.0.10 + '@storybook/core-common': 7.0.12 + '@storybook/manager': 7.0.12 + '@storybook/node-logger': 7.0.12 '@types/ejs': 3.1.2 '@types/find-cache-dir': 3.2.1 '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.17.18) @@ -5254,8 +5244,8 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.0.10(typescript@5.0.4)(vite@4.3.5): - resolution: {integrity: sha512-tKY2QnHni10TE3+Sy2wfR7h4FuribR849VBpDI/LcwtRkCgoOBfMCdEnAKMWyU6qAlY+9KDSOQq9SDTu3WZGOg==} + /@storybook/builder-vite@7.0.12(typescript@5.0.4)(vite@4.3.7): + resolution: {integrity: sha512-6FJNXis+dYs/KrhfRQgz8HcRw/Oq4FaEghCwsjngQDy4PcpQuxkDbvGJKlBaSr92vUL36FWSPq8u5+VGCHjh5Q==} peerDependencies: '@preact/preset-vite': '*' typescript: '>= 4.3.x' @@ -5269,16 +5259,16 @@ packages: vite-plugin-glimmerx: optional: true dependencies: - '@storybook/channel-postmessage': 7.0.10 - '@storybook/channel-websocket': 7.0.10 - '@storybook/client-logger': 7.0.10 - '@storybook/core-common': 7.0.10 - '@storybook/csf-plugin': 7.0.10 + '@storybook/channel-postmessage': 7.0.12 + '@storybook/channel-websocket': 7.0.12 + '@storybook/client-logger': 7.0.12 + '@storybook/core-common': 7.0.12 + '@storybook/csf-plugin': 7.0.12 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.0.10 - '@storybook/preview': 7.0.10 - '@storybook/preview-api': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/node-logger': 7.0.12 + '@storybook/preview': 7.0.12 + '@storybook/preview-api': 7.0.12 + '@storybook/types': 7.0.12 browser-assert: 1.2.1 es-module-lexer: 0.9.3 express: 4.18.2 @@ -5288,19 +5278,19 @@ packages: magic-string: 0.27.0 remark-external-links: 8.0.0 remark-slug: 6.1.0 - rollup: 3.21.6 + rollup: 3.22.0 typescript: 5.0.4 - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true - /@storybook/channel-postmessage@7.0.10: - resolution: {integrity: sha512-Y5ZSp9WYH3HznQ2rrGN78Y5fYM16Bfvyn3iKy5QD38gsQk1gTrra1osIZ0X+lk3sep14D4oW4QMW3DCSrn0Big==} + /@storybook/channel-postmessage@7.0.12: + resolution: {integrity: sha512-Tc7kQZ5yxlZ44Nmmzec92JaDJ6UZ3Ze4cBfiHik4XcnM1PtN8hr8VFoC6a2AIm1ybfIRenfT5w9TH5yriiPIhw==} dependencies: - '@storybook/channels': 7.0.10 - '@storybook/client-logger': 7.0.10 - '@storybook/core-events': 7.0.10 + '@storybook/channels': 7.0.12 + '@storybook/client-logger': 7.0.12 + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 qs: 6.11.1 telejson: 7.0.4 @@ -5328,17 +5318,17 @@ packages: telejson: 7.0.4 dev: true - /@storybook/channel-websocket@7.0.10: - resolution: {integrity: sha512-WXueykS71YxEqKlsIbbmmA6QSChEePffzqs7QASUpHhi21IDqmtq2HhAqYWlQptyqSWYdv6wxrOqwe6z4zakLA==} + /@storybook/channel-websocket@7.0.12: + resolution: {integrity: sha512-UV6b9gX2mQLtXlKaFKCHcy+6MaK2od6BYqSJfainnBjDsMIXyhcf7fJaj0XQkJrbNnRBwGhw+6s8JxL98xp7Ew==} dependencies: - '@storybook/channels': 7.0.10 - '@storybook/client-logger': 7.0.10 + '@storybook/channels': 7.0.12 + '@storybook/client-logger': 7.0.12 '@storybook/global': 5.0.0 telejson: 7.0.4 dev: true - /@storybook/channels@7.0.10: - resolution: {integrity: sha512-hdPaGV3W7s6MkVcg33S5hmkVgqXC16AA7H0ID9MROiU1lQzolKhSqCs2iVfGPQfmWzEJeqWQoEXU7dmCclRM0w==} + /@storybook/channels@7.0.12: + resolution: {integrity: sha512-KDdDmDs8kxAJU+vndTqTNazjLO+XoIPiTRlfP7mk7cgHiQXSjMYy3JSCQ7W0of0Q+9VSl/ve9CNbnGbcQF7rNQ==} dev: true /@storybook/channels@7.0.2: @@ -5349,20 +5339,20 @@ packages: resolution: {integrity: sha512-+34cVmrXZ3lb1s5tDK+OWd5HLtEPSUMas0VKFJ0k9LBpFlVl9aiCZBJRvSYmWL7beauUfa+HSmJgjlD6228ChQ==} dev: true - /@storybook/cli@7.0.10: - resolution: {integrity: sha512-FhtE6Yrk7MMa9AgLb3MTmqiQ3IlWHjjrj7Vcj2QM6BcP342xSe7C1d+V6+tYX/oPOEB3Upz+PKNrju1iHxurQQ==} + /@storybook/cli@7.0.12: + resolution: {integrity: sha512-OABCRIujxsszIJ0CCpKg8Uj4C1UlAwBpBQhv2aMX3lA/pur6Od524syv2ypWu6J2FyvK/ooeyMbjoP7330cIuA==} hasBin: true dependencies: '@babel/core': 7.21.3 '@babel/preset-env': 7.21.4(@babel/core@7.21.3) '@ndelangen/get-tarball': 3.0.7 - '@storybook/codemod': 7.0.10 - '@storybook/core-common': 7.0.10 - '@storybook/core-server': 7.0.10 - '@storybook/csf-tools': 7.0.10 - '@storybook/node-logger': 7.0.10 - '@storybook/telemetry': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/codemod': 7.0.12 + '@storybook/core-common': 7.0.12 + '@storybook/core-server': 7.0.12 + '@storybook/csf-tools': 7.0.12 + '@storybook/node-logger': 7.0.12 + '@storybook/telemetry': 7.0.12 + '@storybook/types': 7.0.12 '@types/semver': 7.5.0 boxen: 5.1.2 chalk: 4.1.2 @@ -5398,8 +5388,8 @@ packages: - utf-8-validate dev: true - /@storybook/client-logger@7.0.10: - resolution: {integrity: sha512-hb8tO+w28ErzjEw69ERMtZT81Xyg835FQjH6Y42ejoGcBA9Z0W6RZmx4RgkcIUOlYXkU6lSnNVne9gXodV4/Hw==} + /@storybook/client-logger@7.0.12: + resolution: {integrity: sha512-MQMtIgGEgdixvxnBvZ2m8hhc0DGJWeCpHtxg7oqBLBEBmCYFueTqDZHl4Z6SoCrK0a2YS5X/BIXOcEtP1ulMKw==} dependencies: '@storybook/global': 5.0.0 dev: true @@ -5416,16 +5406,16 @@ packages: '@storybook/global': 5.0.0 dev: true - /@storybook/codemod@7.0.10: - resolution: {integrity: sha512-BnPknLV3wnaSk0azjFBAWLVfwgUHtFvVk9I6y1idIaQhc0nnegKoa0jTxWigthftZK/Pv9yG3gxG7o7O4KcChQ==} + /@storybook/codemod@7.0.12: + resolution: {integrity: sha512-eGbGZSglvbnY1omzRyEC4XP0FbpuCFKgjXmdHn9faGQUU5EJHwcGYYrRW8JZL3nEVIvNDuRAKzM3p0BVo1xeSQ==} dependencies: '@babel/core': 7.21.3 '@babel/preset-env': 7.21.4(@babel/core@7.21.3) '@babel/types': 7.21.5 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.0.10 - '@storybook/node-logger': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/csf-tools': 7.0.12 + '@storybook/node-logger': 7.0.12 + '@storybook/types': 7.0.12 cross-spawn: 7.0.3 globby: 11.1.0 jscodeshift: 0.14.0(@babel/preset-env@7.21.4) @@ -5436,17 +5426,17 @@ packages: - supports-color dev: true - /@storybook/components@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-jdGiVP+a3XqoGpKkDFGt4g2cgb23aLfMS/RhnuhT7FK6hGh7WFfuuqx4QqQHx4VZCdXIWVIzszaCdGCs7AsW2w==} + /@storybook/components@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-6TxByzYS4+LxwZRioGpP6Zh9If5ctjQs5OnR2UmQvP6HDjmMWYTntoHKIbDwAL9C6MrnQYpPOGCPkqrtODQ4/w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.0.10 + '@storybook/client-logger': 7.0.12 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5454,18 +5444,18 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/core-client@7.0.10: - resolution: {integrity: sha512-sN/TKB7QHWP6josdjyNtoqDXihROPtgvzo5+akfW6+S7hhfsQ4BJd09nkBqEX9E7z81blmFFDUOU3a8bQbPdKQ==} + /@storybook/core-client@7.0.12: + resolution: {integrity: sha512-m0r+Vl3LfU8cJl8UqIwzh0sEN9I//nMaT8UIIm481AINhQTNihQcnYi9jRw7USjfz2fv5CYkg8cEr4KhI8QlRA==} dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/preview-api': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/preview-api': 7.0.12 dev: true - /@storybook/core-common@7.0.10: - resolution: {integrity: sha512-AAYXixukGlpMy8XoSM8cTfcyQ6ijBq5q50xNTj/ssTbGnGSk6POgtoJZf6g8XtS0OxsFXBSxuBuMBBBbKtoztw==} + /@storybook/core-common@7.0.12: + resolution: {integrity: sha512-PFVjYXHUxDQO1oqfqwQe7S3XoLNO0aZYEr9Zl0LiexlxxnU1v+TQjEfNd/H3T0xxpXlsgzhtEcagdzJeAKyh2g==} dependencies: - '@storybook/node-logger': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/node-logger': 7.0.12 + '@storybook/types': 7.0.12 '@types/node': 16.18.16 '@types/pretty-hrtime': 1.0.1 chalk: 4.1.2 @@ -5487,8 +5477,8 @@ packages: - supports-color dev: true - /@storybook/core-events@7.0.10: - resolution: {integrity: sha512-OyBqhxVQOdI78Vgv6nKwXOdIVNChyfktpdxQZP1rz9MpO6MrqMaGAUL7k8xQMQAVx0VY+dAMYZB3bnyN2IC8FA==} + /@storybook/core-events@7.0.12: + resolution: {integrity: sha512-VTmb/zjbz3o1bg+bATzLigVXMVDC/S1FP8CqIrz4mkiys52139FGzMandL2Y2AecPZPGss7ZRdfma28HKVYTRg==} dev: true /@storybook/core-events@7.0.2: @@ -5499,23 +5489,23 @@ packages: resolution: {integrity: sha512-kGrtjlYtjd4iTVk+Phb4CymZaVkB+MGscKAgcO8gfgJ/Q/gq8HQLVZSIzeoCDcDSHOGlBzbg2WVtdHIHhCKlOQ==} dev: true - /@storybook/core-server@7.0.10: - resolution: {integrity: sha512-KFCc3turPed8tiC5IUKTV7oObVmFckMP1XqO7zec2g2NlGQsN83DRso+BA1wpV/bb8AD1NJDU6LJnyN3KKdi1Q==} + /@storybook/core-server@7.0.12: + resolution: {integrity: sha512-X35Kmg7y35Ph4J+gCDJrnVgBwlz4/DzOQofUS6rAbi4KvrPWDJXeM2OzOgx6B0abKl4CeMmjuc0tjbg4vbUFuA==} dependencies: '@aw-web-design/x-default-browser': 1.4.88 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 7.0.10 - '@storybook/core-common': 7.0.10 - '@storybook/core-events': 7.0.10 + '@storybook/builder-manager': 7.0.12 + '@storybook/core-common': 7.0.12 + '@storybook/core-events': 7.0.12 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.0.10 + '@storybook/csf-tools': 7.0.12 '@storybook/docs-mdx': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager': 7.0.10 - '@storybook/node-logger': 7.0.10 - '@storybook/preview-api': 7.0.10 - '@storybook/telemetry': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/manager': 7.0.12 + '@storybook/node-logger': 7.0.12 + '@storybook/preview-api': 7.0.12 + '@storybook/telemetry': 7.0.12 + '@storybook/types': 7.0.12 '@types/detect-port': 1.3.2 '@types/node': 16.18.16 '@types/node-fetch': 2.6.2 @@ -5551,24 +5541,24 @@ packages: - utf-8-validate dev: true - /@storybook/csf-plugin@7.0.10: - resolution: {integrity: sha512-uUty5rLs6O32tJaXIne2/42UxFL3eaRCDgtAoAkGxbUPa/FLYpO0rYtqF2OG9MagwXU7+As5RlLkDLeYAvUzlQ==} + /@storybook/csf-plugin@7.0.12: + resolution: {integrity: sha512-iiH0ynLQV5BYFc0o7RlSJS2S3GT/ffyfbV4rnCnPKdqyo4REEVvmhOuLhwzurtsXsjh+xF6VUYUDN+8/5mbkYw==} dependencies: - '@storybook/csf-tools': 7.0.10 + '@storybook/csf-tools': 7.0.12 unplugin: 0.10.2 transitivePeerDependencies: - supports-color dev: true - /@storybook/csf-tools@7.0.10: - resolution: {integrity: sha512-sl/995jq03HD7/Q9cb54h0glgt7JLGTkfikSlB35NGMEkgEXEswDmpQHA/TbzUYylIxuAwTKghwMqL3IwSSHwA==} + /@storybook/csf-tools@7.0.12: + resolution: {integrity: sha512-EcDzKeENzs4awyjx0VxlONDLibiEtIPDP1XdOCcZGtv3nXXBFtS2WDsYhJHkwyvE37jWTyw2e4xKQmBi0Hjvbw==} dependencies: '@babel/generator': 7.21.3 '@babel/parser': 7.21.8 '@babel/traverse': 7.21.3 '@babel/types': 7.21.5 '@storybook/csf': 0.1.0 - '@storybook/types': 7.0.10 + '@storybook/types': 7.0.12 fs-extra: 11.1.0 recast: 0.23.1 ts-dedent: 2.2.0 @@ -5586,13 +5576,13 @@ packages: resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} dev: true - /@storybook/docs-tools@7.0.10: - resolution: {integrity: sha512-w3m7+LlQGI50i07XjiOzIfoap8rnmsrs8hXGUTodbs9vvLt8HBdUaapOGnYr/1BzA0YQJ7Nz2z1nTirQEphmsQ==} + /@storybook/docs-tools@7.0.12: + resolution: {integrity: sha512-+HykeQLgjyDyF9G7HqY0FHXlX7X5YpQcmNjftJzBrc/GO1EeO0M78d54avcOPyyTfuWOh7oZtSJ0MzjA1qrqaQ==} dependencies: '@babel/core': 7.21.3 - '@storybook/core-common': 7.0.10 - '@storybook/preview-api': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/core-common': 7.0.12 + '@storybook/preview-api': 7.0.12 + '@storybook/types': 7.0.12 '@types/doctrine': 0.0.3 doctrine: 3.0.0 lodash: 4.17.21 @@ -5610,14 +5600,14 @@ packages: resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} dev: true - /@storybook/instrumenter@7.0.10: - resolution: {integrity: sha512-Z+kIidnxaq3tneUnIKB2d0DCqb4lwUdOS/AC43LNvd9C6BWYgj89cIPdLDTNhOWa0ZiEju7wTS+K/3uMvcHZ4w==} + /@storybook/instrumenter@7.0.12: + resolution: {integrity: sha512-jx4rb4AMT1YIOpE0HCdfyLvpYU+94wPkC9vt7sZGWAp7nnYG+KO/lx3XCJaR9qQPIxVYejJtWkeGn4RID79SoQ==} dependencies: - '@storybook/channels': 7.0.10 - '@storybook/client-logger': 7.0.10 - '@storybook/core-events': 7.0.10 + '@storybook/channels': 7.0.12 + '@storybook/client-logger': 7.0.12 + '@storybook/core-events': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.10 + '@storybook/preview-api': 7.0.12 dev: true /@storybook/instrumenter@7.0.2: @@ -5649,20 +5639,20 @@ packages: jest-mock: 27.5.1 dev: true - /@storybook/manager-api@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Dik73GKUX9QCFOvukTXjZoZX0G6n/LrRMkwLggb28E9m8iFt2ivWvF9MVvyRoDffR9VP5t53+nV5fqxqpXWoQw==} + /@storybook/manager-api@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3QXARtxpc6Xxqf5pviUw2UuhK53+IsINSljeWhAqdQ1Gzbywl67TpibTd7xVN6NKxhUH5Bzo9bIZTAzMZGqaKw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.0.10 - '@storybook/client-logger': 7.0.10 - '@storybook/core-events': 7.0.10 + '@storybook/channels': 7.0.12 + '@storybook/client-logger': 7.0.12 + '@storybook/core-events': 7.0.12 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/router': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/router': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 @@ -5674,16 +5664,16 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/manager@7.0.10: - resolution: {integrity: sha512-cFMOOXmcRx1tN50TqC2huOsF91fAvNM82wTDnAbT2FtA+ZHFHNyE1PgWgiKDDepzOpKaG+FfT4bJcQAaAfYOBg==} + /@storybook/manager@7.0.12: + resolution: {integrity: sha512-19BsDcwJOYXn6zEarxvNGDdYLUqZyhX92x6GPHSC4cf8BoxHuhmtnz5vOTZHusCxkKIu/C9W0H6wH2Ma47kDCg==} dev: true /@storybook/mdx2-csf@1.0.0: resolution: {integrity: sha512-dBAnEL4HfxxJmv7LdEYUoZlQbWj9APZNIbOaq0tgF8XkxiIbzqvgB0jhL/9UOrysSDbQWBiCRTu2wOVxedGfmw==} dev: true - /@storybook/node-logger@7.0.10: - resolution: {integrity: sha512-btCCreucTApi7EP84jbfqlFQZDD4Kz9lFLftalZA7nskDZW6i8reNNykTU2Y22TQvlbpqs5kL1N1cEsbG3vepw==} + /@storybook/node-logger@7.0.12: + resolution: {integrity: sha512-VL+NXzc9NuOP6/9alg4Sofz9kh8tmlo3p+UtCIYCHH088yCsB3XsNhkG9lF1C5EZVWcuHxc2u6MMF3ezOjvKfQ==} dependencies: '@types/npmlog': 4.1.4 chalk: 4.1.2 @@ -5691,20 +5681,20 @@ packages: pretty-hrtime: 1.0.3 dev: true - /@storybook/postinstall@7.0.10: - resolution: {integrity: sha512-SVPKGuuvfn1MceLWzYHGbpP77+waLKXglAH4Gkdoa2mKdk3XO45Zn8OhwwNzHuP698boMNaGaB/utBLBpkXMMg==} + /@storybook/postinstall@7.0.12: + resolution: {integrity: sha512-RKNvBLgABBTQwvGyF2jX4vP7OMLB3KvEEOQDoeOKjqyWfekDn5smI+eT714mtmKIH0YMcwmvzLgEdZkjmM/XhA==} dev: true - /@storybook/preview-api@7.0.10: - resolution: {integrity: sha512-URj2YJKbs8hc6JZQ3aA+MmjB4hTSzGZAVFVs3kLUEuaQPDbU1RT5GKxedwF5zlMnkZQPNoaUtopN3z7aF+SKFQ==} + /@storybook/preview-api@7.0.12: + resolution: {integrity: sha512-YI/AfHszIOYt967fsRlc7j6I0zZB+RSsBwD/nMA8y9vszdpQ0MgRhxHgQxFf6cgqbuQcdCsnTIpT0iQ4GHjDXg==} dependencies: - '@storybook/channel-postmessage': 7.0.10 - '@storybook/channels': 7.0.10 - '@storybook/client-logger': 7.0.10 - '@storybook/core-events': 7.0.10 + '@storybook/channel-postmessage': 7.0.12 + '@storybook/channels': 7.0.12 + '@storybook/client-logger': 7.0.12 + '@storybook/core-events': 7.0.12 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/types': 7.0.10 + '@storybook/types': 7.0.12 '@types/qs': 6.9.7 dequal: 2.0.3 lodash: 4.17.21 @@ -5755,12 +5745,12 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/preview@7.0.10: - resolution: {integrity: sha512-IQX8v7OpKeo2Oqeyxo6/uSRys+dJ7zms12jViJWGzx9fg6IchV/iNtf4TBrF3Z2JBNKovk03kICAMHTpZuz9Qg==} + /@storybook/preview@7.0.12: + resolution: {integrity: sha512-za8El/nnkyAo/uqyqAg7PMuP6DSdPoEnDRyIk4LzY7sAGly6i4Uge377cdo1nUBQLS5S4kKIc4xf8TUegb3G1Q==} dev: true - /@storybook/react-dom-shim@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-NLuE2Be/BGmXHufwLp1Gje+IsTb0HWvwzHlci2U430WgwGU8fsTPNgALMrwCpqN9o1KnrRGpysQEoyIYStQBdg==} + /@storybook/react-dom-shim@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-4z9J54TD7uphxPqSuLEzeKTV4oF8Fmv8qFfnT0XZJ2mpYTC2NTbkYoYZQ8N0eYzvNOk6xgfpDqBdmIANf4NaYw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5769,25 +5759,25 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.0.10(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.5): - resolution: {integrity: sha512-ZEwRpMEJAQtMruG/XGha52XHkb3extXudWT5SoXOcfiRy9eK7Y3oJwHR8KHNH3LE+LrRh7c+D53k7eMudRtsNA==} + /@storybook/react-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7): + resolution: {integrity: sha512-SIszevqIKOW+5TwzNposDI+3giSZNVZ7HSu7u2JEpu0Iw/CWyYI06rUgH2ft8Xluhb8vEorZKiZjsdiQDVo64w==} engines: {node: '>=16'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.5) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.7) '@rollup/pluginutils': 4.2.1 - '@storybook/builder-vite': 7.0.10(typescript@5.0.4)(vite@4.3.5) - '@storybook/react': 7.0.10(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) - '@vitejs/plugin-react': 3.1.0(vite@4.3.5) + '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.7) + '@storybook/react': 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + '@vitejs/plugin-react': 3.1.0(vite@4.3.7) ast-types: 0.14.2 magic-string: 0.27.0 react: 18.2.0 react-docgen: 6.0.0-alpha.3 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) transitivePeerDependencies: - '@preact/preset-vite' - supports-color @@ -5795,8 +5785,8 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.0.10(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4): - resolution: {integrity: sha512-/DDUGFz0bk5c/HCfSr7fL74rQc+3s317TDDKY6ZrgUzdIkze4D/TlAbWV78XV/ceeFNi1fLAUzGjFzuDwmVkJw==} + /@storybook/react@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4): + resolution: {integrity: sha512-dKHKc02LSgn3St7U/xj/Rr2DFLbS4dWQka+pS/AOvPPvMAR2gGHVhkmoFuFMf176hUTuE5MCoWBoNJIRMz7ZiQ==} engines: {node: '>=16.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5806,13 +5796,13 @@ packages: typescript: optional: true dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/core-client': 7.0.10 - '@storybook/docs-tools': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/core-client': 7.0.12 + '@storybook/docs-tools': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.10 - '@storybook/react-dom-shim': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/preview-api': 7.0.12 + '@storybook/react-dom-shim': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 '@types/node': 16.18.16 @@ -5834,27 +5824,27 @@ packages: - supports-color dev: true - /@storybook/router@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Vq3nuyrGsvbPYhsaVu0TwtzX8Yb5TZYg7v5gY/uk1brSIk7Mvw64E8WF4TKNhPcWnlxNrfP9S96IZgT9iuuCpw==} + /@storybook/router@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-dOtBiCBGeDem86BCWR7AlTVQjoBk0yw/XZLXS9qcpUfpe+UDjd0Rh21ZdEEMHG1Wfu4d2AhhG5l/JSJ1IE83jQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.0.10 + '@storybook/client-logger': 7.0.12 memoizerific: 1.11.3 qs: 6.11.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/source-loader@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-DtdYllq0piU6vgoVjsuPsWaGlhSOJgJr/kRovu5zltaZzdEOyQZ7e0zQmA4Py0h9jnGbg2fQG9zccofY3jUdJw==} + /@storybook/source-loader@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-dIT4uHiEFgIX/W1aYpKazeu+8GN2OljQsB84oO6Ea887f3emmVJRBGwvoChSAZH+ps2zGput88Lby+W5Paesow==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@storybook/csf': 0.1.0 - '@storybook/types': 7.0.10 + '@storybook/types': 7.0.12 estraverse: 5.3.0 lodash: 4.17.21 prettier: 2.8.8 @@ -5862,11 +5852,11 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/telemetry@7.0.10: - resolution: {integrity: sha512-0xlMECcSU2UnmpDTxKE/+pKpcW88fhxEZxh54yoA6NPpq6SGUN1r5ybUMffJCZ0JgaQ8HOc3Vxd13T3VXAMLXA==} + /@storybook/telemetry@7.0.12: + resolution: {integrity: sha512-oxqe15bn5W+1pLpLjXTfj3H+YPZq3jExjdJwTCUHtFrrsNs0k6dyqAUk8qTOUqOTclANHb6vlNBFJDvZ6qbfEQ==} dependencies: - '@storybook/client-logger': 7.0.10 - '@storybook/core-common': 7.0.10 + '@storybook/client-logger': 7.0.12 + '@storybook/core-common': 7.0.12 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.4 @@ -5889,24 +5879,24 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/theming@7.0.10(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-kKxIMElOUAyIAJOlhU6NS6/F6KpZLWvfGnUYC5V4f5Rsu+lKnbWI/TJ1rCIooz2wZBQ6dv+fjA3sOh5K+LRh2w==} + /@storybook/theming@7.0.12(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-frBkvH7LF8j23ODaywLK4m4LLscw49oKblkZ+30QZkBAzRf2o3a/QSZW2V1zfBo7ygcXiUJ5bIjh7Y17mMJqbQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) - '@storybook/client-logger': 7.0.10 + '@storybook/client-logger': 7.0.12 '@storybook/global': 5.0.0 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/types@7.0.10: - resolution: {integrity: sha512-mFktvN8PjjDFJSjck4spikmjtr0AwfOhcEtIf4UCmUD5JHgGppkQmvO6483nGcprSFcWOvD2uYGs8Wp32wG/MQ==} + /@storybook/types@7.0.12: + resolution: {integrity: sha512-nlvU4MyO2grwPCRQ8alA3AnY1bQxGJ6A4QgJu+1MhtjVenifFlxOQX4H1OiA+YXfjlV096oO5LrxvetJPFAKKQ==} dependencies: - '@storybook/channels': 7.0.10 + '@storybook/channels': 7.0.12 '@types/babel__core': 7.20.0 '@types/express': 4.17.17 file-system-cache: 2.0.2 @@ -5930,23 +5920,23 @@ packages: file-system-cache: 2.0.2 dev: true - /@storybook/vue3-vite@7.0.10(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.5)(vue@3.3.1): - resolution: {integrity: sha512-BbA6uLlNFIpSBW9UAJ9e96yCGGoMho0pogEbkzoRLdw/0OoqDqnRMue78CwW5eiIWXYjNZb3UwAyh9VgYqKk5g==} + /@storybook/vue3-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7)(vue@3.3.2): + resolution: {integrity: sha512-SdAGfBRfm4cR9VNLRcBCLo3rTzeUTvZfyh5ll0cgInCo9gTxwfs1Y4zEmmVqDDOWQ7qlpJanITNGFGiSsdvRmg==} engines: {node: ^14.18 || >=16} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@storybook/builder-vite': 7.0.10(typescript@5.0.4)(vite@4.3.5) - '@storybook/core-server': 7.0.10 - '@storybook/vue3': 7.0.10(vue@3.3.1) - '@vitejs/plugin-vue': 4.2.2(vite@4.3.5)(vue@3.3.1) + '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.7) + '@storybook/core-server': 7.0.12 + '@storybook/vue3': 7.0.12(vue@3.3.2) + '@vitejs/plugin-vue': 4.2.3(vite@4.3.7)(vue@3.3.2) magic-string: 0.27.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) - vue-docgen-api: 4.64.1(vue@3.3.1) + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + vue-docgen-api: 4.64.1(vue@3.3.2) transitivePeerDependencies: - '@preact/preset-vite' - bufferutil @@ -5958,20 +5948,20 @@ packages: - vue dev: true - /@storybook/vue3@7.0.10(vue@3.3.1): - resolution: {integrity: sha512-B4DW/lR9Am06RJM3TGrIgIYzurG6tsgUX9EQ6rQRDFd4EWw1bskcG8MrNwFBBiDBnXe1frL4AdDidF47CFStNg==} + /@storybook/vue3@7.0.12(vue@3.3.2): + resolution: {integrity: sha512-zxRhuuNcM9hT1/s968iHL+diqFqRmpwvEoI7rF1yje09saMck+PFStlE8b/ohQeDtm0GdwVqjbzfHZIdPbivYg==} engines: {node: '>=16.0.0'} peerDependencies: vue: ^3.0.0 dependencies: - '@storybook/core-client': 7.0.10 - '@storybook/docs-tools': 7.0.10 + '@storybook/core-client': 7.0.12 + '@storybook/docs-tools': 7.0.12 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.10 - '@storybook/types': 7.0.10 + '@storybook/preview-api': 7.0.12 + '@storybook/types': 7.0.12 ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.3.1 + vue: 3.3.2 transitivePeerDependencies: - supports-color dev: true @@ -6323,7 +6313,7 @@ packages: '@testing-library/dom': 8.20.0 dev: true - /@testing-library/vue@7.0.0(@vue/compiler-sfc@3.3.1)(vue@3.3.1): + /@testing-library/vue@7.0.0(@vue/compiler-sfc@3.3.2)(vue@3.3.2): resolution: {integrity: sha512-JU/q93HGo2qdm1dCgWymkeQlfpC0/0/DBZ2nAHgEAsVZxX11xVIxT7gbXdI7HACQpUbsUWt1zABGU075Fzt9XQ==} engines: {node: '>=14'} peerDependencies: @@ -6332,9 +6322,9 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@testing-library/dom': 9.2.0 - '@vue/compiler-sfc': 3.3.1 - '@vue/test-utils': 2.3.2(vue@3.3.1) - vue: 3.3.1 + '@vue/compiler-sfc': 3.3.2 + '@vue/test-utils': 2.3.2(vue@3.3.2) + vue: 3.3.2 dev: true /@tokenizer/token@0.3.0: @@ -6373,8 +6363,8 @@ packages: /@types/babel__core@7.20.0: resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==} dependencies: - '@babel/parser': 7.21.4 - '@babel/types': 7.21.4 + '@babel/parser': 7.21.8 + '@babel/types': 7.21.5 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.18.3 @@ -6407,7 +6397,7 @@ packages: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/braces@3.0.1: @@ -6427,7 +6417,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@types/responselike': 1.0.0 dev: false @@ -6460,7 +6450,7 @@ packages: /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/content-disposition@0.5.5: @@ -6525,7 +6515,7 @@ packages: /@types/express-serve-static-core@4.17.33: resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: true @@ -6553,27 +6543,27 @@ packages: resolution: {integrity: sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==} dependencies: '@types/glob': 8.1.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/gulp-rename@2.0.1: @@ -6586,7 +6576,7 @@ packages: /@types/gulp-rename@2.0.2: resolution: {integrity: sha512-CQsXqTVtAXqrPd4IbrrlJEEzRkUR3RXsyZbrVoOVqjlchDDmnyRDatAUisjpQjjCg/wjJrSiNg8T1uAbJ/7Qqg==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@types/vinyl': 2.0.7 dev: true @@ -6665,7 +6655,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: false /@types/lodash@4.14.191: @@ -6713,7 +6703,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 form-data: 3.0.1 /@types/node-fetch@3.0.3: @@ -6743,6 +6733,10 @@ packages: /@types/node@20.1.3: resolution: {integrity: sha512-NP2yfZpgmf2eDRPmgGq+fjGjSwFgYbihA8/gK+ey23qT9RkxsgNTZvGOEpXgzIGqesTYkElELLgtKoMQTys5vA==} + dev: true + + /@types/node@20.1.7: + resolution: {integrity: sha512-WCuw/o4GSwDGMoonES8rcvwsig77dGCMbZDrZr2x4ZZiNW4P/gcoZXe/0twgtobcTkmg9TuKflxYL/DuwDyJzg==} /@types/nodemailer@6.4.7: resolution: {integrity: sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==} @@ -6833,7 +6827,7 @@ packages: /@types/readdir-glob@1.1.1: resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/redis@4.0.11: @@ -6849,7 +6843,7 @@ packages: /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: false /@types/sanitize-html@2.9.0: @@ -6877,7 +6871,7 @@ packages: resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} dependencies: '@types/mime': 3.0.1 - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/serviceworker@0.0.67: @@ -6887,7 +6881,7 @@ packages: /@types/set-cookie-parser@2.4.2: resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /@types/sharp@0.32.0: @@ -6952,7 +6946,7 @@ packages: /@types/undertaker@1.2.8: resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@types/undertaker-registry': 1.0.1 async-done: 1.3.2 dev: true @@ -6981,7 +6975,7 @@ packages: resolution: {integrity: sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==} dependencies: '@types/glob-stream': 6.1.1 - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@types/vinyl': 2.0.7 dev: true @@ -6989,7 +6983,7 @@ packages: resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} dependencies: '@types/expect': 1.20.4 - '@types/node': 20.1.3 + '@types/node': 20.1.7 /@types/web-push@3.3.2: resolution: {integrity: sha512-JxWGVL/m7mWTIg4mRYO+A6s0jPmBkr4iJr39DqJpRJAc+jrPiEe1/asmkwerzRon8ZZDxaZJpsxpv0Z18Wo9gw==} @@ -7037,7 +7031,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true optional: true @@ -7171,7 +7165,7 @@ packages: eslint-visitor-keys: 3.4.1 dev: true - /@vitejs/plugin-react@3.1.0(vite@4.3.5): + /@vitejs/plugin-react@3.1.0(vite@4.3.7): resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -7182,20 +7176,20 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.3) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true - /@vitejs/plugin-vue@4.2.2(vite@4.3.5)(vue@3.3.1): - resolution: {integrity: sha512-kNH4wMAqs13UiZe/2If1ioO0Mjz71rr2oALTl2c5ajBIox9Vz/UGW/wGkr7GA3SC6Eb29c1HtzAtxdGfbXAkfQ==} + /@vitejs/plugin-vue@4.2.3(vite@4.3.7)(vue@3.3.2): + resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.0.0 vue: ^3.2.25 dependencies: - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) - vue: 3.3.1 + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + vue: 3.3.2 /@vitest/coverage-c8@0.31.0(vitest@0.31.0): resolution: {integrity: sha512-h72qN1D962AO7UefQVulm9JFP5ACS7OfhCdBHioXU8f7ohH/+NTZCgAqmgcfRNHHO/8wLFxx+93YVxhodkEJVA==} @@ -7207,7 +7201,7 @@ packages: magic-string: 0.30.0 picocolors: 1.0.0 std-env: 3.3.2 - vitest: 0.31.0(happy-dom@9.16.0)(sass@1.62.1) + vitest: 0.31.0(happy-dom@9.18.3)(sass@1.62.1) dev: true /@vitest/expect@0.31.0: @@ -7261,8 +7255,8 @@ packages: muggle-string: 0.2.2 dev: true - /@volar/typescript@1.4.1(typescript@5.0.4): - resolution: {integrity: sha512-phTy6p9yG6bgMIKQWEeDOi/aeT0njZsb1a/G1mrEuDsLmAn24Le4gDwSsGNhea6Uhu+3gdpUZn2PmZXa+WG2iQ==} + /@volar/typescript@1.4.1-patch.2(typescript@5.0.4): + resolution: {integrity: sha512-lPFYaGt8OdMEzNGJJChF40uYqMO4Z/7Q9fHPQC/NRVtht43KotSXLrkPandVVMf9aPbiJ059eAT+fwHGX16k4w==} peerDependencies: typescript: '*' dependencies: @@ -7270,31 +7264,31 @@ packages: typescript: 5.0.4 dev: true - /@volar/vue-language-core@1.6.4: - resolution: {integrity: sha512-1o+cAtN2DIDNAX/HS8rkjZc8wTMTK+zCab/qtYbvEVlmokhZiDrQeoD9/l0Ug7YCNg+mVuMNHKNBY7pX8U2/Jw==} + /@volar/vue-language-core@1.6.5: + resolution: {integrity: sha512-IF2b6hW4QAxfsLd5mePmLgtkXzNi+YnH6ltCd80gb7+cbdpFMjM1I+w+nSg2kfBTyfu+W8useCZvW89kPTBpzg==} dependencies: '@volar/language-core': 1.4.1 '@volar/source-map': 1.4.1 - '@vue/compiler-dom': 3.3.1 - '@vue/compiler-sfc': 3.3.1 - '@vue/reactivity': 3.3.1 - '@vue/shared': 3.3.1 + '@vue/compiler-dom': 3.3.2 + '@vue/compiler-sfc': 3.3.2 + '@vue/reactivity': 3.3.2 + '@vue/shared': 3.3.2 minimatch: 9.0.0 muggle-string: 0.2.2 vue-template-compiler: 2.7.14 dev: true - /@volar/vue-typescript@1.6.4(typescript@5.0.4): - resolution: {integrity: sha512-qKwgP0KVQR/aaH/SN3AP7RB8NnXPWDn3tjyXP6IT6etxkDeZLBLsXWUD9KMak/RvV1DgbXDuz4F9yuZlbt29rA==} + /@volar/vue-typescript@1.6.5(typescript@5.0.4): + resolution: {integrity: sha512-er9rVClS4PHztMUmtPMDTl+7c7JyrxweKSAEe/o/Noeq2bQx6v3/jZHVHBe8ZNUti5ubJL/+Tg8L3bzmlalV8A==} peerDependencies: typescript: '*' dependencies: - '@volar/typescript': 1.4.1(typescript@5.0.4) - '@volar/vue-language-core': 1.6.4 + '@volar/typescript': 1.4.1-patch.2(typescript@5.0.4) + '@volar/vue-language-core': 1.6.5 typescript: 5.0.4 dev: true - /@vue-macros/common@1.3.1(rollup@3.21.6)(vue@3.3.1): + /@vue-macros/common@1.3.1(rollup@3.22.0)(vue@3.3.2): resolution: {integrity: sha512-Lc5aP/8HNJD1XrnvpeNuWcCf82bZdR3auN/chA1b/1rKZgSnmQkH9f33tKO9qLwXSy+u4hpCi8Rw+oUuF1KCeg==} engines: {node: '>=14.19.0'} peerDependencies: @@ -7304,28 +7298,28 @@ packages: optional: true dependencies: '@babel/types': 7.21.5 - '@rollup/pluginutils': 5.0.2(rollup@3.21.6) - '@vue/compiler-sfc': 3.3.1 + '@rollup/pluginutils': 5.0.2(rollup@3.22.0) + '@vue/compiler-sfc': 3.3.2 local-pkg: 0.4.3 magic-string-ast: 0.1.2 - vue: 3.3.1 + vue: 3.3.2 transitivePeerDependencies: - rollup dev: false - /@vue-macros/reactivity-transform@0.3.6(rollup@3.21.6)(vue@3.3.1): - resolution: {integrity: sha512-PFJRXHEdIP03LeNnfcwjUk8pKWjvyeOZjCNwbLgfqunI9tknG4IQMfl86qswK83f+DoOTMCoeMFoUnmlbr+yUw==} + /@vue-macros/reactivity-transform@0.3.7(rollup@3.22.0)(vue@3.3.2): + resolution: {integrity: sha512-o+u5qstvUjNoaZjr4lUtNf5MuLgQHikvurnk6b2DFd9nB52j+BqOhI22uyn6K6TTAU0i0/PxT5YgwDlwVdvEUw==} engines: {node: '>=14.19.0'} peerDependencies: vue: ^2.7.0 || ^3.2.25 dependencies: '@babel/parser': 7.21.8 - '@vue-macros/common': 1.3.1(rollup@3.21.6)(vue@3.3.1) + '@vue-macros/common': 1.3.1(rollup@3.22.0)(vue@3.3.2) '@vue/compiler-core': 3.3.1 - '@vue/shared': 3.3.1 + '@vue/shared': 3.3.2 magic-string: 0.30.0 unplugin: 1.3.1 - vue: 3.3.1 + vue: 3.3.2 transitivePeerDependencies: - rollup dev: false @@ -7337,12 +7331,21 @@ packages: '@vue/shared': 3.3.1 estree-walker: 2.0.2 source-map-js: 1.0.2 + dev: false - /@vue/compiler-dom@3.3.1: - resolution: {integrity: sha512-VmgIsoLivCft3+oNc5KM7b9wd0nZxP/g2qilMwi1hJyGA624KWnNKHn4hzBQs4FpzydUVpNy+TWVT8KiRCh3MQ==} + /@vue/compiler-core@3.3.2: + resolution: {integrity: sha512-CKZWo1dzsQYTNTft7whzjL0HsrEpMfiK7pjZ2WFE3bC1NA7caUjWioHSK+49y/LK7Bsm4poJZzAMnvZMQ7OTeg==} dependencies: - '@vue/compiler-core': 3.3.1 - '@vue/shared': 3.3.1 + '@babel/parser': 7.21.8 + '@vue/shared': 3.3.2 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + + /@vue/compiler-dom@3.3.2: + resolution: {integrity: sha512-6gS3auANuKXLw0XH6QxkWqyPYPunziS2xb6VRenM3JY7gVfZcJvkCBHkb5RuNY1FCbBO3lkIi0CdXUCW1c7SXw==} + dependencies: + '@vue/compiler-core': 3.3.2 + '@vue/shared': 3.3.2 /@vue/compiler-sfc@2.7.14: resolution: {integrity: sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==} @@ -7352,75 +7355,79 @@ packages: source-map: 0.6.1 dev: false - /@vue/compiler-sfc@3.3.1: - resolution: {integrity: sha512-G+FPwBbXSLaA4+Ry5/bdD9Oda+sRslQcE9o6JSZaougRiT4OjVL0vtkbQHPrGRTULZV28OcrAjRfSZOSB0OTXQ==} + /@vue/compiler-sfc@3.3.2: + resolution: {integrity: sha512-jG4jQy28H4BqzEKsQqqW65BZgmo3vzdLHTBjF+35RwtDdlFE+Fk1VWJYUnDMMqkFBo6Ye1ltSKVOMPgkzYj7SQ==} dependencies: - '@babel/parser': 7.21.4 - '@vue/compiler-core': 3.3.1 - '@vue/compiler-dom': 3.3.1 - '@vue/compiler-ssr': 3.3.1 - '@vue/reactivity-transform': 3.3.1 - '@vue/shared': 3.3.1 + '@babel/parser': 7.21.8 + '@vue/compiler-core': 3.3.2 + '@vue/compiler-dom': 3.3.2 + '@vue/compiler-ssr': 3.3.2 + '@vue/reactivity-transform': 3.3.2 + '@vue/shared': 3.3.2 estree-walker: 2.0.2 magic-string: 0.30.0 postcss: 8.4.23 source-map-js: 1.0.2 - /@vue/compiler-ssr@3.3.1: - resolution: {integrity: sha512-QOQWGNCWuSeyKx4KvWSJlnIMGg+/2oCHgkFUYo7aJ+9Uaaz45yRgKQ+FNigy50NYBQIhpXn2e4OSR8GXh4knrQ==} + /@vue/compiler-ssr@3.3.2: + resolution: {integrity: sha512-K8OfY5FQtZaSOJHHe8xhEfIfLrefL/Y9frv4k4NsyQL3+0lRKxr9QuJhfdBDjkl7Fhz8CzKh63mULvmOfx3l2w==} dependencies: - '@vue/compiler-dom': 3.3.1 - '@vue/shared': 3.3.1 + '@vue/compiler-dom': 3.3.2 + '@vue/shared': 3.3.2 - /@vue/reactivity-transform@3.3.1: - resolution: {integrity: sha512-MkOrJauAGH4MNdxGW/PmrDegMyOGX0wGIdKUZJRBXOTpotDONg7/TPJe2QeGeBCow/5v9iOqZOWCfvmOWIaDMg==} + /@vue/reactivity-transform@3.3.2: + resolution: {integrity: sha512-iu2WaQvlJHdnONrsyv4ibIEnSsuKF+aHFngGj/y1lwpHQtalpVhKg9wsKMoiKXS9zPNjG9mNKzJS9vudvjzvyg==} dependencies: '@babel/parser': 7.21.8 - '@vue/compiler-core': 3.3.1 - '@vue/shared': 3.3.1 + '@vue/compiler-core': 3.3.2 + '@vue/shared': 3.3.2 estree-walker: 2.0.2 magic-string: 0.30.0 - /@vue/reactivity@3.3.1: - resolution: {integrity: sha512-zCfmazOtyUdC1NS/EPiSYJ4RqojqmTAviJyBbyVvY8zAv5NhK44Yfw0E1tt+m5vz0ZO1ptI9jDKBr3MWIEkpgw==} + /@vue/reactivity@3.3.2: + resolution: {integrity: sha512-yX8C4uTgg2Tdj+512EEMnMKbLveoITl7YdQX35AYgx8vBvQGszKiiCN46g4RY6/deeo/5DLbeUUGxCq1qWMf5g==} dependencies: - '@vue/shared': 3.3.1 + '@vue/shared': 3.3.2 - /@vue/runtime-core@3.3.1: - resolution: {integrity: sha512-Ljb37LYafhQqKIasc0r32Cva8gIh6VeSMjlwO6V03tCjHd18gmjP0F4UD+8/a59sGTysAgA8Rb9lIC2DVxRz2Q==} + /@vue/runtime-core@3.3.2: + resolution: {integrity: sha512-qSl95qj0BvKfcsO+hICqFEoLhJn6++HtsPxmTkkadFbuhe3uQfJ8HmQwvEr7xbxBd2rcJB6XOJg7nWAn/ymC5A==} dependencies: - '@vue/reactivity': 3.3.1 - '@vue/shared': 3.3.1 + '@vue/reactivity': 3.3.2 + '@vue/shared': 3.3.2 - /@vue/runtime-dom@3.3.1: - resolution: {integrity: sha512-NBjYbQPtMklb7lsJsM2Juv5Ygry6mvZP7PdH1GZqrzfLkvlplQT3qCtQMd/sib6yiy8t9m/Y4hVU7X9nzb9Oeg==} + /@vue/runtime-dom@3.3.2: + resolution: {integrity: sha512-+drStsJT+0mtgHdarT7cXZReCcTFfm6ptxMrz0kAW5hms6UNBd8Q1pi4JKlncAhu+Ld/TevsSp7pqAZxBBoGng==} dependencies: - '@vue/runtime-core': 3.3.1 - '@vue/shared': 3.3.1 + '@vue/runtime-core': 3.3.2 + '@vue/shared': 3.3.2 csstype: 3.1.1 - /@vue/server-renderer@3.3.1(vue@3.3.1): - resolution: {integrity: sha512-sod8ggOwbkQXw3lBjfzrbdxRS9lw/lNHoMaXghHawNYowf+4WoaLWD5ouz6fPZadUqNKAsqK95p8DYb1vcVfPA==} + /@vue/server-renderer@3.3.2(vue@3.3.2): + resolution: {integrity: sha512-QCwh6OGwJg6GDLE0fbQhRTR6tnU+XDJ1iCsTYHXBiezCXAhqMygFRij7BiLF4ytvvHcg5kX9joX5R5vP85++wg==} peerDependencies: - vue: 3.3.1 + vue: 3.3.2 dependencies: - '@vue/compiler-ssr': 3.3.1 - '@vue/shared': 3.3.1 - vue: 3.3.1 + '@vue/compiler-ssr': 3.3.2 + '@vue/shared': 3.3.2 + vue: 3.3.2 /@vue/shared@3.3.1: resolution: {integrity: sha512-ybDBtQ+479HL/bkeIOIAwgpeAEACzztkvulJLbK3JMFuTOv4qDivmV3AIsR8RHYJ+RD9tQxcHWBsX4GqEcYrfw==} + dev: false - /@vue/test-utils@2.3.2(vue@3.3.1): + /@vue/shared@3.3.2: + resolution: {integrity: sha512-0rFu3h8JbclbnvvKrs7Fe5FNGV9/5X2rPD7KmOzhLSUAiQH5//Hq437Gv0fR5Mev3u/nbtvmLl8XgwCU20/ZfQ==} + + /@vue/test-utils@2.3.2(vue@3.3.2): resolution: {integrity: sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==} peerDependencies: vue: ^3.0.1 dependencies: js-beautify: 1.14.6 - vue: 3.3.1 + vue: 3.3.2 optionalDependencies: - '@vue/compiler-dom': 3.3.1 - '@vue/server-renderer': 3.3.1(vue@3.3.1) + '@vue/compiler-dom': 3.3.2 + '@vue/server-renderer': 3.3.2(vue@3.3.2) dev: true /@webgpu/types@0.1.30: @@ -8113,8 +8120,8 @@ packages: postcss-value-parser: 3.3.1 dev: false - /autosize@5.0.2: - resolution: {integrity: sha512-FPVt5ynkqUAA9gcMZnJHka1XfQgr1WNd/yRfIjmj5WGmjua+u5Hl9hn8M2nU5CNy2bEIcj1ZUwXq7IOHsfZG9w==} + /autosize@6.0.1: + resolution: {integrity: sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==} dev: false /autwh@0.1.0: @@ -8289,7 +8296,7 @@ packages: resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 /bach@1.2.0: resolution: {integrity: sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==} @@ -9435,8 +9442,8 @@ packages: /constantinople@4.0.1: resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} dependencies: - '@babel/parser': 7.21.4 - '@babel/types': 7.21.4 + '@babel/parser': 7.21.8 + '@babel/types': 7.21.5 /content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} @@ -10551,8 +10558,8 @@ packages: - supports-color dev: true - /eslint-plugin-vue@9.12.0(eslint@8.40.0): - resolution: {integrity: sha512-xH8PgpDW2WwmFSmRfs/3iWogef1CJzQqX264I65zz77jDuxF2yLy7+GA2diUM8ZNATuSl1+UehMQkb5YEyau5w==} + /eslint-plugin-vue@9.13.0(eslint@8.40.0): + resolution: {integrity: sha512-aBz9A8WB4wmpnVv0pYUt86cmH9EkcwWzgEwecBxMoRNhQjTL5i4sqadnwShv/hOdr8Hbl8XANGV7dtX9UQIAyA==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 @@ -10563,7 +10570,7 @@ packages: nth-check: 2.1.1 postcss-selector-parser: 6.0.11 semver: 7.5.0 - vue-eslint-parser: 9.2.1(eslint@8.40.0) + vue-eslint-parser: 9.3.0(eslint@8.40.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -12050,6 +12057,18 @@ packages: webidl-conversions: 7.0.0 whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 + dev: false + + /happy-dom@9.18.3: + resolution: {integrity: sha512-b7iMGYeIXvUryNultA0AHEVU0FPpb2djJ/xSVlMDfP7HG4z7FomdqkCEpWtSv1zDL+t1gRUoBbpqFCoUBvjYtg==} + dependencies: + css.escape: 1.5.1 + entities: 4.5.0 + iconv-lite: 0.6.3 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + dev: true /har-schema@2.0.0: resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} @@ -13130,7 +13149,7 @@ packages: '@jest/expect': 29.5.0 '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -13284,6 +13303,45 @@ packages: - supports-color dev: true + /jest-config@29.5.0(@types/node@20.1.7): + resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.21.3 + '@jest/test-sequencer': 29.5.0 + '@jest/types': 29.5.0 + '@types/node': 20.1.7 + babel-jest: 29.5.0(@babel/core@7.21.3) + chalk: 4.1.2 + ci-info: 3.7.1 + deepmerge: 4.2.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.5.0 + jest-environment-node: 29.5.0 + jest-get-type: 29.4.3 + jest-regex-util: 29.4.3 + jest-resolve: 29.5.0 + jest-runner: 29.5.0 + jest-util: 29.5.0 + jest-validate: 29.5.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.5.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /jest-diff@28.1.3: resolution: {integrity: sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -13329,7 +13387,7 @@ packages: '@jest/environment': 29.5.0 '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 jest-mock: 29.5.0 jest-util: 29.5.0 dev: true @@ -13359,7 +13417,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@types/graceful-fs': 4.1.6 - '@types/node': 20.1.3 + '@types/node': 20.1.7 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13410,7 +13468,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 20.1.3 + '@types/node': 20.1.7 dev: true /jest-mock@29.5.0: @@ -13473,7 +13531,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13504,7 +13562,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -13559,7 +13617,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 chalk: 4.1.2 ci-info: 3.7.1 graceful-fs: 4.2.11 @@ -13584,7 +13642,7 @@ packages: dependencies: '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.1.7 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13603,7 +13661,7 @@ packages: resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 jest-util: 29.5.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -17444,8 +17502,8 @@ packages: seedrandom: 2.4.2 dev: false - /rollup@3.21.6: - resolution: {integrity: sha512-SXIICxvxQxR3D4dp/3LDHZIJPC8a4anKMHd4E3Jiz2/JnY+2bEjqrOokAauc5ShGVNFHlEFjBXAXlaxkJqIqSg==} + /rollup@3.22.0: + resolution: {integrity: sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -18248,11 +18306,11 @@ packages: resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} dev: true - /storybook@7.0.10: - resolution: {integrity: sha512-L36+Um+Ra8AKTvv84ODFJfuthmWnR1Lc6pjslcb8LYO+PVlqEOeqSknmTcKntDYwgvKx5lg62urtJxzGdwO0yw==} + /storybook@7.0.12: + resolution: {integrity: sha512-HKi7NQQTZhBGEU3KUFxTNGtIZcG8+hokiO5TwcIr7s7smAVKdvj9vY5YGsVkiWF39o+5UtafW1B/i9D8lBFsYg==} hasBin: true dependencies: - '@storybook/cli': 7.0.10 + '@storybook/cli': 7.0.12 transitivePeerDependencies: - bufferutil - encoding @@ -19598,7 +19656,7 @@ packages: replace-ext: 1.0.1 dev: false - /vite-node@0.31.0(@types/node@20.1.3)(sass@1.62.1): + /vite-node@0.31.0(@types/node@20.1.7)(sass@1.62.1): resolution: {integrity: sha512-8x1x1LNuPvE2vIvkSB7c1mApX5oqlgsxzHQesYF7l5n1gKrEmrClIiZuOFbFDQcjLsmcWSwwmrWrcGWm9Fxc/g==} engines: {node: '>=v14.18.0'} hasBin: true @@ -19608,7 +19666,7 @@ packages: mlly: 1.2.0 pathe: 1.1.0 picocolors: 1.0.0 - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) transitivePeerDependencies: - '@types/node' - less @@ -19623,8 +19681,8 @@ packages: resolution: {integrity: sha512-irjKcKXRn7v5bPAg4mAbsS6DgibpP1VUFL9tlgxU6lloK6V9yw9qCZkS+s2PtbkZpWNzr3TN3zVJAc6J7gJZmA==} dev: true - /vite@4.3.5(@types/node@20.1.3)(sass@1.62.1): - resolution: {integrity: sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==} + /vite@4.3.7(@types/node@20.1.7)(sass@1.62.1): + resolution: {integrity: sha512-MTIFpbIm9v7Hh5b0wSBgkcWzSBz7SAa6K/cBTwS4kUiQJfQLFlZZRJRQgqunCVzhTPCk674tW+0Qaqh3Q00dBg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -19648,10 +19706,10 @@ packages: terser: optional: true dependencies: - '@types/node': 20.1.3 + '@types/node': 20.1.7 esbuild: 0.17.18 postcss: 8.4.23 - rollup: 3.21.6 + rollup: 3.22.0 sass: 1.62.1 optionalDependencies: fsevents: 2.3.2 @@ -19663,12 +19721,12 @@ packages: vitest: '>=0.16.0' dependencies: cross-fetch: 3.1.5 - vitest: 0.31.0(happy-dom@9.16.0)(sass@1.62.1) + vitest: 0.31.0(happy-dom@9.18.3)(sass@1.62.1) transitivePeerDependencies: - encoding dev: true - /vitest@0.31.0(happy-dom@9.16.0)(sass@1.62.1): + /vitest@0.31.0(happy-dom@9.18.3)(sass@1.62.1): resolution: {integrity: sha512-JwWJS9p3GU9GxkG7eBSmr4Q4x4bvVBSswaCFf1PBNHiPx00obfhHRJfgHcnI0ffn+NMlIh9QGvG75FlaIBdKGA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -19701,7 +19759,7 @@ packages: dependencies: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 - '@types/node': 20.1.3 + '@types/node': 20.1.7 '@vitest/expect': 0.31.0 '@vitest/runner': 0.31.0 '@vitest/snapshot': 0.31.0 @@ -19713,7 +19771,7 @@ packages: chai: 4.3.7 concordance: 5.0.4 debug: 4.3.4(supports-color@8.1.1) - happy-dom: 9.16.0 + happy-dom: 9.18.3 local-pkg: 0.4.3 magic-string: 0.30.0 pathe: 1.1.0 @@ -19722,8 +19780,8 @@ packages: strip-literal: 1.0.1 tinybench: 2.4.0 tinypool: 0.5.0 - vite: 4.3.5(@types/node@20.1.3)(sass@1.62.1) - vite-node: 0.31.0(@types/node@20.1.3)(sass@1.62.1) + vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + vite-node: 0.31.0(@types/node@20.1.7)(sass@1.62.1) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -19738,26 +19796,26 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} - /vue-docgen-api@4.64.1(vue@3.3.1): + /vue-docgen-api@4.64.1(vue@3.3.2): resolution: {integrity: sha512-jbOf7ByE3Zvtuk+429Jorl+eIeh2aB2Fx1GUo3xJd1aByJWE8KDlSEa6b11PB1ze8f0sRUBraRDinICCk0KY7g==} dependencies: '@babel/parser': 7.21.8 - '@babel/types': 7.21.4 - '@vue/compiler-dom': 3.3.1 - '@vue/compiler-sfc': 3.3.1 + '@babel/types': 7.21.5 + '@vue/compiler-dom': 3.3.2 + '@vue/compiler-sfc': 3.3.2 ast-types: 0.14.2 hash-sum: 2.0.0 lru-cache: 8.0.4 pug: 3.0.2 recast: 0.22.0 ts-map: 1.0.3 - vue-inbrowser-compiler-independent-utils: 4.64.1(vue@3.3.1) + vue-inbrowser-compiler-independent-utils: 4.64.1(vue@3.3.2) transitivePeerDependencies: - vue dev: true - /vue-eslint-parser@9.2.1(eslint@8.40.0): - resolution: {integrity: sha512-tPOex4n6jit4E7h68auOEbDMwE58XiP4dylfaVTCOVCouR45g+QFDBjgIdEU52EXJxKyjgh91dLfN2rxUcV0bQ==} + /vue-eslint-parser@9.3.0(eslint@8.40.0): + resolution: {integrity: sha512-48IxT9d0+wArT1+3wNIy0tascRoywqSUe2E1YalIC1L8jsUGe5aJQItWfRok7DVFGz3UYvzEI7n5wiTXsCMAcQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' @@ -19774,12 +19832,12 @@ packages: - supports-color dev: true - /vue-inbrowser-compiler-independent-utils@4.64.1(vue@3.3.1): + /vue-inbrowser-compiler-independent-utils@4.64.1(vue@3.3.2): resolution: {integrity: sha512-Hn32n07XZ8j9W8+fmOXPQL+i+W2e/8i6mkH4Ju3H6nR0+cfvmWM95GhczYi5B27+Y8JlCKgAo04IUiYce4mKAw==} peerDependencies: vue: '>=2' dependencies: - vue: 3.3.1 + vue: 3.3.2 dev: true /vue-plyr@7.0.0: @@ -19789,13 +19847,13 @@ packages: vue: 2.7.14 dev: false - /vue-prism-editor@2.0.0-alpha.2(vue@3.3.1): + /vue-prism-editor@2.0.0-alpha.2(vue@3.3.2): resolution: {integrity: sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==} engines: {node: '>=10'} peerDependencies: vue: ^3.0.0 dependencies: - vue: 3.3.1 + vue: 3.3.2 dev: false /vue-template-compiler@2.7.14: @@ -19805,14 +19863,14 @@ packages: he: 1.2.0 dev: true - /vue-tsc@1.6.4(typescript@5.0.4): - resolution: {integrity: sha512-8rg8S1AhRJ6/WriENQEhyqH5wsxSxuD5iaD+QnkZn2ArZ6evlhqfBAIcVN8mfSyCV9DeLkQXkOSv/MaeJiJPAQ==} + /vue-tsc@1.6.5(typescript@5.0.4): + resolution: {integrity: sha512-Wtw3J7CC+JM2OR56huRd5iKlvFWpvDiU+fO1+rqyu4V2nMTotShz4zbOZpW5g9fUOcjnyZYfBo5q5q+D/q27JA==} hasBin: true peerDependencies: typescript: '*' dependencies: - '@volar/vue-language-core': 1.6.4 - '@volar/vue-typescript': 1.6.4(typescript@5.0.4) + '@volar/vue-language-core': 1.6.5 + '@volar/vue-typescript': 1.6.5(typescript@5.0.4) semver: 7.5.0 typescript: 5.0.4 dev: true @@ -19824,22 +19882,22 @@ packages: csstype: 3.1.1 dev: false - /vue@3.3.1: - resolution: {integrity: sha512-3Rwy4I5idbPVSDZu6I+fFh6tdDSZbauImCTqLxE7y0LpHtiDvPeY01OI7RkFPbva1nk4hoO0sv/NzosH2h60sg==} + /vue@3.3.2: + resolution: {integrity: sha512-98hJcAhyDwZoOo2flAQBSPVYG/o0HA9ivIy2ktHshjE+6/q8IMQ+kvDKQzOZTFPxvnNMcGM+zS2A00xeZMA7tA==} dependencies: - '@vue/compiler-dom': 3.3.1 - '@vue/compiler-sfc': 3.3.1 - '@vue/runtime-dom': 3.3.1 - '@vue/server-renderer': 3.3.1(vue@3.3.1) - '@vue/shared': 3.3.1 + '@vue/compiler-dom': 3.3.2 + '@vue/compiler-sfc': 3.3.2 + '@vue/runtime-dom': 3.3.2 + '@vue/server-renderer': 3.3.2(vue@3.3.2) + '@vue/shared': 3.3.2 - /vuedraggable@4.1.0(vue@3.3.1): + /vuedraggable@4.1.0(vue@3.3.2): resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} peerDependencies: vue: ^3.0.1 dependencies: sortablejs: 1.14.0 - vue: 3.3.1 + vue: 3.3.2 dev: false /w3c-xmlserializer@4.0.0: @@ -20054,8 +20112,8 @@ packages: resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/parser': 7.21.4 - '@babel/types': 7.21.4 + '@babel/parser': 7.21.8 + '@babel/types': 7.21.5 assert-never: 1.2.1 babel-walk: 3.0.0-canary-5 @@ -20362,7 +20420,7 @@ packages: sharp: 0.31.3 dev: false - github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.10)(@storybook/components@7.0.10)(@storybook/core-events@7.0.10)(@storybook/manager-api@7.0.10)(@storybook/preview-api@7.0.10)(@storybook/theming@7.0.10)(@storybook/types@7.0.10)(react-dom@18.2.0)(react@18.2.0): + github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.12)(@storybook/components@7.0.12)(@storybook/core-events@7.0.12)(@storybook/manager-api@7.0.12)(@storybook/preview-api@7.0.12)(@storybook/theming@7.0.12)(@storybook/types@7.0.12)(react-dom@18.2.0)(react@18.2.0): resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640 name: storybook-addon-misskey-theme @@ -20383,13 +20441,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/components': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.10 - '@storybook/manager-api': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.10 - '@storybook/theming': 7.0.10(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.10 + '@storybook/blocks': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.12 + '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.12 + '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.12 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true From 747d323584a288a7e6e98849ff9dae4b61753cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Wed, 17 May 2023 07:39:36 +0000 Subject: [PATCH 034/213] ci: fix breaking on foreign repos --- .github/workflows/storybook.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index b04f4260c3..8ca28c2ba9 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -16,12 +16,19 @@ jobs: steps: - uses: actions/checkout@v3.3.0 + if: github.event_name != 'pull_request_target' with: fetch-depth: 0 submodules: true - - name: Checkout HEAD + - uses: actions/checkout@v3.3.0 if: github.event_name == 'pull_request_target' - run: git checkout ${{ github.head_ref }} + with: + fetch-depth: 0 + submodules: true + ref: "refs/pull/${{ github.event.number }}/merge" + - name: Checkout actual HEAD + if: github.event_name == 'pull_request_target' + run: git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3) - name: Install pnpm uses: pnpm/action-setup@v2 with: From 45263f4cd013c89da302435f5baca2d965a4a634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Wed, 17 May 2023 07:51:45 +0000 Subject: [PATCH 035/213] ci: stop MkGalleryPostPreview snapshot --- .../src/components/MkGalleryPostPreview.stories.impl.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts index 57b3e75513..72ac0a58f9 100644 --- a/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts +++ b/packages/frontend/src/components/MkGalleryPostPreview.stories.impl.ts @@ -44,6 +44,10 @@ export const Default = { ], parameters: { layout: 'centered', + chromatic: { + // FIXME: flaky + disableSnapshot: true, + }, }, } satisfies StoryObj<typeof MkGalleryPostPreview>; export const Hover = { From dd60f1a53381ab55cd82e0697da7e20eb252bd9b Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Wed, 17 May 2023 20:00:28 +0000 Subject: [PATCH 036/213] =?UTF-8?q?fix(frontend/MkUrlPreview):=20summaly?= =?UTF-8?q?=E3=81=8C=E3=82=A8=E3=83=A9=E3=83=BC=E3=81=AB=E3=81=AA=E3=81=A3?= =?UTF-8?q?=E3=81=9F=E9=9A=9B=E3=81=AE=E6=8C=99=E5=8B=95=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + locales/ja-JP.yml | 1 + .../frontend/src/components/MkUrlPreview.vue | 30 ++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a20120b483..2ea1c2842a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ ### Client - 開発者モードを追加 - AiScriptを0.13.3に更新 +- Fix: URLプレビューで情報が取得できなかった際の挙動を修正 ## 13.12.2 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 340698a12b..264908482c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1048,6 +1048,7 @@ preventAiLearning: "生成AIによる学習を拒否" preventAiLearningDescription: "外部の文章生成AIや画像生成AIに対して、投稿したノートや画像などのコンテンツを学習の対象にしないように要求します。これはnoaiフラグをHTMLレスポンスに含めることによって実現されますが、この要求に従うかはそのAI次第であるため、学習を完全に防止するものではありません。" options: "オプション" specifyUser: "ユーザー指定" +failedToPreviewUrl: "プレビューできません" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue index 9c5622b1c5..23be814322 100644 --- a/packages/frontend/src/components/MkUrlPreview.vue +++ b/packages/frontend/src/components/MkUrlPreview.vue @@ -41,14 +41,14 @@ <h1 v-else-if="fetching" :class="$style.title"><MkEllipsis/></h1> <h1 v-else :class="$style.title" :title="title ?? undefined">{{ title }}</h1> </header> - <p v-if="unknownUrl" :class="$style.text">{{ i18n.ts.cannotLoad }}</p> + <p v-if="unknownUrl" :class="$style.text">{{ i18n.ts.failedToPreviewUrl }}</p> <p v-else-if="fetching" :class="$style.text"><MkEllipsis/></p> <p v-else-if="description" :class="$style.text" :title="description">{{ description.length > 85 ? description.slice(0, 85) + '…' : description }}</p> <footer :class="$style.footer"> <img v-if="icon" :class="$style.siteIcon" :src="icon"/> - <p v-if="unknownUrl" :class="$style.siteName">?</p> + <p v-if="unknownUrl" :class="$style.siteName">{{ requestUrl.host }}</p> <p v-else-if="fetching" :class="$style.siteName"><MkEllipsis/></p> - <p v-else :class="$style.siteName" :title="sitename ?? undefined">{{ sitename }}</p> + <p v-else :class="$style.siteName" :title="sitename ?? requestUrl.host">{{ sitename ?? requestUrl.host }}</p> </footer> </article> </component> @@ -128,17 +128,33 @@ if (requestUrl.hostname === 'music.youtube.com' && requestUrl.pathname.match('^/ requestUrl.hash = ''; -window.fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${versatileLang}`).then(res => { - res.json().then((info: SummalyResult) => { +window.fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${versatileLang}`) + .then(res => { + if (!res.ok) { + fetching = false; + unknownUrl = true; + return; + } + + return res.json(); + }) + .then((info: SummalyResult) => { + if (info.url == null) { + fetching = false; + unknownUrl = true; + return; + } + + fetching = false; + unknownUrl = false; + title = info.title; description = info.description; thumbnail = info.thumbnail; icon = info.icon; sitename = info.sitename; - fetching = false; player = info.player; }); -}); function adjustTweetHeight(message: any) { if (message.origin !== 'https://platform.twitter.com') return; From 6bb82cda37f56432a527a812a90b73861e38788a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Thu, 18 May 2023 14:16:07 +0900 Subject: [PATCH 037/213] ci: use actual base --- .github/workflows/storybook.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 8ca28c2ba9..72528f95b5 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -28,7 +28,10 @@ jobs: ref: "refs/pull/${{ github.event.number }}/merge" - name: Checkout actual HEAD if: github.event_name == 'pull_request_target' - run: git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3) + id: rev + run: | + echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT + git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3) - name: Install pnpm uses: pnpm/action-setup@v2 with: @@ -75,7 +78,7 @@ jobs: if: github.event_name == 'pull_request_target' id: chromatic_pull_request run: | - DIFF="${{ github.base_ref }} HEAD" + DIFF="${{ steps.rev.outputs.base }} HEAD" if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then DIFF="HEAD" fi From 6173cebdca246f9e1b496d66c237ce4afc60dc31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Thu, 18 May 2023 08:05:09 +0000 Subject: [PATCH 038/213] ci: remove deprecated notifications --- .github/workflows/storybook.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 72528f95b5..a9a5be7588 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -101,18 +101,6 @@ jobs: commit_sha: context.sha, body: 'Chromatic detects changes. Please [review the changes on Chromatic](https://www.chromatic.com/builds?appId=6428f7d7b962f0b79f97d6e4).' }) - - name: Notify that Chromatic will skip testing - uses: actions/github-script@v6.4.0 - if: github.event_name == 'pull_request_target' && steps.chromatic_pull_request.outputs.skip == 'true' - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: 'Chromatic will skip testing but you may still have to [review the changes on Chromatic](https://www.chromatic.com/pullrequests?appId=6428f7d7b962f0b79f97d6e4).' - }) - name: Upload Artifacts uses: actions/upload-artifact@v3 with: From 9b5b3a4d1b887ff29ce79f1639886f3c69def54f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 18 May 2023 18:18:25 +0900 Subject: [PATCH 039/213] perf(backend): pre-compile regexp --- packages/backend/src/core/ReactionService.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index a274b19e4b..2184cfeb41 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -54,6 +54,9 @@ type DecodedReaction = { host?: string | null; }; +const isCustomEmojiRegexp = /^:([\w+-]+)(?:@\.)?:$/; +const decodeCustomEmojiRegexp = /^:([\w+-]+)(?:@([\w.-]+))?:$/; + @Injectable() export class ReactionService { constructor( @@ -306,7 +309,7 @@ export class ReactionService { return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, ''); } - const custom = reaction.match(/^:([\w+-]+)(?:@\.)?:$/); + const custom = reaction.match(isCustomEmojiRegexp); if (custom) { const name = custom[1]; const emoji = reacterHost == null @@ -324,7 +327,7 @@ export class ReactionService { @bindThis public decodeReaction(str: string): DecodedReaction { - const custom = str.match(/^:([\w+-]+)(?:@([\w.-]+))?:$/); + const custom = str.match(decodeCustomEmojiRegexp); if (custom) { const name = custom[1]; From 7ce569424a67c786a4f44993ce74f06989eba9df Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 18 May 2023 18:45:49 +0900 Subject: [PATCH 040/213] =?UTF-8?q?feat:=20=E3=82=AB=E3=82=B9=E3=82=BF?= =?UTF-8?q?=E3=83=A0=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=94=E3=81=A8=E3=81=AB?= =?UTF-8?q?=E3=81=9D=E3=82=8C=E3=82=92=E3=83=AA=E3=82=A2=E3=82=AF=E3=82=B7?= =?UTF-8?q?=E3=83=A7=E3=83=B3=E3=81=A8=E3=81=97=E3=81=A6=E4=BD=BF=E3=81=88?= =?UTF-8?q?=E3=82=8B=E3=83=AD=E3=83=BC=E3=83=AB=E3=82=92=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + locales/ja-JP.yml | 3 + .../migration/1684386446061-emoji-improve.js | 15 ++ .../backend/src/core/CustomEmojiService.ts | 22 +- packages/backend/src/core/MfmService.ts | 2 +- packages/backend/src/core/ReactionService.ts | 51 +++-- packages/backend/src/core/WebfingerService.ts | 7 +- .../src/core/entities/EmojiEntityService.ts | 4 + packages/backend/src/models/entities/Emoji.ts | 16 ++ .../backend/src/models/json-schema/emoji.ts | 21 ++ .../ImportCustomEmojisProcessorService.ts | 3 + .../server/api/endpoints/admin/emoji/add.ts | 31 ++- .../api/endpoints/admin/emoji/update.ts | 27 +++ packages/backend/test/unit/ReactionService.ts | 42 ++-- .../frontend/src/components/MkRolePreview.vue | 13 +- .../src/pages/custom-emojis-manager.vue | 19 +- .../frontend/src/pages/emoji-edit-dialog.vue | 214 ++++++++++++++---- 17 files changed, 376 insertions(+), 115 deletions(-) create mode 100644 packages/backend/migration/1684386446061-emoji-improve.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ea1c2842a..8b6fefc8d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ## 13.x.x (unreleased) ### General +- カスタム絵文字ごとにそれをリアクションとして使えるロールを設定できるように - タイムラインにフォロイーの行った他人へのリプライを含めるかどうかの設定をアカウントに保存するのをやめるように - 今後はAPI呼び出し時およびストリーミング接続時に設定するようになります diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 264908482c..f49f9c5a3c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1049,6 +1049,9 @@ preventAiLearningDescription: "外部の文章生成AIや画像生成AIに対し options: "オプション" specifyUser: "ユーザー指定" failedToPreviewUrl: "プレビューできません" +update: "更新" +rolesThatCanBeUsedThisEmojiAsReaction: "リアクションとして使えるロール" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールの指定が一つもない場合、誰でもリアクションとして使えます。" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/backend/migration/1684386446061-emoji-improve.js b/packages/backend/migration/1684386446061-emoji-improve.js new file mode 100644 index 0000000000..40b0a2bc5e --- /dev/null +++ b/packages/backend/migration/1684386446061-emoji-improve.js @@ -0,0 +1,15 @@ +export class EmojiImprove1684386446061 { + name = 'EmojiImprove1684386446061' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "emoji" ADD "localOnly" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "emoji" ADD "isSensitive" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "emoji" ADD "roleIdsThatCanBeUsedThisEmojiAsReaction" character varying(128) array NOT NULL DEFAULT '{}'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "roleIdsThatCanBeUsedThisEmojiAsReaction"`); + await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "isSensitive"`); + await queryRunner.query(`ALTER TABLE "emoji" DROP COLUMN "localOnly"`); + } +} diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 93557ce617..3499df38b7 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -7,7 +7,7 @@ import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { Emoji } from '@/models/entities/Emoji.js'; -import type { EmojisRepository } from '@/models/index.js'; +import type { EmojisRepository, Role } from '@/models/index.js'; import { bindThis } from '@/decorators.js'; import { MemoryKVCache, RedisSingleCache } from '@/misc/cache.js'; import { UtilityService } from '@/core/UtilityService.js'; @@ -15,6 +15,8 @@ import type { Config } from '@/config.js'; import { query } from '@/misc/prelude/url.js'; import type { Serialized } from '@/server/api/stream/types.js'; +const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/; + @Injectable() export class CustomEmojiService { private cache: MemoryKVCache<Emoji | null>; @@ -63,6 +65,9 @@ export class CustomEmojiService { aliases: string[]; host: string | null; license: string | null; + isSensitive: boolean; + localOnly: boolean; + roleIdsThatCanBeUsedThisEmojiAsReaction: Role['id'][]; }): Promise<Emoji> { const emoji = await this.emojisRepository.insert({ id: this.idService.genId(), @@ -75,6 +80,9 @@ export class CustomEmojiService { publicUrl: data.driveFile.webpublicUrl ?? data.driveFile.url, type: data.driveFile.webpublicType ?? data.driveFile.type, license: data.license, + isSensitive: data.isSensitive, + localOnly: data.localOnly, + roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction, }).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0])); if (data.host == null) { @@ -90,10 +98,14 @@ export class CustomEmojiService { @bindThis public async update(id: Emoji['id'], data: { + driveFile?: DriveFile; name?: string; category?: string | null; aliases?: string[]; license?: string | null; + isSensitive?: boolean; + localOnly?: boolean; + roleIdsThatCanBeUsedThisEmojiAsReaction?: Role['id'][]; }): Promise<void> { const emoji = await this.emojisRepository.findOneByOrFail({ id: id }); const sameNameEmoji = await this.emojisRepository.findOneBy({ name: data.name, host: IsNull() }); @@ -105,6 +117,12 @@ export class CustomEmojiService { category: data.category, aliases: data.aliases, license: data.license, + isSensitive: data.isSensitive, + localOnly: data.localOnly, + originalUrl: data.driveFile != null ? data.driveFile.url : undefined, + publicUrl: data.driveFile != null ? (data.driveFile.webpublicUrl ?? data.driveFile.url) : undefined, + type: data.driveFile != null ? (data.driveFile.webpublicType ?? data.driveFile.type) : undefined, + roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction ?? undefined, }); this.localEmojisCache.refresh(); @@ -259,7 +277,7 @@ export class CustomEmojiService { @bindThis public parseEmojiStr(emojiName: string, noteUserHost: string | null) { - const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/); + const match = emojiName.match(parseEmojiStrRegexp); if (!match) return { name: null, host: null }; const name = match[1]; diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts index 9b2d5dc0ff..dffee16e08 100644 --- a/packages/backend/src/core/MfmService.ts +++ b/packages/backend/src/core/MfmService.ts @@ -83,7 +83,7 @@ export class MfmService { if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) { text += txt; // メンション - } else if (txt.startsWith('@') && !(rel && rel.value.match(/^me /))) { + } else if (txt.startsWith('@') && !(rel && rel.value.startsWith('me '))) { const part = txt.split('@'); if (part.length === 2 && href) { diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 2184cfeb41..27334b33e6 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -20,6 +20,7 @@ import { bindThis } from '@/decorators.js'; import { UtilityService } from '@/core/UtilityService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; +import { RoleService } from '@/core/RoleService.js'; const FALLBACK = '❤'; @@ -75,6 +76,7 @@ export class ReactionService { private utilityService: UtilityService, private metaService: MetaService, private customEmojiService: CustomEmojiService, + private roleService: RoleService, private userEntityService: UserEntityService, private noteEntityService: NoteEntityService, private userBlockingService: UserBlockingService, @@ -88,7 +90,7 @@ export class ReactionService { } @bindThis - public async create(user: { id: User['id']; host: User['host']; isBot: User['isBot'] }, note: Note, reaction?: string | null) { + public async create(user: { id: User['id']; host: User['host']; isBot: User['isBot'] }, note: Note, _reaction?: string | null) { // Check blocking if (note.userId !== user.id) { const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id); @@ -102,10 +104,36 @@ export class ReactionService { throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.'); } + let reaction = _reaction ?? FALLBACK; + if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote') && (user.host != null))) { reaction = '❤️'; - } else { - reaction = await this.toDbReaction(reaction, user.host); + } else if (_reaction) { + const custom = reaction.match(isCustomEmojiRegexp); + if (custom) { + const reacterHost = this.utilityService.toPunyNullable(user.host); + + const name = custom[1]; + const emoji = reacterHost == null + ? (await this.customEmojiService.localEmojisCache.fetch()).get(name) + : await this.emojisRepository.findOneBy({ + host: reacterHost, + name, + }); + + if (emoji) { + if (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0 || (await this.roleService.getUserRoles(user.id)).some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id))) { + reaction = reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; + } else { + // リアクションとして使う権限がない + reaction = FALLBACK; + } + } else { + reaction = FALLBACK; + } + } else { + reaction = this.normalize(reaction ?? null); + } } const record: NoteReaction = { @@ -291,11 +319,9 @@ export class ReactionService { } @bindThis - public async toDbReaction(reaction?: string | null, reacterHost?: string | null): Promise<string> { + public normalize(reaction: string | null): string { if (reaction == null) return FALLBACK; - reacterHost = this.utilityService.toPunyNullable(reacterHost); - // 文字列タイプのリアクションを絵文字に変換 if (Object.keys(legacies).includes(reaction)) return legacies[reaction]; @@ -309,19 +335,6 @@ export class ReactionService { return unicode.match('\u200d') ? unicode : unicode.replace(/\ufe0f/g, ''); } - const custom = reaction.match(isCustomEmojiRegexp); - if (custom) { - const name = custom[1]; - const emoji = reacterHost == null - ? (await this.customEmojiService.localEmojisCache.fetch()).get(name) - : await this.emojisRepository.findOneBy({ - host: reacterHost, - name, - }); - - if (emoji) return reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; - } - return FALLBACK; } diff --git a/packages/backend/src/core/WebfingerService.ts b/packages/backend/src/core/WebfingerService.ts index 3ee7990643..f58a6a10fc 100644 --- a/packages/backend/src/core/WebfingerService.ts +++ b/packages/backend/src/core/WebfingerService.ts @@ -16,6 +16,9 @@ type IWebFinger = { subject: string; }; +const urlRegex = /^https?:\/\//; +const mRegex = /^([^@]+)@(.*)/; + @Injectable() export class WebfingerService { constructor( @@ -35,12 +38,12 @@ export class WebfingerService { @bindThis private genUrl(query: string): string { - if (query.match(/^https?:\/\//)) { + if (query.match(urlRegex)) { const u = new URL(query); return `${u.protocol}//${u.hostname}/.well-known/webfinger?` + urlQuery({ resource: query }); } - const m = query.match(/^([^@]+)@(.*)/); + const m = query.match(mRegex); if (m) { const hostname = m[2]; const useHttp = process.env.MISSKEY_WEBFINGER_USE_HTTP && process.env.MISSKEY_WEBFINGER_USE_HTTP.toLowerCase() === 'true'; diff --git a/packages/backend/src/core/entities/EmojiEntityService.ts b/packages/backend/src/core/entities/EmojiEntityService.ts index 3bad048bc0..0c7bd9ed9a 100644 --- a/packages/backend/src/core/entities/EmojiEntityService.ts +++ b/packages/backend/src/core/entities/EmojiEntityService.ts @@ -26,6 +26,7 @@ export class EmojiEntityService { category: emoji.category, // || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ) url: emoji.publicUrl || emoji.originalUrl, + isSensitive: emoji.isSensitive, }; } @@ -51,6 +52,9 @@ export class EmojiEntityService { // || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ) url: emoji.publicUrl || emoji.originalUrl, license: emoji.license, + isSensitive: emoji.isSensitive, + localOnly: emoji.localOnly, + roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction, }; } diff --git a/packages/backend/src/models/entities/Emoji.ts b/packages/backend/src/models/entities/Emoji.ts index dbb437d439..8fd3e65f5e 100644 --- a/packages/backend/src/models/entities/Emoji.ts +++ b/packages/backend/src/models/entities/Emoji.ts @@ -60,4 +60,20 @@ export class Emoji { length: 1024, nullable: true, }) public license: string | null; + + @Column('boolean', { + default: false, + }) + public localOnly: boolean; + + @Column('boolean', { + default: false, + }) + public isSensitive: boolean; + + // TODO: 定期ジョブで存在しなくなったロールIDを除去するようにする + @Column('varchar', { + array: true, length: 128, default: '{}', + }) + public roleIdsThatCanBeUsedThisEmojiAsReaction: string[]; } diff --git a/packages/backend/src/models/json-schema/emoji.ts b/packages/backend/src/models/json-schema/emoji.ts index db4fd62cf6..c59b5d1ef4 100644 --- a/packages/backend/src/models/json-schema/emoji.ts +++ b/packages/backend/src/models/json-schema/emoji.ts @@ -22,6 +22,10 @@ export const packedEmojiSimpleSchema = { type: 'string', optional: false, nullable: false, }, + isSensitive: { + type: 'boolean', + optional: false, nullable: false, + }, }, } as const; @@ -63,5 +67,22 @@ export const packedEmojiDetailedSchema = { type: 'string', optional: false, nullable: true, }, + isSensitive: { + type: 'boolean', + optional: false, nullable: false, + }, + localOnly: { + type: 'boolean', + optional: false, nullable: false, + }, + roleIdsThatCanBeUsedThisEmojiAsReaction: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, + }, }, } as const; diff --git a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts index cf78d8330c..600468a286 100644 --- a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts @@ -107,6 +107,9 @@ export class ImportCustomEmojisProcessorService { aliases: emojiInfo.aliases, driveFile, license: emojiInfo.license, + isSensitive: emojiInfo.isSensitive, + localOnly: emojiInfo.localOnly, + roleIdsThatCanBeUsedThisEmojiAsReaction: [], }); } diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts index 2fb3e489e7..509224e9c3 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/add.ts @@ -25,9 +25,24 @@ export const meta = { export const paramDef = { type: 'object', properties: { + name: { type: 'string', pattern: '^[a-zA-Z0-9_]+$' }, fileId: { type: 'string', format: 'misskey:id' }, + category: { + type: 'string', + nullable: true, + description: 'Use `null` to reset the category.', + }, + aliases: { type: 'array', items: { + type: 'string', + } }, + license: { type: 'string', nullable: true }, + isSensitive: { type: 'boolean' }, + localOnly: { type: 'boolean' }, + roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: { + type: 'string', + } }, }, - required: ['fileId'], + required: ['name', 'fileId'], } as const; // TODO: ロジックをサービスに切り出す @@ -45,18 +60,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { ) { super(meta, paramDef, async (ps, me) => { const driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); - if (driveFile == null) throw new ApiError(meta.errors.noSuchFile); - const name = driveFile.name.split('.')[0].match(/^[a-z0-9_]+$/) ? driveFile.name.split('.')[0] : `_${rndstr('a-z0-9', 8)}_`; - const emoji = await this.customEmojiService.add({ driveFile, - name, - category: null, - aliases: [], + name: ps.name, + category: ps.category ?? null, + aliases: ps.aliases ?? [], host: null, - license: null, + license: ps.license ?? null, + isSensitive: ps.isSensitive ?? false, + localOnly: ps.localOnly ?? false, + roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [], }); this.moderationLogService.insertModerationLog(me, 'addEmoji', { diff --git a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts index f63348b60b..fb22bdc477 100644 --- a/packages/backend/src/server/api/endpoints/admin/emoji/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/emoji/update.ts @@ -1,6 +1,8 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; +import type { DriveFilesRepository } from '@/models/index.js'; +import { DI } from '@/di-symbols.js'; import { ApiError } from '../../../error.js'; export const meta = { @@ -15,6 +17,11 @@ export const meta = { code: 'NO_SUCH_EMOJI', id: '684dec9d-a8c2-4364-9aa8-456c49cb1dc8', }, + noSuchFile: { + message: 'No such file.', + code: 'NO_SUCH_FILE', + id: '14fb9fd9-0731-4e2f-aeb9-f09e4740333d', + }, sameNameEmojiExists: { message: 'Emoji that have same name already exists.', code: 'SAME_NAME_EMOJI_EXISTS', @@ -28,6 +35,7 @@ export const paramDef = { properties: { id: { type: 'string', format: 'misskey:id' }, name: { type: 'string', pattern: '^[a-zA-Z0-9_]+$' }, + fileId: { type: 'string', format: 'misskey:id' }, category: { type: 'string', nullable: true, @@ -37,6 +45,11 @@ export const paramDef = { type: 'string', } }, license: { type: 'string', nullable: true }, + isSensitive: { type: 'boolean' }, + localOnly: { type: 'boolean' }, + roleIdsThatCanBeUsedThisEmojiAsReaction: { type: 'array', items: { + type: 'string', + } }, }, required: ['id', 'name', 'aliases'], } as const; @@ -45,14 +58,28 @@ export const paramDef = { @Injectable() export default class extends Endpoint<typeof meta, typeof paramDef> { constructor( + @Inject(DI.driveFilesRepository) + private driveFilesRepository: DriveFilesRepository, + private customEmojiService: CustomEmojiService, ) { super(meta, paramDef, async (ps, me) => { + let driveFile; + + if (ps.fileId) { + driveFile = await this.driveFilesRepository.findOneBy({ id: ps.fileId }); + if (driveFile == null) throw new ApiError(meta.errors.noSuchFile); + } + await this.customEmojiService.update(ps.id, { + driveFile, name: ps.name, category: ps.category ?? null, aliases: ps.aliases, license: ps.license ?? null, + isSensitive: ps.isSensitive, + localOnly: ps.localOnly, + roleIdsThatCanBeUsedThisEmojiAsReaction: ps.roleIdsThatCanBeUsedThisEmojiAsReaction, }); }); } diff --git a/packages/backend/test/unit/ReactionService.ts b/packages/backend/test/unit/ReactionService.ts index 38db081ac0..aa68f4117d 100644 --- a/packages/backend/test/unit/ReactionService.ts +++ b/packages/backend/test/unit/ReactionService.ts @@ -15,78 +15,74 @@ describe('ReactionService', () => { reactionService = app.get<ReactionService>(ReactionService); }); - describe('toDbReaction', () => { + describe('normalize', () => { test('絵文字リアクションはそのまま', async () => { - assert.strictEqual(await reactionService.toDbReaction('👍'), '👍'); - assert.strictEqual(await reactionService.toDbReaction('🍅'), '🍅'); + assert.strictEqual(await reactionService.normalize('👍'), '👍'); + assert.strictEqual(await reactionService.normalize('🍅'), '🍅'); }); test('既存のリアクションは絵文字化する pudding', async () => { - assert.strictEqual(await reactionService.toDbReaction('pudding'), '🍮'); + assert.strictEqual(await reactionService.normalize('pudding'), '🍮'); }); test('既存のリアクションは絵文字化する like', async () => { - assert.strictEqual(await reactionService.toDbReaction('like'), '👍'); + assert.strictEqual(await reactionService.normalize('like'), '👍'); }); test('既存のリアクションは絵文字化する love', async () => { - assert.strictEqual(await reactionService.toDbReaction('love'), '❤'); + assert.strictEqual(await reactionService.normalize('love'), '❤'); }); test('既存のリアクションは絵文字化する laugh', async () => { - assert.strictEqual(await reactionService.toDbReaction('laugh'), '😆'); + assert.strictEqual(await reactionService.normalize('laugh'), '😆'); }); test('既存のリアクションは絵文字化する hmm', async () => { - assert.strictEqual(await reactionService.toDbReaction('hmm'), '🤔'); + assert.strictEqual(await reactionService.normalize('hmm'), '🤔'); }); test('既存のリアクションは絵文字化する surprise', async () => { - assert.strictEqual(await reactionService.toDbReaction('surprise'), '😮'); + assert.strictEqual(await reactionService.normalize('surprise'), '😮'); }); test('既存のリアクションは絵文字化する congrats', async () => { - assert.strictEqual(await reactionService.toDbReaction('congrats'), '🎉'); + assert.strictEqual(await reactionService.normalize('congrats'), '🎉'); }); test('既存のリアクションは絵文字化する angry', async () => { - assert.strictEqual(await reactionService.toDbReaction('angry'), '💢'); + assert.strictEqual(await reactionService.normalize('angry'), '💢'); }); test('既存のリアクションは絵文字化する confused', async () => { - assert.strictEqual(await reactionService.toDbReaction('confused'), '😥'); + assert.strictEqual(await reactionService.normalize('confused'), '😥'); }); test('既存のリアクションは絵文字化する rip', async () => { - assert.strictEqual(await reactionService.toDbReaction('rip'), '😇'); + assert.strictEqual(await reactionService.normalize('rip'), '😇'); }); test('既存のリアクションは絵文字化する star', async () => { - assert.strictEqual(await reactionService.toDbReaction('star'), '⭐'); + assert.strictEqual(await reactionService.normalize('star'), '⭐'); }); test('異体字セレクタ除去', async () => { - assert.strictEqual(await reactionService.toDbReaction('㊗️'), '㊗'); + assert.strictEqual(await reactionService.normalize('㊗️'), '㊗'); }); test('異体字セレクタ除去 必要なし', async () => { - assert.strictEqual(await reactionService.toDbReaction('㊗'), '㊗'); - }); - - test('fallback - undefined', async () => { - assert.strictEqual(await reactionService.toDbReaction(undefined), '❤'); + assert.strictEqual(await reactionService.normalize('㊗'), '㊗'); }); test('fallback - null', async () => { - assert.strictEqual(await reactionService.toDbReaction(null), '❤'); + assert.strictEqual(await reactionService.normalize(null), '❤'); }); test('fallback - empty', async () => { - assert.strictEqual(await reactionService.toDbReaction(''), '❤'); + assert.strictEqual(await reactionService.normalize(''), '❤'); }); test('fallback - unknown', async () => { - assert.strictEqual(await reactionService.toDbReaction('unknown'), '❤'); + assert.strictEqual(await reactionService.normalize('unknown'), '❤'); }); }); }); diff --git a/packages/frontend/src/components/MkRolePreview.vue b/packages/frontend/src/components/MkRolePreview.vue index 2f5866f340..9fbe1ec993 100644 --- a/packages/frontend/src/components/MkRolePreview.vue +++ b/packages/frontend/src/components/MkRolePreview.vue @@ -12,8 +12,10 @@ </template> </span> <span :class="$style.name">{{ role.name }}</span> - <span v-if="role.target === 'manual'" :class="$style.users">{{ role.usersCount }} users</span> - <span v-else-if="role.target === 'conditional'" :class="$style.users">({{ i18n.ts._role.conditional }})</span> + <template v-if="detailed"> + <span v-if="role.target === 'manual'" :class="$style.users">{{ role.usersCount }} users</span> + <span v-else-if="role.target === 'conditional'" :class="$style.users">({{ i18n.ts._role.conditional }})</span> + </template> </div> <div :class="$style.description">{{ role.description }}</div> </MkA> @@ -23,10 +25,13 @@ import { } from 'vue'; import { i18n } from '@/i18n'; -const props = defineProps<{ +const props = withDefaults(defineProps<{ role: any; forModeration: boolean; -}>(); + detailed: boolean; +}>(), { + detailed: true, +}); </script> <style lang="scss" module> diff --git a/packages/frontend/src/pages/custom-emojis-manager.vue b/packages/frontend/src/pages/custom-emojis-manager.vue index 3f13f0787d..3da6a0d9cb 100644 --- a/packages/frontend/src/pages/custom-emojis-manager.vue +++ b/packages/frontend/src/pages/custom-emojis-manager.vue @@ -2,7 +2,7 @@ <div> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="900"> + <MkSpacer :contentMax="900"> <div class="ogwlenmc"> <div v-if="tab === 'local'" class="local"> <MkInput v-model="query" :debounce="true" type="search"> @@ -123,15 +123,14 @@ const toggleSelect = (emoji) => { }; const add = async (ev: MouseEvent) => { - const files = await selectFiles(ev.currentTarget ?? ev.target, null); - - const promise = Promise.all(files.map(file => os.api('admin/emoji/add', { - fileId: file.id, - }))); - promise.then(() => { - emojisPaginationComponent.value.reload(); - }); - os.promiseDialog(promise); + os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), { + }, { + done: result => { + if (result.created) { + emojisPaginationComponent.value.prepend(result.created); + } + }, + }, 'closed'); }; const edit = (emoji) => { diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue index 3c829d6a8e..24b72b6f7f 100644 --- a/packages/frontend/src/pages/emoji-edit-dialog.vue +++ b/packages/frontend/src/pages/emoji-edit-dialog.vue @@ -1,84 +1,168 @@ <template> <MkModalWindow ref="dialog" - :width="370" - :with-ok-button="true" - @close="$refs.dialog.close()" + :width="400" + @close="dialog.close()" @closed="$emit('closed')" - @ok="ok()" > - <template #header>:{{ emoji.name }}:</template> + <template v-if="emoji" #header>:{{ emoji.name }}:</template> + <template v-else #header>New emoji</template> - <MkSpacer :margin-min="20" :margin-max="28"> - <div class="_gaps_m"> - <img :src="`/emoji/${emoji.name}.webp`" :class="$style.img"/> - <MkInput v-model="name"> - <template #label>{{ i18n.ts.name }}</template> - </MkInput> - <MkInput v-model="category" :datalist="customEmojiCategories"> - <template #label>{{ i18n.ts.category }}</template> - </MkInput> - <MkInput v-model="aliases"> - <template #label>{{ i18n.ts.tags }}</template> - <template #caption>{{ i18n.ts.setMultipleBySeparatingWithSpace }}</template> - </MkInput> - <MkInput v-model="license"> - <template #label>{{ i18n.ts.license }}</template> - </MkInput> - <MkButton danger @click="del()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> + <div> + <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_gaps_m"> + <div v-if="imgUrl != null" :class="$style.imgs"> + <div style="background: #000;" :class="$style.imgContainer"> + <img :src="imgUrl" :class="$style.img"/> + </div> + <div style="background: #222;" :class="$style.imgContainer"> + <img :src="imgUrl" :class="$style.img"/> + </div> + <div style="background: #ddd;" :class="$style.imgContainer"> + <img :src="imgUrl" :class="$style.img"/> + </div> + <div style="background: #fff;" :class="$style.imgContainer"> + <img :src="imgUrl" :class="$style.img"/> + </div> + </div> + <MkButton rounded style="margin: 0 auto;" @click="changeImage">{{ i18n.ts.selectFile }}</MkButton> + <MkInput v-model="name"> + <template #label>{{ i18n.ts.name }}</template> + </MkInput> + <MkInput v-model="category" :datalist="customEmojiCategories"> + <template #label>{{ i18n.ts.category }}</template> + </MkInput> + <MkInput v-model="aliases"> + <template #label>{{ i18n.ts.tags }}</template> + <template #caption>{{ i18n.ts.setMultipleBySeparatingWithSpace }}</template> + </MkInput> + <MkInput v-model="license"> + <template #label>{{ i18n.ts.license }}</template> + </MkInput> + <MkFolder> + <template #label>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReaction }}</template> + <div class="_gaps"> + <MkInfo>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription }}</MkInfo> + + <MkButton rounded @click="addRole"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> + + <div v-for="role in rolesThatCanBeUsedThisEmojiAsReaction" :key="role.id" :class="$style.roleItem"> + <MkRolePreview :class="$style.role" :role="role" :forModeration="true" :detailed="false"/> + <button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="removeRole(role, $event)"><i class="ti ti-x"></i></button> + <button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button> + </div> + </div> + </MkFolder> + <MkSwitch v-model="isSensitive">isSensitive</MkSwitch> + <MkSwitch v-model="localOnly">{{ i18n.ts.localOnly }}</MkSwitch> + <MkButton danger @click="del()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> + </div> + </MkSpacer> + <div :class="$style.footer"> + <MkButton primary rounded style="margin: 0 auto;" @click="done"><i class="ti ti-check"></i> {{ props.emoji ? i18n.ts.update : i18n.ts.create }}</MkButton> </div> - </MkSpacer> + </div> </MkModalWindow> </template> <script lang="ts" setup> -import { } from 'vue'; +import { computed, watch } from 'vue'; import MkModalWindow from '@/components/MkModalWindow.vue'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; +import MkInfo from '@/components/MkInfo.vue'; +import MkFolder from '@/components/MkFolder.vue'; import * as os from '@/os'; import { i18n } from '@/i18n'; import { customEmojiCategories } from '@/custom-emojis'; +import MkSwitch from '@/components/MkSwitch.vue'; +import { selectFile, selectFiles } from '@/scripts/select-file'; +import MkRolePreview from '@/components/MkRolePreview.vue'; const props = defineProps<{ - emoji: any, + emoji?: any, }>(); let dialog = $ref(null); -let name: string = $ref(props.emoji.name); -let category: string = $ref(props.emoji.category); -let aliases: string = $ref(props.emoji.aliases.join(' ')); -let license: string = $ref(props.emoji.license ?? ''); +let name: string = $ref(props.emoji ? props.emoji.name : ''); +let category: string = $ref(props.emoji ? props.emoji.category : ''); +let aliases: string = $ref(props.emoji ? props.emoji.aliases.join(' ') : ''); +let license: string = $ref(props.emoji ? (props.emoji.license ?? '') : ''); +let isSensitive = $ref(props.emoji ? props.emoji.isSensitive : false); +let localOnly = $ref(props.emoji ? props.emoji.localOnly : false); +let roleIdsThatCanBeUsedThisEmojiAsReaction = $ref(props.emoji ? props.emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : []); +let rolesThatCanBeUsedThisEmojiAsReaction = $ref([]); +let file = $ref(); + +watch($$(roleIdsThatCanBeUsedThisEmojiAsReaction), async () => { + rolesThatCanBeUsedThisEmojiAsReaction = (await Promise.all(roleIdsThatCanBeUsedThisEmojiAsReaction.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null); +}, { immediate: true }); + +const imgUrl = computed(() => file ? file.url : props.emoji ? `/emoji/${props.emoji.name}.webp` : null); const emit = defineEmits<{ - (ev: 'done', v: { deleted?: boolean, updated?: any }): void, + (ev: 'done', v: { deleted?: boolean; updated?: any; created?: any }): void, (ev: 'closed'): void }>(); -function ok() { - update(); +async function changeImage(ev) { + file = await selectFile(ev.currentTarget ?? ev.target, null); } -async function update() { - await os.apiWithDialog('admin/emoji/update', { - id: props.emoji.id, +async function addRole() { + const roles = await os.api('admin/roles/list'); + const currentRoleIds = rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id); + + const { canceled, result: role } = await os.select({ + items: roles.filter(r => !currentRoleIds.includes(r.id)).map(r => ({ text: r.name, value: r })), + }); + if (canceled) return; + + rolesThatCanBeUsedThisEmojiAsReaction.push(role); +} + +async function removeRole(role, ev) { + rolesThatCanBeUsedThisEmojiAsReaction = rolesThatCanBeUsedThisEmojiAsReaction.filter(x => x.id !== role.id); +} + +async function done() { + const params = { name, category, aliases: aliases.split(' '), license: license === '' ? null : license, - }); + isSensitive, + localOnly, + roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id), + }; - emit('done', { - updated: { + if (file) { + params.fileId = file.id; + } + + if (props.emoji) { + await os.apiWithDialog('admin/emoji/update', { id: props.emoji.id, - name, - category, - aliases: aliases.split(' '), - license: license === '' ? null : license, - }, - }); + ...params, + }); - dialog.close(); + emit('done', { + updated: { + id: props.emoji.id, + ...params, + }, + }); + + dialog.close(); + } else { + const created = await os.apiWithDialog('admin/emoji/add', params); + + emit('done', { + created: created, + }); + + dialog.close(); + } } async function del() { @@ -100,9 +184,47 @@ async function del() { </script> <style lang="scss" module> +.imgs { + display: flex; + gap: 8px; + flex-wrap: wrap; + justify-content: center; +} + +.imgContainer { + padding: 8px; + border-radius: 6px; +} + .img { display: block; height: 64px; - margin: 0 auto; + width: 64px; + object-fit: contain; +} + +.roleItem { + display: flex; +} + +.role { + flex: 1; +} + +.roleUnassign { + width: 32px; + height: 32px; + margin-left: 8px; + align-self: center; +} + +.footer { + position: sticky; + bottom: 0; + left: 0; + padding: 12px; + border-top: solid 0.5px var(--divider); + -webkit-backdrop-filter: var(--blur, blur(15px)); + backdrop-filter: var(--blur, blur(15px)); } </style> From db1098a18055e329eb4ebcddb64fabc1c9730dfc Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 18 May 2023 18:48:35 +0900 Subject: [PATCH 041/213] =?UTF-8?q?feat(backend):=20=E3=82=AB=E3=82=B9?= =?UTF-8?q?=E3=82=BF=E3=83=A0=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=94=E3=81=A8?= =?UTF-8?q?=E3=81=AB=E9=80=A3=E5=90=88=E3=81=99=E3=82=8B=E3=81=8B=E3=81=A9?= =?UTF-8?q?=E3=81=86=E3=81=8B=E8=A8=AD=E5=AE=9A=E3=81=A7=E3=81=8D=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + packages/backend/src/core/activitypub/ApRendererService.ts | 6 +++--- packages/backend/src/server/ActivityPubServerService.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b6fefc8d7..6465223203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ ### General - カスタム絵文字ごとにそれをリアクションとして使えるロールを設定できるように +- カスタム絵文字ごとに連合するかどうか設定できるように - タイムラインにフォロイーの行った他人へのリプライを含めるかどうかの設定をアカウントに保存するのをやめるように - 今後はAPI呼び出し時およびストリーミング接続時に設定するようになります diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 60e19bfca5..d8b95ca4d1 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -277,7 +277,7 @@ export class ApRendererService { const name = reaction.replaceAll(':', ''); const emoji = (await this.customEmojiService.localEmojisCache.fetch()).get(name); - if (emoji) object.tag = [this.renderEmoji(emoji)]; + if (emoji && !emoji.localOnly) object.tag = [this.renderEmoji(emoji)]; } return object; @@ -400,7 +400,7 @@ export class ApRendererService { })); const emojis = await this.getEmojis(note.emojis); - const apemojis = emojis.map(emoji => this.renderEmoji(emoji)); + const apemojis = emojis.filter(emoji => !emoji.localOnly).map(emoji => this.renderEmoji(emoji)); const tag = [ ...hashtagTags, @@ -479,7 +479,7 @@ export class ApRendererService { } const emojis = await this.getEmojis(user.emojis); - const apemojis = emojis.map(emoji => this.renderEmoji(emoji)); + const apemojis = emojis.filter(emoji => !emoji.localOnly).map(emoji => this.renderEmoji(emoji)); const hashtagTags = (user.tags ?? []).map(tag => this.renderHashtag(tag)); diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index e675d9cf1b..455acd1e47 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -585,7 +585,7 @@ export class ActivityPubServerService { name: request.params.emoji, }); - if (emoji == null) { + if (emoji == null || emoji.localOnly) { reply.code(404); return; } From 231506772a47cdab965c686d9fb670a0dbd1a73e Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 18 May 2023 20:17:32 +0900 Subject: [PATCH 042/213] tweak of 7ce569424 --- locales/ja-JP.yml | 1 + .../src/core/entities/EmojiEntityService.ts | 3 +- .../backend/src/models/json-schema/emoji.ts | 11 ++- packages/frontend/src/account.ts | 84 ++++++++++--------- .../frontend/src/components/MkEmojiPicker.vue | 11 ++- .../frontend/src/pages/emoji-edit-dialog.vue | 13 +-- 6 files changed, 73 insertions(+), 50 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f49f9c5a3c..94c00bad39 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1052,6 +1052,7 @@ failedToPreviewUrl: "プレビューできません" update: "更新" rolesThatCanBeUsedThisEmojiAsReaction: "リアクションとして使えるロール" rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールの指定が一つもない場合、誰でもリアクションとして使えます。" +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロールである必要があります。" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/backend/src/core/entities/EmojiEntityService.ts b/packages/backend/src/core/entities/EmojiEntityService.ts index 0c7bd9ed9a..4a18cd1b3b 100644 --- a/packages/backend/src/core/entities/EmojiEntityService.ts +++ b/packages/backend/src/core/entities/EmojiEntityService.ts @@ -26,7 +26,8 @@ export class EmojiEntityService { category: emoji.category, // || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ) url: emoji.publicUrl || emoji.originalUrl, - isSensitive: emoji.isSensitive, + isSensitive: emoji.isSensitive ? true : undefined, + roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length > 0 ? emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : undefined, }; } diff --git a/packages/backend/src/models/json-schema/emoji.ts b/packages/backend/src/models/json-schema/emoji.ts index c59b5d1ef4..63f56e77cb 100644 --- a/packages/backend/src/models/json-schema/emoji.ts +++ b/packages/backend/src/models/json-schema/emoji.ts @@ -24,7 +24,16 @@ export const packedEmojiSimpleSchema = { }, isSensitive: { type: 'boolean', - optional: false, nullable: false, + optional: true, nullable: false, + }, + roleIdsThatCanBeUsedThisEmojiAsReaction: { + type: 'array', + optional: true, nullable: false, + items: { + type: 'string', + optional: false, nullable: false, + format: 'id', + }, }, }, } as const; diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index 9b104391d7..4770f616ac 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -3,11 +3,11 @@ import * as misskey from 'misskey-js'; import { showSuspendedDialog } from './scripts/show-suspended-dialog'; import { i18n } from './i18n'; import { miLocalStorage } from './local-storage'; +import { MenuButton } from './types/menu'; import { del, get, set } from '@/scripts/idb-proxy'; import { apiUrl } from '@/config'; import { waiting, api, popup, popupMenu, success, alert } from '@/os'; import { unisonReload, reloadChannel } from '@/scripts/unison-reload'; -import { MenuButton } from './types/menu'; // TODO: 他のタブと永続化されたstateを同期 @@ -101,57 +101,57 @@ function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Pr 'Content-Type': 'application/json', }, }) - .then(res => new Promise<Account | { error: Record<string, any> }>((done2, fail2) => { - if (res.status >= 500 && res.status < 600) { + .then(res => new Promise<Account | { error: Record<string, any> }>((done2, fail2) => { + if (res.status >= 500 && res.status < 600) { // サーバーエラー(5xx)の場合をrejectとする // (認証エラーなど4xxはresolve) - return fail2(res); - } - res.json().then(done2, fail2); - })) - .then(async res => { - if (res.error) { - if (res.error.id === 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370') { + return fail2(res); + } + res.json().then(done2, fail2); + })) + .then(async res => { + if (res.error) { + if (res.error.id === 'a8c724b3-6e9c-4b46-b1a8-bc3ed6258370') { // SUSPENDED - if (forceShowDialog || $i && (token === $i.token || id === $i.id)) { - await showSuspendedDialog(); - } - } else if (res.error.id === 'e5b3b9f0-2b8f-4b9f-9c1f-8c5c1b2e1b1a') { + if (forceShowDialog || $i && (token === $i.token || id === $i.id)) { + await showSuspendedDialog(); + } + } else if (res.error.id === 'e5b3b9f0-2b8f-4b9f-9c1f-8c5c1b2e1b1a') { // USER_IS_DELETED // アカウントが削除されている - if (forceShowDialog || $i && (token === $i.token || id === $i.id)) { - await alert({ - type: 'error', - title: i18n.ts.accountDeleted, - text: i18n.ts.accountDeletedDescription, - }); - } - } else if (res.error.id === 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14') { + if (forceShowDialog || $i && (token === $i.token || id === $i.id)) { + await alert({ + type: 'error', + title: i18n.ts.accountDeleted, + text: i18n.ts.accountDeletedDescription, + }); + } + } else if (res.error.id === 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14') { // AUTHENTICATION_FAILED // トークンが無効化されていたりアカウントが削除されたりしている - if (forceShowDialog || $i && (token === $i.token || id === $i.id)) { + if (forceShowDialog || $i && (token === $i.token || id === $i.id)) { + await alert({ + type: 'error', + title: i18n.ts.tokenRevoked, + text: i18n.ts.tokenRevokedDescription, + }); + } + } else { await alert({ type: 'error', - title: i18n.ts.tokenRevoked, - text: i18n.ts.tokenRevokedDescription, + title: i18n.ts.failedToFetchAccountInformation, + text: JSON.stringify(res.error), }); } - } else { - await alert({ - type: 'error', - title: i18n.ts.failedToFetchAccountInformation, - text: JSON.stringify(res.error), - }); - } - // rejectかつ理由がtrueの場合、削除対象であることを示す - fail(true); - } else { - (res as Account).token = token; - done(res as Account); - } - }) - .catch(fail); + // rejectかつ理由がtrueの場合、削除対象であることを示す + fail(true); + } else { + (res as Account).token = token; + done(res as Account); + } + }) + .catch(fail); }); } @@ -305,3 +305,7 @@ export async function openAccountMenu(opts: { }); } } + +if (_DEV_) { + (window as any).$i = $i; +} diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index 9eaf16374b..093a1ec6d4 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -69,8 +69,8 @@ <XSection v-for="category in customEmojiCategories" :key="`custom:${category}`" - :initial-shown="false" - :emojis="computed(() => customEmojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === category).map(e => `:${e.name}:`))" + :initialShown="false" + :emojis="computed(() => customEmojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === category).filter(filterAvailable).map(e => `:${e.name}:`))" @chosen="chosen" > {{ category || i18n.ts.other }} @@ -102,6 +102,7 @@ import { deviceKind } from '@/scripts/device-kind'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; import { customEmojiCategories, customEmojis } from '@/custom-emojis'; +import { $i } from '@/account'; const props = withDefaults(defineProps<{ showPinned?: boolean; @@ -274,10 +275,14 @@ watch(q, () => { return matches; }; - searchResultCustom.value = Array.from(searchCustom()); + searchResultCustom.value = Array.from(searchCustom()).filter(filterAvailable); searchResultUnicode.value = Array.from(searchUnicode()); }); +function filterAvailable(emoji: Misskey.entities.CustomEmoji): boolean { + return (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction == null || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id))); +} + function focus() { if (!['smartphone', 'tablet'].includes(deviceKind) && !isTouchUsing) { searchEl.value?.focus({ diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue index 24b72b6f7f..e36a26638f 100644 --- a/packages/frontend/src/pages/emoji-edit-dialog.vue +++ b/packages/frontend/src/pages/emoji-edit-dialog.vue @@ -41,16 +41,19 @@ </MkInput> <MkFolder> <template #label>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReaction }}</template> - <div class="_gaps"> - <MkInfo>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription }}</MkInfo> + <template #suffix>{{ rolesThatCanBeUsedThisEmojiAsReaction.length === 0 ? i18n.ts.all : rolesThatCanBeUsedThisEmojiAsReaction.length }}</template> + <div class="_gaps"> <MkButton rounded @click="addRole"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> <div v-for="role in rolesThatCanBeUsedThisEmojiAsReaction" :key="role.id" :class="$style.roleItem"> - <MkRolePreview :class="$style.role" :role="role" :forModeration="true" :detailed="false"/> + <MkRolePreview :class="$style.role" :role="role" :forModeration="true" :detailed="false" style="pointer-events: none;"/> <button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="removeRole(role, $event)"><i class="ti ti-x"></i></button> <button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button> </div> + + <MkInfo>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription }}</MkInfo> + <MkInfo warn>{{ i18n.ts.rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn }}</MkInfo> </div> </MkFolder> <MkSwitch v-model="isSensitive">isSensitive</MkSwitch> @@ -128,8 +131,8 @@ async function removeRole(role, ev) { async function done() { const params = { name, - category, - aliases: aliases.split(' '), + category: category === '' ? null : category, + aliases: aliases.split(' ').filter(x => x !== ''), license: license === '' ? null : license, isSensitive, localOnly, From e3f91446082c1bf17dbda363fb106641729a5c3d Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 18 May 2023 20:29:13 +0900 Subject: [PATCH 043/213] 13.13.0-beta.1 --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6465223203..62f37763f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ --> -## 13.x.x (unreleased) +## 13.13.0 ### General - カスタム絵文字ごとにそれをリアクションとして使えるロールを設定できるように diff --git a/package.json b/package.json index a21d7ab9e3..cc1e2e62e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.12.2", + "version": "13.13.0-beta.1", "codename": "nasubi", "repository": { "type": "git", From a3423bad601ae3577129e4d4c88afb659569af31 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 09:14:54 +0900 Subject: [PATCH 044/213] tweak --- packages/frontend/src/pages/emoji-edit-dialog.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/emoji-edit-dialog.vue b/packages/frontend/src/pages/emoji-edit-dialog.vue index e36a26638f..3208c92738 100644 --- a/packages/frontend/src/pages/emoji-edit-dialog.vue +++ b/packages/frontend/src/pages/emoji-edit-dialog.vue @@ -117,7 +117,7 @@ async function addRole() { const currentRoleIds = rolesThatCanBeUsedThisEmojiAsReaction.map(x => x.id); const { canceled, result: role } = await os.select({ - items: roles.filter(r => !currentRoleIds.includes(r.id)).map(r => ({ text: r.name, value: r })), + items: roles.filter(r => r.isPublic).filter(r => !currentRoleIds.includes(r.id)).map(r => ({ text: r.name, value: r })), }); if (canceled) return; From 527a13b77db229894e12c99ccb29a8ae06cfe898 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 09:15:24 +0900 Subject: [PATCH 045/213] =?UTF-8?q?enhance(frontend):=20=E3=83=AA=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E3=81=AE=E5=8F=96=E3=82=8A?= =?UTF-8?q?=E6=B6=88=E3=81=97/=E5=A4=89=E6=9B=B4=E6=99=82=E3=81=AB?= =?UTF-8?q?=E7=A2=BA=E8=AA=8D=E3=83=80=E3=82=A4=E3=82=A2=E3=83=AD=E3=82=B0?= =?UTF-8?q?=E3=82=92=E5=87=BA=E3=81=99=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + locales/ja-JP.yml | 2 ++ .../components/MkReactionsViewer.reaction.vue | 17 ++++++++++++----- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62f37763f9..d9ce5fbe6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - 今後はAPI呼び出し時およびストリーミング接続時に設定するようになります ### Client +- リアクションの取り消し/変更時に確認ダイアログを出すように - 開発者モードを追加 - AiScriptを0.13.3に更新 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 94c00bad39..4067155a33 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1053,6 +1053,8 @@ update: "更新" rolesThatCanBeUsedThisEmojiAsReaction: "リアクションとして使えるロール" rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールの指定が一つもない場合、誰でもリアクションとして使えます。" rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロールである必要があります。" +cancelReactionConfirm: "リアクションを取り消しますか?" +changeReactionConfirm: "リアクションを変更しますか?" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index 9480af5102..b521171b2a 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -6,7 +6,7 @@ :class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: canToggle, [$style.large]: defaultStore.state.largeNoteReactions }]" @click="toggleReaction()" > - <MkReactionIcon :class="$style.icon" :reaction="reaction" :emoji-url="note.reactionEmojis[reaction.substr(1, reaction.length - 2)]"/> + <MkReactionIcon :class="$style.icon" :reaction="reaction" :emojiUrl="note.reactionEmojis[reaction.substr(1, reaction.length - 2)]"/> <span :class="$style.count">{{ count }}</span> </button> </template> @@ -22,6 +22,7 @@ import { $i } from '@/account'; import MkReactionEffect from '@/components/MkReactionEffect.vue'; import { claimAchievement } from '@/scripts/achievements'; import { defaultStore } from '@/store'; +import { i18n } from '@/i18n'; const props = defineProps<{ reaction: string; @@ -34,11 +35,17 @@ const buttonEl = shallowRef<HTMLElement>(); const canToggle = computed(() => !props.reaction.match(/@\w/) && $i); -const toggleReaction = () => { +async function toggleReaction() { if (!canToggle.value) return; const oldReaction = props.note.myReaction; if (oldReaction) { + const confirm = await os.confirm({ + type: 'warning', + text: oldReaction !== props.reaction ? i18n.ts.changeReactionConfirm : i18n.ts.cancelReactionConfirm, + }); + if (confirm.canceled) return; + os.api('notes/reactions/delete', { noteId: props.note.id, }).then(() => { @@ -58,9 +65,9 @@ const toggleReaction = () => { claimAchievement('reactWithoutRead'); } } -}; +} -const anime = () => { +function anime() { if (document.hidden) return; if (!defaultStore.state.animation) return; @@ -68,7 +75,7 @@ const anime = () => { const x = rect.left + 16; const y = rect.top + (buttonEl.value.offsetHeight / 2); os.popup(MkReactionEffect, { reaction: props.reaction, x, y }, {}, 'end'); -}; +} watch(() => props.count, (newCount, oldCount) => { if (oldCount < newCount) anime(); From 3804c6e7ad8c08f87e99d7e68a7d5c0e8af68dfa Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 09:43:38 +0900 Subject: [PATCH 046/213] =?UTF-8?q?feat:=20=E3=82=BB=E3=83=B3=E3=82=B7?= =?UTF-8?q?=E3=83=86=E3=82=A3=E3=83=96=E3=81=AA=E3=82=AB=E3=82=B9=E3=82=BF?= =?UTF-8?q?=E3=83=A0=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=AE=E3=83=AA=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E5=8F=97=E3=81=91?= =?UTF-8?q?=E5=85=A5=E3=82=8C=E3=81=AA=E3=81=84=E8=A8=AD=E5=AE=9A=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ locales/ja-JP.yml | 4 +++- packages/backend/src/core/ReactionService.ts | 7 ++++++- packages/backend/src/models/entities/Note.ts | 2 +- .../src/server/api/endpoints/notes/create.ts | 2 +- packages/frontend/src/components/MkPostForm.vue | 6 ++++-- packages/frontend/src/pages/settings/profile.vue | 16 +++++++++------- packages/frontend/src/store.ts | 2 +- 8 files changed, 27 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9ce5fbe6c..03b1bb4e29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ ### General - カスタム絵文字ごとにそれをリアクションとして使えるロールを設定できるように - カスタム絵文字ごとに連合するかどうか設定できるように +- カスタム絵文字ごとにセンシティブフラグを設定できるように +- センシティブなカスタム絵文字のリアクションを受け入れない設定が可能に - タイムラインにフォロイーの行った他人へのリプライを含めるかどうかの設定をアカウントに保存するのをやめるように - 今後はAPI呼び出し時およびストリーミング接続時に設定するようになります diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4067155a33..374eeba390 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -990,7 +990,9 @@ postToTheChannel: "チャンネルに投稿" cannotBeChangedLater: "後から変更できません。" reactionAcceptance: "リアクションの受け入れ" likeOnly: "いいねのみ" -likeOnlyForRemote: "リモートからはいいねのみ" +likeOnlyForRemote: "全て (リモートはいいねのみ)" +nonSensitiveOnly: "非センシティブのみ" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "非センシティブのみ (リモートはいいねのみ)" rolesAssignedToMe: "自分に割り当てられたロール" resetPasswordConfirm: "パスワードリセットしますか?" sensitiveWords: "センシティブワード" diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 27334b33e6..4b01b6af7e 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -106,7 +106,7 @@ export class ReactionService { let reaction = _reaction ?? FALLBACK; - if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote') && (user.host != null))) { + if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && (user.host != null))) { reaction = '❤️'; } else if (_reaction) { const custom = reaction.match(isCustomEmojiRegexp); @@ -124,6 +124,11 @@ export class ReactionService { if (emoji) { if (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0 || (await this.roleService.getUserRoles(user.id)).some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id))) { reaction = reacterHost ? `:${name}@${reacterHost}:` : `:${name}:`; + + // センシティブ + if ((note.reactionAcceptance === 'nonSensitiveOnly') && emoji.isSensitive) { + reaction = FALLBACK; + } } else { // リアクションとして使う権限がない reaction = FALLBACK; diff --git a/packages/backend/src/models/entities/Note.ts b/packages/backend/src/models/entities/Note.ts index df508b4dca..4f49a05950 100644 --- a/packages/backend/src/models/entities/Note.ts +++ b/packages/backend/src/models/entities/Note.ts @@ -90,7 +90,7 @@ export class Note { @Column('varchar', { length: 64, nullable: true, }) - public reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | null; + public reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null; @Column('smallint', { default: 0, diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 3f7f2cdece..96be5ed844 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -99,7 +99,7 @@ export const paramDef = { } }, cw: { type: 'string', nullable: true, maxLength: 100 }, localOnly: { type: 'boolean', default: false }, - reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote'], default: null }, + reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null }, noExtractMentions: { type: 'boolean', default: false }, noExtractHashtags: { type: 'boolean', default: false }, noExtractEmojis: { type: 'boolean', default: false }, diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index c65cb7d6e5..c43d353d9c 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -31,7 +31,7 @@ <span v-if="!localOnly"><i class="ti ti-rocket"></i></span> <span v-else><i class="ti ti-rocket-off"></i></span> </button> - <button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" :class="['_button', $style.headerRightItem, $style.reactionAcceptance, { [$style.danger]: reactionAcceptance }]" @click="toggleReactionAcceptance"> + <button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" :class="['_button', $style.headerRightItem, $style.reactionAcceptance, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance"> <span v-if="reactionAcceptance === 'likeOnly'"><i class="ti ti-heart"></i></span> <span v-else-if="reactionAcceptance === 'likeOnlyForRemote'"><i class="ti ti-heart-plus"></i></span> <span v-else><i class="ti ti-icons"></i></span> @@ -484,8 +484,10 @@ async function toggleReactionAcceptance() { title: i18n.ts.reactionAcceptance, items: [ { value: null, text: i18n.ts.all }, - { value: 'likeOnly' as const, text: i18n.ts.likeOnly }, { value: 'likeOnlyForRemote' as const, text: i18n.ts.likeOnlyForRemote }, + { value: 'nonSensitiveOnly' as const, text: i18n.ts.nonSensitiveOnly }, + { value: 'nonSensitiveOnlyForLocalLikeOnlyForRemote' as const, text: i18n.ts.nonSensitiveOnlyForLocalLikeOnlyForRemote }, + { value: 'likeOnly' as const, text: i18n.ts.likeOnly }, ], default: reactionAcceptance, }); diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 35af43d789..11e891b784 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -8,21 +8,21 @@ <MkButton primary rounded :class="$style.bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton> </div> - <MkInput v-model="profile.name" :max="30" manual-save> + <MkInput v-model="profile.name" :max="30" manualSave> <template #label>{{ i18n.ts._profile.name }}</template> </MkInput> - <MkTextarea v-model="profile.description" :max="500" tall manual-save> + <MkTextarea v-model="profile.description" :max="500" tall manualSave> <template #label>{{ i18n.ts._profile.description }}</template> <template #caption>{{ i18n.ts._profile.youCanIncludeHashtags }}</template> </MkTextarea> - <MkInput v-model="profile.location" manual-save> + <MkInput v-model="profile.location" manualSave> <template #label>{{ i18n.ts.location }}</template> <template #prefix><i class="ti ti-map-pin"></i></template> </MkInput> - <MkInput v-model="profile.birthday" type="date" manual-save> + <MkInput v-model="profile.birthday" type="date" manualSave> <template #label>{{ i18n.ts.birthday }}</template> <template #prefix><i class="ti ti-cake"></i></template> </MkInput> @@ -48,7 +48,7 @@ <Sortable v-model="fields" class="_gaps_s" - item-key="id" + itemKey="id" :animation="150" :handle="'.' + $style.dragItemHandle" @start="e => e.item.classList.add('active')" @@ -59,7 +59,7 @@ <button v-if="!fieldEditMode" class="_button" :class="$style.dragItemHandle" tabindex="-1"><i class="ti ti-menu"></i></button> <button v-if="fieldEditMode" :disabled="fields.length <= 1" class="_button" :class="$style.dragItemRemove" @click="deleteField(index)"><i class="ti ti-x"></i></button> <div :class="$style.dragItemForm"> - <FormSplit :min-width="200"> + <FormSplit :minWidth="200"> <MkInput v-model="element.name" small> <template #label>{{ i18n.ts._profile.metadataLabel }}</template> </MkInput> @@ -88,8 +88,10 @@ <MkSelect v-model="reactionAcceptance"> <template #label>{{ i18n.ts.reactionAcceptance }}</template> <option :value="null">{{ i18n.ts.all }}</option> - <option value="likeOnly">{{ i18n.ts.likeOnly }}</option> <option value="likeOnlyForRemote">{{ i18n.ts.likeOnlyForRemote }}</option> + <option value="nonSensitiveOnly">{{ i18n.ts.nonSensitiveOnly }}</option> + <option value="nonSensitiveOnlyForLocalLikeOnlyForRemote">{{ i18n.ts.nonSensitiveOnlyForLocalLikeOnlyForRemote }}</option> + <option value="likeOnly">{{ i18n.ts.likeOnly }}</option> </MkSelect> </div> </template> diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 0af4b5c021..aa4b98c05c 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -92,7 +92,7 @@ export const defaultStore = markRaw(new Storage('base', { }, reactionAcceptance: { where: 'account', - default: null as 'likeOnly' | 'likeOnlyForRemote' | null, + default: 'nonSensitiveOnly' as 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null, }, mutedWords: { where: 'account', From 59255e11b8989d1e4f60c222590d2918a61adb54 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Fri, 19 May 2023 09:44:06 +0900 Subject: [PATCH 047/213] =?UTF-8?q?perf:=20MkImgWithBlurhash=E3=81=A8MkMed?= =?UTF-8?q?iaImage=E3=82=92=E6=9C=80=E9=81=A9=E5=8C=96=20(#10782)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #10781 * fix tsconfig * fetch image?? * Revert "fetch image??" This reverts commit 0925c28d5a4f328264c39d5591dc736795541683. * wip * Revert "wip" This reverts commit be97c6cb88318bcea441edeeecb69b6d6ed0dd8f. * loading="eager" * loading="eager" 2 * error * wip * wip * wip * wip * clean up * fix * 生成するworkerを1つにする? * clean up * use buraha * wip * smaller width, height * update buraha * clean up * fix * Update MkMediaImage.vue * Update MkImgWithBlurhash.vue * Revert "fix(frontend): センシティブ設定された画像を開くとき一瞬レイアウトが崩れる問題を修正" This reverts commit 41e9aa6f9b03107518224e2ebde8889c64408204. * Update MkMediaList.vue * Update MkMediaList.vue * Update MkMediaList.vue * Update CHANGELOG.md * wait for decode * fix * ? * (test) remove container-type: inline-size; * Revert "(test) remove container-type: inline-size;" This reverts commit 9448e64228428175a3d624c04df1bfad0f59cb69. * container-name * Revert "container-name" This reverts commit 94385d32213a00a06a59fbd2296d6ef1b5f91785. * width: 100%; * improve performance * refactor * wip * WIP * wip * Revert "wip" This reverts commit 36e3b75cab8114e423544b79a8e2df353880f43b. * Revert "WIP" This reverts commit 05b729ef9189aea052ba411ac10f30a46cc668c8. * Revert "wip" This reverts commit 0801e7936116c58154d7cecfea955dd15fa61a77. * #10860 * wip * no worker * Revert "no worker" This reverts commit a9c49e4fb49976958a7594393343d52be0e082d7. * :v: * workerNumber固定は不要 --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> --- CHANGELOG.md | 1 + packages/frontend/package.json | 2 +- .../src/components/MkGalleryPostPreview.vue | 15 +- .../src/components/MkImgWithBlurhash.vue | 196 +++++++++++++----- .../frontend/src/components/MkMediaImage.vue | 55 +++-- .../frontend/src/components/MkMediaList.vue | 65 +++++- .../src/components/global/MkAvatar.vue | 3 +- .../frontend/src/pages/settings/general.vue | 3 +- .../src/scripts/worker-multi-dispatch.ts | 75 +++++++ .../frontend/src/workers/draw-blurhash.ts | 15 ++ packages/frontend/src/workers/test-webgl2.ts | 7 + packages/frontend/src/workers/tsconfig.json | 5 + packages/frontend/vite.config.ts | 4 + pnpm-lock.yaml | 12 +- 14 files changed, 367 insertions(+), 91 deletions(-) create mode 100644 packages/frontend/src/scripts/worker-multi-dispatch.ts create mode 100644 packages/frontend/src/workers/draw-blurhash.ts create mode 100644 packages/frontend/src/workers/test-webgl2.ts create mode 100644 packages/frontend/src/workers/tsconfig.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b1bb4e29..9729589632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,7 @@ Meilisearchの設定に`index`が必要になりました。値はMisskeyサー * 画像が全て隠れた状態で表示されるようになります - 閲覧注意設定された画像は表示した状態でもそれが閲覧注意だと分かる表示をするように - モデレーターはノートに添付された画像上から直接NSFW設定できるように +- 1枚だけのメディアリストの画像のアスペクト比を画像に応じて縦長にするように - プロフィール設定「追加情報」の項目の削除と並び替えができるように - 新しい実績を追加 - AiScriptを0.13.2に更新 diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 7e6c1442b1..2f754f8aa2 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -25,9 +25,9 @@ "@vue-macros/reactivity-transform": "0.3.7", "@vue/compiler-sfc": "3.3.2", "autosize": "6.0.1", - "blurhash": "2.0.5", "broadcast-channel": "4.20.2", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", + "buraha": "github:misskey-dev/buraha", "canvas-confetti": "1.6.0", "chart.js": "4.3.0", "chartjs-adapter-date-fns": "3.0.0", diff --git a/packages/frontend/src/components/MkGalleryPostPreview.vue b/packages/frontend/src/components/MkGalleryPostPreview.vue index 4f8f7b945a..fccc33dcc2 100644 --- a/packages/frontend/src/components/MkGalleryPostPreview.vue +++ b/packages/frontend/src/components/MkGalleryPostPreview.vue @@ -5,12 +5,9 @@ <ImgWithBlurhash class="img layered" :transition="safe ? null : { - enterActiveClass: $style.transition_toggle_enterActive, + duration: 500, leaveActiveClass: $style.transition_toggle_leaveActive, - enterFromClass: $style.transition_toggle_enterFrom, leaveToClass: $style.transition_toggle_leaveTo, - enterToClass: $style.transition_toggle_enterTo, - leaveFromClass: $style.transition_toggle_leaveFrom, }" :src="post.files[0].thumbnailUrl" :hash="post.files[0].blurhash" @@ -53,24 +50,16 @@ function leaveHover(): void { </script> <style lang="scss" module> -.transition_toggle_enterActive, .transition_toggle_leaveActive { - transition: opacity 0.5s; + transition: opacity .5s; position: absolute; top: 0; left: 0; } -.transition_toggle_enterFrom, .transition_toggle_leaveTo { opacity: 0; } - -.transition_toggle_enterTo, -.transition_toggle_leaveFrom { - transition: none; - opacity: 1; -} </style> <style lang="scss" scoped> diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 6406a35060..de14d9ea28 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -1,30 +1,56 @@ <template> -<div :class="[$style.root, { [$style.cover]: cover }]" :title="title ?? ''"> - <img v-if="!loaded && src && !forceBlurhash" :class="$style.loader" :src="src" @load="onLoad"/> - <Transition - mode="in-out" - :enter-active-class="defaultStore.state.animation && (props.transition?.enterActiveClass ?? $style['transition_toggle_enterActive']) || undefined" - :leave-active-class="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style['transition_toggle_leaveActive']) || undefined" +<div ref="root" :class="[$style.root, { [$style.cover]: cover }]" :title="title ?? ''"> + <TransitionGroup + :duration="defaultStore.state.animation && props.transition?.duration || undefined" + :enter-active-class="defaultStore.state.animation && props.transition?.enterActiveClass || undefined" + :leave-active-class="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style['transition_leaveActive']) || undefined" :enter-from-class="defaultStore.state.animation && props.transition?.enterFromClass || undefined" :leave-to-class="defaultStore.state.animation && props.transition?.leaveToClass || undefined" - :enter-to-class="defaultStore.state.animation && (props.transition?.enterToClass ?? $style['transition_toggle_enterTo']) || undefined" - :leave-from-class="defaultStore.state.animation && (props.transition?.leaveFromClass ?? $style['transition_toggle_leaveFrom']) || undefined" + :enter-to-class="defaultStore.state.animation && props.transition?.enterToClass || undefined" + :leave-from-class="defaultStore.state.animation && props.transition?.leaveFromClass || undefined" > - <canvas v-if="!loaded || forceBlurhash" ref="canvas" :class="$style.canvas" :width="width" :height="height" :title="title ?? undefined"/> - <img v-else :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined"/> - </Transition> + <canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined"/> + <img v-show="!hide" key="img" ref="img" :height="imgHeight" :width="imgWidth" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async"/> + </TransitionGroup> </div> </template> -<script lang="ts" setup> -import { onMounted, shallowRef, useCssModule, watch } from 'vue'; -import { decode } from 'blurhash'; -import { defaultStore } from '@/store'; +<script lang="ts"> +import DrawBlurhash from '@/workers/draw-blurhash?worker'; +import TestWebGL2 from '@/workers/test-webgl2?worker'; +import { WorkerMultiDispatch } from '@/scripts/worker-multi-dispatch'; +import { $ref } from 'vue/macros'; +import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; +const workerPromise = new Promise<WorkerMultiDispatch | null>(resolve => { + const testWorker = new TestWebGL2(); + testWorker.addEventListener('message', event => { + if (event.data.result) { + const workers = new WorkerMultiDispatch( + () => new DrawBlurhash(), + Math.min(navigator.hardwareConcurrency - 1, 4), + ); + resolve(workers); + if (_DEV_) console.log('WebGL2 in worker is supported!'); + } else { + resolve(null); + if (_DEV_) console.log('WebGL2 in worker is not supported...'); + } + testWorker.terminate(); + }); +}); +</script> + +<script lang="ts" setup> +import { computed, nextTick, onMounted, onUnmounted, shallowRef, useCssModule, watch } from 'vue'; +import { v4 as uuid } from 'uuid'; +import { render } from 'buraha'; +import { defaultStore } from '@/store'; const $style = useCssModule(); const props = withDefaults(defineProps<{ transition?: { + duration?: number | { enter: number; leave: number; }; enterActiveClass?: string; leaveActiveClass?: string; enterFromClass?: string; @@ -51,67 +77,141 @@ const props = withDefaults(defineProps<{ forceBlurhash: false, }); +const viewId = uuid(); const canvas = shallowRef<HTMLCanvasElement>(); +const root = shallowRef<HTMLDivElement>(); +const img = shallowRef<HTMLImageElement>(); let loaded = $ref(false); -let width = $ref(props.width); -let height = $ref(props.height); +let canvasWidth = $ref(64); +let canvasHeight = $ref(64); +let imgWidth = $ref(props.width); +let imgHeight = $ref(props.height); +let bitmapTmp = $ref<CanvasImageSource | undefined>(); +const hide = computed(() => !loaded || props.forceBlurhash); -function onLoad() { - loaded = true; +function waitForDecode() { + if (props.src != null && props.src !== '') { + nextTick() + .then(() => img.value?.decode()) + .then(() => { + loaded = true; + }, error => { + console.error('Error occured during decoding image', img.value, error); + throw Error(error); + }); + } else { + loaded = false; + } } -watch([() => props.width, () => props.height], () => { +watch([() => props.width, () => props.height, root], () => { const ratio = props.width / props.height; if (ratio > 1) { - width = Math.round(64 * ratio); - height = 64; + canvasWidth = Math.round(64 * ratio); + canvasHeight = 64; } else { - width = 64; - height = Math.round(64 / ratio); + canvasWidth = 64; + canvasHeight = Math.round(64 / ratio); } + + const clientWidth = root.value?.clientWidth ?? 300; + imgWidth = clientWidth; + imgHeight = Math.round(clientWidth / ratio); }, { immediate: true, }); -function draw() { - if (props.hash == null || !canvas.value) return; - const pixels = decode(props.hash, width, height); +function drawImage(bitmap: CanvasImageSource) { + // canvasがない(mountedされていない)場合はTmpに保存しておく + if (!canvas.value) { + bitmapTmp = bitmap; + return; + } + + // canvasがあれば描画する + bitmapTmp = undefined; const ctx = canvas.value.getContext('2d'); - const imageData = ctx!.createImageData(width, height); - imageData.data.set(pixels); - ctx!.putImageData(imageData, 0, 0); + if (!ctx) return; + ctx.drawImage(bitmap, 0, 0, canvasWidth, canvasHeight); } -watch([() => props.hash, canvas], () => { +async function draw() { + if (!canvas.value || props.hash == null) return; + + const ctx = canvas.value.getContext('2d'); + if (!ctx) return; + + // avgColorでお茶をにごす + ctx.beginPath(); + ctx.fillStyle = extractAvgColorFromBlurhash(props.hash) ?? '#888'; + ctx.fillRect(0, 0, canvasWidth, canvasHeight); + + const workers = await workerPromise; + if (workers) { + workers.postMessage( + { + id: viewId, + hash: props.hash, + width: canvasWidth, + height: canvasHeight, + }, + undefined, + ); + } else { + try { + const work = document.createElement('canvas'); + work.width = canvasWidth; + work.height = canvasHeight; + render(props.hash, work); + ctx.drawImage(work, 0, 0, canvasWidth, canvasHeight); + } catch (error) { + console.error('Error occured during drawing blurhash', error); + } + } +} + +function workerOnMessage(event: MessageEvent) { + if (event.data.id !== viewId) return; + drawImage(event.data.bitmap as ImageBitmap); +} + +workerPromise.then(worker => { + if (worker) { + worker.addListener(workerOnMessage); + } + + draw(); +}); + +watch(() => props.src, () => { + waitForDecode(); +}); + +watch(() => props.hash, () => { draw(); }); onMounted(() => { - draw(); + // drawImageがmountedより先に呼ばれている場合はここで描画する + if (bitmapTmp) { + drawImage(bitmapTmp); + } + waitForDecode(); +}); + +onUnmounted(() => { + workerPromise.then(worker => { + worker?.removeListener(workerOnMessage); + }); }); </script> <style lang="scss" module> -.transition_toggle_enterActive, -.transition_toggle_leaveActive { +.transition_leaveActive { position: absolute; top: 0; left: 0; } - -.transition_toggle_enterTo, -.transition_toggle_leaveFrom { - opacity: 0; -} - -.loader { - position: absolute; - top: 0; - left: 0; - width: 0; - height: 0; -} - .root { position: relative; width: 100%; diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index 42dc9e79ff..b235dd8bd5 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -1,29 +1,40 @@ <template> -<div v-if="hide" :class="$style.hidden" @click="hide = false"> - <ImgWithBlurhash style="filter: brightness(0.5);" :hash="image.blurhash" :title="image.comment" :alt="image.comment" :width="image.properties.width" :height="image.properties.height" :force-blurhash="defaultStore.state.enableDataSaverMode"/> - <div :class="$style.hiddenText"> - <div :class="$style.hiddenTextWrapper"> - <b v-if="image.isSensitive" style="display: block;"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.enableDataSaverMode ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }}</b> - <b v-else style="display: block;"><i class="ti ti-photo"></i> {{ defaultStore.state.enableDataSaverMode && image.size ? bytes(image.size) : i18n.ts.image }}</b> - <span style="display: block;">{{ i18n.ts.clickToShow }}</span> - </div> - </div> -</div> -<div v-else :class="$style.visible" :style="darkMode ? '--c: rgb(255 255 255 / 2%);' : '--c: rgb(0 0 0 / 2%);'"> +<div :class="hide ? $style.hidden : $style.visible" :style="darkMode ? '--c: rgb(255 255 255 / 2%);' : '--c: rgb(0 0 0 / 2%);'" @click="onclick"> <a :class="$style.imageContainer" :href="image.url" :title="image.name" > - <ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.comment || image.name" :title="image.comment || image.name" :width="image.properties.width" :height="image.properties.height" :cover="false"/> + <ImgWithBlurhash + :hash="image.blurhash" + :src="(defaultStore.state.enableDataSaverMode && hide) ? null : url" + :force-blurhash="hide" + :cover="hide" + :alt="image.comment || image.name" + :title="image.comment || image.name" + :width="image.properties.width" + :height="image.properties.height" + :style="hide ? 'filter: brightness(0.5);' : null" + /> </a> - <div :class="$style.indicators"> - <div v-if="['image/gif', 'image/apng'].includes(image.type)" :class="$style.indicator">GIF</div> - <div v-if="image.comment" :class="$style.indicator">ALT</div> - <div v-if="image.isSensitive" :class="$style.indicator" style="color: var(--warn);">NSFW</div> - </div> - <button v-tooltip="i18n.ts.hide" :class="$style.hide" class="_button" @click="hide = true"><i class="ti ti-eye-off"></i></button> - <button :class="$style.menu" class="_button" @click.stop="showMenu"><i class="ti ti-dots"></i></button> + <template v-if="hide"> + <div :class="$style.hiddenText"> + <div :class="$style.hiddenTextWrapper"> + <b v-if="image.isSensitive" style="display: block;"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.enableDataSaverMode ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }}</b> + <b v-else style="display: block;"><i class="ti ti-photo"></i> {{ defaultStore.state.enableDataSaverMode && image.size ? bytes(image.size) : i18n.ts.image }}</b> + <span style="display: block;">{{ i18n.ts.clickToShow }}</span> + </div> + </div> + </template> + <template v-else> + <div :class="$style.indicators"> + <div v-if="['image/gif', 'image/apng'].includes(image.type)" :class="$style.indicator">GIF</div> + <div v-if="image.comment" :class="$style.indicator">ALT</div> + <div v-if="image.isSensitive" :class="$style.indicator" style="color: var(--warn);">NSFW</div> + </div> + <button v-tooltip="i18n.ts.hide" :class="$style.hide" class="_button" @click.stop.prevent="hide = true"><i class="ti ti-eye-off"></i></button> + <button :class="$style.menu" class="_button" @click.stop="showMenu"><i class="ti ti-dots"></i></button> + </template> </div> </template> @@ -53,6 +64,12 @@ const url = $computed(() => (props.raw || defaultStore.state.loadRawImages) : props.image.thumbnailUrl, ); +function onclick() { + if (hide) { + hide = false; + } +} + // Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする watch(() => props.image, () => { hide = (defaultStore.state.nsfw === 'force' || defaultStore.state.enableDataSaverMode) ? true : (props.image.isSensitive && defaultStore.state.nsfw !== 'ignore'); diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue index e456ff3eec..0f41ef248f 100644 --- a/packages/frontend/src/components/MkMediaList.vue +++ b/packages/frontend/src/components/MkMediaList.vue @@ -7,6 +7,7 @@ :class="[ $style.medias, count <= 4 ? $style['n' + count] : $style.nMany, + $style[`n1${defaultStore.reactiveState.mediaListWithOneImageAppearance.value}`] ]" > <template v-for="media in mediaList.filter(media => previewable(media))"> @@ -19,7 +20,7 @@ </template> <script lang="ts" setup> -import { onMounted, ref, useCssModule, watch } from 'vue'; +import { onMounted, ref, useCssModule, watch, shallowRef } from 'vue'; import * as misskey from 'misskey-js'; import PhotoSwipeLightbox from 'photoswipe/lightbox'; import PhotoSwipe from 'photoswipe'; @@ -38,11 +39,42 @@ const props = defineProps<{ const $style = useCssModule(); -const gallery = ref<HTMLDivElement>(); +const gallery = shallowRef<HTMLDivElement>(); const pswpZIndex = os.claimZIndex('middle'); document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString()); const count = $computed(() => props.mediaList.filter(media => previewable(media)).length); +function calcAspectRatio() { + if (!gallery.value) return; + + let img = props.mediaList[0]; + + if (props.mediaList.length !== 1 || !(img.properties.width && img.properties.height)) { + gallery.value.style.aspectRatio = ''; + return; + } + + // アスペクト比上限設定では、横長の場合は高さを縮小させる + const ratioMax = (ratio: number) => `${Math.max(ratio, img.properties.width / img.properties.height).toString()} / 1`; + + switch (defaultStore.state.mediaListWithOneImageAppearance) { + case '16_9': + gallery.value.style.aspectRatio = ratioMax(16 / 9); + break; + case '1_1': + gallery.value.style.aspectRatio = ratioMax(1); + break; + case '2_3': + gallery.value.style.aspectRatio = ratioMax(2 / 3); + break; + default: + gallery.value.style.aspectRatio = ''; + break; + } +} + +watch([defaultStore.reactiveState.mediaListWithOneImageAppearance, gallery], () => calcAspectRatio()); + onMounted(() => { const lightbox = new PhotoSwipeLightbox({ dataSource: props.mediaList @@ -162,12 +194,37 @@ const previewable = (file: misskey.entities.DriveFile): boolean => { display: grid; grid-gap: 8px; - // for webkit height: 100%; + width: 100%; &.n1 { - aspect-ratio: 16/9; grid-template-rows: 1fr; + + // default (expand) + min-height: 64px; + max-height: clamp( + 64px, + 50cqh, + min(360px, 50vh) + ); + + &.n116_9 { + min-height: none; + max-height: none; + aspect-ratio: 16 / 9; // fallback + } + + &.n11_1{ + min-height: none; + max-height: none; + aspect-ratio: 1 / 1; // fallback + } + + &.n12_3 { + min-height: none; + max-height: none; + aspect-ratio: 2 / 3; // fallback + } } &.n2 { diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index 42abdcbdcc..df26ca3171 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -1,6 +1,6 @@ <template> <component :is="link ? MkA : 'span'" v-user-preview="preview ? user.id : undefined" v-bind="bound" class="_noSelect" :class="[$style.root, { [$style.animation]: animation, [$style.cat]: user.isCat, [$style.square]: squareAvatars }]" :style="{ color }" :title="acct(user)" @click="onClick"> - <img :class="$style.inner" :src="url" decoding="async"/> + <MkImgWithBlurhash :class="$style.inner" :src="url" :hash="user?.avatarBlurhash" :cover="true"/> <MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/> <div v-if="user.isCat" :class="[$style.ears]"> <div :class="$style.earLeft"> @@ -30,6 +30,7 @@ import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-bl import { acct, userPage } from '@/filters/user'; import MkUserOnlineIndicator from '@/components/MkUserOnlineIndicator.vue'; import { defaultStore } from '@/store'; +import MkImgWithBlurhash from '../MkImgWithBlurhash.vue'; const animation = $ref(defaultStore.state.animation); const squareAvatars = $ref(defaultStore.state.squareAvatars); diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 0dfc847049..9d06d35e60 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -56,7 +56,7 @@ <option value="ignore">{{ i18n.ts._nsfw.ignore }}</option> <option value="force">{{ i18n.ts._nsfw.force }}</option> </MkSelect> - <!-- + <MkRadios v-model="mediaListWithOneImageAppearance"> <template #label>{{ i18n.ts.mediaListWithOneImageAppearance }}</template> <option value="expand">{{ i18n.ts.default }}</option> @@ -64,7 +64,6 @@ <option value="1_1">{{ i18n.t('limitTo', { x: '1:1' }) }}</option> <option value="2_3">{{ i18n.t('limitTo', { x: '2:3' }) }}</option> </MkRadios> - --> </div> </FormSection> diff --git a/packages/frontend/src/scripts/worker-multi-dispatch.ts b/packages/frontend/src/scripts/worker-multi-dispatch.ts new file mode 100644 index 0000000000..1847a8ccff --- /dev/null +++ b/packages/frontend/src/scripts/worker-multi-dispatch.ts @@ -0,0 +1,75 @@ +function defaultUseWorkerNumber(prev: number, totalWorkers: number) { + return prev + 1; +} + +export class WorkerMultiDispatch<POST = any, RETURN = any> { + private symbol = Symbol('WorkerMultiDispatch'); + private workers: Worker[] = []; + private terminated = false; + private prevWorkerNumber = 0; + private getUseWorkerNumber = defaultUseWorkerNumber; + private finalizationRegistry: FinalizationRegistry<symbol>; + + constructor(workerConstructor: () => Worker, concurrency: number, getUseWorkerNumber = defaultUseWorkerNumber) { + this.getUseWorkerNumber = getUseWorkerNumber; + for (let i = 0; i < concurrency; i++) { + this.workers.push(workerConstructor()); + } + + this.finalizationRegistry = new FinalizationRegistry(() => { + this.terminate(); + }); + this.finalizationRegistry.register(this, this.symbol); + + if (_DEV_) console.log('WorkerMultiDispatch: Created', this); + } + + public postMessage(message: POST, options?: Transferable[] | StructuredSerializeOptions, useWorkerNumber: typeof defaultUseWorkerNumber = this.getUseWorkerNumber) { + let workerNumber = useWorkerNumber(this.prevWorkerNumber, this.workers.length); + workerNumber = Math.abs(Math.round(workerNumber)) % this.workers.length; + if (_DEV_) console.log('WorkerMultiDispatch: Posting message to worker', workerNumber, useWorkerNumber); + this.prevWorkerNumber = workerNumber; + + // 不毛だがunionをoverloadに突っ込めない + // https://stackoverflow.com/questions/66507585/overload-signatures-union-types-and-no-overload-matches-this-call-error + // https://github.com/microsoft/TypeScript/issues/14107 + if (Array.isArray(options)) { + this.workers[workerNumber].postMessage(message, options); + } else { + this.workers[workerNumber].postMessage(message, options); + } + return workerNumber; + } + + public addListener(callback: (this: Worker, ev: MessageEvent<RETURN>) => any, options?: boolean | AddEventListenerOptions) { + this.workers.forEach(worker => { + worker.addEventListener('message', callback, options); + }); + } + + public removeListener(callback: (this: Worker, ev: MessageEvent<RETURN>) => any, options?: boolean | AddEventListenerOptions) { + this.workers.forEach(worker => { + worker.removeEventListener('message', callback, options); + }); + } + + public terminate() { + this.terminated = true; + if (_DEV_) console.log('WorkerMultiDispatch: Terminating', this); + this.workers.forEach(worker => { + worker.terminate(); + }); + this.workers = []; + this.finalizationRegistry.unregister(this); + } + + public isTerminated() { + return this.terminated; + } + public getWorkers() { + return this.workers; + } + public getSymbol() { + return this.symbol; + } +} diff --git a/packages/frontend/src/workers/draw-blurhash.ts b/packages/frontend/src/workers/draw-blurhash.ts new file mode 100644 index 0000000000..5f2168a44a --- /dev/null +++ b/packages/frontend/src/workers/draw-blurhash.ts @@ -0,0 +1,15 @@ +import { render } from 'buraha'; + +onmessage = (event) => { + // console.log(event.data); + if (!('id' in event.data && typeof event.data.id === 'string')) { + return; + } + if (!('hash' in event.data && typeof event.data.hash === 'string')) { + return; + } + const work = new OffscreenCanvas(event.data.width ?? 64, event.data.height ?? 64); + render(event.data.hash, work); + const bitmap = work.transferToImageBitmap(); + postMessage({ id: event.data.id, bitmap }); +}; diff --git a/packages/frontend/src/workers/test-webgl2.ts b/packages/frontend/src/workers/test-webgl2.ts new file mode 100644 index 0000000000..4769524d9c --- /dev/null +++ b/packages/frontend/src/workers/test-webgl2.ts @@ -0,0 +1,7 @@ +const canvas = new OffscreenCanvas(1, 1); +const gl = canvas.getContext('webgl2'); +if (gl) { + postMessage({ result: true }); +} else { + postMessage({ result: false }); +} diff --git a/packages/frontend/src/workers/tsconfig.json b/packages/frontend/src/workers/tsconfig.json new file mode 100644 index 0000000000..8ee8930465 --- /dev/null +++ b/packages/frontend/src/workers/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "lib": ["esnext", "webworker"], + } +} diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 339761e78c..3de9f9bdba 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -139,6 +139,10 @@ export function getConfig(): UserConfig { }, }, + worker: { + format: 'es', + }, + test: { environment: 'happy-dom', deps: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f98ed0f654..d5217b71fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -657,15 +657,15 @@ importers: autosize: specifier: 6.0.1 version: 6.0.1 - blurhash: - specifier: 2.0.5 - version: 2.0.5 broadcast-channel: specifier: 4.20.2 version: 4.20.2 browser-image-resizer: specifier: github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3 version: github.com/misskey-dev/browser-image-resizer/0227e860621e55cbed0aabe6dc601096a7748c4a + buraha: + specifier: github:misskey-dev/buraha + version: github.com/misskey-dev/buraha/92b20c1ab15c5cb5a224cf3b1ecd4f6baca12b7c canvas-confetti: specifier: 1.6.0 version: 1.6.0 @@ -20410,6 +20410,12 @@ packages: version: 2.2.1-misskey.3 dev: false + github.com/misskey-dev/buraha/92b20c1ab15c5cb5a224cf3b1ecd4f6baca12b7c: + resolution: {tarball: https://codeload.github.com/misskey-dev/buraha/tar.gz/92b20c1ab15c5cb5a224cf3b1ecd4f6baca12b7c} + name: buraha + version: 0.0.0 + dev: false + github.com/misskey-dev/sharp-read-bmp/02d9dc189fa7df0c4bea09330be26741772dac01: resolution: {tarball: https://codeload.github.com/misskey-dev/sharp-read-bmp/tar.gz/02d9dc189fa7df0c4bea09330be26741772dac01} name: sharp-read-bmp From f68c743f392bad9f7f27e36c33985a7080ec56b2 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 09:48:48 +0900 Subject: [PATCH 048/213] add note --- packages/frontend/src/components/MkReactionsViewer.reaction.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index b521171b2a..aabebb3abf 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -38,6 +38,8 @@ const canToggle = computed(() => !props.reaction.match(/@\w/) && $i); async function toggleReaction() { if (!canToggle.value) return; + // TODO: その絵文字を使う権限があるかどうか確認 + const oldReaction = props.note.myReaction; if (oldReaction) { const confirm = await os.confirm({ From dddbc1c894f53d6891ca7760dd9382c19931661a Mon Sep 17 00:00:00 2001 From: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com> Date: Fri, 19 May 2023 10:06:12 +0900 Subject: [PATCH 049/213] =?UTF-8?q?feat:=20=E5=85=AC=E9=96=8B=E3=83=AA?= =?UTF-8?q?=E3=82=B9=E3=83=88=20(#10842)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: まず公開できるように (misskey-dev/misskey#10447) * feat: 公開したリストのページを作成 (misskey-dev/misskey#10447) * feat: いいねできるように * feat: インポートに対応 * wip * wip * CHANGELOGを編集 * add note * refactor --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> --- CHANGELOG.md | 1 + .../migration/1683847157541-UserList.js | 13 ++ .../1683869758873-UserListFavorites.js | 19 +++ .../core/entities/UserListEntityService.ts | 1 + packages/backend/src/di-symbols.ts | 1 + .../backend/src/models/RepositoryModule.ts | 10 +- .../backend/src/models/entities/UserList.ts | 6 + .../src/models/entities/UserListFavorite.ts | 33 ++++ packages/backend/src/models/index.ts | 3 + .../src/models/json-schema/user-list.ts | 5 + packages/backend/src/postgres.ts | 2 + .../backend/src/server/api/EndpointsModule.ts | 12 ++ packages/backend/src/server/api/endpoints.ts | 6 + .../users/lists/create-from-public.ts | 148 ++++++++++++++++++ .../api/endpoints/users/lists/favorite.ts | 70 +++++++++ .../server/api/endpoints/users/lists/list.ts | 45 +++++- .../server/api/endpoints/users/lists/show.ts | 35 ++++- .../api/endpoints/users/lists/unfavorite.ts | 63 ++++++++ .../api/endpoints/users/lists/update.ts | 5 +- .../components/MkReactionsViewer.reaction.vue | 2 + packages/frontend/src/pages/list.vue | 148 ++++++++++++++++++ .../frontend/src/pages/my-lists/index.vue | 1 + packages/frontend/src/pages/my-lists/list.vue | 90 ++++++----- packages/frontend/src/pages/user/index.vue | 6 + packages/frontend/src/pages/user/lists.vue | 51 ++++++ packages/frontend/src/router.ts | 4 + 26 files changed, 726 insertions(+), 54 deletions(-) create mode 100644 packages/backend/migration/1683847157541-UserList.js create mode 100644 packages/backend/migration/1683869758873-UserListFavorites.js create mode 100644 packages/backend/src/models/entities/UserListFavorite.ts create mode 100644 packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts create mode 100644 packages/backend/src/server/api/endpoints/users/lists/favorite.ts create mode 100644 packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts create mode 100644 packages/frontend/src/pages/list.vue create mode 100644 packages/frontend/src/pages/user/lists.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 9729589632..9945415380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - センシティブなカスタム絵文字のリアクションを受け入れない設定が可能に - タイムラインにフォロイーの行った他人へのリプライを含めるかどうかの設定をアカウントに保存するのをやめるように - 今後はAPI呼び出し時およびストリーミング接続時に設定するようになります +- リストを公開できるようになりました ### Client - リアクションの取り消し/変更時に確認ダイアログを出すように diff --git a/packages/backend/migration/1683847157541-UserList.js b/packages/backend/migration/1683847157541-UserList.js new file mode 100644 index 0000000000..b50a50eed8 --- /dev/null +++ b/packages/backend/migration/1683847157541-UserList.js @@ -0,0 +1,13 @@ +export class UserList1683847157541 { + name = 'UserList1683847157541' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_list" ADD "isPublic" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`CREATE INDEX "IDX_48a00f08598662b9ca540521eb" ON "user_list" ("isPublic") `); + } + + async down(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_48a00f08598662b9ca540521eb"`); + await queryRunner.query(`ALTER TABLE "user_list" DROP COLUMN "isPublic"`); + } +} diff --git a/packages/backend/migration/1683869758873-UserListFavorites.js b/packages/backend/migration/1683869758873-UserListFavorites.js new file mode 100644 index 0000000000..ac9c4c42b9 --- /dev/null +++ b/packages/backend/migration/1683869758873-UserListFavorites.js @@ -0,0 +1,19 @@ +export class UserListFavorites1683869758873 { + name = 'UserListFavorites1683869758873' + + async up(queryRunner) { + await queryRunner.query(`CREATE TABLE "user_list_favorite" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "userListId" character varying(32) NOT NULL, CONSTRAINT "PK_c0974b21e18502a4c8178e09fe6" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE INDEX "IDX_016f613dc4feb807e03e3e7da9" ON "user_list_favorite" ("userId") `); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_d6765a8c2a4c17c33f9d7f948b" ON "user_list_favorite" ("userId", "userListId") `); + await queryRunner.query(`ALTER TABLE "user_list_favorite" ADD CONSTRAINT "FK_016f613dc4feb807e03e3e7da92" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + await queryRunner.query(`ALTER TABLE "user_list_favorite" ADD CONSTRAINT "FK_4d52b20bfe32c8552e7a61e80d2" FOREIGN KEY ("userListId") REFERENCES "user_list"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user_list_favorite" DROP CONSTRAINT "FK_4d52b20bfe32c8552e7a61e80d2"`); + await queryRunner.query(`ALTER TABLE "user_list_favorite" DROP CONSTRAINT "FK_016f613dc4feb807e03e3e7da92"`); + await queryRunner.query(`DROP INDEX "public"."IDX_d6765a8c2a4c17c33f9d7f948b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_016f613dc4feb807e03e3e7da9"`); + await queryRunner.query(`DROP TABLE "user_list_favorite"`); + } +} diff --git a/packages/backend/src/core/entities/UserListEntityService.ts b/packages/backend/src/core/entities/UserListEntityService.ts index 2461cb2c12..8628819278 100644 --- a/packages/backend/src/core/entities/UserListEntityService.ts +++ b/packages/backend/src/core/entities/UserListEntityService.ts @@ -35,6 +35,7 @@ export class UserListEntityService { createdAt: userList.createdAt.toISOString(), name: userList.name, userIds: users.map(x => x.userId), + isPublic: userList.isPublic, }; } } diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index c06c7a7159..4a073f102f 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -25,6 +25,7 @@ export const DI = { userSecurityKeysRepository: Symbol('userSecurityKeysRepository'), userPublickeysRepository: Symbol('userPublickeysRepository'), userListsRepository: Symbol('userListsRepository'), + userListFavoritesRepository: Symbol('userListFavoritesRepository'), userListJoiningsRepository: Symbol('userListJoiningsRepository'), userNotePiningsRepository: Symbol('userNotePiningsRepository'), userIpsRepository: Symbol('userIpsRepository'), diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts index 588c98b58d..4231acc046 100644 --- a/packages/backend/src/models/RepositoryModule.ts +++ b/packages/backend/src/models/RepositoryModule.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; -import { User, Note, Announcement, AnnouncementRead, App, NoteFavorite, NoteThreadMuting, NoteReaction, NoteUnread, Poll, PollVote, UserProfile, UserKeypair, UserPending, AttestationChallenge, UserSecurityKey, UserPublickey, UserList, UserListJoining, UserNotePining, UserIp, UsedUsername, Following, FollowRequest, Instance, Emoji, DriveFile, DriveFolder, Meta, Muting, RenoteMuting, Blocking, SwSubscription, Hashtag, AbuseUserReport, RegistrationTicket, AuthSession, AccessToken, Signin, Page, PageLike, GalleryPost, GalleryLike, ModerationLog, Clip, ClipNote, Antenna, PromoNote, PromoRead, Relay, MutedNote, Channel, ChannelFollowing, ChannelFavorite, RegistryItem, Webhook, Ad, PasswordResetRequest, RetentionAggregation, FlashLike, Flash, Role, RoleAssignment, ClipFavorite, UserMemo } from './index.js'; +import { User, Note, Announcement, AnnouncementRead, App, NoteFavorite, NoteThreadMuting, NoteReaction, NoteUnread, Poll, PollVote, UserProfile, UserKeypair, UserPending, AttestationChallenge, UserSecurityKey, UserPublickey, UserList, UserListJoining, UserNotePining, UserIp, UsedUsername, Following, FollowRequest, Instance, Emoji, DriveFile, DriveFolder, Meta, Muting, RenoteMuting, Blocking, SwSubscription, Hashtag, AbuseUserReport, RegistrationTicket, AuthSession, AccessToken, Signin, Page, PageLike, GalleryPost, GalleryLike, ModerationLog, Clip, ClipNote, Antenna, PromoNote, PromoRead, Relay, MutedNote, Channel, ChannelFollowing, ChannelFavorite, RegistryItem, Webhook, Ad, PasswordResetRequest, RetentionAggregation, FlashLike, Flash, Role, RoleAssignment, ClipFavorite, UserMemo, UserListFavorite } from './index.js'; import type { DataSource } from 'typeorm'; import type { Provider } from '@nestjs/common'; @@ -112,6 +112,12 @@ const $userListsRepository: Provider = { inject: [DI.db], }; +const $userListFavoritesRepository: Provider = { + provide: DI.userListFavoritesRepository, + useFactory: (db: DataSource) => db.getRepository(UserListFavorite), + inject: [DI.db], +}; + const $userListJoiningsRepository: Provider = { provide: DI.userListJoiningsRepository, useFactory: (db: DataSource) => db.getRepository(UserListJoining), @@ -416,6 +422,7 @@ const $userMemosRepository: Provider = { $userSecurityKeysRepository, $userPublickeysRepository, $userListsRepository, + $userListFavoritesRepository, $userListJoiningsRepository, $userNotePiningsRepository, $userIpsRepository, @@ -483,6 +490,7 @@ const $userMemosRepository: Provider = { $userSecurityKeysRepository, $userPublickeysRepository, $userListsRepository, + $userListFavoritesRepository, $userListJoiningsRepository, $userNotePiningsRepository, $userIpsRepository, diff --git a/packages/backend/src/models/entities/UserList.ts b/packages/backend/src/models/entities/UserList.ts index b8a4b54d4c..94f3dc3cb3 100644 --- a/packages/backend/src/models/entities/UserList.ts +++ b/packages/backend/src/models/entities/UserList.ts @@ -19,6 +19,12 @@ export class UserList { }) public userId: User['id']; + @Index() + @Column('boolean', { + default: false, + }) + public isPublic: boolean; + @ManyToOne(type => User, { onDelete: 'CASCADE', }) diff --git a/packages/backend/src/models/entities/UserListFavorite.ts b/packages/backend/src/models/entities/UserListFavorite.ts new file mode 100644 index 0000000000..e57abb460a --- /dev/null +++ b/packages/backend/src/models/entities/UserListFavorite.ts @@ -0,0 +1,33 @@ +import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm'; +import { id } from '../id.js'; +import { User } from './User.js'; +import { UserList } from './UserList.js'; + +@Entity() +@Index(['userId', 'userListId'], { unique: true }) +export class UserListFavorite { + @PrimaryColumn(id()) + public id: string; + + @Column('timestamp with time zone') + public createdAt: Date; + + @Index() + @Column(id()) + public userId: User['id']; + + @ManyToOne(type => User, { + onDelete: 'CASCADE', + }) + @JoinColumn() + public user: User | null; + + @Column(id()) + public userListId: UserList['id']; + + @ManyToOne(type => UserList, { + onDelete: 'CASCADE', + }) + @JoinColumn() + public userList: UserList | null; +} diff --git a/packages/backend/src/models/index.ts b/packages/backend/src/models/index.ts index b8ba28db9b..4b230ab742 100644 --- a/packages/backend/src/models/index.ts +++ b/packages/backend/src/models/index.ts @@ -49,6 +49,7 @@ import { User } from '@/models/entities/User.js'; import { UserIp } from '@/models/entities/UserIp.js'; import { UserKeypair } from '@/models/entities/UserKeypair.js'; import { UserList } from '@/models/entities/UserList.js'; +import { UserListFavorite } from './entities/UserListFavorite.js'; import { UserListJoining } from '@/models/entities/UserListJoining.js'; import { UserNotePining } from '@/models/entities/UserNotePining.js'; import { UserPending } from '@/models/entities/UserPending.js'; @@ -117,6 +118,7 @@ export { UserIp, UserKeypair, UserList, + UserListFavorite, UserListJoining, UserNotePining, UserPending, @@ -184,6 +186,7 @@ export type UsersRepository = Repository<User>; export type UserIpsRepository = Repository<UserIp>; export type UserKeypairsRepository = Repository<UserKeypair>; export type UserListsRepository = Repository<UserList>; +export type UserListFavoritesRepository = Repository<UserListFavorite>; export type UserListJoiningsRepository = Repository<UserListJoining>; export type UserNotePiningsRepository = Repository<UserNotePining>; export type UserPendingsRepository = Repository<UserPending>; diff --git a/packages/backend/src/models/json-schema/user-list.ts b/packages/backend/src/models/json-schema/user-list.ts index 3ba5dc4a8a..1e620516e4 100644 --- a/packages/backend/src/models/json-schema/user-list.ts +++ b/packages/backend/src/models/json-schema/user-list.ts @@ -25,5 +25,10 @@ export const packedUserListSchema = { format: 'id', }, }, + isPublic: { + type: 'boolean', + nullable: false, + optional: false, + }, }, } as const; diff --git a/packages/backend/src/postgres.ts b/packages/backend/src/postgres.ts index f3d404e6c9..488979c409 100644 --- a/packages/backend/src/postgres.ts +++ b/packages/backend/src/postgres.ts @@ -57,6 +57,7 @@ import { User } from '@/models/entities/User.js'; import { UserIp } from '@/models/entities/UserIp.js'; import { UserKeypair } from '@/models/entities/UserKeypair.js'; import { UserList } from '@/models/entities/UserList.js'; +import { UserListFavorite } from '@/models/entities/UserListFavorite.js'; import { UserListJoining } from '@/models/entities/UserListJoining.js'; import { UserNotePining } from '@/models/entities/UserNotePining.js'; import { UserPending } from '@/models/entities/UserPending.js'; @@ -132,6 +133,7 @@ export const entities = [ UserKeypair, UserPublickey, UserList, + UserListFavorite, UserListJoining, UserNotePining, UserSecurityKey, diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index ee1aae5b6c..1e32e9988d 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -321,6 +321,9 @@ import * as ep___users_lists_pull from './endpoints/users/lists/pull.js'; import * as ep___users_lists_push from './endpoints/users/lists/push.js'; import * as ep___users_lists_show from './endpoints/users/lists/show.js'; import * as ep___users_lists_update from './endpoints/users/lists/update.js'; +import * as ep___users_lists_favorite from './endpoints/users/lists/favorite.js'; +import * as ep___users_lists_unfavorite from './endpoints/users/lists/unfavorite.js'; +import * as ep___users_lists_create_from_public from './endpoints/users/lists/create-from-public.js'; import * as ep___users_notes from './endpoints/users/notes.js'; import * as ep___users_pages from './endpoints/users/pages.js'; import * as ep___users_reactions from './endpoints/users/reactions.js'; @@ -659,6 +662,9 @@ const $users_lists_pull: Provider = { provide: 'ep:users/lists/pull', useClass: const $users_lists_push: Provider = { provide: 'ep:users/lists/push', useClass: ep___users_lists_push.default }; const $users_lists_show: Provider = { provide: 'ep:users/lists/show', useClass: ep___users_lists_show.default }; const $users_lists_update: Provider = { provide: 'ep:users/lists/update', useClass: ep___users_lists_update.default }; +const $users_lists_favorite: Provider = { provide: 'ep:users/lists/favorite', useClass: ep___users_lists_favorite.default }; +const $users_lists_unfavorite: Provider = { provide: 'ep:users/lists/unfavorite', useClass: ep___users_lists_unfavorite.default }; +const $users_lists_create_from_public: Provider = { provide: 'ep:users/lists/create-from-public', useClass: ep___users_lists_create_from_public.default }; const $users_notes: Provider = { provide: 'ep:users/notes', useClass: ep___users_notes.default }; const $users_pages: Provider = { provide: 'ep:users/pages', useClass: ep___users_pages.default }; const $users_reactions: Provider = { provide: 'ep:users/reactions', useClass: ep___users_reactions.default }; @@ -1001,6 +1007,9 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $users_lists_push, $users_lists_show, $users_lists_update, + $users_lists_favorite, + $users_lists_unfavorite, + $users_lists_create_from_public, $users_notes, $users_pages, $users_reactions, @@ -1335,6 +1344,9 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $users_lists_push, $users_lists_show, $users_lists_update, + $users_lists_favorite, + $users_lists_unfavorite, + $users_lists_create_from_public, $users_notes, $users_pages, $users_reactions, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 09bd7cbff4..7e678a6404 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -320,6 +320,9 @@ import * as ep___users_lists_list from './endpoints/users/lists/list.js'; import * as ep___users_lists_pull from './endpoints/users/lists/pull.js'; import * as ep___users_lists_push from './endpoints/users/lists/push.js'; import * as ep___users_lists_show from './endpoints/users/lists/show.js'; +import * as ep___users_lists_favorite from './endpoints/users/lists/favorite.js'; +import * as ep___users_lists_unfavorite from './endpoints/users/lists/unfavorite.js'; +import * as ep___users_lists_create_from_public from './endpoints/users/lists/create-from-public.js'; import * as ep___users_lists_update from './endpoints/users/lists/update.js'; import * as ep___users_notes from './endpoints/users/notes.js'; import * as ep___users_pages from './endpoints/users/pages.js'; @@ -656,7 +659,10 @@ const eps = [ ['users/lists/pull', ep___users_lists_pull], ['users/lists/push', ep___users_lists_push], ['users/lists/show', ep___users_lists_show], + ['users/lists/favorite', ep___users_lists_favorite], + ['users/lists/unfavorite', ep___users_lists_unfavorite], ['users/lists/update', ep___users_lists_update], + ['users/lists/create-from-public', ep___users_lists_create_from_public], ['users/notes', ep___users_notes], ['users/pages', ep___users_pages], ['users/reactions', ep___users_reactions], diff --git a/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts new file mode 100644 index 0000000000..8591e4ab96 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/users/lists/create-from-public.ts @@ -0,0 +1,148 @@ +import { Inject, Injectable } from '@nestjs/common'; +import type { UserListsRepository, UserListJoiningsRepository, BlockingsRepository } from '@/models/index.js'; +import { IdService } from '@/core/IdService.js'; +import type { UserList } from '@/models/entities/UserList.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { GetterService } from '@/server/api/GetterService.js'; +import { UserListEntityService } from '@/core/entities/UserListEntityService.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '@/server/api/error.js'; +import { RoleService } from '@/core/RoleService.js'; +import { UserListService } from '@/core/UserListService.js'; + +export const meta = { + requireCredential: true, + prohibitMoved: true, + res: { + type: 'object', + optional: false, nullable: false, + ref: 'UserList', + }, + + errors: { + tooManyUserLists: { + message: 'You cannot create user list any more.', + code: 'TOO_MANY_USERLISTS', + id: 'e9c105b2-c595-47de-97fb-7f7c2c33e92f', + }, + noSuchList: { + message: 'No such list.', + code: 'NO_SUCH_LIST', + id: '9292f798-6175-4f7d-93f4-b6742279667d', + }, + noSuchUser: { + message: 'No such user.', + code: 'NO_SUCH_USER', + id: '13c457db-a8cb-4d88-b70a-211ceeeabb5f', + }, + + alreadyAdded: { + message: 'That user has already been added to that list.', + code: 'ALREADY_ADDED', + id: 'c3ad6fdb-692b-47ee-a455-7bd12c7af615', + }, + + youHaveBeenBlocked: { + message: 'You cannot push this user because you have been blocked by this user.', + code: 'YOU_HAVE_BEEN_BLOCKED', + id: 'a2497f2a-2389-439c-8626-5298540530f4', + }, + + tooManyUsers: { + message: 'You can not push users any more.', + code: 'TOO_MANY_USERS', + id: '1845ea77-38d1-426e-8e4e-8b83b24f5bd7', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + name: { type: 'string', minLength: 1, maxLength: 100 }, + listId: { type: 'string', format: 'misskey:id' }, + }, + required: ['name', 'listId'], +} as const; + +@Injectable() +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor( + @Inject(DI.userListsRepository) + private userListsRepository: UserListsRepository, + + @Inject(DI.userListJoiningsRepository) + private userListJoiningsRepository: UserListJoiningsRepository, + + @Inject(DI.blockingsRepository) + private blockingsRepository: BlockingsRepository, + + private userListService: UserListService, + private userListEntityService: UserListEntityService, + private idService: IdService, + private getterService: GetterService, + private roleService: RoleService, + ) { + super(meta, paramDef, async (ps, me) => { + const list = await this.userListsRepository.findOneBy({ + id: ps.listId, + isPublic: true, + }); + if (list === null) throw new ApiError(meta.errors.noSuchList); + const currentCount = await this.userListsRepository.countBy({ + userId: me.id, + }); + if (currentCount > (await this.roleService.getUserPolicies(me.id)).userListLimit) { + throw new ApiError(meta.errors.tooManyUserLists); + } + + const userList = await this.userListsRepository.insert({ + id: this.idService.genId(), + createdAt: new Date(), + userId: me.id, + name: ps.name, + } as UserList).then(x => this.userListsRepository.findOneByOrFail(x.identifiers[0])); + + const users = (await this.userListJoiningsRepository.findBy({ + userListId: ps.listId, + })).map(x => x.userId); + + for (const user of users) { + const currentUser = await this.getterService.getUser(user).catch(err => { + if (err.id === '15348ddd-432d-49c2-8a5a-8069753becff') throw new ApiError(meta.errors.noSuchUser); + throw err; + }); + + if (currentUser.id !== me.id) { + const block = await this.blockingsRepository.findOneBy({ + blockerId: currentUser.id, + blockeeId: me.id, + }); + if (block) { + throw new ApiError(meta.errors.youHaveBeenBlocked); + } + } + + const exist = await this.userListJoiningsRepository.findOneBy({ + userListId: userList.id, + userId: currentUser.id, + }); + + if (exist) { + throw new ApiError(meta.errors.alreadyAdded); + } + + try { + await this.userListService.push(currentUser, userList, me); + } catch (err) { + if (err instanceof UserListService.TooManyUsersError) { + throw new ApiError(meta.errors.tooManyUsers); + } + throw err; + } + } + return await this.userListEntityService.pack(userList); + }); + } +} + diff --git a/packages/backend/src/server/api/endpoints/users/lists/favorite.ts b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts new file mode 100644 index 0000000000..263852fde1 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/users/lists/favorite.ts @@ -0,0 +1,70 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { UserListFavoritesRepository, UserListsRepository } from '@/models/index.js'; +import { IdService } from '@/core/IdService.js'; +import { ApiError } from '@/server/api/error.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + requireCredential: true, + errors: { + noSuchList: { + message: 'No such user list.', + code: 'NO_SUCH_USER_LIST', + id: '7dbaf3cf-7b42-4b8f-b431-b3919e580dbe', + }, + + alreadyFavorited: { + message: 'The list has already been favorited.', + code: 'ALREADY_FAVORITED', + id: '6425bba0-985b-461e-af1b-518070e72081', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + }, + required: ['listId'], +} as const; + +@Injectable() // eslint-disable-next-line import/no-default-export +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor ( + @Inject(DI.userListsRepository) + private userListsRepository: UserListsRepository, + + @Inject(DI.userListFavoritesRepository) + private userListFavoritesRepository: UserListFavoritesRepository, + private idService: IdService, + ) { + super(meta, paramDef, async (ps, me) => { + const userList = await this.userListsRepository.findOneBy({ + id: ps.listId, + isPublic: true, + }); + + if (userList === null) { + throw new ApiError(meta.errors.noSuchList); + } + + const exist = await this.userListFavoritesRepository.findOneBy({ + userId: me.id, + userListId: ps.listId, + }); + + if (exist !== null) { + throw new ApiError(meta.errors.alreadyFavorited); + } + + await this.userListFavoritesRepository.insert({ + id: this.idService.genId(), + createdAt: new Date(), + userId: me.id, + userListId: ps.listId, + }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/users/lists/list.ts b/packages/backend/src/server/api/endpoints/users/lists/list.ts index 2104c4377d..eab29944b2 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/list.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/list.ts @@ -1,13 +1,14 @@ import { Inject, Injectable } from '@nestjs/common'; -import type { UserListsRepository } from '@/models/index.js'; +import type { UserListsRepository, UsersRepository } from '@/models/index.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { UserListEntityService } from '@/core/entities/UserListEntityService.js'; +import { ApiError } from '@/server/api/error.js'; import { DI } from '@/di-symbols.js'; export const meta = { tags: ['lists', 'account'], - requireCredential: true, + requireCredential: false, kind: 'read:account', @@ -22,26 +23,58 @@ export const meta = { ref: 'UserList', }, }, + errors: { + noSuchUser: { + message: 'No such user.', + code: 'NO_SUCH_USER', + id: 'a8af4a82-0980-4cc4-a6af-8b0ffd54465e', + }, + remoteUser: { + message: 'Not allowed to load the remote user\'s list', + code: 'REMOTE_USER_NOT_ALLOWED', + id: '53858f1b-3315-4a01-81b7-db9b48d4b79a', + }, + invalidParam: { + message: 'Invalid param.', + code: 'INVALID_PARAM', + id: 'ab36de0e-29e9-48cb-9732-d82f1281620d', + }, + }, } as const; export const paramDef = { type: 'object', - properties: {}, + properties: { + userId: { type: 'string', format: 'misskey:id' }, + }, required: [], } as const; -// eslint-disable-next-line import/no-default-export -@Injectable() +@Injectable() // eslint-disable-next-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { constructor( + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + @Inject(DI.userListsRepository) private userListsRepository: UserListsRepository, private userListEntityService: UserListEntityService, ) { super(meta, paramDef, async (ps, me) => { - const userLists = await this.userListsRepository.findBy({ + if (typeof ps.userId !== 'undefined') { + const user = await this.usersRepository.findOneBy({ id: ps.userId }); + if (user === null) throw new ApiError(meta.errors.noSuchUser); + if (user.host !== null) throw new ApiError(meta.errors.remoteUser); + } else if (me === null) { + throw new ApiError(meta.errors.invalidParam); + } + + const userLists = await this.userListsRepository.findBy(typeof ps.userId === 'undefined' && me !== null ? { userId: me.id, + } : { + userId: ps.userId, + isPublic: true, }); return await Promise.all(userLists.map(x => this.userListEntityService.pack(x))); diff --git a/packages/backend/src/server/api/endpoints/users/lists/show.ts b/packages/backend/src/server/api/endpoints/users/lists/show.ts index 77f9cba808..8077841c8c 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/show.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/show.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; -import type { UserListsRepository } from '@/models/index.js'; +import type { UserListsRepository, UserListFavoritesRepository } from '@/models/index.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { UserListEntityService } from '@/core/entities/UserListEntityService.js'; import { DI } from '@/di-symbols.js'; @@ -8,7 +8,7 @@ import { ApiError } from '../../../error.js'; export const meta = { tags: ['lists', 'account'], - requireCredential: true, + requireCredential: false, kind: 'read:account', @@ -33,31 +33,54 @@ export const paramDef = { type: 'object', properties: { listId: { type: 'string', format: 'misskey:id' }, + forPublic: { type: 'boolean', default: false }, }, required: ['listId'], } as const; -// eslint-disable-next-line import/no-default-export -@Injectable() +@Injectable() // eslint-disable-next-line import/no-default-export export default class extends Endpoint<typeof meta, typeof paramDef> { constructor( @Inject(DI.userListsRepository) private userListsRepository: UserListsRepository, + @Inject(DI.userListFavoritesRepository) + private userListFavoritesRepository: UserListFavoritesRepository, + private userListEntityService: UserListEntityService, ) { super(meta, paramDef, async (ps, me) => { + const additionalProperties: Partial<{ likedCount: number, isLiked: boolean }> = {}; // Fetch the list - const userList = await this.userListsRepository.findOneBy({ + const userList = await this.userListsRepository.findOneBy(!ps.forPublic && me !== null ? { id: ps.listId, userId: me.id, + } : { + id: ps.listId, + isPublic: true, }); if (userList == null) { throw new ApiError(meta.errors.noSuchList); } - return await this.userListEntityService.pack(userList); + if (ps.forPublic && userList.isPublic) { + additionalProperties.likedCount = await this.userListFavoritesRepository.countBy({ + userListId: ps.listId, + }); + if (me !== null) { + additionalProperties.isLiked = (await this.userListFavoritesRepository.findOneBy({ + userId: me.id, + userListId: ps.listId, + }) !== null); + } else { + additionalProperties.isLiked = false; + } + } + return { + ...await this.userListEntityService.pack(userList), + ...additionalProperties, + }; }); } } diff --git a/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts new file mode 100644 index 0000000000..be8e317816 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/users/lists/unfavorite.ts @@ -0,0 +1,63 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import type { UserListFavoritesRepository, UserListsRepository } from '@/models/index.js'; +import { ApiError } from '@/server/api/error.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + requireCredential: true, + errors: { + noSuchList: { + message: 'No such user list.', + code: 'NO_SUCH_USER_LIST', + id: 'baedb33e-76b8-4b0c-86a8-9375c0a7b94b', + }, + + notFavorited: { + message: 'You have not favorited the list.', + code: 'ALREADY_FAVORITED', + id: '835c4b27-463d-4cfa-969b-a9058678d465', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + }, + required: ['listId'], +} as const; + +@Injectable() // eslint-disable-next-line import/no-default-export +export default class extends Endpoint<typeof meta, typeof paramDef> { + constructor ( + @Inject(DI.userListsRepository) + private userListsRepository: UserListsRepository, + + @Inject(DI.userListFavoritesRepository) + private userListFavoritesRepository: UserListFavoritesRepository, + ) { + super(meta, paramDef, async (ps, me) => { + const userList = await this.userListsRepository.findOneBy({ + id: ps.listId, + isPublic: true, + }); + + if (userList === null) { + throw new ApiError(meta.errors.noSuchList); + } + + const exist = await this.userListFavoritesRepository.findOneBy({ + userListId: ps.listId, + userId: me.id, + }); + + if (exist === null) { + throw new ApiError(meta.errors.notFavorited); + } + + await this.userListFavoritesRepository.delete({ id: exist.id }); + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/users/lists/update.ts b/packages/backend/src/server/api/endpoints/users/lists/update.ts index 6453d7d980..b0a95a2f28 100644 --- a/packages/backend/src/server/api/endpoints/users/lists/update.ts +++ b/packages/backend/src/server/api/endpoints/users/lists/update.ts @@ -34,8 +34,9 @@ export const paramDef = { properties: { listId: { type: 'string', format: 'misskey:id' }, name: { type: 'string', minLength: 1, maxLength: 100 }, + isPublic: { type: 'boolean' }, }, - required: ['listId', 'name'], + required: ['listId'], } as const; // eslint-disable-next-line import/no-default-export @@ -48,7 +49,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { private userListEntityService: UserListEntityService, ) { super(meta, paramDef, async (ps, me) => { - // Fetch the list const userList = await this.userListsRepository.findOneBy({ id: ps.listId, userId: me.id, @@ -60,6 +60,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { await this.userListsRepository.update(userList.id, { name: ps.name, + isPublic: ps.isPublic, }); return await this.userListEntityService.pack(userList.id); diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index b521171b2a..aabebb3abf 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -38,6 +38,8 @@ const canToggle = computed(() => !props.reaction.match(/@\w/) && $i); async function toggleReaction() { if (!canToggle.value) return; + // TODO: その絵文字を使う権限があるかどうか確認 + const oldReaction = props.note.myReaction; if (oldReaction) { const confirm = await os.confirm({ diff --git a/packages/frontend/src/pages/list.vue b/packages/frontend/src/pages/list.vue new file mode 100644 index 0000000000..a09ff854ca --- /dev/null +++ b/packages/frontend/src/pages/list.vue @@ -0,0 +1,148 @@ +<template> +<MkStickyContainer> + <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> + <MKSpacer v-if="!(typeof error === 'undefined')" :content-max="1200"> + <div :class="$style.root"> + <img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> + <p :class="$style.text"> + <i class="ti ti-alert-triangle"></i> + {{ i18n.ts.nothing }} + </p> + </div> + </MKSpacer> + <MkSpacer v-else-if="list" :content-max="700" :class="$style.main"> + <div v-if="list" class="members _margin"> + <div :class="$style.member_text">{{ i18n.ts.members }}</div> + <div class="_gaps_s"> + <div v-for="user in users" :key="user.id" :class="$style.userItem"> + <MkA :class="$style.userItemBody" :to="`${userPage(user)}`"> + <MkUserCardMini :user="user"/> + </MkA> + </div> + </div> + </div> + <MkButton v-if="list.isLiked" v-tooltip="i18n.ts.unlike" inline :class="$style.button" as-like primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="list.likedCount > 0" class="count">{{ list.likedCount }}</span></MkButton> + <MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" as-like @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton> + <MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton> + </MkSpacer> +</MkStickyContainer> +</template> + +<script lang="ts" setup> +import { watch, computed } from 'vue'; +import * as os from '@/os'; +import { userPage } from '@/filters/user'; +import { i18n } from '@/i18n'; +import MkUserCardMini from '@/components/MkUserCardMini.vue'; +import MkButton from '@/components/MkButton.vue'; +import { definePageMetadata } from '@/scripts/page-metadata'; + +const props = defineProps<{ + listId: string; +}>(); + +let list = $ref(null); +let error = $ref(); +let users = $ref([]); + +function fetchList(): void { + os.api('users/lists/show', { + listId: props.listId, + forPublic: true, + }).then(_list => { + list = _list; + os.api('users/show', { + userIds: list.userIds, + }).then(_users => { + users = _users; + }); + }).catch(err => { + error = err; + }); +} + +function like() { + os.apiWithDialog('users/lists/favorite', { + listId: list.id, + }).then(() => { + list.isLiked = true; + list.likedCount++; + }); +} + +function unlike() { + os.apiWithDialog('users/lists/unfavorite', { + listId: list.id, + }).then(() => { + list.isLiked = false; + list.likedCount--; + }); +} + +async function create() { + const { canceled, result: name } = await os.inputText({ + title: i18n.ts.enterListName, + }); + if (canceled) return; + await os.apiWithDialog('users/lists/create-from-public', { name: name, listId: list.id }); +} + +watch(() => props.listId, fetchList, { immediate: true }); + +const headerActions = $computed(() => []); + +const headerTabs = $computed(() => []); + +definePageMetadata(computed(() => list ? { + title: list.name, + icon: 'ti ti-list', +} : null)); +</script> +<style lang="scss" module> +.main { + min-height: calc(100cqh - (var(--stickyTop, 0px) + var(--stickyBottom, 0px))); +} + +.userItem { + display: flex; +} + +.userItemBody { + flex: 1; + min-width: 0; + margin-right: 8px; + + &:hover { + text-decoration: none; + } +} +.member_text { + margin: 5px; +} + +.root { + padding: 32px; + text-align: center; + align-items: center; +} + +.text { + margin: 0 0 8px 0; +} + +.img { + vertical-align: bottom; + width: 128px; + height: 128px; + margin-bottom: 16px; + border-radius: 16px; +} + +.button { + margin-right: 10px; +} + +.import { + margin-right: 4px; +} +</style> diff --git a/packages/frontend/src/pages/my-lists/index.vue b/packages/frontend/src/pages/my-lists/index.vue index 47437f3e57..6068e375ea 100644 --- a/packages/frontend/src/pages/my-lists/index.vue +++ b/packages/frontend/src/pages/my-lists/index.vue @@ -70,6 +70,7 @@ definePageMetadata({ padding: 16px; border: solid 1px var(--divider); border-radius: 6px; + margin-bottom: 8px; &:hover { border: solid 1px var(--accent); diff --git a/packages/frontend/src/pages/my-lists/list.vue b/packages/frontend/src/pages/my-lists/list.vue index 86201e8e0c..dd431e8dc0 100644 --- a/packages/frontend/src/pages/my-lists/list.vue +++ b/packages/frontend/src/pages/my-lists/list.vue @@ -1,35 +1,43 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :class="$style.main"> - <div v-if="list" class="members _margin"> - <div class="">{{ i18n.ts.members }}</div> - <div class="_gaps_s"> - <div v-for="user in users" :key="user.id" :class="$style.userItem"> - <MkA :class="$style.userItemBody" :to="`${userPage(user)}`"> - <MkUserCardMini :user="user"/> - </MkA> - <button class="_button" :class="$style.remove" @click="removeUser(user, $event)"><i class="ti ti-x"></i></button> + <MkSpacer :contentMax="700" :class="$style.main"> + <div v-if="list" class="_gaps"> + <MkFolder> + <template #label>{{ i18n.ts.settings }}</template> + + <div class="_gaps"> + <MkInput v-model="name"> + <template #label>{{ i18n.ts.name }}</template> + </MkInput> + <MkSwitch v-model="isPublic">{{ i18n.ts.public }}</MkSwitch> + <div class="_buttons"> + <MkButton rounded primary @click="updateSettings">{{ i18n.ts.save }}</MkButton> + <MkButton rounded danger @click="deleteList()">{{ i18n.ts.delete }}</MkButton> + </div> </div> - </div> + </MkFolder> + + <MkFolder defaultOpen> + <template #label>{{ i18n.ts.members }}</template> + + <div class="_gaps_s"> + <MkButton rounded primary style="margin: 0 auto;" @click="addUser()">{{ i18n.ts.addUser }}</MkButton> + <div v-for="user in users" :key="user.id" :class="$style.userItem"> + <MkA :class="$style.userItemBody" :to="`${userPage(user)}`"> + <MkUserCardMini :user="user"/> + </MkA> + <button class="_button" :class="$style.remove" @click="removeUser(user, $event)"><i class="ti ti-x"></i></button> + </div> + </div> + </MkFolder> </div> </MkSpacer> - <template #footer> - <div :class="$style.footer"> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="16"> - <div class="_buttons"> - <MkButton inline rounded primary @click="addUser()">{{ i18n.ts.addUser }}</MkButton> - <MkButton inline rounded @click="renameList()">{{ i18n.ts.rename }}</MkButton> - <MkButton inline rounded danger @click="deleteList()">{{ i18n.ts.delete }}</MkButton> - </div> - </MkSpacer> - </div> - </template> </MkStickyContainer> </template> <script lang="ts" setup> -import { computed, watch } from 'vue'; +import { computed, ref, watch } from 'vue'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os'; import { mainRouter } from '@/router'; @@ -37,6 +45,9 @@ import { definePageMetadata } from '@/scripts/page-metadata'; import { i18n } from '@/i18n'; import { userPage } from '@/filters/user'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; +import MkSwitch from '@/components/MkSwitch.vue'; +import MkFolder from '@/components/MkFolder.vue'; +import MkInput from '@/components/MkInput.vue'; import { userListsCache } from '@/cache'; const props = defineProps<{ @@ -45,12 +56,17 @@ const props = defineProps<{ let list = $ref(null); let users = $ref([]); +const isPublic = ref(false); +const name = ref(''); function fetchList() { os.api('users/lists/show', { listId: props.listId, }).then(_list => { list = _list; + name.value = list.name; + isPublic.value = list.isPublic; + os.api('users/show', { userIds: list.userIds, }).then(_users => { @@ -86,23 +102,6 @@ async function removeUser(user, ev) { }], ev.currentTarget ?? ev.target); } -async function renameList() { - const { canceled, result: name } = await os.inputText({ - title: i18n.ts.enterListName, - default: list.name, - }); - if (canceled) return; - - await os.api('users/lists/update', { - listId: list.id, - name: name, - }); - - userListsCache.delete(); - - list.name = name; -} - async function deleteList() { const { canceled } = await os.confirm({ type: 'warning', @@ -117,6 +116,19 @@ async function deleteList() { mainRouter.push('/my/lists'); } +async function updateSettings() { + await os.apiWithDialog('users/lists/update', { + listId: list.id, + name: name.value, + isPublic: isPublic.value, + }); + + userListsCache.delete(); + + list.name = name.value; + list.isPublic = isPublic.value; +} + watch(() => props.listId, fetchList, { immediate: true }); const headerActions = $computed(() => []); diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index 03a226cc09..07f7d30f0c 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -10,6 +10,7 @@ <XAchievements v-else-if="tab === 'achievements'" :user="user"/> <XReactions v-else-if="tab === 'reactions'" :user="user"/> <XClips v-else-if="tab === 'clips'" :user="user"/> + <XLists v-else-if="tab === 'lists'" :user="user"/> <XPages v-else-if="tab === 'pages'" :user="user"/> <XGallery v-else-if="tab === 'gallery'" :user="user"/> </div> @@ -36,6 +37,7 @@ const XActivity = defineAsyncComponent(() => import('./activity.vue')); const XAchievements = defineAsyncComponent(() => import('./achievements.vue')); const XReactions = defineAsyncComponent(() => import('./reactions.vue')); const XClips = defineAsyncComponent(() => import('./clips.vue')); +const XLists = defineAsyncComponent(() => import('./lists.vue')); const XPages = defineAsyncComponent(() => import('./pages.vue')); const XGallery = defineAsyncComponent(() => import('./gallery.vue')); @@ -90,6 +92,10 @@ const headerTabs = $computed(() => user ? [{ key: 'clips', title: i18n.ts.clips, icon: 'ti ti-paperclip', +}, { + key: 'lists', + title: i18n.ts.lists, + icon: 'ti ti-list', }, { key: 'pages', title: i18n.ts.pages, diff --git a/packages/frontend/src/pages/user/lists.vue b/packages/frontend/src/pages/user/lists.vue new file mode 100644 index 0000000000..78f03d2b38 --- /dev/null +++ b/packages/frontend/src/pages/user/lists.vue @@ -0,0 +1,51 @@ +<template> +<MkStickyContainer> + <MkSpacer :contentMax="700"> + <div> + <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="lists"> + <MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/list/${ list.id }`"> + <div>{{ list.name }}</div> + <MkAvatars :userIds="list.userIds"/> + </MkA> + </MkPagination> + </div> + </MkSpacer> +</MkStickyContainer> +</template> + +<script lang="ts" setup> +import {} from 'vue'; +import * as misskey from 'misskey-js'; +import MkPagination from '@/components/MkPagination.vue'; +import MkStickyContainer from '@/components/global/MkStickyContainer.vue'; +import MkSpacer from '@/components/global/MkSpacer.vue'; +import MkAvatars from '@/components/MkAvatars.vue'; + +const props = defineProps<{ + user: misskey.entities.UserDetailed; +}>(); + +const pagination = { + endpoint: 'users/lists/list' as const, + noPaging: true, + limit: 10, + params: { + userId: props.user.id, + }, +}; +</script> + +<style lang="scss" module> +.list { + display: block; + padding: 16px; + border: solid 1px var(--divider); + border-radius: 6px; + margin-bottom: 8px; + + &:hover { + border: solid 1px var(--accent); + text-decoration: none; + } +} +</style> diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index add4bd9217..6b11137d79 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -30,6 +30,10 @@ export const routes = [{ name: 'note', path: '/notes/:noteId', component: page(() => import('./pages/note.vue')), +}, { + name: 'list', + path: '/list/:listId', + component: page(() => import('./pages/list.vue')), }, { path: '/clips/:clipId', component: page(() => import('./pages/clip.vue')), From 0c0ae6ff90029d8a5e0526c2c20276794db41114 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 10:07:29 +0900 Subject: [PATCH 050/213] 13.13.0-beta.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc1e2e62e5..5a8e1e7b20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0-beta.1", + "version": "13.13.0-beta.2", "codename": "nasubi", "repository": { "type": "git", From 8317772436590e76fc4a10bd7cf0f26c5120f80c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=BE=E3=81=A3=E3=81=B4=E3=83=BC?= <75538777+mappi-pr@users.noreply.github.com> Date: Fri, 19 May 2023 11:35:46 +0900 Subject: [PATCH 051/213] =?UTF-8?q?fix:Firefox=E3=81=A7=E3=82=B5=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=82=A2=E3=83=83=E3=83=97=E3=81=99=E3=82=8B=E6=99=82?= =?UTF-8?q?=E3=80=81=E3=83=A1=E3=83=BC=E3=83=AB=E3=82=A2=E3=83=89=E3=83=AC?= =?UTF-8?q?=E3=82=B9=E3=81=8C=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E5=90=8D?= =?UTF-8?q?=E3=81=A8=E3=81=97=E3=81=A6=E8=AA=8D=E8=AD=98=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=82=8B#10523=20(#10869)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix:Firefoxでサインアップする時、メールアドレスがユーザー名として認識される * Update CHANGELOG.md edit CHANGELOG.md --- CHANGELOG.md | 1 + packages/frontend/src/components/MkSignupDialog.form.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9945415380..454974ca23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - 開発者モードを追加 - AiScriptを0.13.3に更新 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 +- Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正 ## 13.12.2 diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index 0e8bdb321e..c8d805cc1c 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -9,7 +9,7 @@ <template #label>{{ i18n.ts.invitationCode }}</template> <template #prefix><i class="ti ti-key"></i></template> </MkInput> - <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" required data-cy-signup-username @update:model-value="onChangeUsername"> + <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" autocomplete="username" required data-cy-signup-username @update:model-value="onChangeUsername"> <template #label>{{ i18n.ts.username }} <div v-tooltip:dialog="i18n.ts.usernameInfo" class="_button _help"><i class="ti ti-help-circle"></i></div></template> <template #prefix>@</template> <template #suffix>@{{ host }}</template> From 95b9284e79d00bb47184122760fac3933e8ef5ae Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 13:35:46 +0900 Subject: [PATCH 052/213] :art: --- .../src/pages/admin/other-settings.vue | 25 ++++++++++++++++--- .../frontend/src/pages/admin/settings.vue | 24 +++--------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/packages/frontend/src/pages/admin/other-settings.vue b/packages/frontend/src/pages/admin/other-settings.vue index 62dff6ce7f..15d720a070 100644 --- a/packages/frontend/src/pages/admin/other-settings.vue +++ b/packages/frontend/src/pages/admin/other-settings.vue @@ -1,9 +1,17 @@ <template> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> - none + <div class="_gaps_s"> + <MkSwitch v-model="enableChartsForRemoteUser"> + <template #label>{{ i18n.ts.enableChartsForRemoteUser }}</template> + </MkSwitch> + + <MkSwitch v-model="enableChartsForFederatedInstances"> + <template #label>{{ i18n.ts.enableChartsForFederatedInstances }}</template> + </MkSwitch> + </div> </FormSuspense> </MkSpacer> </MkStickyContainer> @@ -17,13 +25,22 @@ import * as os from '@/os'; import { fetchInstance } from '@/instance'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import MkSwitch from '@/components/MkSwitch.vue'; + +let enableChartsForRemoteUser: boolean = $ref(false); +let enableChartsForFederatedInstances: boolean = $ref(false); async function init() { - await os.api('admin/meta'); + const meta = await os.api('admin/meta'); + enableChartsForRemoteUser = meta.enableChartsForRemoteUser; + enableChartsForFederatedInstances = meta.enableChartsForFederatedInstances; } function save() { - os.apiWithDialog('admin/update-meta').then(() => { + os.apiWithDialog('admin/update-meta', { + enableChartsForRemoteUser, + enableChartsForFederatedInstances, + }).then(() => { fetchInstance(); }); } diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index 7ec3c381f3..39d5ae8607 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -2,7 +2,7 @@ <div> <MkStickyContainer> <template #header><XHeader :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <div class="_gaps_m"> <MkInput v-model="name"> @@ -13,7 +13,7 @@ <template #label>{{ i18n.ts.instanceDescription }}</template> </MkTextarea> - <FormSplit :min-width="300"> + <FormSplit :minWidth="300"> <MkInput v-model="maintainerName"> <template #label>{{ i18n.ts.maintainerName }}</template> </MkInput> @@ -29,18 +29,6 @@ <template #caption>{{ i18n.ts.pinnedUsersDescription }}</template> </MkTextarea> - <FormSection> - <div class="_gaps_s"> - <MkSwitch v-model="enableChartsForRemoteUser"> - <template #label>{{ i18n.ts.enableChartsForRemoteUser }}</template> - </MkSwitch> - - <MkSwitch v-model="enableChartsForFederatedInstances"> - <template #label>{{ i18n.ts.enableChartsForFederatedInstances }}</template> - </MkSwitch> - </div> - </FormSection> - <FormSection> <template #label>{{ i18n.ts.theme }}</template> @@ -128,7 +116,7 @@ </MkSpacer> <template #footer> <div :class="$style.footer"> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="16"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="16"> <MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> </MkSpacer> </div> @@ -166,8 +154,6 @@ let defaultDarkTheme: any = $ref(null); let pinnedUsers: string = $ref(''); let cacheRemoteFiles: boolean = $ref(false); let enableServiceWorker: boolean = $ref(false); -let enableChartsForRemoteUser: boolean = $ref(false); -let enableChartsForFederatedInstances: boolean = $ref(false); let swPublicKey: any = $ref(null); let swPrivateKey: any = $ref(null); let deeplAuthKey: string = $ref(''); @@ -188,8 +174,6 @@ async function init() { pinnedUsers = meta.pinnedUsers.join('\n'); cacheRemoteFiles = meta.cacheRemoteFiles; enableServiceWorker = meta.enableServiceWorker; - enableChartsForRemoteUser = meta.enableChartsForRemoteUser; - enableChartsForFederatedInstances = meta.enableChartsForFederatedInstances; swPublicKey = meta.swPublickey; swPrivateKey = meta.swPrivateKey; deeplAuthKey = meta.deeplAuthKey; @@ -211,8 +195,6 @@ function save() { pinnedUsers: pinnedUsers.split('\n'), cacheRemoteFiles, enableServiceWorker, - enableChartsForRemoteUser, - enableChartsForFederatedInstances, swPublicKey, swPrivateKey, deeplAuthKey, From 6a5ef5b6f29eee9e36f42ac163f065880cd80e8b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 13:58:09 +0900 Subject: [PATCH 053/213] refactor --- packages/frontend/.eslintrc.js | 5 +- .../src/components/MkAbuseReportWindow.vue | 4 +- .../src/components/MkAccountMoved.vue | 4 +- packages/frontend/src/components/MkAsUi.vue | 12 +-- .../frontend/src/components/MkAvatars.vue | 2 +- packages/frontend/src/components/MkChart.vue | 34 ++++----- .../src/components/MkChartTooltip.vue | 2 +- .../frontend/src/components/MkContainer.vue | 14 ++-- .../frontend/src/components/MkContextMenu.vue | 8 +- .../src/components/MkCropperDialog.vue | 2 +- packages/frontend/src/components/MkDialog.vue | 2 +- .../src/components/MkDrive.navFolder.vue | 18 ++--- packages/frontend/src/components/MkDrive.vue | 24 +++--- .../src/components/MkDriveFileThumbnail.vue | 52 ++++++------- .../src/components/MkDriveSelectDialog.vue | 6 +- .../frontend/src/components/MkDriveWindow.vue | 8 +- .../src/components/MkEmojiPickerDialog.vue | 14 ++-- .../src/components/MkEmojiPickerWindow.vue | 11 +-- .../components/MkFileCaptionEditWindow.vue | 6 +- .../src/components/MkFoldableSection.vue | 74 +++++++++---------- packages/frontend/src/components/MkFolder.vue | 16 ++-- .../frontend/src/components/MkFormDialog.vue | 10 +-- .../src/components/MkGalleryPostPreview.vue | 2 +- .../frontend/src/components/MkImageViewer.vue | 2 +- .../src/components/MkImgWithBlurhash.vue | 14 ++-- .../frontend/src/components/MkKeyValue.vue | 26 +++---- .../frontend/src/components/MkLaunchPad.vue | 2 +- .../frontend/src/components/MkMediaImage.vue | 2 +- .../frontend/src/components/MkMediaVideo.vue | 2 +- .../frontend/src/components/MkMenu.child.vue | 2 +- packages/frontend/src/components/MkMenu.vue | 2 +- packages/frontend/src/components/MkModal.vue | 10 +-- packages/frontend/src/components/MkNote.vue | 8 +- .../src/components/MkNoteDetailed.vue | 6 +- .../frontend/src/components/MkNoteSimple.vue | 2 +- packages/frontend/src/components/MkNotes.vue | 2 +- .../src/components/MkNotification.vue | 4 +- .../MkNotificationSettingWindow.vue | 6 +- .../src/components/MkNotifications.vue | 4 +- .../frontend/src/components/MkPageWindow.vue | 12 +-- .../frontend/src/components/MkPagination.vue | 8 +- .../frontend/src/components/MkPollEditor.vue | 2 +- .../frontend/src/components/MkPopupMenu.vue | 4 +- .../frontend/src/components/MkPostForm.vue | 2 +- .../src/components/MkPostFormAttaches.vue | 2 +- .../src/components/MkPostFormDialog.vue | 4 +- .../MkPushNotificationAllowButton.vue | 38 +++++----- .../src/components/MkReactedUsersDialog.vue | 4 +- .../src/components/MkReactionIcon.vue | 4 +- .../src/components/MkReactionTooltip.vue | 4 +- .../components/MkReactionsViewer.details.vue | 4 +- .../src/components/MkReactionsViewer.vue | 12 +-- .../src/components/MkRenotedUsersDialog.vue | 4 +- packages/frontend/src/components/MkSignin.vue | 6 +- .../src/components/MkSigninDialog.vue | 4 +- .../src/components/MkSignupDialog.form.vue | 10 +-- .../src/components/MkSignupDialog.rules.vue | 8 +- .../src/components/MkSignupDialog.vue | 10 +-- .../src/components/MkSubNoteContent.vue | 4 +- .../frontend/src/components/MkTimeline.vue | 2 +- packages/frontend/src/components/MkToast.vue | 10 +-- .../src/components/MkTokenGenerateWindow.vue | 8 +- .../frontend/src/components/MkTooltip.vue | 10 +-- .../frontend/src/components/MkUpdated.vue | 2 +- .../src/components/MkUrlPreviewPopup.vue | 2 +- .../frontend/src/components/MkUserPopup.vue | 10 +-- .../src/components/MkUserSelectDialog.vue | 10 +-- .../components/MkUserSetupDialog.Follow.vue | 4 +- .../components/MkUserSetupDialog.Profile.vue | 4 +- .../src/components/MkUserSetupDialog.vue | 22 +++--- .../src/components/MkUsersTooltip.vue | 2 +- .../src/components/MkVisibilityPicker.vue | 2 +- .../src/components/MkWaitingDialog.vue | 2 +- .../frontend/src/components/MkWidgets.vue | 10 +-- packages/frontend/src/components/MkWindow.vue | 10 +-- .../src/components/MkYouTubePlayer.vue | 2 +- .../frontend/src/components/global/MkAcct.vue | 2 +- .../src/components/global/MkAvatar.vue | 2 +- .../components/global/MkPageHeader.tabs.vue | 4 +- .../src/components/global/MkPageHeader.vue | 4 +- .../src/components/global/MkUserName.vue | 2 +- 81 files changed, 342 insertions(+), 354 deletions(-) diff --git a/packages/frontend/.eslintrc.js b/packages/frontend/.eslintrc.js index a1e1f57e10..303b74ca16 100644 --- a/packages/frontend/.eslintrc.js +++ b/packages/frontend/.eslintrc.js @@ -62,9 +62,8 @@ module.exports = { 'vue/max-attributes-per-line': 'off', 'vue/html-self-closing': 'off', 'vue/singleline-html-element-content-newline': 'off', - // (vue/vue3-recommended disabled the autofix for Vue 2 compatibility) - 'vue/v-on-event-hyphenation': ['warn', 'always', { autofix: true }], - 'vue/attribute-hyphenation': ['warn', 'never'], + 'vue/v-on-event-hyphenation': ['error', 'never', { autofix: true }], + 'vue/attribute-hyphenation': ['error', 'never'], }, globals: { // Node.js diff --git a/packages/frontend/src/components/MkAbuseReportWindow.vue b/packages/frontend/src/components/MkAbuseReportWindow.vue index 7a1b7d532e..48236782d9 100644 --- a/packages/frontend/src/components/MkAbuseReportWindow.vue +++ b/packages/frontend/src/components/MkAbuseReportWindow.vue @@ -1,5 +1,5 @@ <template> -<MkWindow ref="uiWindow" :initial-width="400" :initial-height="500" :can-resize="true" @closed="emit('closed')"> +<MkWindow ref="uiWindow" :initialWidth="400" :initialHeight="500" :canResize="true" @closed="emit('closed')"> <template #header> <i class="ti ti-exclamation-circle" style="margin-right: 0.5em;"></i> <I18n :src="i18n.ts.reportAbuseOf" tag="span"> @@ -8,7 +8,7 @@ </template> </I18n> </template> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div class="_gaps_m" :class="$style.root"> <div class=""> <MkTextarea v-model="comment"> diff --git a/packages/frontend/src/components/MkAccountMoved.vue b/packages/frontend/src/components/MkAccountMoved.vue index b02bfdc2b8..bc07b9ba5f 100644 --- a/packages/frontend/src/components/MkAccountMoved.vue +++ b/packages/frontend/src/components/MkAccountMoved.vue @@ -7,11 +7,11 @@ </template> <script lang="ts" setup> +import { ref } from 'vue'; +import { UserLite } from 'misskey-js/built/entities'; import MkMention from './MkMention.vue'; import { i18n } from '@/i18n'; import { host as localHost } from '@/config'; -import { ref } from 'vue'; -import { UserLite } from 'misskey-js/built/entities'; import { api } from '@/os'; const user = ref<UserLite>(); diff --git a/packages/frontend/src/components/MkAsUi.vue b/packages/frontend/src/components/MkAsUi.vue index 6ade5316c6..8bfcfa6aa6 100644 --- a/packages/frontend/src/components/MkAsUi.vue +++ b/packages/frontend/src/components/MkAsUi.vue @@ -11,29 +11,29 @@ <div v-else-if="c.type === 'buttons'" class="_buttons" :style="{ justifyContent: align }"> <MkButton v-for="button in c.buttons" :primary="button.primary" :rounded="button.rounded" :disabled="button.disabled" inline :small="size === 'small'" @click="button.onClick">{{ button.text }}</MkButton> </div> - <MkSwitch v-else-if="c.type === 'switch'" :model-value="valueForSwitch" @update:model-value="onSwitchUpdate"> + <MkSwitch v-else-if="c.type === 'switch'" :modelValue="valueForSwitch" @update:modelValue="onSwitchUpdate"> <template v-if="c.label" #label>{{ c.label }}</template> <template v-if="c.caption" #caption>{{ c.caption }}</template> </MkSwitch> - <MkTextarea v-else-if="c.type === 'textarea'" :model-value="c.default" @update:model-value="c.onInput"> + <MkTextarea v-else-if="c.type === 'textarea'" :modelValue="c.default" @update:modelValue="c.onInput"> <template v-if="c.label" #label>{{ c.label }}</template> <template v-if="c.caption" #caption>{{ c.caption }}</template> </MkTextarea> - <MkInput v-else-if="c.type === 'textInput'" :small="size === 'small'" :model-value="c.default" @update:model-value="c.onInput"> + <MkInput v-else-if="c.type === 'textInput'" :small="size === 'small'" :modelValue="c.default" @update:modelValue="c.onInput"> <template v-if="c.label" #label>{{ c.label }}</template> <template v-if="c.caption" #caption>{{ c.caption }}</template> </MkInput> - <MkInput v-else-if="c.type === 'numberInput'" :small="size === 'small'" :model-value="c.default" type="number" @update:model-value="c.onInput"> + <MkInput v-else-if="c.type === 'numberInput'" :small="size === 'small'" :modelValue="c.default" type="number" @update:modelValue="c.onInput"> <template v-if="c.label" #label>{{ c.label }}</template> <template v-if="c.caption" #caption>{{ c.caption }}</template> </MkInput> - <MkSelect v-else-if="c.type === 'select'" :small="size === 'small'" :model-value="c.default" @update:model-value="c.onChange"> + <MkSelect v-else-if="c.type === 'select'" :small="size === 'small'" :modelValue="c.default" @update:modelValue="c.onChange"> <template v-if="c.label" #label>{{ c.label }}</template> <template v-if="c.caption" #caption>{{ c.caption }}</template> <option v-for="item in c.items" :key="item.value" :value="item.value">{{ item.text }}</option> </MkSelect> <MkButton v-else-if="c.type === 'postFormButton'" :primary="c.primary" :rounded="c.rounded" :small="size === 'small'" inline @click="openPostForm">{{ c.text }}</MkButton> - <MkFolder v-else-if="c.type === 'folder'" :default-open="c.opened"> + <MkFolder v-else-if="c.type === 'folder'" :defaultOpen="c.opened"> <template #label>{{ c.title }}</template> <template v-for="child in c.children" :key="child"> <MkAsUi v-if="!g(child).hidden" :component="g(child)" :components="props.components" :size="size"/> diff --git a/packages/frontend/src/components/MkAvatars.vue b/packages/frontend/src/components/MkAvatars.vue index 995a72e511..630620fc08 100644 --- a/packages/frontend/src/components/MkAvatars.vue +++ b/packages/frontend/src/components/MkAvatars.vue @@ -1,7 +1,7 @@ <template> <div> <div v-for="user in users" :key="user.id" style="display:inline-block;width:32px;height:32px;margin-right:8px;"> - <MkAvatar :user="user" style="width:32px;height:32px;" indicator link preview/> + <MkAvatar :user="user" style="width:32px; height:32px;" indicator link preview/> </div> </div> </template> diff --git a/packages/frontend/src/components/MkChart.vue b/packages/frontend/src/components/MkChart.vue index 06d5b9949a..00ff98774b 100644 --- a/packages/frontend/src/components/MkChart.vue +++ b/packages/frontend/src/components/MkChart.vue @@ -1,8 +1,8 @@ <template> -<div class="cbbedffa"> +<div :class="$style.root"> <canvas ref="chartEl"></canvas> <MkChartLegend ref="legendEl" style="margin-top: 8px;"/> - <div v-if="fetching" class="fetching"> + <div v-if="fetching" :class="$style.fetching"> <MkLoading/> </div> </div> @@ -817,22 +817,22 @@ onMounted(() => { /* eslint-enable id-denylist */ </script> -<style lang="scss" scoped> -.cbbedffa { +<style lang="scss" module> +.root { position: relative; +} - > .fetching { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - -webkit-backdrop-filter: var(--blur, blur(12px)); - backdrop-filter: var(--blur, blur(12px)); - display: flex; - justify-content: center; - align-items: center; - cursor: wait; - } +.fetching { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + -webkit-backdrop-filter: var(--blur, blur(12px)); + backdrop-filter: var(--blur, blur(12px)); + display: flex; + justify-content: center; + align-items: center; + cursor: wait; } </style> diff --git a/packages/frontend/src/components/MkChartTooltip.vue b/packages/frontend/src/components/MkChartTooltip.vue index 7cfe535edd..fe5b78754d 100644 --- a/packages/frontend/src/components/MkChartTooltip.vue +++ b/packages/frontend/src/components/MkChartTooltip.vue @@ -1,5 +1,5 @@ <template> -<MkTooltip ref="tooltip" :showing="showing" :x="x" :y="y" :max-width="340" :direction="'top'" :inner-margin="16" @closed="emit('closed')"> +<MkTooltip ref="tooltip" :showing="showing" :x="x" :y="y" :maxWidth="340" :direction="'top'" :innerMargin="16" @closed="emit('closed')"> <div v-if="title || series"> <div v-if="title" :class="$style.title">{{ title }}</div> <template v-if="series"> diff --git a/packages/frontend/src/components/MkContainer.vue b/packages/frontend/src/components/MkContainer.vue index d03331a6eb..d2d0fa3e4b 100644 --- a/packages/frontend/src/components/MkContainer.vue +++ b/packages/frontend/src/components/MkContainer.vue @@ -6,7 +6,7 @@ <slot name="header"></slot> </div> <div :class="$style.headerSub"> - <slot name="func" :button-style-class="$style.headerButton"></slot> + <slot name="func" :buttonStyleClass="$style.headerButton"></slot> <button v-if="foldable" :class="$style.headerButton" class="_button" @click="() => showBody = !showBody"> <template v-if="showBody"><i class="ti ti-chevron-up"></i></template> <template v-else><i class="ti ti-chevron-down"></i></template> @@ -14,14 +14,14 @@ </div> </header> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" @enter="enter" - @after-enter="afterEnter" + @afterEnter="afterEnter" @leave="leave" - @after-leave="afterLeave" + @afterLeave="afterLeave" > <div v-show="showBody" ref="contentEl" :class="[$style.content, { [$style.omitted]: omitted }]"> <slot></slot> diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue index b81c806b0c..fb11834f4d 100644 --- a/packages/frontend/src/components/MkContextMenu.vue +++ b/packages/frontend/src/components/MkContextMenu.vue @@ -1,10 +1,10 @@ <template> <Transition appear - :enter-active-class="defaultStore.state.animation ? $style.transition_fade_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_fade_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''" > <div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}"> <MkMenu :items="items" :align="'left'" @close="$emit('closed')"/> diff --git a/packages/frontend/src/components/MkCropperDialog.vue b/packages/frontend/src/components/MkCropperDialog.vue index 043a614e46..82363499b7 100644 --- a/packages/frontend/src/components/MkCropperDialog.vue +++ b/packages/frontend/src/components/MkCropperDialog.vue @@ -4,7 +4,7 @@ :width="800" :height="500" :scroll="false" - :with-ok-button="true" + :withOkButton="true" @close="cancel()" @ok="ok()" @closed="$emit('closed')" diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue index 9f5404ce15..bd4da6c545 100644 --- a/packages/frontend/src/components/MkDialog.vue +++ b/packages/frontend/src/components/MkDialog.vue @@ -1,5 +1,5 @@ <template> -<MkModal ref="modal" :prefer-type="'dialog'" :z-priority="'high'" @click="done(true)" @closed="emit('closed')"> +<MkModal ref="modal" :preferType="'dialog'" :zPriority="'high'" @click="done(true)" @closed="emit('closed')"> <div :class="$style.root"> <div v-if="icon" :class="$style.icon"> <i :class="icon"></i> diff --git a/packages/frontend/src/components/MkDrive.navFolder.vue b/packages/frontend/src/components/MkDrive.navFolder.vue index dbbfef5f05..3349603d3b 100644 --- a/packages/frontend/src/components/MkDrive.navFolder.vue +++ b/packages/frontend/src/components/MkDrive.navFolder.vue @@ -1,13 +1,13 @@ <template> -<div class="drylbebk" - :class="{ draghover }" +<div + :class="[$style.root, { [$style.draghover]: draghover }]" @click="onClick" @dragover.prevent.stop="onDragover" @dragenter="onDragenter" @dragleave="onDragleave" @drop.stop="onDrop" > - <i v-if="folder == null" class="ti ti-cloud"></i> + <i v-if="folder == null" class="ti ti-cloud" style="margin-right: 4px;"></i> <span>{{ folder == null ? i18n.ts.drive : folder.name }}</span> </div> </template> @@ -130,18 +130,10 @@ function onDrop(ev: DragEvent) { } </script> -<style lang="scss" scoped> -.drylbebk { - > * { - pointer-events: none; - } - +<style lang="scss" module> +.root { &.draghover { background: #eee; } - - > i { - margin-right: 4px; - } } </style> diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index edeaabfba4..86534dae43 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -4,21 +4,21 @@ <div class="path" @contextmenu.prevent.stop="() => {}"> <XNavFolder :class="{ current: folder == null }" - :parent-folder="folder" + :parentFolder="folder" @move="move" @upload="upload" - @remove-file="removeFile" - @remove-folder="removeFolder" + @removeFile="removeFile" + @removeFolder="removeFolder" /> <template v-for="f in hierarchyFolders"> <span class="separator"><i class="ti ti-chevron-right"></i></span> <XNavFolder :folder="f" - :parent-folder="folder" + :parentFolder="folder" @move="move" @upload="upload" - @remove-file="removeFile" - @remove-folder="removeFolder" + @removeFile="removeFile" + @removeFolder="removeFolder" /> </template> <span v-if="folder != null" class="separator"><i class="ti ti-chevron-right"></i></span> @@ -43,13 +43,13 @@ v-anim="i" class="folder" :folder="f" - :select-mode="select === 'folder'" - :is-selected="selectedFolders.some(x => x.id === f.id)" + :selectMode="select === 'folder'" + :isSelected="selectedFolders.some(x => x.id === f.id)" @chosen="chooseFolder" @move="move" @upload="upload" - @remove-file="removeFile" - @remove-folder="removeFolder" + @removeFile="removeFile" + @removeFolder="removeFolder" @dragstart="isDragSource = true" @dragend="isDragSource = false" /> @@ -64,8 +64,8 @@ v-anim="i" class="file" :file="file" - :select-mode="select === 'file'" - :is-selected="selectedFiles.some(x => x.id === file.id)" + :selectMode="select === 'file'" + :isSelected="selectedFiles.some(x => x.id === file.id)" @chosen="chooseFile" @dragstart="isDragSource = true" @dragend="isDragSource = false" diff --git a/packages/frontend/src/components/MkDriveFileThumbnail.vue b/packages/frontend/src/components/MkDriveFileThumbnail.vue index 33379ed5ca..490aed6e04 100644 --- a/packages/frontend/src/components/MkDriveFileThumbnail.vue +++ b/packages/frontend/src/components/MkDriveFileThumbnail.vue @@ -1,16 +1,16 @@ <template> -<div ref="thumbnail" class="zdjebgpv"> +<div ref="thumbnail" :class="$style.root"> <ImgWithBlurhash v-if="isThumbnailAvailable" :hash="file.blurhash" :src="file.thumbnailUrl" :alt="file.name" :title="file.name" :cover="fit !== 'contain'"/> - <i v-else-if="is === 'image'" class="ti ti-photo icon"></i> - <i v-else-if="is === 'video'" class="ti ti-video icon"></i> - <i v-else-if="is === 'audio' || is === 'midi'" class="ti ti-file-music icon"></i> - <i v-else-if="is === 'csv'" class="ti ti-file-text icon"></i> - <i v-else-if="is === 'pdf'" class="ti ti-file-text icon"></i> - <i v-else-if="is === 'textfile'" class="ti ti-file-text icon"></i> - <i v-else-if="is === 'archive'" class="ti ti-file-zip icon"></i> - <i v-else class="ti ti-file icon"></i> + <i v-else-if="is === 'image'" class="ti ti-photo" :class="$style.icon"></i> + <i v-else-if="is === 'video'" class="ti ti-video" :class="$style.icon"></i> + <i v-else-if="is === 'audio' || is === 'midi'" class="ti ti-file-music" :class="$style.icon"></i> + <i v-else-if="is === 'csv'" class="ti ti-file-text" :class="$style.icon"></i> + <i v-else-if="is === 'pdf'" class="ti ti-file-text" :class="$style.icon"></i> + <i v-else-if="is === 'textfile'" class="ti ti-file-text" :class="$style.icon"></i> + <i v-else-if="is === 'archive'" class="ti ti-file-zip" :class="$style.icon"></i> + <i v-else class="ti ti-file" :class="$style.icon"></i> - <i v-if="isThumbnailAvailable && is === 'video'" class="ti ti-video icon-sub"></i> + <i v-if="isThumbnailAvailable && is === 'video'" class="ti ti-video" :class="$style.iconSub"></i> </div> </template> @@ -53,28 +53,28 @@ const isThumbnailAvailable = computed(() => { }); </script> -<style lang="scss" scoped> -.zdjebgpv { +<style lang="scss" module> +.root { position: relative; display: flex; background: var(--panel); border-radius: 8px; overflow: clip; +} - > .icon-sub { - position: absolute; - width: 30%; - height: auto; - margin: 0; - right: 4%; - bottom: 4%; - } +.iconSub { + position: absolute; + width: 30%; + height: auto; + margin: 0; + right: 4%; + bottom: 4%; +} - > .icon { - pointer-events: none; - margin: auto; - font-size: 32px; - color: #777; - } +.icon { + pointer-events: none; + margin: auto; + font-size: 32px; + color: #777; } </style> diff --git a/packages/frontend/src/components/MkDriveSelectDialog.vue b/packages/frontend/src/components/MkDriveSelectDialog.vue index 8d2b19c013..da873cb90b 100644 --- a/packages/frontend/src/components/MkDriveSelectDialog.vue +++ b/packages/frontend/src/components/MkDriveSelectDialog.vue @@ -3,8 +3,8 @@ ref="dialog" :width="800" :height="500" - :with-ok-button="true" - :ok-button-disabled="(type === 'file') && (selected.length === 0)" + :withOkButton="true" + :okButtonDisabled="(type === 'file') && (selected.length === 0)" @click="cancel()" @close="cancel()" @ok="ok()" @@ -14,7 +14,7 @@ {{ multiple ? ((type === 'file') ? i18n.ts.selectFiles : i18n.ts.selectFolders) : ((type === 'file') ? i18n.ts.selectFile : i18n.ts.selectFolder) }} <span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span> </template> - <XDrive :multiple="multiple" :select="type" @change-selection="onChangeSelection" @selected="ok()"/> + <XDrive :multiple="multiple" :select="type" @changeSelection="onChangeSelection" @selected="ok()"/> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkDriveWindow.vue b/packages/frontend/src/components/MkDriveWindow.vue index 8b2abc15a3..64ccbec9c3 100644 --- a/packages/frontend/src/components/MkDriveWindow.vue +++ b/packages/frontend/src/components/MkDriveWindow.vue @@ -1,15 +1,15 @@ <template> <MkWindow ref="window" - :initial-width="800" - :initial-height="500" - :can-resize="true" + :initialWidth="800" + :initialHeight="500" + :canResize="true" @closed="emit('closed')" > <template #header> {{ i18n.ts.drive }} </template> - <XDrive :initial-folder="initialFolder"/> + <XDrive :initialFolder="initialFolder"/> </MkWindow> </template> diff --git a/packages/frontend/src/components/MkEmojiPickerDialog.vue b/packages/frontend/src/components/MkEmojiPickerDialog.vue index c568d4ed5c..d60921803b 100644 --- a/packages/frontend/src/components/MkEmojiPickerDialog.vue +++ b/packages/frontend/src/components/MkEmojiPickerDialog.vue @@ -2,10 +2,10 @@ <MkModal ref="modal" v-slot="{ type, maxHeight }" - :z-priority="'middle'" - :prefer-type="asReactionPicker && defaultStore.state.reactionPickerUseDrawerForMobile === false ? 'popup' : 'auto'" - :transparent-bg="true" - :manual-showing="manualShowing" + :zPriority="'middle'" + :preferType="asReactionPicker && defaultStore.state.reactionPickerUseDrawerForMobile === false ? 'popup' : 'auto'" + :transparentBg="true" + :manualShowing="manualShowing" :src="src" @click="modal?.close()" @opening="opening" @@ -16,9 +16,9 @@ ref="picker" class="ryghynhb _popup _shadow" :class="{ drawer: type === 'drawer' }" - :show-pinned="showPinned" - :as-reaction-picker="asReactionPicker" - :as-drawer="type === 'drawer'" + :showPinned="showPinned" + :asReactionPicker="asReactionPicker" + :asDrawer="type === 'drawer'" :max-height="maxHeight" @chosen="chosen" /> diff --git a/packages/frontend/src/components/MkEmojiPickerWindow.vue b/packages/frontend/src/components/MkEmojiPickerWindow.vue index 84970410e9..9fecfd6082 100644 --- a/packages/frontend/src/components/MkEmojiPickerWindow.vue +++ b/packages/frontend/src/components/MkEmojiPickerWindow.vue @@ -1,13 +1,14 @@ <template> -<MkWindow ref="window" - :initial-width="300" - :initial-height="290" - :can-resize="true" +<MkWindow + ref="window" + :initialWidth="300" + :initialHeight="290" + :canResize="true" :mini="true" :front="true" @closed="emit('closed')" > - <MkEmojiPicker :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" as-window :class="$style.picker" @chosen="chosen"/> + <MkEmojiPicker :showPinned="showPinned" :asReactionPicker="asReactionPicker" asWindow :class="$style.picker" @chosen="chosen"/> </MkWindow> </template> diff --git a/packages/frontend/src/components/MkFileCaptionEditWindow.vue b/packages/frontend/src/components/MkFileCaptionEditWindow.vue index 95eef45df0..61b87bda78 100644 --- a/packages/frontend/src/components/MkFileCaptionEditWindow.vue +++ b/packages/frontend/src/components/MkFileCaptionEditWindow.vue @@ -3,14 +3,14 @@ ref="dialog" :width="400" :height="450" - :with-ok-button="true" - :ok-button-disabled="false" + :withOkButton="true" + :okButtonDisabled="false" @ok="ok()" @close="dialog.close()" @closed="emit('closed')" > <template #header>{{ i18n.ts.describeFile }}</template> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <MkDriveFileThumbnail :file="file" fit="contain" style="height: 100px; margin-bottom: 16px;"/> <MkTextarea v-model="caption" autofocus :placeholder="i18n.ts.inputNewDescription"> <template #label>{{ i18n.ts.caption }}</template> diff --git a/packages/frontend/src/components/MkFoldableSection.vue b/packages/frontend/src/components/MkFoldableSection.vue index f52c66a8be..5dd07fc7da 100644 --- a/packages/frontend/src/components/MkFoldableSection.vue +++ b/packages/frontend/src/components/MkFoldableSection.vue @@ -1,9 +1,9 @@ <template> -<div ref="el" class="ssazuxis"> - <header class="_button" :style="{ background: bg }" @click="showBody = !showBody"> - <div class="title"><div><slot name="header"></slot></div></div> - <div class="divider"></div> - <button class="_button"> +<div ref="el" :class="$style.root"> + <header :class="$style.header" class="_button" :style="{ background: bg }" @click="showBody = !showBody"> + <div :class="$style.title"><div><slot name="header"></slot></div></div> + <div :class="$style.divider"></div> + <button class="_button" :class="$style.button"> <template v-if="showBody"><i class="ti ti-chevron-up"></i></template> <template v-else><i class="ti ti-chevron-down"></i></template> </button> @@ -11,9 +11,9 @@ <Transition :name="defaultStore.state.animation ? 'folder-toggle' : ''" @enter="enter" - @after-enter="afterEnter" + @afterEnter="afterEnter" @leave="leave" - @after-leave="afterLeave" + @afterLeave="afterLeave" > <div v-show="showBody"> <slot></slot> @@ -86,7 +86,7 @@ onMounted(() => { }); </script> -<style lang="scss" scoped> +<style lang="scss" module> .folder-toggle-enter-active, .folder-toggle-leave-active { overflow-y: clip; transition: opacity 0.5s, height 0.5s !important; @@ -98,45 +98,41 @@ onMounted(() => { opacity: 0; } -.ssazuxis { +.root { position: relative; +} - > header { - display: flex; - position: relative; - z-index: 10; - position: sticky; - top: var(--stickyTop, 0px); - -webkit-backdrop-filter: var(--blur, blur(8px)); - backdrop-filter: var(--blur, blur(20px)); +.header { + display: flex; + position: relative; + z-index: 10; + position: sticky; + top: var(--stickyTop, 0px); + -webkit-backdrop-filter: var(--blur, blur(8px)); + backdrop-filter: var(--blur, blur(20px)); +} - > .title { - display: grid; - place-content: center; - margin: 0; - padding: 12px 16px 12px 0; - } +.title { + display: grid; + place-content: center; + margin: 0; + padding: 12px 16px 12px 0; +} - > .divider { - flex: 1; - margin: auto; - height: 1px; - background: var(--divider); - } +.divider { + flex: 1; + margin: auto; + height: 1px; + background: var(--divider); +} - > button { - padding: 12px 0 12px 16px; - } - } +.button { + padding: 12px 0 12px 16px; } @container (max-width: 500px) { - .ssazuxis { - > header { - > .title { - padding: 8px 10px 8px 0; - } - } + .title { + padding: 8px 10px 8px 0; } } </style> diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index 8800f31400..526f5e94ea 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -6,7 +6,7 @@ <div :class="$style.headerIcon"><slot name="icon"></slot></div> <div :class="$style.headerText"> <div :class="$style.headerTextMain"> - <MkCondensedLine :min-scale="2 / 3"><slot name="label"></slot></MkCondensedLine> + <MkCondensedLine :minScale="2 / 3"><slot name="label"></slot></MkCondensedLine> </div> <div :class="$style.headerTextSub"> <slot name="caption"></slot> @@ -22,18 +22,18 @@ <div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : null, overflow: maxHeight ? `auto` : null }" :aria-hidden="!opened"> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" @enter="enter" - @after-enter="afterEnter" + @afterEnter="afterEnter" @leave="leave" - @after-leave="afterLeave" + @afterLeave="afterLeave" > <KeepAlive> <div v-show="opened"> - <MkSpacer :margin-min="14" :margin-max="22"> + <MkSpacer :marginMin="14" :marginMax="22"> <slot></slot> </MkSpacer> </div> diff --git a/packages/frontend/src/components/MkFormDialog.vue b/packages/frontend/src/components/MkFormDialog.vue index b4ef54aecd..6d2b391e6d 100644 --- a/packages/frontend/src/components/MkFormDialog.vue +++ b/packages/frontend/src/components/MkFormDialog.vue @@ -2,9 +2,9 @@ <MkModalWindow ref="dialog" :width="450" - :can-close="false" - :with-ok-button="true" - :ok-button-disabled="false" + :canClose="false" + :withOkButton="true" + :okButtonDisabled="false" @click="cancel()" @ok="ok()" @close="cancel()" @@ -14,7 +14,7 @@ {{ title }} </template> - <MkSpacer :margin-min="20" :margin-max="32"> + <MkSpacer :marginMin="20" :marginMax="32"> <div class="_gaps_m"> <template v-for="item in Object.keys(form).filter(item => !form[item].hidden)"> <MkInput v-if="form[item].type === 'number'" v-model="values[item]" type="number" :step="form[item].step || 1"> @@ -41,7 +41,7 @@ <template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ i18n.ts.optional }})</span></template> <option v-for="item in form[item].options" :key="item.value" :value="item.value">{{ item.label }}</option> </MkRadios> - <MkRange v-else-if="form[item].type === 'range'" v-model="values[item]" :min="form[item].min" :max="form[item].max" :step="form[item].step" :text-converter="form[item].textConverter"> + <MkRange v-else-if="form[item].type === 'range'" v-model="values[item]" :min="form[item].min" :max="form[item].max" :step="form[item].step" :textConverter="form[item].textConverter"> <template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ i18n.ts.optional }})</span></template> <template v-if="form[item].description" #caption>{{ form[item].description }}</template> </MkRange> diff --git a/packages/frontend/src/components/MkGalleryPostPreview.vue b/packages/frontend/src/components/MkGalleryPostPreview.vue index fccc33dcc2..3a39ad963b 100644 --- a/packages/frontend/src/components/MkGalleryPostPreview.vue +++ b/packages/frontend/src/components/MkGalleryPostPreview.vue @@ -11,7 +11,7 @@ }" :src="post.files[0].thumbnailUrl" :hash="post.files[0].blurhash" - :force-blurhash="!show" + :forceBlurhash="!show" /> </Transition> </div> diff --git a/packages/frontend/src/components/MkImageViewer.vue b/packages/frontend/src/components/MkImageViewer.vue index a90e27e502..e3b2ebe651 100644 --- a/packages/frontend/src/components/MkImageViewer.vue +++ b/packages/frontend/src/components/MkImageViewer.vue @@ -1,5 +1,5 @@ <template> -<MkModal ref="modal" :z-priority="'middle'" @click="modal.close()" @closed="emit('closed')"> +<MkModal ref="modal" :zPriority="'middle'" @click="modal.close()" @closed="emit('closed')"> <div class="xubzgfga"> <header>{{ image.name }}</header> <img :src="image.url" :alt="image.comment" :title="image.comment" @click="modal.close()"/> diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index de14d9ea28..38406cc0be 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -2,12 +2,12 @@ <div ref="root" :class="[$style.root, { [$style.cover]: cover }]" :title="title ?? ''"> <TransitionGroup :duration="defaultStore.state.animation && props.transition?.duration || undefined" - :enter-active-class="defaultStore.state.animation && props.transition?.enterActiveClass || undefined" - :leave-active-class="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style['transition_leaveActive']) || undefined" - :enter-from-class="defaultStore.state.animation && props.transition?.enterFromClass || undefined" - :leave-to-class="defaultStore.state.animation && props.transition?.leaveToClass || undefined" - :enter-to-class="defaultStore.state.animation && props.transition?.enterToClass || undefined" - :leave-from-class="defaultStore.state.animation && props.transition?.leaveFromClass || undefined" + :enterActiveClass="defaultStore.state.animation && props.transition?.enterActiveClass || undefined" + :leaveActiveClass="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style['transition_leaveActive']) || undefined" + :enterFromClass="defaultStore.state.animation && props.transition?.enterFromClass || undefined" + :leaveToClass="defaultStore.state.animation && props.transition?.leaveToClass || undefined" + :enterToClass="defaultStore.state.animation && props.transition?.enterToClass || undefined" + :leaveFromClass="defaultStore.state.animation && props.transition?.leaveFromClass || undefined" > <canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined"/> <img v-show="!hide" key="img" ref="img" :height="imgHeight" :width="imgWidth" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async"/> @@ -16,10 +16,10 @@ </template> <script lang="ts"> +import { $ref } from 'vue/macros'; import DrawBlurhash from '@/workers/draw-blurhash?worker'; import TestWebGL2 from '@/workers/test-webgl2?worker'; import { WorkerMultiDispatch } from '@/scripts/worker-multi-dispatch'; -import { $ref } from 'vue/macros'; import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; const workerPromise = new Promise<WorkerMultiDispatch | null>(resolve => { diff --git a/packages/frontend/src/components/MkKeyValue.vue b/packages/frontend/src/components/MkKeyValue.vue index ff69c79641..4b6a775635 100644 --- a/packages/frontend/src/components/MkKeyValue.vue +++ b/packages/frontend/src/components/MkKeyValue.vue @@ -1,9 +1,9 @@ <template> -<div class="alqyeyti" :class="{ oneline }"> - <div class="key"> +<div :class="[$style.root, { [$style.oneline]: oneline }]"> + <div :class="$style.key"> <slot name="key"></slot> </div> - <div class="value"> + <div :class="$style.value"> <slot name="value"></slot> <button v-if="copy" v-tooltip="i18n.ts.copy" class="_textButton" style="margin-left: 0.5em;" @click="copy_"><i class="ti ti-copy"></i></button> </div> @@ -30,24 +30,18 @@ const copy_ = () => { }; </script> -<style lang="scss" scoped> -.alqyeyti { - > .key { - font-size: 0.85em; - padding: 0 0 0.25em 0; - opacity: 0.75; - } - +<style lang="scss" module> +.root { &.oneline { display: flex; - > .key { + .key { width: 30%; font-size: 1em; padding: 0 8px 0 0; } - > .value { + .value { width: 70%; white-space: nowrap; overflow: hidden; @@ -55,4 +49,10 @@ const copy_ = () => { } } } + +.key { + font-size: 0.85em; + padding: 0 0 0.25em 0; + opacity: 0.75; +} </style> diff --git a/packages/frontend/src/components/MkLaunchPad.vue b/packages/frontend/src/components/MkLaunchPad.vue index 80e5cc8270..9262778612 100644 --- a/packages/frontend/src/components/MkLaunchPad.vue +++ b/packages/frontend/src/components/MkLaunchPad.vue @@ -1,5 +1,5 @@ <template> -<MkModal ref="modal" v-slot="{ type, maxHeight }" :prefer-type="preferedModalType" :anchor="anchor" :transparent-bg="true" :src="src" @click="modal.close()" @closed="emit('closed')"> +<MkModal ref="modal" v-slot="{ type, maxHeight }" :preferType="preferedModalType" :anchor="anchor" :transparentBg="true" :src="src" @click="modal.close()" @closed="emit('closed')"> <div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }"> <div class="main"> <template v-for="item in items"> diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index b235dd8bd5..c1f8ab3a67 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -8,7 +8,7 @@ <ImgWithBlurhash :hash="image.blurhash" :src="(defaultStore.state.enableDataSaverMode && hide) ? null : url" - :force-blurhash="hide" + :forceBlurhash="hide" :cover="hide" :alt="image.comment || image.name" :title="image.comment || image.name" diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index a4b76300e6..e2c1bed785 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -27,8 +27,8 @@ <script lang="ts" setup> import { ref } from 'vue'; import * as misskey from 'misskey-js'; -import bytes from '@/filters/bytes'; import VuePlyr from 'vue-plyr'; +import bytes from '@/filters/bytes'; import { defaultStore } from '@/store'; import 'vue-plyr/dist/vue-plyr.css'; import { i18n } from '@/i18n'; diff --git a/packages/frontend/src/components/MkMenu.child.vue b/packages/frontend/src/components/MkMenu.child.vue index e0935efbe7..4fedfe7014 100644 --- a/packages/frontend/src/components/MkMenu.child.vue +++ b/packages/frontend/src/components/MkMenu.child.vue @@ -1,6 +1,6 @@ <template> <div ref="el" :class="$style.root"> - <MkMenu :items="items" :align="align" :width="width" :as-drawer="false" @close="onChildClosed"/> + <MkMenu :items="items" :align="align" :width="width" :asDrawer="false" @close="onChildClosed"/> </div> </template> diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index e513a65a32..2697e3e21a 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -50,7 +50,7 @@ </span> </div> <div v-if="childMenu" :class="$style.child"> - <XChild ref="child" :items="childMenu" :target-element="childTarget" :root-element="itemsEl" showing @actioned="childActioned"/> + <XChild ref="child" :items="childMenu" :targetElement="childTarget" :rootElement="itemsEl" showing @actioned="childActioned"/> </div> </div> </template> diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue index 99df9e8150..a33bb2d0e2 100644 --- a/packages/frontend/src/components/MkModal.vue +++ b/packages/frontend/src/components/MkModal.vue @@ -1,11 +1,11 @@ <template> <Transition :name="transitionName" - :enter-active-class="$style['transition_' + transitionName + '_enterActive']" - :leave-active-class="$style['transition_' + transitionName + '_leaveActive']" - :enter-from-class="$style['transition_' + transitionName + '_enterFrom']" - :leave-to-class="$style['transition_' + transitionName + '_leaveTo']" - :duration="transitionDuration" appear @after-leave="emit('closed')" @enter="emit('opening')" @after-enter="onOpened" + :enterActiveClass="$style['transition_' + transitionName + '_enterActive']" + :leaveActiveClass="$style['transition_' + transitionName + '_leaveActive']" + :enterFromClass="$style['transition_' + transitionName + '_enterFrom']" + :leaveToClass="$style['transition_' + transitionName + '_leaveTo']" + :duration="transitionDuration" appear @afterLeave="emit('closed')" @enter="emit('opening')" @afterEnter="onOpened" > <div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> <div data-cy-bg :data-cy-transparent="isEnableBgTransparent" class="_modalBg" :class="[$style.bg, { [$style.bgTransparent]: isEnableBgTransparent }]" :style="{ zIndex }" @click="onBgClick" @mousedown="onBgClick" @contextmenu.prevent.stop="() => {}"></div> diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index d95f8de311..e0f2ab61c5 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -55,17 +55,17 @@ <div :class="$style.text"> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> - <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> + <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> <div v-if="translating || translation" :class="$style.translation"> <MkLoading v-if="translating" mini/> <div v-else :class="$style.translated"> <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b> - <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> + <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> </div> </div> </div> <div v-if="appearNote.files.length > 0" :class="$style.files"> - <MkMediaList :media-list="appearNote.files"/> + <MkMediaList :mediaList="appearNote.files"/> </div> <MkPoll v-if="appearNote.poll" :note="appearNote" :class="$style.poll"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/> @@ -79,7 +79,7 @@ </div> <MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA> </div> - <MkReactionsViewer :note="appearNote" :max-number="16"> + <MkReactionsViewer :note="appearNote" :maxNumber="16"> <template #more> <button class="_button" :class="$style.reactionDetailsButton" @click="showReactions"> {{ i18n.ts.more }} diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 0d6d329d98..fe39328e14 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -65,18 +65,18 @@ <div class="text"> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> - <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> + <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> <a v-if="appearNote.renote != null" class="rp">RN:</a> <div v-if="translating || translation" class="translation"> <MkLoading v-if="translating" mini/> <div v-else class="translated"> <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b> - <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emoji-urls="appearNote.emojis"/> + <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> </div> </div> </div> <div v-if="appearNote.files.length > 0" class="files"> - <MkMediaList :media-list="appearNote.files"/> + <MkMediaList :mediaList="appearNote.files"/> </div> <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/> <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" class="url-preview"/> diff --git a/packages/frontend/src/components/MkNoteSimple.vue b/packages/frontend/src/components/MkNoteSimple.vue index bd27a43b61..21be1454a7 100644 --- a/packages/frontend/src/components/MkNoteSimple.vue +++ b/packages/frontend/src/components/MkNoteSimple.vue @@ -5,7 +5,7 @@ <MkNoteHeader :class="$style.header" :note="note" :mini="true"/> <div> <p v-if="note.cw != null" :class="$style.cw"> - <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :i="$i" :emoji-urls="note.emojis"/> + <Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :i="$i" :emojiUrls="note.emojis"/> <MkCwButton v-model="showContent" :note="note"/> </p> <div v-show="note.cw == null || showContent"> diff --git a/packages/frontend/src/components/MkNotes.vue b/packages/frontend/src/components/MkNotes.vue index a4e949c898..9cc2b7a967 100644 --- a/packages/frontend/src/components/MkNotes.vue +++ b/packages/frontend/src/components/MkNotes.vue @@ -15,7 +15,7 @@ :items="notes" :direction="pagination.reversed ? 'up' : 'down'" :reversed="pagination.reversed" - :no-gap="noGap" + :noGap="noGap" :ad="true" :class="$style.notes" > diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index efae687e66..b4c424e79e 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -20,8 +20,8 @@ v-else-if="notification.type === 'reaction'" ref="reactionRef" :reaction="notification.reaction ? notification.reaction.replace(/^:(\w+):$/, ':$1@.:') : notification.reaction" - :custom-emojis="notification.note.emojis" - :no-style="true" + :customEmojis="notification.note.emojis" + :noStyle="true" style="width: 100%; height: 100%;" /> </div> diff --git a/packages/frontend/src/components/MkNotificationSettingWindow.vue b/packages/frontend/src/components/MkNotificationSettingWindow.vue index f6d0e5681d..598d3a0551 100644 --- a/packages/frontend/src/components/MkNotificationSettingWindow.vue +++ b/packages/frontend/src/components/MkNotificationSettingWindow.vue @@ -3,15 +3,15 @@ ref="dialog" :width="400" :height="450" - :with-ok-button="true" - :ok-button-disabled="false" + :withOkButton="true" + :okButtonDisabled="false" @ok="ok()" @close="dialog?.close()" @closed="emit('closed')" > <template #header>{{ i18n.ts.notificationSetting }}</template> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div class="_gaps_m"> <template v-if="showGlobalToggle"> <MkSwitch v-model="useGlobalSetting"> diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index 8cb1b064ba..70224bffa1 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -8,9 +8,9 @@ </template> <template #default="{ items: notifications }"> - <MkDateSeparatedList v-slot="{ item: notification }" :class="$style.list" :items="notifications" :no-gap="true"> + <MkDateSeparatedList v-slot="{ item: notification }" :class="$style.list" :items="notifications" :noGap="true"> <MkNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :key="notification.id" :note="notification.note"/> - <XNotification v-else :key="notification.id" :notification="notification" :with-time="true" :full="true" class="_panel notification"/> + <XNotification v-else :key="notification.id" :notification="notification" :withTime="true" :full="true" class="_panel notification"/> </MkDateSeparatedList> </template> </MkPagination> diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index bd842c486a..709b5a52df 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -1,12 +1,12 @@ <template> <MkWindow ref="windowEl" - :initial-width="500" - :initial-height="500" - :can-resize="true" - :close-button="true" - :buttons-left="buttonsLeft" - :buttons-right="buttonsRight" + :initialWidth="500" + :initialHeight="500" + :canResize="true" + :closeButton="true" + :buttonsLeft="buttonsLeft" + :buttonsRight="buttonsRight" :contextmenu="contextmenu" @closed="$emit('closed')" > diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index cd8af560e4..740094b113 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -1,9 +1,9 @@ <template> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_fade_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_fade_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''" mode="out-in" > <MkLoading v-if="fetching"/> diff --git a/packages/frontend/src/components/MkPollEditor.vue b/packages/frontend/src/components/MkPollEditor.vue index 471ec39169..2da9339944 100644 --- a/packages/frontend/src/components/MkPollEditor.vue +++ b/packages/frontend/src/components/MkPollEditor.vue @@ -5,7 +5,7 @@ </p> <ul> <li v-for="(choice, i) in choices" :key="i"> - <MkInput class="input" small :model-value="choice" :placeholder="i18n.t('_poll.choiceN', { n: i + 1 })" @update:model-value="onInput(i, $event)"> + <MkInput class="input" small :modelValue="choice" :placeholder="i18n.t('_poll.choiceN', { n: i + 1 })" @update:modelValue="onInput(i, $event)"> </MkInput> <button class="_button" @click="remove(i)"> <i class="ti ti-x"></i> diff --git a/packages/frontend/src/components/MkPopupMenu.vue b/packages/frontend/src/components/MkPopupMenu.vue index 93b9eb401d..30af365669 100644 --- a/packages/frontend/src/components/MkPopupMenu.vue +++ b/packages/frontend/src/components/MkPopupMenu.vue @@ -1,6 +1,6 @@ <template> -<MkModal ref="modal" v-slot="{ type, maxHeight }" :z-priority="'high'" :src="src" :transparent-bg="true" @click="modal.close()" @close="emit('closing')" @closed="emit('closed')"> - <MkMenu :items="items" :align="align" :width="width" :max-height="maxHeight" :as-drawer="type === 'drawer'" :class="{ [$style.drawer]: type === 'drawer' }" @close="modal.close()"/> +<MkModal ref="modal" v-slot="{ type, maxHeight }" :zPriority="'high'" :src="src" :transparentBg="true" @click="modal.close()" @close="emit('closing')" @closed="emit('closed')"> + <MkMenu :items="items" :align="align" :width="width" :max-height="maxHeight" :asDrawer="type === 'drawer'" :class="{ [$style.drawer]: type === 'drawer' }" @close="modal.close()"/> </MkModal> </template> diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index c43d353d9c..668f023e51 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -66,7 +66,7 @@ <div v-if="maxTextLength - textLength < 100" :class="['_acrylic', $style.textCount, { [$style.textOver]: textLength > maxTextLength }]">{{ maxTextLength - textLength }}</div> </div> <input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags"> - <XPostFormAttaches v-model="files" :class="$style.attaches" @detach="detachFile" @change-sensitive="updateFileSensitive" @change-name="updateFileName"/> + <XPostFormAttaches v-model="files" :class="$style.attaches" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/> <MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/> <MkNotePreview v-if="showPreview" :class="$style.preview" :text="text"/> <div v-if="showingOptions" style="padding: 8px 16px;"> diff --git a/packages/frontend/src/components/MkPostFormAttaches.vue b/packages/frontend/src/components/MkPostFormAttaches.vue index 760c6e5d08..5227afee0d 100644 --- a/packages/frontend/src/components/MkPostFormAttaches.vue +++ b/packages/frontend/src/components/MkPostFormAttaches.vue @@ -1,6 +1,6 @@ <template> <div v-show="props.modelValue.length != 0" class="skeikyzd"> - <Sortable :model-value="props.modelValue" class="files" item-key="id" :animation="150" :delay="100" :delay-on-touch-only="true" @update:model-value="v => emit('update:modelValue', v)"> + <Sortable :modelValue="props.modelValue" class="files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)"> <template #item="{element}"> <div class="file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)"> <MkDriveFileThumbnail :data-id="element.id" class="thumbnail" :file="element" fit="cover"/> diff --git a/packages/frontend/src/components/MkPostFormDialog.vue b/packages/frontend/src/components/MkPostFormDialog.vue index 6326c498d7..98af92c6f8 100644 --- a/packages/frontend/src/components/MkPostFormDialog.vue +++ b/packages/frontend/src/components/MkPostFormDialog.vue @@ -1,6 +1,6 @@ <template> -<MkModal ref="modal" :prefer-type="'dialog'" @click="modal.close()" @closed="onModalClosed()"> - <MkPostForm ref="form" style="margin: 0 auto auto auto;" v-bind="props" autofocus freeze-after-posted @posted="onPosted" @cancel="modal.close()" @esc="modal.close()"/> +<MkModal ref="modal" :preferType="'dialog'" @click="modal.close()" @closed="onModalClosed()"> + <MkPostForm ref="form" style="margin: 0 auto auto auto;" v-bind="props" autofocus freezeAfterPosted @posted="onPosted" @cancel="modal.close()" @esc="modal.close()"/> </MkModal> </template> diff --git a/packages/frontend/src/components/MkPushNotificationAllowButton.vue b/packages/frontend/src/components/MkPushNotificationAllowButton.vue index b98c814f24..448084d9ba 100644 --- a/packages/frontend/src/components/MkPushNotificationAllowButton.vue +++ b/packages/frontend/src/components/MkPushNotificationAllowButton.vue @@ -72,28 +72,28 @@ function subscribe() { userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(instance.swPublickey), }) - .then(async subscription => { - pushSubscription = subscription; + .then(async subscription => { + pushSubscription = subscription; - // Register - pushRegistrationInServer = await api('sw/register', { - endpoint: subscription.endpoint, - auth: encode(subscription.getKey('auth')), - publickey: encode(subscription.getKey('p256dh')), - }); - }, async err => { // When subscribe failed + // Register + pushRegistrationInServer = await api('sw/register', { + endpoint: subscription.endpoint, + auth: encode(subscription.getKey('auth')), + publickey: encode(subscription.getKey('p256dh')), + }); + }, async err => { // When subscribe failed // 通知が許可されていなかったとき - if (err?.name === 'NotAllowedError') { - console.info('User denied the notification permission request.'); - return; - } + if (err?.name === 'NotAllowedError') { + console.info('User denied the notification permission request.'); + return; + } - // 違うapplicationServerKey (または gcm_sender_id)のサブスクリプションが - // 既に存在していることが原因でエラーになった可能性があるので、 - // そのサブスクリプションを解除しておく - // (これは実行されなさそうだけど、おまじない的に古い実装から残してある) - await unsubscribe(); - }), null, null); + // 違うapplicationServerKey (または gcm_sender_id)のサブスクリプションが + // 既に存在していることが原因でエラーになった可能性があるので、 + // そのサブスクリプションを解除しておく + // (これは実行されなさそうだけど、おまじない的に古い実装から残してある) + await unsubscribe(); + }), null, null); } async function unsubscribe() { diff --git a/packages/frontend/src/components/MkReactedUsersDialog.vue b/packages/frontend/src/components/MkReactedUsersDialog.vue index 0c0cc36692..cd2a359d5c 100644 --- a/packages/frontend/src/components/MkReactedUsersDialog.vue +++ b/packages/frontend/src/components/MkReactedUsersDialog.vue @@ -8,7 +8,7 @@ > <template #header>{{ i18n.ts.reactionsList }}</template> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div v-if="note" class="_gaps"> <div v-if="reactions.length === 0" class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> @@ -22,7 +22,7 @@ </button> </div> <MkA v-for="user in users" :key="user.id" :to="userPage(user)" @click="dialog.close()"> - <MkUserCardMini :user="user" :with-chart="false"/> + <MkUserCardMini :user="user" :withChart="false"/> </MkA> </template> </div> diff --git a/packages/frontend/src/components/MkReactionIcon.vue b/packages/frontend/src/components/MkReactionIcon.vue index 29b3f9b85b..dfb06f63c4 100644 --- a/packages/frontend/src/components/MkReactionIcon.vue +++ b/packages/frontend/src/components/MkReactionIcon.vue @@ -1,6 +1,6 @@ <template> -<MkCustomEmoji v-if="reaction[0] === ':'" :name="reaction" :normal="true" :no-style="noStyle" :url="emojiUrl"/> -<MkEmoji v-else :emoji="reaction" :normal="true" :no-style="noStyle"/> +<MkCustomEmoji v-if="reaction[0] === ':'" :name="reaction" :normal="true" :noStyle="noStyle" :url="emojiUrl"/> +<MkEmoji v-else :emoji="reaction" :normal="true" :noStyle="noStyle"/> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/components/MkReactionTooltip.vue b/packages/frontend/src/components/MkReactionTooltip.vue index 4d67dc3da2..34afa72232 100644 --- a/packages/frontend/src/components/MkReactionTooltip.vue +++ b/packages/frontend/src/components/MkReactionTooltip.vue @@ -1,7 +1,7 @@ <template> -<MkTooltip ref="tooltip" :showing="showing" :target-element="targetElement" :max-width="340" @closed="emit('closed')"> +<MkTooltip ref="tooltip" :showing="showing" :targetElement="targetElement" :maxWidth="340" @closed="emit('closed')"> <div :class="$style.root"> - <MkReactionIcon :reaction="reaction" :class="$style.icon" :no-style="true"/> + <MkReactionIcon :reaction="reaction" :class="$style.icon" :noStyle="true"/> <div :class="$style.name">{{ reaction.replace('@.', '') }}</div> </div> </MkTooltip> diff --git a/packages/frontend/src/components/MkReactionsViewer.details.vue b/packages/frontend/src/components/MkReactionsViewer.details.vue index f5e611c62a..99960f5d25 100644 --- a/packages/frontend/src/components/MkReactionsViewer.details.vue +++ b/packages/frontend/src/components/MkReactionsViewer.details.vue @@ -1,8 +1,8 @@ <template> -<MkTooltip ref="tooltip" :showing="showing" :target-element="targetElement" :max-width="340" @closed="emit('closed')"> +<MkTooltip ref="tooltip" :showing="showing" :targetElement="targetElement" :maxWidth="340" @closed="emit('closed')"> <div :class="$style.root"> <div :class="$style.reaction"> - <MkReactionIcon :reaction="reaction" :class="$style.reactionIcon" :no-style="true"/> + <MkReactionIcon :reaction="reaction" :class="$style.reactionIcon" :noStyle="true"/> <div :class="$style.reactionName">{{ getReactionName(reaction) }}</div> </div> <div :class="$style.users"> diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue index 3219c8a92c..ce146463ec 100644 --- a/packages/frontend/src/components/MkReactionsViewer.vue +++ b/packages/frontend/src/components/MkReactionsViewer.vue @@ -1,13 +1,13 @@ <template> <TransitionGroup - :enter-active-class="defaultStore.state.animation ? $style.transition_x_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_x_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_x_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_x_leaveTo : ''" - :move-class="defaultStore.state.animation ? $style.transition_x_move : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_x_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_x_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_x_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_x_leaveTo : ''" + :moveClass="defaultStore.state.animation ? $style.transition_x_move : ''" tag="div" :class="$style.root" > - <XReaction v-for="[reaction, count] in reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/> + <XReaction v-for="[reaction, count] in reactions" :key="reaction" :reaction="reaction" :count="count" :isInitial="initialReactions.has(reaction)" :note="note"/> <slot v-if="hasMoreReactions" name="more"/> </TransitionGroup> </template> diff --git a/packages/frontend/src/components/MkRenotedUsersDialog.vue b/packages/frontend/src/components/MkRenotedUsersDialog.vue index 56025535f1..814a68d4da 100644 --- a/packages/frontend/src/components/MkRenotedUsersDialog.vue +++ b/packages/frontend/src/components/MkRenotedUsersDialog.vue @@ -8,7 +8,7 @@ > <template #header>{{ i18n.ts.renotesList }}</template> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div v-if="renotes" class="_gaps"> <div v-if="renotes.length === 0" class="_fullinfo"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> @@ -16,7 +16,7 @@ </div> <template v-else> <MkA v-for="user in users" :key="user.id" :to="userPage(user)" @click="dialog.close()"> - <MkUserCardMini :user="user" :with-chart="false"/> + <MkUserCardMini :user="user" :withChart="false"/> </MkA> </template> </div> diff --git a/packages/frontend/src/components/MkSignin.vue b/packages/frontend/src/components/MkSignin.vue index 6eae8ecf84..b1a509b9e6 100644 --- a/packages/frontend/src/components/MkSignin.vue +++ b/packages/frontend/src/components/MkSignin.vue @@ -6,11 +6,11 @@ {{ message }} </MkInfo> <div v-if="!totpLogin" class="normal-signin _gaps_m"> - <MkInput v-model="username" :placeholder="i18n.ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autocomplete="username" autofocus required data-cy-signin-username @update:model-value="onUsernameChange"> + <MkInput v-model="username" :placeholder="i18n.ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autocomplete="username" autofocus required data-cy-signin-username @update:modelValue="onUsernameChange"> <template #prefix>@</template> <template #suffix>@{{ host }}</template> </MkInput> - <MkInput v-if="!user || user && !user.usePasswordLessLogin" v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password" :with-password-toggle="true" required data-cy-signin-password> + <MkInput v-if="!user || user && !user.usePasswordLessLogin" v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password" :withPasswordToggle="true" required data-cy-signin-password> <template #prefix><i class="ti ti-lock"></i></template> <template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template> </MkInput> @@ -28,7 +28,7 @@ </div> <div class="twofa-group totp-group"> <p style="margin-bottom:0;">{{ i18n.ts.twoStepAuthentication }}</p> - <MkInput v-if="user && user.usePasswordLessLogin" v-model="password" type="password" autocomplete="current-password" :with-password-toggle="true" required> + <MkInput v-if="user && user.usePasswordLessLogin" v-model="password" type="password" autocomplete="current-password" :withPasswordToggle="true" required> <template #label>{{ i18n.ts.password }}</template> <template #prefix><i class="ti ti-lock"></i></template> </MkInput> diff --git a/packages/frontend/src/components/MkSigninDialog.vue b/packages/frontend/src/components/MkSigninDialog.vue index 08e41d6ae5..eb5876e584 100644 --- a/packages/frontend/src/components/MkSigninDialog.vue +++ b/packages/frontend/src/components/MkSigninDialog.vue @@ -8,8 +8,8 @@ > <template #header>{{ i18n.ts.login }}</template> - <MkSpacer :margin-min="20" :margin-max="28"> - <MkSignin :auto-set="autoSet" :message="message" @login="onLogin"/> + <MkSpacer :marginMin="20" :marginMax="28"> + <MkSignin :autoSet="autoSet" :message="message" @login="onLogin"/> </MkSpacer> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index 0e8bdb321e..4395078c11 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -3,13 +3,13 @@ <div :class="$style.banner"> <i class="ti ti-user-edit"></i> </div> - <MkSpacer :margin-min="20" :margin-max="32"> + <MkSpacer :marginMin="20" :marginMax="32"> <form class="_gaps_m" autocomplete="new-password" @submit.prevent="onSubmit"> <MkInput v-if="instance.disableRegistration" v-model="invitationCode" type="text" :spellcheck="false" required> <template #label>{{ i18n.ts.invitationCode }}</template> <template #prefix><i class="ti ti-key"></i></template> </MkInput> - <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" required data-cy-signup-username @update:model-value="onChangeUsername"> + <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :spellcheck="false" required data-cy-signup-username @update:modelValue="onChangeUsername"> <template #label>{{ i18n.ts.username }} <div v-tooltip:dialog="i18n.ts.usernameInfo" class="_button _help"><i class="ti ti-help-circle"></i></div></template> <template #prefix>@</template> <template #suffix>@{{ host }}</template> @@ -24,7 +24,7 @@ <span v-else-if="usernameState === 'max-range'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.tooLong }}</span> </template> </MkInput> - <MkInput v-if="instance.emailRequiredForSignup" v-model="email" :debounce="true" type="email" :spellcheck="false" required data-cy-signup-email @update:model-value="onChangeEmail"> + <MkInput v-if="instance.emailRequiredForSignup" v-model="email" :debounce="true" type="email" :spellcheck="false" required data-cy-signup-email @update:modelValue="onChangeEmail"> <template #label>{{ i18n.ts.emailAddress }} <div v-tooltip:dialog="i18n.ts._signup.emailAddressInfo" class="_button _help"><i class="ti ti-help-circle"></i></div></template> <template #prefix><i class="ti ti-mail"></i></template> <template #caption> @@ -39,7 +39,7 @@ <span v-else-if="emailState === 'error'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.error }}</span> </template> </MkInput> - <MkInput v-model="password" type="password" autocomplete="new-password" required data-cy-signup-password @update:model-value="onChangePassword"> + <MkInput v-model="password" type="password" autocomplete="new-password" required data-cy-signup-password @update:modelValue="onChangePassword"> <template #label>{{ i18n.ts.password }}</template> <template #prefix><i class="ti ti-lock"></i></template> <template #caption> @@ -48,7 +48,7 @@ <span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="ti ti-check ti-fw"></i> {{ i18n.ts.strongPassword }}</span> </template> </MkInput> - <MkInput v-model="retypedPassword" type="password" autocomplete="new-password" required data-cy-signup-password-retype @update:model-value="onChangePasswordRetype"> + <MkInput v-model="retypedPassword" type="password" autocomplete="new-password" required data-cy-signup-password-retype @update:modelValue="onChangePasswordRetype"> <template #label>{{ i18n.ts.password }} ({{ i18n.ts.retype }})</template> <template #prefix><i class="ti ti-lock"></i></template> <template #caption> diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue index 6da81c3bcb..b6ffba6cc7 100644 --- a/packages/frontend/src/components/MkSignupDialog.rules.vue +++ b/packages/frontend/src/components/MkSignupDialog.rules.vue @@ -3,7 +3,7 @@ <div :class="$style.banner"> <i class="ti ti-checklist"></i> </div> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div class="_gaps_m"> <div v-if="instance.disableRegistration"> <MkInfo warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo> @@ -11,7 +11,7 @@ <div style="text-align: center;">{{ i18n.ts.pleaseConfirmBelowBeforeSignup }}</div> - <MkFolder v-if="availableServerRules" :default-open="true"> + <MkFolder v-if="availableServerRules" :defaultOpen="true"> <template #label>{{ i18n.ts.serverRules }}</template> <template #suffix><i v-if="agreeServerRules" class="ti ti-check" style="color: var(--success)"></i></template> @@ -22,7 +22,7 @@ <MkSwitch v-model="agreeServerRules" style="margin-top: 16px;">{{ i18n.ts.agree }}</MkSwitch> </MkFolder> - <MkFolder v-if="availableTos" :default-open="true"> + <MkFolder v-if="availableTos" :defaultOpen="true"> <template #label>{{ i18n.ts.termsOfService }}</template> <template #suffix><i v-if="agreeTos" class="ti ti-check" style="color: var(--success)"></i></template> @@ -31,7 +31,7 @@ <MkSwitch v-model="agreeTos" style="margin-top: 16px;">{{ i18n.ts.agree }}</MkSwitch> </MkFolder> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #label>{{ i18n.ts.basicNotesBeforeCreateAccount }}</template> <template #suffix><i v-if="agreeNote" class="ti ti-check" style="color: var(--success)"></i></template> diff --git a/packages/frontend/src/components/MkSignupDialog.vue b/packages/frontend/src/components/MkSignupDialog.vue index 17f8b86425..d8d002fdb6 100644 --- a/packages/frontend/src/components/MkSignupDialog.vue +++ b/packages/frontend/src/components/MkSignupDialog.vue @@ -11,16 +11,16 @@ <div style="overflow-x: clip;"> <Transition mode="out-in" - :enter-active-class="$style.transition_x_enterActive" - :leave-active-class="$style.transition_x_leaveActive" - :enter-from-class="$style.transition_x_enterFrom" - :leave-to-class="$style.transition_x_leaveTo" + :enterActiveClass="$style.transition_x_enterActive" + :leaveActiveClass="$style.transition_x_leaveActive" + :enterFromClass="$style.transition_x_enterFrom" + :leaveToClass="$style.transition_x_leaveTo" > <template v-if="!isAcceptedServerRule"> <XServerRules @done="isAcceptedServerRule = true" @cancel="dialog.close()"/> </template> <template v-else> - <XSignup :auto-set="autoSet" @signup="onSignup" @signup-email-pending="onSignupEmailPending"/> + <XSignup :autoSet="autoSet" @signup="onSignup" @signupEmailPending="onSignupEmailPending"/> </template> </Transition> </div> diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue index 1ac7107aa7..5f32391c7e 100644 --- a/packages/frontend/src/components/MkSubNoteContent.vue +++ b/packages/frontend/src/components/MkSubNoteContent.vue @@ -4,12 +4,12 @@ <span v-if="note.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <span v-if="note.deletedAt" style="opacity: 0.5">({{ i18n.ts.deleted }})</span> <MkA v-if="note.replyId" :class="$style.reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> - <Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i" :emoji-urls="note.emojis"/> + <Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i" :emojiUrls="note.emojis"/> <MkA v-if="note.renoteId" :class="$style.rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> </div> <details v-if="note.files.length > 0"> <summary>({{ i18n.t('withNFiles', { n: note.files.length }) }})</summary> - <MkMediaList :media-list="note.files"/> + <MkMediaList :mediaList="note.files"/> </details> <details v-if="note.poll"> <summary>{{ i18n.ts.poll }}</summary> diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index 25d813e39f..2adc4f1d0c 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -1,5 +1,5 @@ <template> -<MkNotes ref="tlComponent" :no-gap="!defaultStore.state.showGapBetweenNotesInTimeline" :pagination="pagination" @queue="emit('queue', $event)"/> +<MkNotes ref="tlComponent" :noGap="!defaultStore.state.showGapBetweenNotesInTimeline" :pagination="pagination" @queue="emit('queue', $event)"/> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/components/MkToast.vue b/packages/frontend/src/components/MkToast.vue index ad53c7f289..e135f56472 100644 --- a/packages/frontend/src/components/MkToast.vue +++ b/packages/frontend/src/components/MkToast.vue @@ -1,11 +1,11 @@ <template> <div> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_toast_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_toast_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_toast_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_toast_leaveTo : ''" - appear @after-leave="emit('closed')" + :enterActiveClass="defaultStore.state.animation ? $style.transition_toast_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_toast_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_toast_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_toast_leaveTo : ''" + appear @afterLeave="emit('closed')" > <div v-if="showing" class="_acrylic" :class="$style.root" :style="{ zIndex }"> <div style="padding: 16px 24px;"> diff --git a/packages/frontend/src/components/MkTokenGenerateWindow.vue b/packages/frontend/src/components/MkTokenGenerateWindow.vue index 56be044405..3ddd81aaee 100644 --- a/packages/frontend/src/components/MkTokenGenerateWindow.vue +++ b/packages/frontend/src/components/MkTokenGenerateWindow.vue @@ -3,16 +3,16 @@ ref="dialog" :width="400" :height="450" - :with-ok-button="true" - :ok-button-disabled="false" - :can-close="false" + :withOkButton="true" + :okButtonDisabled="false" + :canClose="false" @close="dialog.close()" @closed="$emit('closed')" @ok="ok()" > <template #header>{{ title || i18n.ts.generateAccessToken }}</template> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div class="_gaps_m"> <div v-if="information"> <MkInfo warn>{{ information }}</MkInfo> diff --git a/packages/frontend/src/components/MkTooltip.vue b/packages/frontend/src/components/MkTooltip.vue index ea39198706..91c9b70a5a 100644 --- a/packages/frontend/src/components/MkTooltip.vue +++ b/packages/frontend/src/components/MkTooltip.vue @@ -1,10 +1,10 @@ <template> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_tooltip_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_tooltip_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_tooltip_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_tooltip_leaveTo : ''" - appear @after-leave="emit('closed')" + :enterActiveClass="defaultStore.state.animation ? $style.transition_tooltip_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_tooltip_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_tooltip_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_tooltip_leaveTo : ''" + appear @afterLeave="emit('closed')" > <div v-show="showing" ref="el" :class="$style.root" class="_acrylic _shadow" :style="{ zIndex, maxWidth: maxWidth + 'px' }"> <slot> diff --git a/packages/frontend/src/components/MkUpdated.vue b/packages/frontend/src/components/MkUpdated.vue index eed7fa71f6..3a0b2abb4e 100644 --- a/packages/frontend/src/components/MkUpdated.vue +++ b/packages/frontend/src/components/MkUpdated.vue @@ -1,5 +1,5 @@ <template> -<MkModal ref="modal" :z-priority="'middle'" @click="$refs.modal.close()" @closed="$emit('closed')"> +<MkModal ref="modal" :zPriority="'middle'" @click="$refs.modal.close()" @closed="$emit('closed')"> <div :class="$style.root"> <div :class="$style.title"><MkSparkle>{{ i18n.ts.misskeyUpdated }}</MkSparkle></div> <div :class="$style.version">✨{{ version }}🚀</div> diff --git a/packages/frontend/src/components/MkUrlPreviewPopup.vue b/packages/frontend/src/components/MkUrlPreviewPopup.vue index 30204b91c1..36a9e2f73f 100644 --- a/packages/frontend/src/components/MkUrlPreviewPopup.vue +++ b/packages/frontend/src/components/MkUrlPreviewPopup.vue @@ -1,6 +1,6 @@ <template> <div :class="$style.root" :style="{ zIndex, top: top + 'px', left: left + 'px' }"> - <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" @after-leave="emit('closed')"> + <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" @afterLeave="emit('closed')"> <MkUrlPreview v-if="showing" class="_popup _shadow" :url="url"/> </Transition> </div> diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index 8ca0355448..c9ff02cc76 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -1,10 +1,10 @@ <template> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_popup_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_popup_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_popup_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_popup_leaveTo : ''" - appear @after-leave="emit('closed')" + :enterActiveClass="defaultStore.state.animation ? $style.transition_popup_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_popup_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_popup_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_popup_leaveTo : ''" + appear @afterLeave="emit('closed')" > <div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }"> <div v-if="user != null"> diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue index dc78bbf42d..9ba5d9fc53 100644 --- a/packages/frontend/src/components/MkUserSelectDialog.vue +++ b/packages/frontend/src/components/MkUserSelectDialog.vue @@ -1,8 +1,8 @@ <template> <MkModalWindow ref="dialogEl" - :with-ok-button="true" - :ok-button-disabled="selected == null" + :withOkButton="true" + :okButtonDisabled="selected == null" @click="cancel()" @close="cancel()" @ok="ok()" @@ -11,12 +11,12 @@ <template #header>{{ i18n.ts.selectUser }}</template> <div :class="$style.root"> <div :class="$style.form"> - <FormSplit :min-width="170"> - <MkInput v-model="username" :autofocus="true" @update:model-value="search"> + <FormSplit :minWidth="170"> + <MkInput v-model="username" :autofocus="true" @update:modelValue="search"> <template #label>{{ i18n.ts.username }}</template> <template #prefix>@</template> </MkInput> - <MkInput v-model="host" :datalist="[hostname]" @update:model-value="search"> + <MkInput v-model="host" :datalist="[hostname]" @update:modelValue="search"> <template #label>{{ i18n.ts.host }}</template> <template #prefix>@</template> </MkInput> diff --git a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue index a2a195cb09..789f88a8fe 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Follow.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Follow.vue @@ -2,7 +2,7 @@ <div class="_gaps"> <div style="text-align: center;">{{ i18n.ts._initialAccountSetting.followUsers }}</div> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #label>{{ i18n.ts.recommended }}</template> <MkPagination :pagination="pinnedUsers"> @@ -14,7 +14,7 @@ </MkPagination> </MkFolder> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #label>{{ i18n.ts.popularUsers }}</template> <MkPagination :pagination="popularUsers"> diff --git a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue index 109d26dfaa..3107209b97 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.Profile.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.Profile.vue @@ -12,11 +12,11 @@ </div> </FormSlot> - <MkInput v-model="name" :max="30" manual-save data-cy-user-setup-user-name> + <MkInput v-model="name" :max="30" manualSave data-cy-user-setup-user-name> <template #label>{{ i18n.ts._profile.name }}</template> </MkInput> - <MkTextarea v-model="description" :max="500" tall manual-save data-cy-user-setup-user-description> + <MkTextarea v-model="description" :max="500" tall manualSave data-cy-user-setup-user-description> <template #label>{{ i18n.ts._profile.description }}</template> </MkTextarea> diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 5c04faadca..252c2eecce 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -20,15 +20,15 @@ </div> <Transition mode="out-in" - :enter-active-class="$style.transition_x_enterActive" - :leave-active-class="$style.transition_x_leaveActive" - :enter-from-class="$style.transition_x_enterFrom" - :leave-to-class="$style.transition_x_leaveTo" + :enterActiveClass="$style.transition_x_enterActive" + :leaveActiveClass="$style.transition_x_leaveActive" + :enterFromClass="$style.transition_x_enterFrom" + :leaveToClass="$style.transition_x_leaveTo" > <template v-if="page === 0"> <div :class="$style.centerPage"> <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-confetti" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i> <div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.accountCreated }}</div> @@ -40,7 +40,7 @@ </template> <template v-else-if="page === 1"> <div style="height: 100cqh; overflow: auto;"> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <XProfile/> <div class="_buttonsCenter" style="margin-top: 16px;"> <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> @@ -50,7 +50,7 @@ </template> <template v-else-if="page === 2"> <div style="height: 100cqh; overflow: auto;"> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <XPrivacy/> <div class="_buttonsCenter" style="margin-top: 16px;"> <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> @@ -60,7 +60,7 @@ </template> <template v-else-if="page === 3"> <div style="height: 100cqh; overflow: auto;"> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <XFollow/> </MkSpacer> <div :class="$style.pageFooter"> @@ -70,12 +70,12 @@ </template> <template v-else-if="page === 4"> <div :class="$style.centerPage"> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-bell-ringing-2" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i> <div style="font-size: 120%;">{{ i18n.ts.pushNotification }}</div> <div style="padding: 0 16px;">{{ i18n.t('_initialAccountSetting.pushNotificationDescription', { name: instance.name ?? host }) }}</div> - <MkPushNotificationAllowButton primary show-only-to-register style="margin: 0 auto;"/> + <MkPushNotificationAllowButton primary showOnlyToRegister style="margin: 0 auto;"/> <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> </div> </MkSpacer> @@ -84,7 +84,7 @@ <template v-else-if="page === 5"> <div :class="$style.centerPage"> <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> - <MkSpacer :margin-min="20" :margin-max="28"> + <MkSpacer :marginMin="20" :marginMax="28"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--accent);"></i> <div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.initialAccountSettingCompleted }}</div> diff --git a/packages/frontend/src/components/MkUsersTooltip.vue b/packages/frontend/src/components/MkUsersTooltip.vue index d0f95fceda..bed725cd1d 100644 --- a/packages/frontend/src/components/MkUsersTooltip.vue +++ b/packages/frontend/src/components/MkUsersTooltip.vue @@ -1,5 +1,5 @@ <template> -<MkTooltip ref="tooltip" :showing="showing" :target-element="targetElement" :max-width="250" @closed="emit('closed')"> +<MkTooltip ref="tooltip" :showing="showing" :targetElement="targetElement" :maxWidth="250" @closed="emit('closed')"> <div :class="$style.root"> <div v-for="u in users" :key="u.id" :class="$style.user"> <MkAvatar :class="$style.avatar" :user="u"/> diff --git a/packages/frontend/src/components/MkVisibilityPicker.vue b/packages/frontend/src/components/MkVisibilityPicker.vue index c181d84bc0..c8dbe90944 100644 --- a/packages/frontend/src/components/MkVisibilityPicker.vue +++ b/packages/frontend/src/components/MkVisibilityPicker.vue @@ -1,5 +1,5 @@ <template> -<MkModal ref="modal" v-slot="{ type }" :z-priority="'high'" :src="src" @click="modal.close()" @closed="emit('closed')"> +<MkModal ref="modal" v-slot="{ type }" :zPriority="'high'" :src="src" @click="modal.close()" @closed="emit('closed')"> <div class="_popup" :class="{ [$style.root]: true, [$style.asDrawer]: type === 'drawer' }"> <div :class="[$style.label, $style.item]"> {{ i18n.ts.visibility }} diff --git a/packages/frontend/src/components/MkWaitingDialog.vue b/packages/frontend/src/components/MkWaitingDialog.vue index da98da29d0..1b6ab1f13a 100644 --- a/packages/frontend/src/components/MkWaitingDialog.vue +++ b/packages/frontend/src/components/MkWaitingDialog.vue @@ -1,5 +1,5 @@ <template> -<MkModal ref="modal" :prefer-type="'dialog'" :z-priority="'high'" @click="success ? done() : () => {}" @closed="emit('closed')"> +<MkModal ref="modal" :preferType="'dialog'" :zPriority="'high'" @click="success ? done() : () => {}" @closed="emit('closed')"> <div :class="[$style.root, { [$style.iconOnly]: (text == null) || success }]"> <i v-if="success" :class="[$style.icon, $style.success]" class="ti ti-check"></i> <MkLoading v-else :class="[$style.icon, $style.waiting]" :em="true"/> diff --git a/packages/frontend/src/components/MkWidgets.vue b/packages/frontend/src/components/MkWidgets.vue index ad1c02a488..9fd1d61632 100644 --- a/packages/frontend/src/components/MkWidgets.vue +++ b/packages/frontend/src/components/MkWidgets.vue @@ -10,26 +10,26 @@ <MkButton inline @click="$emit('exit')">{{ i18n.ts.close }}</MkButton> </header> <Sortable - :model-value="props.widgets" - item-key="id" + :modelValue="props.widgets" + itemKey="id" handle=".handle" :animation="150" :group="{ name: 'SortableMkWidgets' }" :class="$style['edit-editing']" - @update:model-value="v => emit('updateWidgets', v)" + @update:modelValue="v => emit('updateWidgets', v)" > <template #item="{element}"> <div :class="[$style.widget, $style['customize-container']]" data-cy-customize-container> <button :class="$style['customize-container-config']" class="_button" @click.prevent.stop="configWidget(element.id)"><i class="ti ti-settings"></i></button> <button :class="$style['customize-container-remove']" data-cy-customize-container-remove class="_button" @click.prevent.stop="removeWidget(element)"><i class="ti ti-x"></i></button> <div class="handle"> - <component :is="`widget-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style['customize-container-handle-widget']" :widget="element" @update-props="updateWidget(element.id, $event)"/> + <component :is="`widget-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style['customize-container-handle-widget']" :widget="element" @updateProps="updateWidget(element.id, $event)"/> </div> </div> </template> </Sortable> </template> - <component :is="`widget-${widget.name}`" v-for="widget in widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @update-props="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/> + <component :is="`widget-${widget.name}`" v-for="widget in widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @updateProps="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/> </div> </template> diff --git a/packages/frontend/src/components/MkWindow.vue b/packages/frontend/src/components/MkWindow.vue index b662479b2a..dafabf2ba8 100644 --- a/packages/frontend/src/components/MkWindow.vue +++ b/packages/frontend/src/components/MkWindow.vue @@ -1,11 +1,11 @@ <template> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_window_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_window_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_window_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_window_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_window_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_window_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_window_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_window_leaveTo : ''" appear - @after-leave="$emit('closed')" + @afterLeave="$emit('closed')" > <div v-if="showing" ref="rootEl" :class="[$style.root, { [$style.maximized]: maximized }]"> <div :class="$style.body" class="_shadow" @mousedown="onBodyMousedown" @keydown="onKeydown"> diff --git a/packages/frontend/src/components/MkYouTubePlayer.vue b/packages/frontend/src/components/MkYouTubePlayer.vue index 4d765fe2f7..0edfd98efc 100644 --- a/packages/frontend/src/components/MkYouTubePlayer.vue +++ b/packages/frontend/src/components/MkYouTubePlayer.vue @@ -1,5 +1,5 @@ <template> -<MkWindow :initial-width="640" :initial-height="402" :can-resize="true" :close-button="true"> +<MkWindow :initialWidth="640" :initialHeight="402" :canResize="true" :closeButton="true"> <template #header> <i class="icon ti ti-brand-youtube" style="margin-right: 0.5em;"></i> <span>{{ title ?? 'YouTube' }}</span> diff --git a/packages/frontend/src/components/global/MkAcct.vue b/packages/frontend/src/components/global/MkAcct.vue index 59358aef70..f93659f5ed 100644 --- a/packages/frontend/src/components/global/MkAcct.vue +++ b/packages/frontend/src/components/global/MkAcct.vue @@ -1,5 +1,5 @@ <template> -<MkCondensedLine v-if="defaultStore.state.enableCondensedLineForAcct" :min-scale="2 / 3"> +<MkCondensedLine v-if="defaultStore.state.enableCondensedLineForAcct" :minScale="2 / 3"> <span>@{{ user.username }}</span> <span v-if="user.host || detail || defaultStore.state.showFullAcct" style="opacity: 0.5;">@{{ user.host || host }}</span> </MkCondensedLine> diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index df26ca3171..422b35c9dd 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -24,13 +24,13 @@ <script lang="ts" setup> import { watch } from 'vue'; import * as misskey from 'misskey-js'; +import MkImgWithBlurhash from '../MkImgWithBlurhash.vue'; import MkA from './MkA.vue'; import { getStaticImageUrl } from '@/scripts/media-proxy'; import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; import { acct, userPage } from '@/filters/user'; import MkUserOnlineIndicator from '@/components/MkUserOnlineIndicator.vue'; import { defaultStore } from '@/store'; -import MkImgWithBlurhash from '../MkImgWithBlurhash.vue'; const animation = $ref(defaultStore.state.animation); const squareAvatars = $ref(defaultStore.state.squareAvatars); diff --git a/packages/frontend/src/components/global/MkPageHeader.tabs.vue b/packages/frontend/src/components/global/MkPageHeader.tabs.vue index 9e1da64e61..d71343baf9 100644 --- a/packages/frontend/src/components/global/MkPageHeader.tabs.vue +++ b/packages/frontend/src/components/global/MkPageHeader.tabs.vue @@ -15,8 +15,8 @@ {{ t.title }} </div> <Transition - v-else mode="in-out" @enter="enter" @after-enter="afterEnter" @leave="leave" - @after-leave="afterLeave" + v-else mode="in-out" @enter="enter" @afterEnter="afterEnter" @leave="leave" + @afterLeave="afterLeave" > <div v-show="t.key === tab" :class="[$style.tabTitle, $style.animate]">{{ t.title }}</div> </Transition> diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index b91d378b17..0a21d39bca 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -21,7 +21,7 @@ </div> </div> </div> - <XTabs v-if="!narrow || hideTitle" :class="$style.tabs" :tab="tab" :tabs="tabs" :root-el="el" @update:tab="key => emit('update:tab', key)" @tab-click="onTabClick"/> + <XTabs v-if="!narrow || hideTitle" :class="$style.tabs" :tab="tab" :tabs="tabs" :rootEl="el" @update:tab="key => emit('update:tab', key)" @tabClick="onTabClick"/> </template> <div v-if="(!thin_ && narrow && !hideTitle) || (actions && actions.length > 0)" :class="$style.buttonsRight"> <template v-for="action in actions"> @@ -30,7 +30,7 @@ </div> </div> <div v-if="(narrow && !hideTitle) && hasTabs" :class="[$style.lower, { [$style.slim]: narrow, [$style.thin]: thin_ }]"> - <XTabs :class="$style.tabs" :tab="tab" :tabs="tabs" :root-el="el" @update:tab="key => emit('update:tab', key)" @tab-click="onTabClick"/> + <XTabs :class="$style.tabs" :tab="tab" :tabs="tabs" :rootEl="el" @update:tab="key => emit('update:tab', key)" @tabClick="onTabClick"/> </div> </div> </template> diff --git a/packages/frontend/src/components/global/MkUserName.vue b/packages/frontend/src/components/global/MkUserName.vue index 4186a4a4fb..c9e85c5460 100644 --- a/packages/frontend/src/components/global/MkUserName.vue +++ b/packages/frontend/src/components/global/MkUserName.vue @@ -1,5 +1,5 @@ <template> -<Mfm :text="user.name ?? user.username" :author="user" :plain="true" :nowrap="nowrap" :emoji-urls="user.emojis"/> +<Mfm :text="user.name ?? user.username" :author="user" :plain="true" :nowrap="nowrap" :emojiUrls="user.emojis"/> </template> <script lang="ts" setup> From 56d4658b36edbd754b9e64a3b43f7befca28747d Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 14:08:51 +0900 Subject: [PATCH 054/213] refactor(frontend): use css module --- packages/frontend/src/components/MkPoll.vue | 114 +++++++++----------- 1 file changed, 49 insertions(+), 65 deletions(-) diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue index 0810061ff9..e2ca5603e3 100644 --- a/packages/frontend/src/components/MkPoll.vue +++ b/packages/frontend/src/components/MkPoll.vue @@ -1,19 +1,19 @@ <template> -<div class="tivcixzd" :class="{ done: closed || isVoted }"> - <ul> - <li v-for="(choice, i) in note.poll.choices" :key="i" :class="{ voted: choice.voted }" @click="vote(i)"> - <div class="backdrop" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div> - <span> - <template v-if="choice.isVoted"><i class="ti ti-check"></i></template> +<div :class="{ [$style.done]: closed || isVoted }"> + <ul :class="$style.choices"> + <li v-for="(choice, i) in note.poll.choices" :key="i" :class="[$style.choice, { [$style.voted]: choice.voted }]" @click="vote(i)"> + <div :class="$style.bg" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div> + <span :class="$style.fg"> + <template v-if="choice.isVoted"><i class="ti ti-check" style="margin-right: 4px; color: var(--accent);"></i></template> <Mfm :text="choice.text" :plain="true"/> - <span v-if="showResult" class="votes">({{ i18n.t('_poll.votesCount', { n: choice.votes }) }})</span> + <span v-if="showResult" style="margin-left: 4px; opacity: 0.7;">({{ i18n.t('_poll.votesCount', { n: choice.votes }) }})</span> </span> </li> </ul> - <p v-if="!readOnly"> + <p v-if="!readOnly" :class="$style.info"> <span>{{ i18n.t('_poll.totalVotes', { n: total }) }}</span> <span> · </span> - <a v-if="!closed && !isVoted" @click="showResult = !showResult">{{ showResult ? i18n.ts._poll.vote : i18n.ts._poll.showResult }}</a> + <a v-if="!closed && !isVoted" style="color: inherit;" @click="showResult = !showResult">{{ showResult ? i18n.ts._poll.vote : i18n.ts._poll.showResult }}</a> <span v-if="isVoted">{{ i18n.ts._poll.voted }}</span> <span v-else-if="closed">{{ i18n.ts._poll.closed }}</span> <span v-if="remaining > 0"> · {{ timer }}</span> @@ -86,67 +86,51 @@ const vote = async (id) => { }; </script> -<style lang="scss" scoped> -.tivcixzd { - > ul { - display: block; - margin: 0; - padding: 0; - list-style: none; +<style lang="scss" module> +.choices { + display: block; + margin: 0; + padding: 0; + list-style: none; +} - > li { - display: block; - position: relative; - margin: 4px 0; - padding: 4px; - //border: solid 0.5px var(--divider); - background: var(--accentedBg); - border-radius: 4px; - overflow: clip; - cursor: pointer; +.choice { + display: block; + position: relative; + margin: 4px 0; + padding: 4px; + //border: solid 0.5px var(--divider); + background: var(--accentedBg); + border-radius: 4px; + overflow: clip; + cursor: pointer; +} - > .backdrop { - position: absolute; - top: 0; - left: 0; - height: 100%; - background: var(--accent); - background: linear-gradient(90deg,var(--buttonGradateA),var(--buttonGradateB)); - transition: width 1s ease; - } +.bg { + position: absolute; + top: 0; + left: 0; + height: 100%; + background: var(--accent); + background: linear-gradient(90deg,var(--buttonGradateA),var(--buttonGradateB)); + transition: width 1s ease; +} - > span { - position: relative; - display: inline-block; - padding: 3px 5px; - background: var(--panel); - border-radius: 3px; +.fg { + position: relative; + display: inline-block; + padding: 3px 5px; + background: var(--panel); + border-radius: 3px; +} - > i { - margin-right: 4px; - color: var(--accent); - } +.info { + color: var(--fg); +} - > .votes { - margin-left: 4px; - opacity: 0.7; - } - } - } - } - - > p { - color: var(--fg); - - a { - color: inherit; - } - } - - &.done { - > ul > li { - cursor: default; - } +.done { + .choice { + cursor: default; } } </style> From 95470a40a7c2377d8cc8a2b923d9214ebc6f7f82 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 16:20:53 +0900 Subject: [PATCH 055/213] refactor --- packages/frontend/src/pages/_error_.vue | 54 ++++++-------- packages/frontend/src/pages/about-misskey.vue | 6 +- packages/frontend/src/pages/about.emojis.vue | 52 ++++---------- .../frontend/src/pages/about.federation.vue | 25 +++---- packages/frontend/src/pages/about.vue | 8 +-- packages/frontend/src/pages/achievements.vue | 2 +- packages/frontend/src/pages/admin-file.vue | 4 +- packages/frontend/src/pages/ads.vue | 2 +- packages/frontend/src/pages/announcements.vue | 2 +- packages/frontend/src/pages/api-console.vue | 4 +- packages/frontend/src/pages/auth.vue | 2 +- .../frontend/src/pages/channel-editor.vue | 6 +- packages/frontend/src/pages/channel.vue | 8 +-- packages/frontend/src/pages/channels.vue | 4 +- packages/frontend/src/pages/clicker.vue | 2 +- packages/frontend/src/pages/clip.vue | 6 +- packages/frontend/src/pages/emojis.emoji.vue | 54 +++++++------- .../frontend/src/pages/explore.featured.vue | 2 +- packages/frontend/src/pages/explore.roles.vue | 4 +- packages/frontend/src/pages/explore.users.vue | 10 +-- packages/frontend/src/pages/favorites.vue | 4 +- .../frontend/src/pages/follow-requests.vue | 2 +- packages/frontend/src/pages/follow.vue | 2 +- packages/frontend/src/pages/instance-info.vue | 6 +- packages/frontend/src/pages/list.vue | 8 +-- packages/frontend/src/pages/miauth.vue | 2 +- packages/frontend/src/pages/not-found.vue | 2 +- packages/frontend/src/pages/note.vue | 72 ++++++++----------- packages/frontend/src/pages/notifications.vue | 4 +- packages/frontend/src/pages/page.vue | 6 +- packages/frontend/src/pages/pages.vue | 2 +- packages/frontend/src/pages/registry.keys.vue | 2 +- .../frontend/src/pages/registry.value.vue | 2 +- packages/frontend/src/pages/registry.vue | 2 +- .../frontend/src/pages/reset-password.vue | 2 +- packages/frontend/src/pages/role.vue | 8 ++- packages/frontend/src/pages/scratchpad.vue | 4 +- packages/frontend/src/pages/search.user.vue | 2 +- packages/frontend/src/pages/search.vue | 4 +- packages/frontend/src/pages/share.vue | 12 ++-- packages/frontend/src/pages/tag.vue | 2 +- packages/frontend/src/pages/theme-editor.vue | 12 ++-- packages/frontend/src/pages/timeline.vue | 4 +- packages/frontend/src/pages/user-info.vue | 10 +-- packages/frontend/src/pages/user-tag.vue | 2 +- .../frontend/src/pages/welcome.entrance.a.vue | 10 +-- .../frontend/src/pages/welcome.timeline.vue | 4 +- .../src/widgets/WidgetActivity.calendar.vue | 18 +++-- .../frontend/src/widgets/WidgetActivity.vue | 11 ++- .../frontend/src/widgets/WidgetAichan.vue | 11 ++- .../frontend/src/widgets/WidgetAiscript.vue | 11 ++- .../src/widgets/WidgetAiscriptApp.vue | 13 ++-- .../frontend/src/widgets/WidgetButton.vue | 9 +-- .../frontend/src/widgets/WidgetCalendar.vue | 9 +-- .../frontend/src/widgets/WidgetClicker.vue | 13 ++-- packages/frontend/src/widgets/WidgetClock.vue | 17 ++--- .../src/widgets/WidgetDigitalClock.vue | 11 ++- .../frontend/src/widgets/WidgetFederation.vue | 11 ++- .../src/widgets/WidgetInstanceCloud.vue | 11 ++- .../src/widgets/WidgetInstanceInfo.vue | 9 +-- .../frontend/src/widgets/WidgetJobQueue.vue | 9 +-- packages/frontend/src/widgets/WidgetMemo.vue | 11 ++- .../src/widgets/WidgetNotifications.vue | 15 ++-- .../src/widgets/WidgetOnlineUsers.vue | 9 +-- .../frontend/src/widgets/WidgetPhotos.vue | 11 ++- .../frontend/src/widgets/WidgetPostForm.vue | 9 +-- .../frontend/src/widgets/WidgetProfile.vue | 9 +-- packages/frontend/src/widgets/WidgetRss.vue | 11 ++- .../frontend/src/widgets/WidgetRssTicker.vue | 11 ++- .../frontend/src/widgets/WidgetSlideshow.vue | 9 +-- .../frontend/src/widgets/WidgetTimeline.vue | 11 ++- .../frontend/src/widgets/WidgetTrends.vue | 11 ++- .../frontend/src/widgets/WidgetUnixClock.vue | 9 +-- .../frontend/src/widgets/WidgetUserList.vue | 11 ++- 74 files changed, 310 insertions(+), 439 deletions(-) diff --git a/packages/frontend/src/pages/_error_.vue b/packages/frontend/src/pages/_error_.vue index f53fec7d94..f27d2df336 100644 --- a/packages/frontend/src/pages/_error_.vue +++ b/packages/frontend/src/pages/_error_.vue @@ -1,18 +1,20 @@ <template> <MkLoading v-if="!loaded"/> <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear> - <div v-show="loaded" class="mjndxjch"> - <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> - <p><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p> - <p v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</p> - <p v-else-if="serverIsDead">{{ i18n.ts.serverIsDead }}</p> - <template v-else> - <p>{{ i18n.ts.newVersionOfClientAvailable }}</p> - <p>{{ i18n.ts.youShouldUpgradeClient }}</p> - <MkButton class="button primary" @click="reload">{{ i18n.ts.reload }}</MkButton> - </template> - <p><MkA to="/docs/general/troubleshooting" class="_link">{{ i18n.ts.troubleshooting }}</MkA></p> - <p v-if="error" class="error">ERROR: {{ error }}</p> + <div v-show="loaded" :class="$style.root"> + <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost" :class="$style.img"/> + <div class="_gaps"> + <p><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p> + <p v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</p> + <p v-else-if="serverIsDead">{{ i18n.ts.serverIsDead }}</p> + <template v-else> + <p>{{ i18n.ts.newVersionOfClientAvailable }}</p> + <p>{{ i18n.ts.youShouldUpgradeClient }}</p> + <MkButton style="margin: 8px auto;" @click="reload">{{ i18n.ts.reload }}</MkButton> + </template> + <p><MkA to="/docs/general/troubleshooting" class="_link">{{ i18n.ts.troubleshooting }}</MkA></p> + <p v-if="error" style="opacity: 0.7;">ERROR: {{ error }}</p> + </div> </div> </Transition> </template> @@ -64,28 +66,16 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.mjndxjch { +<style lang="scss" module> +.root { padding: 32px; text-align: center; +} - > p { - margin: 0 0 12px 0; - } - - > .button { - margin: 8px auto; - } - - > img { - vertical-align: bottom; - height: 128px; - margin-bottom: 24px; - border-radius: 16px; - } - - > .error { - opacity: 0.7; - } +.img { + vertical-align: bottom; + height: 128px; + margin-bottom: 24px; + border-radius: 16px; } </style> diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index b487916ff6..d86a5e1126 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <div style="overflow: clip;"> - <MkSpacer :content-max="600" :margin-min="20"> + <MkSpacer :contentMax="600" :marginMin="20"> <div class="_gaps_m znqjceqz"> <div v-panel class="about"> <div ref="containerEl" class="container" :class="{ playing: easterEggEngine != null }"> @@ -10,8 +10,8 @@ <div class="misskey">Misskey</div> <div class="version">v{{ version }}</div> <span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"> - <MkCustomEmoji v-if="emoji.emoji[0] === ':'" class="emoji" :name="emoji.emoji" :normal="true" :no-style="true"/> - <MkEmoji v-else class="emoji" :emoji="emoji.emoji" :normal="true" :no-style="true"/> + <MkCustomEmoji v-if="emoji.emoji[0] === ':'" class="emoji" :name="emoji.emoji" :normal="true" :noStyle="true"/> + <MkEmoji v-else class="emoji" :emoji="emoji.emoji" :normal="true" :noStyle="true"/> </span> </div> <button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button> diff --git a/packages/frontend/src/pages/about.emojis.vue b/packages/frontend/src/pages/about.emojis.vue index 2d82fcf277..3744bed10f 100644 --- a/packages/frontend/src/pages/about.emojis.vue +++ b/packages/frontend/src/pages/about.emojis.vue @@ -1,5 +1,5 @@ <template> -<div class="driuhtrh _gaps"> +<div class="_gaps"> <MkButton v-if="$i && ($i.isModerator || $i.policies.canManageCustomEmojis)" primary link to="/custom-emojis-manager">{{ i18n.ts.manageCustomEmojis }}</MkButton> <div class="query"> @@ -14,17 +14,17 @@ --> </div> - <MkFoldableSection v-if="searchEmojis" class="emojis"> + <MkFoldableSection v-if="searchEmojis"> <template #header>{{ i18n.ts.searchResult }}</template> - <div class="zuvgdzyt"> - <XEmoji v-for="emoji in searchEmojis" :key="emoji.name" class="emoji" :emoji="emoji"/> + <div :class="$style.emojis"> + <XEmoji v-for="emoji in searchEmojis" :key="emoji.name" :emoji="emoji"/> </div> </MkFoldableSection> - <MkFoldableSection v-for="category in customEmojiCategories" v-once :key="category" class="emojis"> + <MkFoldableSection v-for="category in customEmojiCategories" v-once :key="category"> <template #header>{{ category || i18n.ts.other }}</template> - <div class="zuvgdzyt"> - <XEmoji v-for="emoji in customEmojis.filter(e => e.category === category)" :key="emoji.name" class="emoji" :emoji="emoji"/> + <div :class="$style.emojis"> + <XEmoji v-for="emoji in customEmojis.filter(e => e.category === category)" :key="emoji.name" :emoji="emoji"/> </div> </MkFoldableSection> </div> @@ -57,7 +57,7 @@ function search() { if (queryarry) { searchEmojis = customEmojis.value.filter(emoji => - queryarry.includes(`:${emoji.name}:`) + queryarry.includes(`:${emoji.name}:`), ); } else { searchEmojis = customEmojis.value.filter(emoji => emoji.name.includes(q) || emoji.aliases.includes(q)); @@ -84,36 +84,10 @@ watch($$(selectedTags), () => { }, { deep: true }); </script> -<style lang="scss" scoped> -.driuhtrh { - background: var(--bg); - - > .query { - background: var(--bg); - - > .tags { - > .tag { - display: inline-block; - margin: 8px 8px 0 0; - padding: 4px 8px; - font-size: 0.9em; - background: var(--accentedBg); - border-radius: 5px; - - &.active { - background: var(--accent); - color: var(--fgOnAccent); - } - } - } - } - - > .emojis { - .zuvgdzyt { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); - grid-gap: 12px; - } - } +<style lang="scss" module> +.emojis { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); + grid-gap: 12px; } </style> diff --git a/packages/frontend/src/pages/about.federation.vue b/packages/frontend/src/pages/about.federation.vue index 8fe613a9a8..a8c6c05d8b 100644 --- a/packages/frontend/src/pages/about.federation.vue +++ b/packages/frontend/src/pages/about.federation.vue @@ -1,6 +1,6 @@ <template> -<div class="taeiyria"> - <div class="query"> +<div> + <div> <MkInput v-model="host" :debounce="true" class=""> <template #prefix><i class="ti ti-search"></i></template> <template #label>{{ i18n.ts.host }}</template> @@ -35,8 +35,8 @@ </div> <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination"> - <div class="dqokceoi"> - <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" class="instance" :to="`/instance-info/${instance.host}`"> + <div :class="$style.items"> + <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" :class="$style.item" :to="`/instance-info/${instance.host}`"> <MkInstanceCardMini :instance="instance"/> </MkA> </div> @@ -82,21 +82,14 @@ function getStatus(instance) { } </script> -<style lang="scss" scoped> -.taeiyria { - > .query { - background: var(--bg); - margin-bottom: 16px; - } -} - -.dqokceoi { +<style lang="scss" module> +.items { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); grid-gap: 12px; +} - > .instance:hover { - text-decoration: none; - } +.item:hover { + text-decoration: none; } </style> diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue index 8e29990426..693d369b89 100644 --- a/packages/frontend/src/pages/about.vue +++ b/packages/frontend/src/pages/about.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer v-if="tab === 'overview'" :content-max="600" :margin-min="20"> + <MkSpacer v-if="tab === 'overview'" :contentMax="600" :marginMin="20"> <div class="_gaps_m"> <div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"> <div style="overflow: clip;"> @@ -80,13 +80,13 @@ </FormSection> </div> </MkSpacer> - <MkSpacer v-else-if="tab === 'emojis'" :content-max="1000" :margin-min="20"> + <MkSpacer v-else-if="tab === 'emojis'" :contentMax="1000" :marginMin="20"> <XEmojis/> </MkSpacer> - <MkSpacer v-else-if="tab === 'federation'" :content-max="1000" :margin-min="20"> + <MkSpacer v-else-if="tab === 'federation'" :contentMax="1000" :marginMin="20"> <XFederation/> </MkSpacer> - <MkSpacer v-else-if="tab === 'charts'" :content-max="1000" :margin-min="20"> + <MkSpacer v-else-if="tab === 'charts'" :contentMax="1000" :marginMin="20"> <MkInstanceStats/> </MkSpacer> </MkStickyContainer> diff --git a/packages/frontend/src/pages/achievements.vue b/packages/frontend/src/pages/achievements.vue index 1eef7a53fe..dc47d8dde0 100644 --- a/packages/frontend/src/pages/achievements.vue +++ b/packages/frontend/src/pages/achievements.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader/></template> - <MkSpacer :content-max="1200"> + <MkSpacer :contentMax="1200"> <MkAchievements :user="$i"/> </MkSpacer> </MkStickyContainer> diff --git a/packages/frontend/src/pages/admin-file.vue b/packages/frontend/src/pages/admin-file.vue index 1d309a7377..24c863ba62 100644 --- a/packages/frontend/src/pages/admin-file.vue +++ b/packages/frontend/src/pages/admin-file.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer v-if="file" :content-max="600" :margin-min="16" :margin-max="32"> + <MkSpacer v-if="file" :contentMax="600" :marginMin="16" :marginMax="32"> <div v-if="tab === 'overview'" class="cxqhhsmd _gaps_m"> <a class="thumbnail" :href="file.url" target="_blank"> <MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/> @@ -32,7 +32,7 @@ <MkUserCardMini :user="file.user"/> </MkA> <div> - <MkSwitch v-model="isSensitive" @update:model-value="toggleIsSensitive">NSFW</MkSwitch> + <MkSwitch v-model="isSensitive" @update:modelValue="toggleIsSensitive">NSFW</MkSwitch> </div> <div> diff --git a/packages/frontend/src/pages/ads.vue b/packages/frontend/src/pages/ads.vue index 728ef3c0b1..4cf2e4b2e5 100644 --- a/packages/frontend/src/pages/ads.vue +++ b/packages/frontend/src/pages/ads.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><MkPageHeader/></template> - <MkSpacer :content-max="500"> + <MkSpacer :contentMax="500"> <div class="_gaps"> <MkAd v-for="ad in instance.ads" :key="ad.id" :specify="ad"/> </div> diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue index 16a0ee8373..3dfb9e5554 100644 --- a/packages/frontend/src/pages/announcements.vue +++ b/packages/frontend/src/pages/announcements.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <MkPagination v-slot="{items}" :pagination="pagination" class="ruryvtyk _gaps_m"> <section v-for="(announcement, i) in items" :key="announcement.id" class="announcement _panel"> <div class="header"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> diff --git a/packages/frontend/src/pages/api-console.vue b/packages/frontend/src/pages/api-console.vue index 7d2828e91d..3a3cb3d7d3 100644 --- a/packages/frontend/src/pages/api-console.vue +++ b/packages/frontend/src/pages/api-console.vue @@ -1,10 +1,10 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div class="_gaps_m"> <div class="_gaps_m"> - <MkInput v-model="endpoint" :datalist="endpoints" @update:model-value="onEndpointChange()"> + <MkInput v-model="endpoint" :datalist="endpoints" @update:modelValue="onEndpointChange()"> <template #label>Endpoint</template> </MkInput> <MkTextarea v-model="body" code> diff --git a/packages/frontend/src/pages/auth.vue b/packages/frontend/src/pages/auth.vue index 2f40e7ded6..54e76805bf 100644 --- a/packages/frontend/src/pages/auth.vue +++ b/packages/frontend/src/pages/auth.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="500"> + <MkSpacer :contentMax="500"> <div v-if="state == 'fetch-session-error'"> <p>{{ i18n.ts.somethingHappened }}</p> </div> diff --git a/packages/frontend/src/pages/channel-editor.vue b/packages/frontend/src/pages/channel-editor.vue index a74ab40473..0a358a141b 100644 --- a/packages/frontend/src/pages/channel-editor.vue +++ b/packages/frontend/src/pages/channel-editor.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div v-if="channelId == null || channel != null" class="_gaps_m"> <MkInput v-model="name"> <template #label>{{ i18n.ts.name }}</template> @@ -23,7 +23,7 @@ </div> </div> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #label>{{ i18n.ts.pinnedNotes }}</template> <div class="_gaps"> @@ -31,7 +31,7 @@ <Sortable v-model="pinnedNotes" - item-key="id" + itemKey="id" :handle="'.' + $style.pinnedNoteHandle" :animation="150" > diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 59ca6c83bd..bcc0fc6860 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -1,12 +1,12 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :class="$style.main"> + <MkSpacer :contentMax="700" :class="$style.main"> <div v-if="channel && tab === 'overview'" class="_gaps"> <div class="_panel" :class="$style.bannerContainer"> <XChannelFollowButton :channel="channel" :full="true" :class="$style.subscribe"/> - <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" as-like class="button" rounded primary :class="$style.favorite" @click="unfavorite()"><i class="ti ti-star"></i></MkButton> - <MkButton v-else v-tooltip="i18n.ts.favorite" as-like class="button" rounded :class="$style.favorite" @click="favorite()"><i class="ti ti-star"></i></MkButton> + <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike class="button" rounded primary :class="$style.favorite" @click="unfavorite()"><i class="ti ti-star"></i></MkButton> + <MkButton v-else v-tooltip="i18n.ts.favorite" asLike class="button" rounded :class="$style.favorite" @click="favorite()"><i class="ti ti-star"></i></MkButton> <div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" :class="$style.banner"> <div :class="$style.bannerStatus"> <div><i class="ti ti-users ti-fw"></i><I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> @@ -51,7 +51,7 @@ </MkSpacer> <template #footer> <div :class="$style.footer"> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="16"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="16"> <div class="_buttonsCenter"> <MkButton inline rounded primary gradate @click="openPostForm()"><i class="ti ti-pencil"></i> {{ i18n.ts.postToTheChannel }}</MkButton> </div> diff --git a/packages/frontend/src/pages/channels.vue b/packages/frontend/src/pages/channels.vue index e670cdd864..0c4ccc1bcd 100644 --- a/packages/frontend/src/pages/channels.vue +++ b/packages/frontend/src/pages/channels.vue @@ -1,13 +1,13 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div v-if="tab === 'search'"> <div class="_gaps"> <MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search"> <template #prefix><i class="ti ti-search"></i></template> </MkInput> - <MkRadios v-model="searchType" @update:model-value="search()"> + <MkRadios v-model="searchType" @update:modelValue="search()"> <option value="nameAndDescription">{{ i18n.ts._channel.nameAndDescription }}</option> <option value="nameOnly">{{ i18n.ts._channel.nameOnly }}</option> </MkRadios> diff --git a/packages/frontend/src/pages/clicker.vue b/packages/frontend/src/pages/clicker.vue index 24eae32e13..69ecc9e772 100644 --- a/packages/frontend/src/pages/clicker.vue +++ b/packages/frontend/src/pages/clicker.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <MkClickerGame/> </MkSpacer> </MkStickyContainer> diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue index 9207a9fa9b..654c44ae02 100644 --- a/packages/frontend/src/pages/clip.vue +++ b/packages/frontend/src/pages/clip.vue @@ -1,14 +1,14 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <div v-if="clip"> <div class="okzinsic _panel"> <div v-if="clip.description" class="description"> <Mfm :text="clip.description" :isNote="false" :i="$i"/> </div> - <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" as-like class="button" rounded primary @click="unfavorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> - <MkButton v-else v-tooltip="i18n.ts.favorite" as-like class="button" rounded @click="favorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> + <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike class="button" rounded primary @click="unfavorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> + <MkButton v-else v-tooltip="i18n.ts.favorite" asLike class="button" rounded @click="favorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> <div class="user"> <MkAvatar :user="clip.user" class="avatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/> </div> diff --git a/packages/frontend/src/pages/emojis.emoji.vue b/packages/frontend/src/pages/emojis.emoji.vue index bdd21b29ee..e9fab6a313 100644 --- a/packages/frontend/src/pages/emojis.emoji.vue +++ b/packages/frontend/src/pages/emojis.emoji.vue @@ -1,9 +1,9 @@ <template> -<button class="zuvgdzyu _button" @click="menu"> - <img :src="emoji.url" class="img" loading="lazy"/> - <div class="body"> - <div class="name _monospace">{{ emoji.name }}</div> - <div class="info">{{ emoji.aliases.join(' ') }}</div> +<button class="_button" :class="$style.root" @click="menu"> + <img :src="emoji.url" :class="$style.img" loading="lazy"/> + <div :class="$style.body"> + <div :class="$style.name" class="_monospace">{{ emoji.name }}</div> + <div :class="$style.info">{{ emoji.aliases.join(' ') }}</div> </div> </button> </template> @@ -49,8 +49,8 @@ function menu(ev) { } </script> -<style lang="scss" scoped> -.zuvgdzyu { +<style lang="scss" module> +.root { display: flex; align-items: center; padding: 12px; @@ -61,29 +61,29 @@ function menu(ev) { &:hover { border-color: var(--accent); } +} - > .img { - width: 42px; - height: 42px; - object-fit: contain; - } +.img { + width: 42px; + height: 42px; + object-fit: contain; +} - > .body { - padding: 0 0 0 8px; - white-space: nowrap; - overflow: hidden; +.body { + padding: 0 0 0 8px; + white-space: nowrap; + overflow: hidden; +} - > .name { - text-overflow: ellipsis; - overflow: hidden; - } +.name { + text-overflow: ellipsis; + overflow: hidden; +} - > .info { - opacity: 0.5; - font-size: 0.9em; - text-overflow: ellipsis; - overflow: hidden; - } - } +.info { + opacity: 0.5; + font-size: 0.9em; + text-overflow: ellipsis; + overflow: hidden; } </style> diff --git a/packages/frontend/src/pages/explore.featured.vue b/packages/frontend/src/pages/explore.featured.vue index a972ae04ec..5c71313738 100644 --- a/packages/frontend/src/pages/explore.featured.vue +++ b/packages/frontend/src/pages/explore.featured.vue @@ -1,5 +1,5 @@ <template> -<MkSpacer :content-max="800"> +<MkSpacer :contentMax="800"> <MkTab v-model="tab" style="margin-bottom: var(--margin);"> <option value="notes">{{ i18n.ts.notes }}</option> <option value="polls">{{ i18n.ts.poll }}</option> diff --git a/packages/frontend/src/pages/explore.roles.vue b/packages/frontend/src/pages/explore.roles.vue index 6ac469f7ba..c855d79f45 100644 --- a/packages/frontend/src/pages/explore.roles.vue +++ b/packages/frontend/src/pages/explore.roles.vue @@ -1,7 +1,7 @@ <template> -<MkSpacer :content-max="700"> +<MkSpacer :contentMax="700"> <div class="_gaps_s"> - <MkRolePreview v-for="role in roles" :key="role.id" :role="role" :for-moderation="false"/> + <MkRolePreview v-for="role in roles" :key="role.id" :role="role" :forModeration="false"/> </div> </MkSpacer> </template> diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue index f9c833dd29..785dbaa343 100644 --- a/packages/frontend/src/pages/explore.users.vue +++ b/packages/frontend/src/pages/explore.users.vue @@ -1,24 +1,24 @@ <template> -<MkSpacer :content-max="1200"> +<MkSpacer :contentMax="1200"> <MkTab v-model="origin" style="margin-bottom: var(--margin);"> <option value="local">{{ i18n.ts.local }}</option> <option value="remote">{{ i18n.ts.remote }}</option> </MkTab> <div v-if="origin === 'local'"> <template v-if="tag == null"> - <MkFoldableSection class="_margin" persist-key="explore-pinned-users"> + <MkFoldableSection class="_margin" persistKey="explore-pinned-users"> <template #header><i class="ti ti-bookmark ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.pinnedUsers }}</template> <MkUserList :pagination="pinnedUsers"/> </MkFoldableSection> - <MkFoldableSection class="_margin" persist-key="explore-popular-users"> + <MkFoldableSection class="_margin" persistKey="explore-popular-users"> <template #header><i class="ti ti-chart-line ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.popularUsers }}</template> <MkUserList :pagination="popularUsers"/> </MkFoldableSection> - <MkFoldableSection class="_margin" persist-key="explore-recently-updated-users"> + <MkFoldableSection class="_margin" persistKey="explore-recently-updated-users"> <template #header><i class="ti ti-message ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyUpdatedUsers }}</template> <MkUserList :pagination="recentlyUpdatedUsers"/> </MkFoldableSection> - <MkFoldableSection class="_margin" persist-key="explore-recently-registered-users"> + <MkFoldableSection class="_margin" persistKey="explore-recently-registered-users"> <template #header><i class="ti ti-plus ti-fw" style="margin-right: 0.5em;"></i>{{ i18n.ts.recentlyRegisteredUsers }}</template> <MkUserList :pagination="recentlyRegisteredUsers"/> </MkFoldableSection> diff --git a/packages/frontend/src/pages/favorites.vue b/packages/frontend/src/pages/favorites.vue index 0dc9b9dc8f..460bf65d1e 100644 --- a/packages/frontend/src/pages/favorites.vue +++ b/packages/frontend/src/pages/favorites.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <MkPagination :pagination="pagination"> <template #empty> <div class="_fullinfo"> @@ -11,7 +11,7 @@ </template> <template #default="{ items }"> - <MkDateSeparatedList v-slot="{ item }" :items="items" :direction="'down'" :no-gap="false" :ad="false"> + <MkDateSeparatedList v-slot="{ item }" :items="items" :direction="'down'" :noGap="false" :ad="false"> <MkNote :key="item.id" :note="item.note" :class="$style.note"/> </MkDateSeparatedList> </template> diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue index a51d1c78a4..1452942a1e 100644 --- a/packages/frontend/src/pages/follow-requests.vue +++ b/packages/frontend/src/pages/follow-requests.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <MkPagination ref="paginationComponent" :pagination="pagination"> <template #empty> <div class="_fullinfo"> diff --git a/packages/frontend/src/pages/follow.vue b/packages/frontend/src/pages/follow.vue index 828246d678..d14b663364 100644 --- a/packages/frontend/src/pages/follow.vue +++ b/packages/frontend/src/pages/follow.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-follow-page"> +<div> </div> </template> diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index ba5fda137a..83997b2555 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer v-if="instance" :content-max="600" :margin-min="16" :margin-max="32"> + <MkSpacer v-if="instance" :contentMax="600" :marginMin="16" :marginMax="32"> <div v-if="tab === 'overview'" class="_gaps_m"> <div class="fnfelxur"> <img :src="faviconUrl" alt="" class="icon"/> @@ -29,8 +29,8 @@ <FormSection v-if="iAmModerator"> <template #label>Moderation</template> <div class="_gaps_s"> - <MkSwitch v-model="suspended" @update:model-value="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</MkSwitch> - <MkSwitch v-model="isBlocked" @update:model-value="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch> + <MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.stopActivityDelivery }}</MkSwitch> + <MkSwitch v-model="isBlocked" @update:modelValue="toggleBlock">{{ i18n.ts.blockThisInstance }}</MkSwitch> <MkButton @click="refreshMetadata"><i class="ti ti-refresh"></i> Refresh metadata</MkButton> </div> </FormSection> diff --git a/packages/frontend/src/pages/list.vue b/packages/frontend/src/pages/list.vue index a09ff854ca..f92c06d1c5 100644 --- a/packages/frontend/src/pages/list.vue +++ b/packages/frontend/src/pages/list.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MKSpacer v-if="!(typeof error === 'undefined')" :content-max="1200"> + <MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200"> <div :class="$style.root"> <img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> <p :class="$style.text"> @@ -10,7 +10,7 @@ </p> </div> </MKSpacer> - <MkSpacer v-else-if="list" :content-max="700" :class="$style.main"> + <MkSpacer v-else-if="list" :contentMax="700" :class="$style.main"> <div v-if="list" class="members _margin"> <div :class="$style.member_text">{{ i18n.ts.members }}</div> <div class="_gaps_s"> @@ -21,8 +21,8 @@ </div> </div> </div> - <MkButton v-if="list.isLiked" v-tooltip="i18n.ts.unlike" inline :class="$style.button" as-like primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="list.likedCount > 0" class="count">{{ list.likedCount }}</span></MkButton> - <MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" as-like @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton> + <MkButton v-if="list.isLiked" v-tooltip="i18n.ts.unlike" inline :class="$style.button" asLike primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="list.likedCount > 0" class="count">{{ list.likedCount }}</span></MkButton> + <MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton> <MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton> </MkSpacer> </MkStickyContainer> diff --git a/packages/frontend/src/pages/miauth.vue b/packages/frontend/src/pages/miauth.vue index 8e0624f555..553946cd9e 100644 --- a/packages/frontend/src/pages/miauth.vue +++ b/packages/frontend/src/pages/miauth.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <div v-if="$i"> <div v-if="state == 'waiting'"> <MkLoading/> diff --git a/packages/frontend/src/pages/not-found.vue b/packages/frontend/src/pages/not-found.vue index e58e44ef79..2c9d949017 100644 --- a/packages/frontend/src/pages/not-found.vue +++ b/packages/frontend/src/pages/not-found.vue @@ -1,5 +1,5 @@ <template> -<div class="ipledcug"> +<div> <div class="_fullinfo"> <img src="https://xn--931a.moe/assets/not-found.jpg" class="_ghost"/> <div>{{ i18n.ts.notFoundDescription }}</div> diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue index d9baa1096a..c519cefbaf 100644 --- a/packages/frontend/src/pages/note.vue +++ b/packages/frontend/src/pages/note.vue @@ -1,33 +1,33 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> - <div class="fcuexfpr"> + <MkSpacer :contentMax="800"> + <div> <Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in"> - <div v-if="note" class="note"> + <div v-if="note"> <div v-if="showNext" class="_margin"> - <MkNotes class="" :pagination="nextPagination" :no-gap="true"/> + <MkNotes class="" :pagination="nextPagination" :noGap="true"/> </div> - <div class="main _margin"> - <MkButton v-if="!showNext && hasNext" class="load next" @click="showNext = true"><i class="ti ti-chevron-up"></i></MkButton> - <div class="note _margin _gaps_s"> + <div class="_margin"> + <MkButton v-if="!showNext && hasNext" :class="$style.loadNext" @click="showNext = true"><i class="ti ti-chevron-up"></i></MkButton> + <div class="_margin _gaps_s"> <MkRemoteCaution v-if="note.user.host != null" :href="note.url ?? note.uri"/> - <MkNoteDetailed :key="note.id" v-model:note="note" class="note"/> + <MkNoteDetailed :key="note.id" v-model:note="note" :class="$style.note"/> </div> - <div v-if="clips && clips.length > 0" class="clips _margin"> - <div class="title">{{ i18n.ts.clip }}</div> + <div v-if="clips && clips.length > 0" class="_margin"> + <div style="font-weight: bold; padding: 12px;">{{ i18n.ts.clip }}</div> <div class="_gaps"> <MkA v-for="item in clips" :key="item.id" :to="`/clips/${item.id}`"> <MkClipPreview :clip="item"/> </MkA> </div> </div> - <MkButton v-if="!showPrev && hasPrev" class="load prev" @click="showPrev = true"><i class="ti ti-chevron-down"></i></MkButton> + <MkButton v-if="!showPrev && hasPrev" :class="$style.loadPrev" @click="showPrev = true"><i class="ti ti-chevron-down"></i></MkButton> </div> <div v-if="showPrev" class="_margin"> - <MkNotes class="" :pagination="prevPagination" :no-gap="true"/> + <MkNotes class="" :pagination="prevPagination" :noGap="true"/> </div> </div> <MkError v-else-if="error" @retry="fetchNote()"/> @@ -137,7 +137,7 @@ definePageMetadata(computed(() => note ? { } : null)); </script> -<style lang="scss" scoped> +<style lang="scss" module> .fade-enter-active, .fade-leave-active { transition: opacity 0.125s ease; @@ -147,39 +147,23 @@ definePageMetadata(computed(() => note ? { opacity: 0; } -.fcuexfpr { - background: var(--bg); +.loadNext, +.loadPrev { + min-width: 0; + margin: 0 auto; + border-radius: 999px; +} - > .note { - > .main { - > .load { - min-width: 0; - margin: 0 auto; - border-radius: 999px; +.loadNext { + margin-bottom: var(--margin); +} - &.next { - margin-bottom: var(--margin); - } +.loadPrev { + margin-top: var(--margin); +} - &.prev { - margin-top: var(--margin); - } - } - - > .note { - > .note { - border-radius: var(--radius); - background: var(--panel); - } - } - - > .clips { - > .title { - font-weight: bold; - padding: 12px; - } - } - } - } +.note { + border-radius: var(--radius); + background: var(--panel); } </style> diff --git a/packages/frontend/src/pages/notifications.vue b/packages/frontend/src/pages/notifications.vue index 1789606cd8..8196f91868 100644 --- a/packages/frontend/src/pages/notifications.vue +++ b/packages/frontend/src/pages/notifications.vue @@ -1,9 +1,9 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <div v-if="tab === 'all'"> - <XNotifications class="notifications" :include-types="includeTypes"/> + <XNotifications class="notifications" :includeTypes="includeTypes"/> </div> <div v-else-if="tab === 'mentions'"> <MkNotes :pagination="mentionsPagination"/> diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue index 5a0f58c8df..27a4cd0595 100644 --- a/packages/frontend/src/pages/page.vue +++ b/packages/frontend/src/pages/page.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in"> <div v-if="page" :key="page.id" class="xcukqgmh"> <div class="main"> @@ -18,8 +18,8 @@ </div> <div class="actions"> <div class="like"> - <MkButton v-if="page.isLiked" v-tooltip="i18n.ts._pages.unlike" class="button" as-like primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> - <MkButton v-else v-tooltip="i18n.ts._pages.like" class="button" as-like @click="like()"><i class="ti ti-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> + <MkButton v-if="page.isLiked" v-tooltip="i18n.ts._pages.unlike" class="button" asLike primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> + <MkButton v-else v-tooltip="i18n.ts._pages.like" class="button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="page.likedCount > 0" class="count">{{ page.likedCount }}</span></MkButton> </div> <div class="other"> <button v-tooltip="i18n.ts.shareWithNote" v-click-anime class="_button" @click="shareWithNote"><i class="ti ti-repeat ti-fw"></i></button> diff --git a/packages/frontend/src/pages/pages.vue b/packages/frontend/src/pages/pages.vue index 0427332ab2..b72271dbf7 100644 --- a/packages/frontend/src/pages/pages.vue +++ b/packages/frontend/src/pages/pages.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div v-if="tab === 'featured'" class="rknalgpo"> <MkPagination v-slot="{items}" :pagination="featuredPagesPagination"> <MkPagePreview v-for="page in items" :key="page.id" class="ckltabjg" :page="page"/> diff --git a/packages/frontend/src/pages/registry.keys.vue b/packages/frontend/src/pages/registry.keys.vue index 52b7c256e0..b1d41fe2c7 100644 --- a/packages/frontend/src/pages/registry.keys.vue +++ b/packages/frontend/src/pages/registry.keys.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="600" :margin-min="16"> + <MkSpacer :contentMax="600" :marginMin="16"> <div class="_gaps_m"> <FormSplit> <MkKeyValue> diff --git a/packages/frontend/src/pages/registry.value.vue b/packages/frontend/src/pages/registry.value.vue index 6ff07e2b77..513a2f8feb 100644 --- a/packages/frontend/src/pages/registry.value.vue +++ b/packages/frontend/src/pages/registry.value.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="600" :margin-min="16"> + <MkSpacer :contentMax="600" :marginMin="16"> <div class="_gaps_m"> <FormInfo warn>{{ i18n.ts.editTheseSettingsMayBreakAccount }}</FormInfo> diff --git a/packages/frontend/src/pages/registry.vue b/packages/frontend/src/pages/registry.vue index 016af22815..6bfb9bce58 100644 --- a/packages/frontend/src/pages/registry.vue +++ b/packages/frontend/src/pages/registry.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="600" :margin-min="16"> + <MkSpacer :contentMax="600" :marginMin="16"> <MkButton primary @click="createKey">{{ i18n.ts._registry.createKey }}</MkButton> <FormSection v-if="scopes"> diff --git a/packages/frontend/src/pages/reset-password.vue b/packages/frontend/src/pages/reset-password.vue index ab7a96a8d0..9d57307314 100644 --- a/packages/frontend/src/pages/reset-password.vue +++ b/packages/frontend/src/pages/reset-password.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer v-if="token" :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer v-if="token" :contentMax="700" :marginMin="16" :marginMax="32"> <div class="_gaps_m"> <MkInput v-model="password" type="password"> <template #prefix><i class="ti ti-lock"></i></template> diff --git a/packages/frontend/src/pages/role.vue b/packages/frontend/src/pages/role.vue index fe39c594ba..e85ab0917a 100644 --- a/packages/frontend/src/pages/role.vue +++ b/packages/frontend/src/pages/role.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template> - <MKSpacer v-if="!(typeof error === 'undefined')" :content-max="1200"> + <MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200"> <div :class="$style.root"> <img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> <p :class="$style.text"> @@ -10,17 +10,18 @@ </p> </div> </MKSpacer> - <MkSpacer v-else-if="tab === 'users'" :content-max="1200"> + <MkSpacer v-else-if="tab === 'users'" :contentMax="1200"> <div class="_gaps_s"> <div v-if="role">{{ role.description }}</div> <MkUserList :pagination="users" :extractor="(item) => item.user"/> </div> </MkSpacer> - <MkSpacer v-else-if="tab === 'timeline'" :content-max="700"> + <MkSpacer v-else-if="tab === 'timeline'" :contentMax="700"> <MkTimeline ref="timeline" src="role" :role="props.role"/> </MkSpacer> </MkStickyContainer> </template> + <script lang="ts" setup> import { computed, watch } from 'vue'; import * as os from '@/os'; @@ -80,6 +81,7 @@ definePageMetadata(computed(() => ({ icon: 'ti ti-badge', }))); </script> + <style lang="scss" module> .root { padding: 32px; diff --git a/packages/frontend/src/pages/scratchpad.vue b/packages/frontend/src/pages/scratchpad.vue index fb78546cb1..22eb00dad4 100644 --- a/packages/frontend/src/pages/scratchpad.vue +++ b/packages/frontend/src/pages/scratchpad.vue @@ -1,8 +1,8 @@ <template> -<MkSpacer :content-max="800"> +<MkSpacer :contentMax="800"> <div :class="$style.root"> <div :class="$style.editor" class="_panel"> - <PrismEditor v-model="code" class="_code code" :highlight="highlighter" :line-numbers="false"/> + <PrismEditor v-model="code" class="_code code" :highlight="highlighter" :lineNumbers="false"/> <MkButton style="position: absolute; top: 8px; right: 8px;" primary @click="run()"><i class="ti ti-player-play"></i></MkButton> </div> diff --git a/packages/frontend/src/pages/search.user.vue b/packages/frontend/src/pages/search.user.vue index 23a8978fd1..bd1389ffef 100644 --- a/packages/frontend/src/pages/search.user.vue +++ b/packages/frontend/src/pages/search.user.vue @@ -4,7 +4,7 @@ <MkInput v-model="searchQuery" :large="true" :autofocus="true" type="search"> <template #prefix><i class="ti ti-search"></i></template> </MkInput> - <MkRadios v-model="searchOrigin" @update:model-value="search()"> + <MkRadios v-model="searchOrigin" @update:modelValue="search()"> <option value="combined">{{ i18n.ts.all }}</option> <option value="local">{{ i18n.ts.local }}</option> <option value="remote">{{ i18n.ts.remote }}</option> diff --git a/packages/frontend/src/pages/search.vue b/packages/frontend/src/pages/search.vue index 9f3d8da560..dcaf42e648 100644 --- a/packages/frontend/src/pages/search.vue +++ b/packages/frontend/src/pages/search.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer v-if="tab === 'note'" :content-max="800"> + <MkSpacer v-if="tab === 'note'" :contentMax="800"> <div v-if="notesSearchAvailable"> <XNote/> </div> @@ -11,7 +11,7 @@ </div> </MkSpacer> - <MkSpacer v-else-if="tab === 'user'" :content-max="800"> + <MkSpacer v-else-if="tab === 'user'" :contentMax="800"> <XUser/> </MkSpacer> </MkStickyContainer> diff --git a/packages/frontend/src/pages/share.vue b/packages/frontend/src/pages/share.vue index 5abb234893..5c10198f7a 100644 --- a/packages/frontend/src/pages/share.vue +++ b/packages/frontend/src/pages/share.vue @@ -1,18 +1,18 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <MkPostForm v-if="state === 'writing'" fixed :instant="true" - :initial-text="initialText" - :initial-visibility="visibility" - :initial-files="files" - :initial-local-only="localOnly" + :initialText="initialText" + :initialVisibility="visibility" + :initialFiles="files" + :initialLocalOnly="localOnly" :reply="reply" :renote="renote" - :initial-visible-users="visibleUsers" + :initialVisibleUsers="visibleUsers" class="_panel" @posted="state = 'posted'" /> diff --git a/packages/frontend/src/pages/tag.vue b/packages/frontend/src/pages/tag.vue index 511052c424..b53db3f67b 100644 --- a/packages/frontend/src/pages/tag.vue +++ b/packages/frontend/src/pages/tag.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <MkNotes class="" :pagination="pagination"/> </MkSpacer> </MkStickyContainer> diff --git a/packages/frontend/src/pages/theme-editor.vue b/packages/frontend/src/pages/theme-editor.vue index 56fdfdf782..f942b5005b 100644 --- a/packages/frontend/src/pages/theme-editor.vue +++ b/packages/frontend/src/pages/theme-editor.vue @@ -1,9 +1,9 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="800" :marginMin="16" :marginMax="32"> <div class="cwepdizn _gaps_m"> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #label>{{ i18n.ts.backgroundColor }}</template> <div class="cwepdizn-colors"> <div class="row"> @@ -19,7 +19,7 @@ </div> </MkFolder> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #label>{{ i18n.ts.accentColor }}</template> <div class="cwepdizn-colors"> <div class="row"> @@ -30,7 +30,7 @@ </div> </MkFolder> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #label>{{ i18n.ts.textColor }}</template> <div class="cwepdizn-colors"> <div class="row"> @@ -41,7 +41,7 @@ </div> </MkFolder> - <MkFolder :default-open="false"> + <MkFolder :defaultOpen="false"> <template #icon><i class="ti ti-code"></i></template> <template #label>{{ i18n.ts.editCode }}</template> @@ -53,7 +53,7 @@ </div> </MkFolder> - <MkFolder :default-open="false"> + <MkFolder :defaultOpen="false"> <template #label>{{ i18n.ts.addDescription }}</template> <div class="_gaps_m"> diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 1bf4cdc99a..2c971e9cab 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> - <template #header><MkPageHeader v-model:tab="src" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :display-my-avatar="true"/></template> - <MkSpacer :content-max="800"> + <template #header><MkPageHeader v-model:tab="src" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/></template> + <MkSpacer :contentMax="800"> <div ref="rootEl" v-hotkey.global="keymap"> <XTutorial v-if="$i && defaultStore.reactiveState.timelineTutorial.value != -1" class="_panel" style="margin-bottom: var(--margin);"/> <MkPostForm v-if="defaultStore.reactiveState.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--margin);"/> diff --git a/packages/frontend/src/pages/user-info.vue b/packages/frontend/src/pages/user-info.vue index 94718d1533..56e8737e1c 100644 --- a/packages/frontend/src/pages/user-info.vue +++ b/packages/frontend/src/pages/user-info.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="600" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="600" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <div v-if="tab === 'overview'" class="_gaps_m"> <div class="aeakzknw"> @@ -88,7 +88,7 @@ </div> <div v-else-if="tab === 'moderation'" class="_gaps_m"> - <MkSwitch v-model="suspended" @update:model-value="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch> + <MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch> <div> <MkButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton> @@ -112,7 +112,7 @@ <MkButton v-if="user.host == null && iAmModerator" primary rounded @click="assignRole"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton> <div v-for="role in info.roles" :key="role.id" :class="$style.roleItem"> - <MkRolePreview :class="$style.role" :role="role" :for-moderation="true"/> + <MkRolePreview :class="$style.role" :role="role" :forModeration="true"/> <button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="unassignRole(role, $event)"><i class="ti ti-x"></i></button> <button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button> </div> @@ -135,10 +135,10 @@ <MkFolder> <template #icon><i class="ti ti-cloud"></i></template> <template #label>{{ i18n.ts.files }}</template> - <MkFileListForAdmin :pagination="filesPagination" view-mode="grid"/> + <MkFileListForAdmin :pagination="filesPagination" viewMode="grid"/> </MkFolder> - <MkTextarea v-model="moderationNote" manual-save> + <MkTextarea v-model="moderationNote" manualSave> <template #label>Moderation note</template> </MkTextarea> </div> diff --git a/packages/frontend/src/pages/user-tag.vue b/packages/frontend/src/pages/user-tag.vue index fac7593e9c..01ef1126cb 100644 --- a/packages/frontend/src/pages/user-tag.vue +++ b/packages/frontend/src/pages/user-tag.vue @@ -2,7 +2,7 @@ <MkStickyContainer> <template #header><MkPageHeader/></template> - <MkSpacer :content-max="1200"> + <MkSpacer :contentMax="1200"> <div class="_gaps_s"> <MkUserList :pagination="tagUsers"/> </div> diff --git a/packages/frontend/src/pages/welcome.entrance.a.vue b/packages/frontend/src/pages/welcome.entrance.a.vue index 929152bd5a..f082b4b3c7 100644 --- a/packages/frontend/src/pages/welcome.entrance.a.vue +++ b/packages/frontend/src/pages/welcome.entrance.a.vue @@ -6,11 +6,11 @@ <div class="shape2"></div> <img src="/client-assets/misskey.svg" class="misskey"/> <div class="emojis"> - <MkEmoji :normal="true" :no-style="true" emoji="👍"/> - <MkEmoji :normal="true" :no-style="true" emoji="❤"/> - <MkEmoji :normal="true" :no-style="true" emoji="😆"/> - <MkEmoji :normal="true" :no-style="true" emoji="🎉"/> - <MkEmoji :normal="true" :no-style="true" emoji="🍮"/> + <MkEmoji :normal="true" :noStyle="true" emoji="👍"/> + <MkEmoji :normal="true" :noStyle="true" emoji="❤"/> + <MkEmoji :normal="true" :noStyle="true" emoji="😆"/> + <MkEmoji :normal="true" :noStyle="true" emoji="🎉"/> + <MkEmoji :normal="true" :noStyle="true" emoji="🍮"/> </div> <div class="contents"> <MkVisitorDashboard/> diff --git a/packages/frontend/src/pages/welcome.timeline.vue b/packages/frontend/src/pages/welcome.timeline.vue index 6ec6e3f863..46a0775579 100644 --- a/packages/frontend/src/pages/welcome.timeline.vue +++ b/packages/frontend/src/pages/welcome.timeline.vue @@ -9,10 +9,10 @@ <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> </div> <div v-if="note.files.length > 0" :class="$style.richcontent"> - <MkMediaList :media-list="note.files"/> + <MkMediaList :mediaList="note.files"/> </div> <div v-if="note.poll"> - <MkPoll :note="note" :read-only="true"/> + <MkPoll :note="note" :readOnly="true"/> </div> </div> <MkReactionsViewer ref="reactionsViewer" :note="note"/> diff --git a/packages/frontend/src/widgets/WidgetActivity.calendar.vue b/packages/frontend/src/widgets/WidgetActivity.calendar.vue index 84f6af1c13..110f1d32eb 100644 --- a/packages/frontend/src/widgets/WidgetActivity.calendar.vue +++ b/packages/frontend/src/widgets/WidgetActivity.calendar.vue @@ -1,25 +1,31 @@ <template> <svg viewBox="0 0 21 7"> - <rect v-for="record in activity" class="day" + <rect + v-for="record in activity" class="day" width="1" height="1" :x="record.x" :y="record.date.weekday" rx="1" ry="1" - fill="transparent"> + fill="transparent" + > <title>{{ record.date.year }}/{{ record.date.month + 1 }}/{{ record.date.day }}</title> </rect> - <rect v-for="record in activity" class="day" + <rect + v-for="record in activity" class="day" :width="record.v" :height="record.v" :x="record.x + ((1 - record.v) / 2)" :y="record.date.weekday + ((1 - record.v) / 2)" rx="1" ry="1" :fill="record.color" - style="pointer-events: none;"/> - <rect class="today" + style="pointer-events: none;" + /> + <rect + class="today" width="1" height="1" :x="activity[0].x" :y="activity[0].date.weekday" rx="1" ry="1" fill="none" stroke-width="0.1" - stroke="#f73520"/> + stroke="#f73520" + /> </svg> </template> diff --git a/packages/frontend/src/widgets/WidgetActivity.vue b/packages/frontend/src/widgets/WidgetActivity.vue index e7f8819abd..892b24f69d 100644 --- a/packages/frontend/src/widgets/WidgetActivity.vue +++ b/packages/frontend/src/widgets/WidgetActivity.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent" data-cy-mkw-activity class="mkw-activity"> +<MkContainer :showHeader="widgetProps.showHeader" :naked="widgetProps.transparent" data-cy-mkw-activity class="mkw-activity"> <template #icon><i class="ti ti-chart-line"></i></template> <template #header>{{ i18n.ts._widgets.activity }}</template> <template #func="{ buttonStyleClass }"><button class="_button" :class="buttonStyleClass" @click="toggleView()"><i class="ti ti-selector"></i></button></template> @@ -16,7 +16,7 @@ <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import XCalendar from './WidgetActivity.calendar.vue'; import XChart from './WidgetActivity.chart.vue'; import { GetFormResultType } from '@/scripts/form'; @@ -45,11 +45,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure, save } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetAichan.vue b/packages/frontend/src/widgets/WidgetAichan.vue index 0c485441d2..797dd9c09f 100644 --- a/packages/frontend/src/widgets/WidgetAichan.vue +++ b/packages/frontend/src/widgets/WidgetAichan.vue @@ -1,12 +1,12 @@ <template> -<MkContainer :naked="widgetProps.transparent" :show-header="false" data-cy-mkw-aichan class="mkw-aichan"> +<MkContainer :naked="widgetProps.transparent" :showHeader="false" data-cy-mkw-aichan class="mkw-aichan"> <iframe ref="live2d" :class="$style.root" src="https://misskey-dev.github.io/mascot-web/?scale=1.5&y=1.1&eyeY=100" @click="touched"></iframe> </MkContainer> </template> <script lang="ts" setup> import { onMounted, onUnmounted, shallowRef } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; const name = 'ai'; @@ -20,11 +20,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetAiscript.vue b/packages/frontend/src/widgets/WidgetAiscript.vue index 947dbe5e77..d6c94cd56a 100644 --- a/packages/frontend/src/widgets/WidgetAiscript.vue +++ b/packages/frontend/src/widgets/WidgetAiscript.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" data-cy-mkw-aiscript class="mkw-aiscript"> +<MkContainer :showHeader="widgetProps.showHeader" data-cy-mkw-aiscript class="mkw-aiscript"> <template #icon><i class="ti ti-terminal-2"></i></template> <template #header>{{ i18n.ts._widgets.aiscript }}</template> @@ -16,7 +16,7 @@ <script lang="ts" setup> import { ref } from 'vue'; import { Interpreter, Parser, utils } from '@syuilo/aiscript'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import MkContainer from '@/components/MkContainer.vue'; @@ -41,11 +41,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetAiscriptApp.vue b/packages/frontend/src/widgets/WidgetAiscriptApp.vue index 455a6e6ea5..3b67972e40 100644 --- a/packages/frontend/src/widgets/WidgetAiscriptApp.vue +++ b/packages/frontend/src/widgets/WidgetAiscriptApp.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" class="mkw-aiscriptApp"> +<MkContainer :showHeader="widgetProps.showHeader" class="mkw-aiscriptApp"> <template #header>App</template> <div :class="$style.root"> <MkAsUi v-if="root" :component="root" :components="components" size="small"/> @@ -10,7 +10,7 @@ <script lang="ts" setup> import { onMounted, Ref, ref, watch } from 'vue'; import { Interpreter, Parser } from '@syuilo/aiscript'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import { createAiScriptEnv } from '@/scripts/aiscript/api'; @@ -35,12 +35,9 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); - +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); + const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, props, diff --git a/packages/frontend/src/widgets/WidgetButton.vue b/packages/frontend/src/widgets/WidgetButton.vue index 98260caeef..bcb380f849 100644 --- a/packages/frontend/src/widgets/WidgetButton.vue +++ b/packages/frontend/src/widgets/WidgetButton.vue @@ -8,7 +8,7 @@ <script lang="ts" setup> import { Interpreter, Parser } from '@syuilo/aiscript'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import { createAiScriptEnv } from '@/scripts/aiscript/api'; @@ -35,11 +35,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetCalendar.vue b/packages/frontend/src/widgets/WidgetCalendar.vue index 58d0732263..447525837c 100644 --- a/packages/frontend/src/widgets/WidgetCalendar.vue +++ b/packages/frontend/src/widgets/WidgetCalendar.vue @@ -34,7 +34,7 @@ <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import { i18n } from '@/i18n'; import { useInterval } from '@/scripts/use-interval'; @@ -50,11 +50,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetClicker.vue b/packages/frontend/src/widgets/WidgetClicker.vue index 981788a3c5..b7be2e8c83 100644 --- a/packages/frontend/src/widgets/WidgetClicker.vue +++ b/packages/frontend/src/widgets/WidgetClicker.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" class="mkw-clicker"> +<MkContainer :showHeader="widgetProps.showHeader" class="mkw-clicker"> <template #icon><i class="ti ti-cookie"></i></template> <template #header>Clicker</template> <MkClickerGame/> @@ -7,7 +7,7 @@ </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import MkClickerGame from '@/components/MkClickerGame.vue'; @@ -23,12 +23,9 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); - +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); + const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, props, diff --git a/packages/frontend/src/widgets/WidgetClock.vue b/packages/frontend/src/widgets/WidgetClock.vue index ebd73cb9f5..7d814dcd53 100644 --- a/packages/frontend/src/widgets/WidgetClock.vue +++ b/packages/frontend/src/widgets/WidgetClock.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :naked="widgetProps.transparent" :show-header="false" data-cy-mkw-clock class="mkw-clock"> +<MkContainer :naked="widgetProps.transparent" :showHeader="false" data-cy-mkw-clock class="mkw-clock"> <div class="vubelbmv" :class="widgetProps.size"> <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label a abbrev">{{ tzAbbrev }}</div> <MkAnalogClock @@ -7,11 +7,11 @@ :thickness="widgetProps.thickness" :offset="tzOffset" :graduations="widgetProps.graduations" - :fade-graduations="widgetProps.fadeGraduations" + :fadeGraduations="widgetProps.fadeGraduations" :twentyfour="widgetProps.twentyFour" - :s-animation="widgetProps.sAnimation" + :sAnimation="widgetProps.sAnimation" /> - <MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" class="_monospace label c time" :show-s="false" :offset="tzOffset"/> + <MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" class="_monospace label c time" :showS="false" :offset="tzOffset"/> <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label d offset">{{ tzOffsetLabel }}</div> </div> </MkContainer> @@ -19,7 +19,7 @@ <script lang="ts" setup> import { } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import MkAnalogClock from '@/components/MkAnalogClock.vue'; @@ -114,11 +114,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetDigitalClock.vue b/packages/frontend/src/widgets/WidgetDigitalClock.vue index cdd9c3a401..6148177d9a 100644 --- a/packages/frontend/src/widgets/WidgetDigitalClock.vue +++ b/packages/frontend/src/widgets/WidgetDigitalClock.vue @@ -2,14 +2,14 @@ <div data-cy-mkw-digitalClock class="_monospace" :class="[$style.root, { _panel: !widgetProps.transparent }]" :style="{ fontSize: `${widgetProps.fontSize}em` }"> <div v-if="widgetProps.showLabel" :class="$style.label">{{ tzAbbrev }}</div> <div> - <MkDigitalClock :show-ms="widgetProps.showMs" :offset="tzOffset"/> + <MkDigitalClock :showMs="widgetProps.showMs" :offset="tzOffset"/> </div> <div v-if="widgetProps.showLabel" :class="$style.label">{{ tzOffsetLabel }}</div> </div> </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import { timezones } from '@/scripts/timezones'; import MkDigitalClock from '@/components/MkDigitalClock.vue'; @@ -49,11 +49,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetFederation.vue b/packages/frontend/src/widgets/WidgetFederation.vue index 2033b074e0..951c4aaa6d 100644 --- a/packages/frontend/src/widgets/WidgetFederation.vue +++ b/packages/frontend/src/widgets/WidgetFederation.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" :foldable="foldable" :scrollable="scrollable" data-cy-mkw-federation class="mkw-federation"> +<MkContainer :showHeader="widgetProps.showHeader" :foldable="foldable" :scrollable="scrollable" data-cy-mkw-federation class="mkw-federation"> <template #icon><i class="ti ti-whirl"></i></template> <template #header>{{ i18n.ts._widgets.federation }}</template> @@ -21,7 +21,7 @@ <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import MkMiniChart from '@/components/MkMiniChart.vue'; @@ -42,11 +42,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps> & { foldable?: boolean; scrollable?: boolean; }>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; foldable?: boolean; scrollable?: boolean; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetInstanceCloud.vue b/packages/frontend/src/widgets/WidgetInstanceCloud.vue index b157807655..79bd4b55fd 100644 --- a/packages/frontend/src/widgets/WidgetInstanceCloud.vue +++ b/packages/frontend/src/widgets/WidgetInstanceCloud.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :naked="widgetProps.transparent" :show-header="false" class="mkw-instance-cloud"> +<MkContainer :naked="widgetProps.transparent" :showHeader="false" class="mkw-instance-cloud"> <div class=""> <MkTagCloud v-if="activeInstances"> <li v-for="instance in activeInstances" :key="instance.id"> @@ -14,7 +14,7 @@ <script lang="ts" setup> import { } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import MkTagCloud from '@/components/MkTagCloud.vue'; @@ -33,11 +33,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetInstanceInfo.vue b/packages/frontend/src/widgets/WidgetInstanceInfo.vue index d702fd2cb0..c77b98f8f4 100644 --- a/packages/frontend/src/widgets/WidgetInstanceInfo.vue +++ b/packages/frontend/src/widgets/WidgetInstanceInfo.vue @@ -15,7 +15,7 @@ </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import { host } from '@/config'; import { instance } from '@/instance'; @@ -27,11 +27,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetJobQueue.vue b/packages/frontend/src/widgets/WidgetJobQueue.vue index 73a4802595..3c8ffdb55a 100644 --- a/packages/frontend/src/widgets/WidgetJobQueue.vue +++ b/packages/frontend/src/widgets/WidgetJobQueue.vue @@ -47,7 +47,7 @@ <script lang="ts" setup> import { onUnmounted, reactive } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import { useStream } from '@/stream'; import number from '@/filters/number'; @@ -69,11 +69,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetMemo.vue b/packages/frontend/src/widgets/WidgetMemo.vue index 959cf776ad..78d27a31b9 100644 --- a/packages/frontend/src/widgets/WidgetMemo.vue +++ b/packages/frontend/src/widgets/WidgetMemo.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" data-cy-mkw-memo class="mkw-memo"> +<MkContainer :showHeader="widgetProps.showHeader" data-cy-mkw-memo class="mkw-memo"> <template #icon><i class="ti ti-note"></i></template> <template #header>{{ i18n.ts._widgets.memo }}</template> @@ -12,7 +12,7 @@ <script lang="ts" setup> import { ref, watch } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import { defaultStore } from '@/store'; @@ -33,11 +33,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetNotifications.vue b/packages/frontend/src/widgets/WidgetNotifications.vue index 661f68b278..a24aa9b2e9 100644 --- a/packages/frontend/src/widgets/WidgetNotifications.vue +++ b/packages/frontend/src/widgets/WidgetNotifications.vue @@ -1,18 +1,18 @@ <template> -<MkContainer :style="`height: ${widgetProps.height}px;`" :show-header="widgetProps.showHeader" :scrollable="true" data-cy-mkw-notifications class="mkw-notifications"> +<MkContainer :style="`height: ${widgetProps.height}px;`" :showHeader="widgetProps.showHeader" :scrollable="true" data-cy-mkw-notifications class="mkw-notifications"> <template #icon><i class="ti ti-bell"></i></template> <template #header>{{ i18n.ts.notifications }}</template> <template #func="{ buttonStyleClass }"><button class="_button" :class="buttonStyleClass" @click="configureNotification()"><i class="ti ti-settings"></i></button></template> <div> - <XNotifications :include-types="widgetProps.includingTypes"/> + <XNotifications :includeTypes="widgetProps.includingTypes"/> </div> </MkContainer> </template> <script lang="ts" setup> import { defineAsyncComponent } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import XNotifications from '@/components/MkNotifications.vue'; @@ -39,12 +39,9 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); - +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); + const { widgetProps, configure, save } = useWidgetPropsManager(name, widgetPropsDef, props, diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue index 19195d6fde..f95103b0b9 100644 --- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue +++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue @@ -8,7 +8,7 @@ <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; @@ -26,11 +26,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetPhotos.vue b/packages/frontend/src/widgets/WidgetPhotos.vue index 1484aa1941..5c6a8cbf83 100644 --- a/packages/frontend/src/widgets/WidgetPhotos.vue +++ b/packages/frontend/src/widgets/WidgetPhotos.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent" :class="$style.root" :data-transparent="widgetProps.transparent ? true : null" data-cy-mkw-photos class="mkw-photos"> +<MkContainer :showHeader="widgetProps.showHeader" :naked="widgetProps.transparent" :class="$style.root" :data-transparent="widgetProps.transparent ? true : null" data-cy-mkw-photos class="mkw-photos"> <template #icon><i class="ti ti-camera"></i></template> <template #header>{{ i18n.ts._widgets.photos }}</template> @@ -18,7 +18,7 @@ <script lang="ts" setup> import { onUnmounted, ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import { useStream } from '@/stream'; import { getStaticImageUrl } from '@/scripts/media-proxy'; @@ -42,11 +42,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetPostForm.vue b/packages/frontend/src/widgets/WidgetPostForm.vue index 7a96b00217..bc63f02821 100644 --- a/packages/frontend/src/widgets/WidgetPostForm.vue +++ b/packages/frontend/src/widgets/WidgetPostForm.vue @@ -4,7 +4,7 @@ <script lang="ts" setup> import { } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkPostForm from '@/components/MkPostForm.vue'; @@ -15,11 +15,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetProfile.vue b/packages/frontend/src/widgets/WidgetProfile.vue index 819663a366..72e229ef8f 100644 --- a/packages/frontend/src/widgets/WidgetProfile.vue +++ b/packages/frontend/src/widgets/WidgetProfile.vue @@ -17,7 +17,7 @@ </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import { $i } from '@/account'; import { userPage } from '@/filters/user'; @@ -29,11 +29,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue index 18fa2e2c22..1be882c66d 100644 --- a/packages/frontend/src/widgets/WidgetRss.vue +++ b/packages/frontend/src/widgets/WidgetRss.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" data-cy-mkw-rss class="mkw-rss"> +<MkContainer :showHeader="widgetProps.showHeader" data-cy-mkw-rss class="mkw-rss"> <template #icon><i class="ti ti-rss"></i></template> <template #header>RSS</template> <template #func="{ buttonStyleClass }"><button class="_button" :class="buttonStyleClass" @click="configure"><i class="ti ti-settings"></i></button></template> @@ -19,7 +19,7 @@ <script lang="ts" setup> import { ref, watch, computed } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import { url as base } from '@/config'; @@ -49,11 +49,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue index b0408f0d7f..135ca37026 100644 --- a/packages/frontend/src/widgets/WidgetRssTicker.vue +++ b/packages/frontend/src/widgets/WidgetRssTicker.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :naked="widgetProps.transparent" :show-header="widgetProps.showHeader" class="mkw-rss-ticker"> +<MkContainer :naked="widgetProps.transparent" :showHeader="widgetProps.showHeader" class="mkw-rss-ticker"> <template #icon><i class="ti ti-rss"></i></template> <template #header>RSS</template> <template #func="{ buttonStyleClass }"><button class="_button" :class="buttonStyleClass" @click="configure"><i class="ti ti-settings"></i></button></template> @@ -23,7 +23,7 @@ <script lang="ts" setup> import { ref, watch, computed } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import MarqueeText from '@/components/MkMarquee.vue'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; @@ -73,11 +73,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetSlideshow.vue b/packages/frontend/src/widgets/WidgetSlideshow.vue index 915e7aaaf4..d4ede57926 100644 --- a/packages/frontend/src/widgets/WidgetSlideshow.vue +++ b/packages/frontend/src/widgets/WidgetSlideshow.vue @@ -13,7 +13,7 @@ <script lang="ts" setup> import { onMounted, ref, shallowRef } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import { useInterval } from '@/scripts/use-interval'; @@ -35,11 +35,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure, save } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetTimeline.vue b/packages/frontend/src/widgets/WidgetTimeline.vue index 71ee75f6cb..3d497c2e23 100644 --- a/packages/frontend/src/widgets/WidgetTimeline.vue +++ b/packages/frontend/src/widgets/WidgetTimeline.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" :style="`height: ${widgetProps.height}px;`" :scrollable="true" data-cy-mkw-timeline class="mkw-timeline"> +<MkContainer :showHeader="widgetProps.showHeader" :style="`height: ${widgetProps.height}px;`" :scrollable="true" data-cy-mkw-timeline class="mkw-timeline"> <template #icon> <i v-if="widgetProps.src === 'home'" class="ti ti-home"></i> <i v-else-if="widgetProps.src === 'local'" class="ti ti-planet"></i> @@ -30,7 +30,7 @@ <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import * as os from '@/os'; import MkContainer from '@/components/MkContainer.vue'; @@ -71,11 +71,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure, save } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetTrends.vue b/packages/frontend/src/widgets/WidgetTrends.vue index 01450a7ab5..36f908d5ea 100644 --- a/packages/frontend/src/widgets/WidgetTrends.vue +++ b/packages/frontend/src/widgets/WidgetTrends.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" data-cy-mkw-trends class="mkw-trends"> +<MkContainer :showHeader="widgetProps.showHeader" data-cy-mkw-trends class="mkw-trends"> <template #icon><i class="ti ti-hash"></i></template> <template #header>{{ i18n.ts._widgets.trends }}</template> @@ -20,7 +20,7 @@ <script lang="ts" setup> import { ref } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import MkMiniChart from '@/components/MkMiniChart.vue'; @@ -40,11 +40,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetUnixClock.vue b/packages/frontend/src/widgets/WidgetUnixClock.vue index 22162d2b2c..f1af71adda 100644 --- a/packages/frontend/src/widgets/WidgetUnixClock.vue +++ b/packages/frontend/src/widgets/WidgetUnixClock.vue @@ -12,7 +12,7 @@ <script lang="ts" setup> import { onUnmounted, ref, watch } from 'vue'; -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; const name = 'unixClock'; @@ -39,11 +39,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure } = useWidgetPropsManager(name, widgetPropsDef, diff --git a/packages/frontend/src/widgets/WidgetUserList.vue b/packages/frontend/src/widgets/WidgetUserList.vue index b8811d2fed..4380fdb62f 100644 --- a/packages/frontend/src/widgets/WidgetUserList.vue +++ b/packages/frontend/src/widgets/WidgetUserList.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" class="mkw-userList"> +<MkContainer :showHeader="widgetProps.showHeader" class="mkw-userList"> <template #icon><i class="ti ti-users"></i></template> <template #header>{{ list ? list.name : i18n.ts._widgets.userList }}</template> <template #func="{ buttonStyleClass }"><button class="_button" :class="buttonStyleClass" @click="configure()"><i class="ti ti-settings"></i></button></template> @@ -19,7 +19,7 @@ </template> <script lang="ts" setup> -import { useWidgetPropsManager, Widget, WidgetComponentExpose } from './widget'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { GetFormResultType } from '@/scripts/form'; import MkContainer from '@/components/MkContainer.vue'; import * as os from '@/os'; @@ -43,11 +43,8 @@ const widgetPropsDef = { type WidgetProps = GetFormResultType<typeof widgetPropsDef>; -// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない -//const props = defineProps<WidgetComponentProps<WidgetProps>>(); -//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); -const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); -const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); +const props = defineProps<WidgetComponentProps<WidgetProps>>(); +const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); const { widgetProps, configure, save } = useWidgetPropsManager(name, widgetPropsDef, From 4a703d7cf63ae799e1bec020b790bea3a431ff62 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 16:25:48 +0900 Subject: [PATCH 056/213] refactor --- .../frontend/src/pages/antenna-timeline.vue | 72 +++++++++---------- packages/frontend/src/pages/timeline.vue | 14 ++-- .../frontend/src/pages/user-list-timeline.vue | 72 +++++++++---------- 3 files changed, 73 insertions(+), 85 deletions(-) diff --git a/packages/frontend/src/pages/antenna-timeline.vue b/packages/frontend/src/pages/antenna-timeline.vue index 62e8178af1..a22714791f 100644 --- a/packages/frontend/src/pages/antenna-timeline.vue +++ b/packages/frontend/src/pages/antenna-timeline.vue @@ -1,19 +1,20 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <div ref="rootEl" v-hotkey.global="keymap" class="tqmomfks"> - <div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> - <div class="tl"> - <MkTimeline - ref="tlEl" :key="antennaId" - class="tl" - src="antenna" - :antenna="antennaId" - :sound="true" - @queue="queueUpdated" - /> + <MkSpacer :contentMax="800"> + <div ref="rootEl" v-hotkey.global="keymap"> + <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> + <div :class="$style.tl"> + <MkTimeline + ref="tlEl" :key="antennaId" + src="antenna" + :antenna="antennaId" + :sound="true" + @queue="queueUpdated" + /> + </div> </div> - </div> + </MkSpacer> </MkStickyContainer> </template> @@ -89,36 +90,29 @@ definePageMetadata(computed(() => antenna ? { } : null)); </script> -<style lang="scss" scoped> -.tqmomfks { - padding: var(--margin); +<style lang="scss" module> +.new { + position: sticky; + top: calc(var(--stickyTop, 0px) + 16px); + z-index: 1000; + width: 100%; + margin: calc(-0.675em - 8px) 0; - > .new { - position: sticky; - top: calc(var(--stickyTop, 0px) + 16px); - z-index: 1000; - width: 100%; - margin: calc(-0.675em - 8px - var(--margin)) 0 calc(-0.675em - 8px); - - > button { - display: block; - margin: var(--margin) auto 0 auto; - padding: 8px 16px; - border-radius: 32px; - } - } - - > .tl { - background: var(--bg); - border-radius: var(--radius); - overflow: clip; + &:first-child { + margin-top: calc(-0.675em - 8px - var(--margin)); } } -@container (min-width: 800px) { - .tqmomfks { - max-width: 800px; - margin: 0 auto; - } +.newButton { + display: block; + margin: var(--margin) auto 0 auto; + padding: 8px 16px; + border-radius: 32px; +} + +.tl { + background: var(--bg); + border-radius: var(--radius); + overflow: clip; } </style> diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 2c971e9cab..a441c6f728 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -6,7 +6,7 @@ <XTutorial v-if="$i && defaultStore.reactiveState.timelineTutorial.value != -1" class="_panel" style="margin-bottom: var(--margin);"/> <MkPostForm v-if="defaultStore.reactiveState.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--margin);"/> - <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> + <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> <div :class="$style.tl"> <MkTimeline ref="tlComponent" @@ -187,13 +187,13 @@ definePageMetadata(computed(() => ({ &:first-child { margin-top: calc(-0.675em - 8px - var(--margin)); } +} - > button { - display: block; - margin: var(--margin) auto 0 auto; - padding: 8px 16px; - border-radius: 32px; - } +.newButton { + display: block; + margin: var(--margin) auto 0 auto; + padding: 8px 16px; + border-radius: 32px; } .postForm { diff --git a/packages/frontend/src/pages/user-list-timeline.vue b/packages/frontend/src/pages/user-list-timeline.vue index acf7ea9b2c..f66670e1f6 100644 --- a/packages/frontend/src/pages/user-list-timeline.vue +++ b/packages/frontend/src/pages/user-list-timeline.vue @@ -1,19 +1,20 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <div ref="rootEl" class="eqqrhokj"> - <div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> - <div class="tl"> - <MkTimeline - ref="tlEl" :key="listId" - class="tl" - src="list" - :list="listId" - :sound="true" - @queue="queueUpdated" - /> + <MkSpacer :contentMax="800"> + <div ref="rootEl"> + <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> + <div :class="$style.tl"> + <MkTimeline + ref="tlEl" :key="listId" + src="list" + :list="listId" + :sound="true" + @queue="queueUpdated" + /> + </div> </div> - </div> + </MkSpacer> </MkStickyContainer> </template> @@ -82,36 +83,29 @@ definePageMetadata(computed(() => list ? { } : null)); </script> -<style lang="scss" scoped> -.eqqrhokj { - padding: var(--margin); +<style lang="scss" module> +.new { + position: sticky; + top: calc(var(--stickyTop, 0px) + 16px); + z-index: 1000; + width: 100%; + margin: calc(-0.675em - 8px) 0; - > .new { - position: sticky; - top: calc(var(--stickyTop, 0px) + 16px); - z-index: 1000; - width: 100%; - margin: calc(-0.675em - 8px - var(--margin)) 0 calc(-0.675em - 8px); - - > button { - display: block; - margin: var(--margin) auto 0 auto; - padding: 8px 16px; - border-radius: 32px; - } - } - - > .tl { - background: var(--bg); - border-radius: var(--radius); - overflow: clip; + &:first-child { + margin-top: calc(-0.675em - 8px - var(--margin)); } } -@container (min-width: 800px) { - .eqqrhokj { - max-width: 800px; - margin: 0 auto; - } +.newButton { + display: block; + margin: var(--margin) auto 0 auto; + padding: 8px 16px; + border-radius: 32px; +} + +.tl { + background: var(--bg); + border-radius: var(--radius); + overflow: clip; } </style> From be2142bb1322a04e3d870454011ec7dad008d1b6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 16:30:39 +0900 Subject: [PATCH 057/213] refactor --- packages/frontend/src/ui/minimum.vue | 6 +++--- packages/frontend/src/ui/zen.vue | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/frontend/src/ui/minimum.vue b/packages/frontend/src/ui/minimum.vue index 628390e3f7..e656f00bb2 100644 --- a/packages/frontend/src/ui/minimum.vue +++ b/packages/frontend/src/ui/minimum.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-app" style="container-type: inline-size;"> +<div :class="$style.root" style="container-type: inline-size;"> <RouterView/> <XCommon/> @@ -26,8 +26,8 @@ provideMetadataReceiver((info) => { document.documentElement.style.overflowY = 'scroll'; </script> -<style lang="scss" scoped> -.mk-app { +<style lang="scss" module> +.root { min-height: 100dvh; box-sizing: border-box; } diff --git a/packages/frontend/src/ui/zen.vue b/packages/frontend/src/ui/zen.vue index 628390e3f7..e656f00bb2 100644 --- a/packages/frontend/src/ui/zen.vue +++ b/packages/frontend/src/ui/zen.vue @@ -1,5 +1,5 @@ <template> -<div class="mk-app" style="container-type: inline-size;"> +<div :class="$style.root" style="container-type: inline-size;"> <RouterView/> <XCommon/> @@ -26,8 +26,8 @@ provideMetadataReceiver((info) => { document.documentElement.style.overflowY = 'scroll'; </script> -<style lang="scss" scoped> -.mk-app { +<style lang="scss" module> +.root { min-height: 100dvh; box-sizing: border-box; } From acd5e0b8f637fe904ea2dcaf265089e860cd6a42 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 16:34:56 +0900 Subject: [PATCH 058/213] update deps --- packages/backend/package.json | 26 +- packages/frontend/package.json | 16 +- pnpm-lock.yaml | 972 +++++++++++++++++++-------------- 3 files changed, 591 insertions(+), 423 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 4bab4a7341..89a1a986b7 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -51,9 +51,9 @@ "@aws-sdk/client-s3": "3.321.1", "@aws-sdk/lib-storage": "3.321.1", "@aws-sdk/node-http-handler": "3.321.1", - "@bull-board/api": "5.1.2", - "@bull-board/fastify": "5.1.2", - "@bull-board/ui": "5.1.2", + "@bull-board/api": "5.2.0", + "@bull-board/fastify": "5.2.0", + "@bull-board/ui": "5.2.0", "@discordapp/twemoji": "14.1.2", "@fastify/accepts": "4.1.0", "@fastify/cookie": "8.3.0", @@ -62,13 +62,13 @@ "@fastify/multipart": "7.6.0", "@fastify/static": "6.10.1", "@fastify/view": "7.4.1", - "@nestjs/common": "9.4.0", - "@nestjs/core": "9.4.0", - "@nestjs/testing": "9.4.0", + "@nestjs/common": "9.4.1", + "@nestjs/core": "9.4.1", + "@nestjs/testing": "9.4.1", "@peertube/http-signature": "1.7.0", "@sinonjs/fake-timers": "10.0.2", "@swc/cli": "0.1.62", - "@swc/core": "1.3.56", + "@swc/core": "1.3.59", "accepts": "1.3.8", "ajv": "8.12.0", "archiver": "5.3.1", @@ -93,7 +93,7 @@ "fluent-ffmpeg": "2.1.2", "form-data": "4.0.0", "got": "12.6.0", - "happy-dom": "9.16.0", + "happy-dom": "9.19.2", "hpagent": "1.2.0", "ioredis": "5.3.2", "ip-cidr": "3.1.0", @@ -116,7 +116,7 @@ "os-utils": "0.0.14", "otpauth": "9.1.2", "parse5": "7.1.2", - "pg": "8.10.0", + "pg": "8.11.0", "private-ip": "3.0.0", "probe-image-size": "7.2.3", "promise-limit": "2.7.0", @@ -136,10 +136,10 @@ "s-age": "1.1.2", "sanitize-html": "2.10.0", "seedrandom": "3.0.5", - "semver": "7.5.0", + "semver": "7.5.1", "sharp": "0.32.1", "sharp-read-bmp": "github:misskey-dev/sharp-read-bmp", - "slacc": "0.0.7", + "slacc": "0.0.9", "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", "summaly": "github:misskey-dev/summaly", @@ -178,9 +178,9 @@ "@types/jsonld": "1.5.8", "@types/jsrsasign": "10.5.8", "@types/mime-types": "2.1.1", - "@types/node": "20.1.3", + "@types/node": "20.2.1", "@types/node-fetch": "3.0.3", - "@types/nodemailer": "6.4.7", + "@types/nodemailer": "6.4.8", "@types/oauth": "0.9.1", "@types/pg": "8.6.6", "@types/pug": "2.0.6", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 2f754f8aa2..a32cfbd8a7 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -23,7 +23,7 @@ "@tabler/icons-webfont": "2.17.0", "@vitejs/plugin-vue": "4.2.3", "@vue-macros/reactivity-transform": "0.3.7", - "@vue/compiler-sfc": "3.3.2", + "@vue/compiler-sfc": "3.3.4", "autosize": "6.0.1", "broadcast-channel": "4.20.2", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", @@ -70,8 +70,8 @@ "typescript": "5.0.4", "uuid": "9.0.0", "vanilla-tilt": "1.8.0", - "vite": "4.3.7", - "vue": "3.3.2", + "vite": "4.3.8", + "vue": "3.3.4", "vue-plyr": "7.0.0", "vue-prism-editor": "2.0.0-alpha.2", "vuedraggable": "next" @@ -103,7 +103,7 @@ "@types/gulp-rename": "2.0.2", "@types/matter-js": "0.18.3", "@types/micromatch": "4.0.2", - "@types/node": "20.1.7", + "@types/node": "20.2.1", "@types/punycode": "2.1.0", "@types/sanitize-html": "2.9.0", "@types/seedrandom": "3.0.5", @@ -115,8 +115,8 @@ "@types/ws": "8.5.4", "@typescript-eslint/eslint-plugin": "5.59.5", "@typescript-eslint/parser": "5.59.5", - "@vitest/coverage-c8": "0.31.0", - "@vue/runtime-core": "3.3.2", + "@vitest/coverage-c8": "0.31.1", + "@vue/runtime-core": "3.3.4", "astring": "1.8.4", "chokidar-cli": "3.0.0", "cross-env": "7.0.3", @@ -125,7 +125,7 @@ "eslint-plugin-import": "2.27.5", "eslint-plugin-vue": "9.13.0", "fast-glob": "3.2.12", - "happy-dom": "9.18.3", + "happy-dom": "9.19.2", "micromatch": "3.1.10", "msw": "1.2.1", "msw-storybook-addon": "1.8.0", @@ -137,7 +137,7 @@ "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "summaly": "github:misskey-dev/summaly", "vite-plugin-turbosnap": "1.0.2", - "vitest": "0.31.0", + "vitest": "0.31.1", "vitest-fetch-mock": "0.2.2", "vue-eslint-parser": "9.3.0", "vue-tsc": "1.6.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5217b71fb..b3c6f08ba4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,14 +74,14 @@ importers: specifier: 3.321.1 version: 3.321.1 '@bull-board/api': - specifier: 5.1.2 - version: 5.1.2(@bull-board/ui@5.1.2) + specifier: 5.2.0 + version: 5.2.0(@bull-board/ui@5.2.0) '@bull-board/fastify': - specifier: 5.1.2 - version: 5.1.2 + specifier: 5.2.0 + version: 5.2.0 '@bull-board/ui': - specifier: 5.1.2 - version: 5.1.2 + specifier: 5.2.0 + version: 5.2.0 '@discordapp/twemoji': specifier: 14.1.2 version: 14.1.2 @@ -107,14 +107,14 @@ importers: specifier: 7.4.1 version: 7.4.1 '@nestjs/common': - specifier: 9.4.0 - version: 9.4.0(reflect-metadata@0.1.13)(rxjs@7.8.1) + specifier: 9.4.1 + version: 9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/core': - specifier: 9.4.0 - version: 9.4.0(@nestjs/common@9.4.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) + specifier: 9.4.1 + version: 9.4.1(@nestjs/common@9.4.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/testing': - specifier: 9.4.0 - version: 9.4.0(@nestjs/common@9.4.0)(@nestjs/core@9.4.0) + specifier: 9.4.1 + version: 9.4.1(@nestjs/common@9.4.1)(@nestjs/core@9.4.1) '@peertube/http-signature': specifier: 1.7.0 version: 1.7.0 @@ -123,10 +123,10 @@ importers: version: 10.0.2 '@swc/cli': specifier: 0.1.62 - version: 0.1.62(@swc/core@1.3.56)(chokidar@3.5.3) + version: 0.1.62(@swc/core@1.3.59)(chokidar@3.5.3) '@swc/core': - specifier: 1.3.56 - version: 1.3.56 + specifier: 1.3.59 + version: 1.3.59 accepts: specifier: 1.3.8 version: 1.3.8 @@ -200,8 +200,8 @@ importers: specifier: 12.6.0 version: 12.6.0 happy-dom: - specifier: 9.16.0 - version: 9.16.0 + specifier: 9.19.2 + version: 9.19.2 hpagent: specifier: 1.2.0 version: 1.2.0 @@ -269,8 +269,8 @@ importers: specifier: 7.1.2 version: 7.1.2 pg: - specifier: 8.10.0 - version: 8.10.0 + specifier: 8.11.0 + version: 8.11.0 private-ip: specifier: 3.0.0 version: 3.0.0 @@ -329,8 +329,8 @@ importers: specifier: 3.0.5 version: 3.0.5 semver: - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.5.1 + version: 7.5.1 sharp: specifier: 0.32.1 version: 0.32.1 @@ -338,8 +338,8 @@ importers: specifier: github:misskey-dev/sharp-read-bmp version: github.com/misskey-dev/sharp-read-bmp/02d9dc189fa7df0c4bea09330be26741772dac01 slacc: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 strict-event-emitter-types: specifier: 2.0.0 version: 2.0.0 @@ -369,7 +369,7 @@ importers: version: 14.0.0 typeorm: specifier: 0.3.16 - version: 0.3.16(ioredis@5.3.2)(pg@8.10.0) + version: 0.3.16(ioredis@5.3.2)(pg@8.11.0) typescript: specifier: 5.0.4 version: 5.0.4 @@ -476,7 +476,7 @@ importers: version: 29.5.0 '@swc/jest': specifier: 0.2.26 - version: 0.2.26(@swc/core@1.3.56) + version: 0.2.26(@swc/core@1.3.59) '@types/accepts': specifier: 1.3.5 version: 1.3.5 @@ -523,14 +523,14 @@ importers: specifier: 2.1.1 version: 2.1.1 '@types/node': - specifier: 20.1.3 - version: 20.1.3 + specifier: 20.2.1 + version: 20.2.1 '@types/node-fetch': specifier: 3.0.3 version: 3.0.3 '@types/nodemailer': - specifier: 6.4.7 - version: 6.4.7 + specifier: 6.4.8 + version: 6.4.8 '@types/oauth': specifier: 0.9.1 version: 0.9.1 @@ -617,7 +617,7 @@ importers: version: 6.1.0 jest: specifier: 29.5.0 - version: 29.5.0(@types/node@20.1.3) + version: 29.5.0(@types/node@20.2.1) jest-mock: specifier: 29.5.0 version: 29.5.0 @@ -647,13 +647,13 @@ importers: version: 2.17.0 '@vitejs/plugin-vue': specifier: 4.2.3 - version: 4.2.3(vite@4.3.7)(vue@3.3.2) + version: 4.2.3(vite@4.3.8)(vue@3.3.4) '@vue-macros/reactivity-transform': specifier: 0.3.7 - version: 0.3.7(rollup@3.22.0)(vue@3.3.2) + version: 0.3.7(rollup@3.22.0)(vue@3.3.4) '@vue/compiler-sfc': - specifier: 3.3.2 - version: 3.3.2 + specifier: 3.3.4 + version: 3.3.4 autosize: specifier: 6.0.1 version: 6.0.1 @@ -793,20 +793,20 @@ importers: specifier: 1.8.0 version: 1.8.0 vite: - specifier: 4.3.7 - version: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + specifier: 4.3.8 + version: 4.3.8(@types/node@20.2.1)(sass@1.62.1) vue: - specifier: 3.3.2 - version: 3.3.2 + specifier: 3.3.4 + version: 3.3.4 vue-plyr: specifier: 7.0.0 version: 7.0.0 vue-prism-editor: specifier: 2.0.0-alpha.2 - version: 2.0.0-alpha.2(vue@3.3.2) + version: 2.0.0-alpha.2(vue@3.3.4) vuedraggable: specifier: next - version: 4.1.0(vue@3.3.2) + version: 4.1.0(vue@3.3.4) devDependencies: '@storybook/addon-actions': specifier: 7.0.12 @@ -846,7 +846,7 @@ importers: version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) '@storybook/react-vite': specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7) + version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8) '@storybook/testing-library': specifier: 0.1.0 version: 0.1.0 @@ -858,16 +858,16 @@ importers: version: 7.0.12 '@storybook/vue3': specifier: 7.0.12 - version: 7.0.12(vue@3.3.2) + version: 7.0.12(vue@3.3.4) '@storybook/vue3-vite': specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7)(vue@3.3.2) + version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4) '@testing-library/jest-dom': specifier: 5.16.5 version: 5.16.5 '@testing-library/vue': specifier: 7.0.0 - version: 7.0.0(@vue/compiler-sfc@3.3.2)(vue@3.3.2) + version: 7.0.0(@vue/compiler-sfc@3.3.4)(vue@3.3.4) '@types/escape-regexp': specifier: 0.0.1 version: 0.0.1 @@ -887,8 +887,8 @@ importers: specifier: 4.0.2 version: 4.0.2 '@types/node': - specifier: 20.1.7 - version: 20.1.7 + specifier: 20.2.1 + version: 20.2.1 '@types/punycode': specifier: 2.1.0 version: 2.1.0 @@ -923,11 +923,11 @@ importers: specifier: 5.59.5 version: 5.59.5(eslint@8.40.0)(typescript@5.0.4) '@vitest/coverage-c8': - specifier: 0.31.0 - version: 0.31.0(vitest@0.31.0) + specifier: 0.31.1 + version: 0.31.1(vitest@0.31.1) '@vue/runtime-core': - specifier: 3.3.2 - version: 3.3.2 + specifier: 3.3.4 + version: 3.3.4 astring: specifier: 1.8.4 version: 1.8.4 @@ -953,8 +953,8 @@ importers: specifier: 3.2.12 version: 3.2.12 happy-dom: - specifier: 9.18.3 - version: 9.18.3 + specifier: 9.19.2 + version: 9.19.2 micromatch: specifier: 3.1.10 version: 3.1.10 @@ -989,11 +989,11 @@ importers: specifier: 1.0.2 version: 1.0.2 vitest: - specifier: 0.31.0 - version: 0.31.0(happy-dom@9.18.3)(sass@1.62.1) + specifier: 0.31.1 + version: 0.31.1(happy-dom@9.19.2)(sass@1.62.1) vitest-fetch-mock: specifier: 0.2.2 - version: 0.2.2(vitest@0.31.0) + version: 0.2.2(vitest@0.31.1) vue-eslint-parser: specifier: 9.3.0 version: 9.3.0(eslint@8.40.0) @@ -1005,7 +1005,7 @@ importers: dependencies: '@swc/cli': specifier: 0.1.62 - version: 0.1.62(@swc/core@1.3.56)(chokidar@3.5.3) + version: 0.1.62(@swc/core@1.3.59)(chokidar@3.5.3) '@swc/core': specifier: 1.3.56 version: 1.3.56 @@ -1090,11 +1090,11 @@ packages: resolution: {integrity: sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==} dev: true - /@ampproject/remapping@2.2.0: - resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.1.1 + '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 dev: true @@ -2093,7 +2093,7 @@ packages: resolution: {integrity: sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==} engines: {node: '>=6.9.0'} dependencies: - '@ampproject/remapping': 2.2.0 + '@ampproject/remapping': 2.2.1 '@babel/code-frame': 7.18.6 '@babel/generator': 7.21.3 '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) @@ -3364,15 +3364,6 @@ packages: - supports-color dev: true - /@babel/types@7.21.4: - resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.21.5 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - /@babel/types@7.21.5: resolution: {integrity: sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==} engines: {node: '>=6.9.0'} @@ -3389,29 +3380,29 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@bull-board/api@5.1.2(@bull-board/ui@5.1.2): - resolution: {integrity: sha512-NLV88eDnOMd0XuYUNBcaYL6UdxbGYY91kP+P5Jled6CGcYmXLXv/mzAopxmgctqmP07cjC2EXN/4Oc7dyalDqA==} + /@bull-board/api@5.2.0(@bull-board/ui@5.2.0): + resolution: {integrity: sha512-1HGF2EF/4zI3+Cj414nQzwFprLXOJTlVdqXUf5UEBS4HtYafWv93mGIwkrD8S4Bpz4VSvM87adF6tQPJ7Ewt+w==} peerDependencies: - '@bull-board/ui': 5.1.2 + '@bull-board/ui': 5.2.0 dependencies: - '@bull-board/ui': 5.1.2 + '@bull-board/ui': 5.2.0 redis-info: 3.1.0 dev: false - /@bull-board/fastify@5.1.2: - resolution: {integrity: sha512-qiURhcqMfER5hp4RtgepMDbPj5H4ZKNOgK+7RIG3bd3d0tBoLjXzooXFryxzd6w130pXU9/crUMtcMP+Ulaj6g==} + /@bull-board/fastify@5.2.0: + resolution: {integrity: sha512-tvvgCAxFoiogqmAhxUiAOV/rXBVXlmg7JO3jkePA778O/YSiE7nrwwjiiLbLNuIYLZfdoYnRK4bIDmLeg1nK2A==} dependencies: - '@bull-board/api': 5.1.2(@bull-board/ui@5.1.2) - '@bull-board/ui': 5.1.2 + '@bull-board/api': 5.2.0(@bull-board/ui@5.2.0) + '@bull-board/ui': 5.2.0 '@fastify/static': 6.10.1 '@fastify/view': 7.4.1 ejs: 3.1.8 dev: false - /@bull-board/ui@5.1.2: - resolution: {integrity: sha512-DXXbKA4NLo5D19Vssrg4pPFaFjXVzjFN0ht4GVuoJQejy7t/RVrWzZCjdyVuSiOFTlG3SyB39zW5a95Q5EXUTg==} + /@bull-board/ui@5.2.0: + resolution: {integrity: sha512-f2sgs7AjOVch7tFhbmlVCkhZjJWboxwNxWEfAsIUd1WidUC+Ef5J02tpQvu7apzRtu5zcn8IiJtI5HFO6oKaCA==} dependencies: - '@bull-board/api': 5.1.2(@bull-board/ui@5.1.2) + '@bull-board/api': 5.2.0(@bull-board/ui@5.2.0) dev: false /@canvas/image-data@1.0.0: @@ -3977,7 +3968,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 chalk: 4.1.2 jest-message-util: 29.5.0 jest-util: 29.5.0 @@ -3998,14 +3989,14 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.5.0 - jest-config: 29.5.0(@types/node@20.1.7) + jest-config: 29.5.0(@types/node@20.2.1) jest-haste-map: 29.5.0 jest-message-util: 29.5.0 jest-regex-util: 29.4.3 @@ -4039,7 +4030,7 @@ packages: dependencies: '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 jest-mock: 29.5.0 dev: true @@ -4066,7 +4057,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@sinonjs/fake-timers': 10.0.2 - '@types/node': 20.1.7 + '@types/node': 20.2.1 jest-message-util: 29.5.0 jest-mock: 29.5.0 jest-util: 29.5.0 @@ -4099,7 +4090,7 @@ packages: '@jest/transform': 29.5.0 '@jest/types': 29.5.0 '@jridgewell/trace-mapping': 0.3.17 - '@types/node': 20.1.7 + '@types/node': 20.2.1 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -4193,7 +4184,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.1.7 + '@types/node': 20.2.1 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: true @@ -4205,12 +4196,12 @@ packages: '@jest/schemas': 29.4.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.1.7 + '@types/node': 20.2.1 '@types/yargs': 17.0.19 chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.0.4)(vite@4.3.7): + /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.0.4)(vite@4.3.8): resolution: {integrity: sha512-ou4ZJSXMMWHqGS4g8uNRbC5TiTWxAgQZiVucoUrOCWuPrTbkpJbmVyIi9jU72SBry7gQtuMEDp4YR8EEXAg7VQ==} peerDependencies: typescript: '>= 4.3.x' @@ -4224,15 +4215,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.0.4) typescript: 5.0.4 - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) - dev: true - - /@jridgewell/gen-mapping@0.1.1: - resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) dev: true /@jridgewell/gen-mapping@0.3.2: @@ -4296,7 +4279,7 @@ packages: nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.5.0 + semver: 7.5.1 tar: 6.1.13 transitivePeerDependencies: - encoding @@ -4445,8 +4428,8 @@ packages: tar-fs: 2.1.1 dev: true - /@nestjs/common@9.4.0(reflect-metadata@0.1.13)(rxjs@7.8.1): - resolution: {integrity: sha512-RUcVAQsEF4WPrmzFXEOUfZnPwrLTe1UVlzXTlSyfqfqbdWDPKDGlIPVelBLfc5/+RRUQ0I5iE4+CQvpCmkqldw==} + /@nestjs/common@9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1): + resolution: {integrity: sha512-VA5XXLAvXG3vY4GqvvuevL7Ooi5RRsov+ydMlgc1rPswgxkSVWaPTqNibsP4C6y5XJtKfc4Ol+zoe2w/LeYJTQ==} peerDependencies: cache-manager: <=5 class-transformer: '*' @@ -4468,8 +4451,8 @@ packages: uid: 2.0.2 dev: false - /@nestjs/core@9.4.0(@nestjs/common@9.4.0)(reflect-metadata@0.1.13)(rxjs@7.8.1): - resolution: {integrity: sha512-yTLryCgFD0462wPe4HIzhyTcDgibt8Stfwb5YzcX7Ma0NM4m8uBIpcPG109KBubp8ZmV85e5mw4rl20qLQQVsQ==} + /@nestjs/core@9.4.1(@nestjs/common@9.4.1)(reflect-metadata@0.1.13)(rxjs@7.8.1): + resolution: {integrity: sha512-KbG0L5UVaI9kjZv3QkSyCf8Cz5lj11hy60n+NPoO0GZmJbhWkfsjletwKpwlpMeGbi7jLGTsU+HPDgprANSNEA==} requiresBuild: true peerDependencies: '@nestjs/common': ^9.0.0 @@ -4486,7 +4469,7 @@ packages: '@nestjs/websockets': optional: true dependencies: - '@nestjs/common': 9.4.0(reflect-metadata@0.1.13)(rxjs@7.8.1) + '@nestjs/common': 9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -4499,8 +4482,8 @@ packages: - encoding dev: false - /@nestjs/testing@9.4.0(@nestjs/common@9.4.0)(@nestjs/core@9.4.0): - resolution: {integrity: sha512-xZWp363P4otcebg++gSjUcdCfTK0RorORzyFq3aLaSAQOlq8kxfFDRIKzEATR4aOUfqTMMsAA8lhnMJWf35N6A==} + /@nestjs/testing@9.4.1(@nestjs/common@9.4.1)(@nestjs/core@9.4.1): + resolution: {integrity: sha512-DErwymDxsY80dH2v3eZDVOhjDv6oY6YsaI3GnUEU+gUrYa8qxxKPHfOofAsFF7SExfeJo5c8RQRfazW3bQupJA==} peerDependencies: '@nestjs/common': ^9.0.0 '@nestjs/core': ^9.0.0 @@ -4512,8 +4495,8 @@ packages: '@nestjs/platform-express': optional: true dependencies: - '@nestjs/common': 9.4.0(reflect-metadata@0.1.13)(rxjs@7.8.1) - '@nestjs/core': 9.4.0(@nestjs/common@9.4.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) + '@nestjs/common': 9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1) + '@nestjs/core': 9.4.1(@nestjs/common@9.4.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) tslib: 2.5.0 dev: false @@ -4540,7 +4523,7 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} dependencies: '@gar/promisify': 1.1.3 - semver: 7.5.0 + semver: 7.5.1 dev: false /@npmcli/move-file@2.0.1: @@ -4826,7 +4809,7 @@ packages: lodash.values: 4.3.0 object-hash: 3.0.0 packageurl-js: 1.0.1 - semver: 7.5.0 + semver: 7.5.1 tslib: 2.5.0 dev: false @@ -5244,7 +5227,7 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.0.12(typescript@5.0.4)(vite@4.3.7): + /@storybook/builder-vite@7.0.12(typescript@5.0.4)(vite@4.3.8): resolution: {integrity: sha512-6FJNXis+dYs/KrhfRQgz8HcRw/Oq4FaEghCwsjngQDy4PcpQuxkDbvGJKlBaSr92vUL36FWSPq8u5+VGCHjh5Q==} peerDependencies: '@preact/preset-vite': '*' @@ -5280,7 +5263,7 @@ packages: remark-slug: 6.1.0 rollup: 3.22.0 typescript: 5.0.4 - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true @@ -5374,7 +5357,7 @@ packages: prompts: 2.4.2 puppeteer-core: 2.1.1 read-pkg-up: 7.0.1 - semver: 7.5.0 + semver: 7.5.1 shelljs: 0.8.5 simple-update-notifier: 1.1.0 strip-json-comments: 3.1.1 @@ -5527,7 +5510,7 @@ packages: pretty-hrtime: 1.0.3 prompts: 2.4.2 read-pkg-up: 7.0.1 - semver: 7.5.0 + semver: 7.5.1 serve-favicon: 2.5.0 telejson: 7.0.4 ts-dedent: 2.2.0 @@ -5658,7 +5641,7 @@ packages: memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - semver: 7.5.0 + semver: 7.5.1 store2: 2.14.2 telejson: 7.0.4 ts-dedent: 2.2.0 @@ -5759,7 +5742,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7): + /@storybook/react-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8): resolution: {integrity: sha512-SIszevqIKOW+5TwzNposDI+3giSZNVZ7HSu7u2JEpu0Iw/CWyYI06rUgH2ft8Xluhb8vEorZKiZjsdiQDVo64w==} engines: {node: '>=16'} peerDependencies: @@ -5767,17 +5750,17 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.7) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.8) '@rollup/pluginutils': 4.2.1 - '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.7) + '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.8) '@storybook/react': 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) - '@vitejs/plugin-react': 3.1.0(vite@4.3.7) + '@vitejs/plugin-react': 3.1.0(vite@4.3.8) ast-types: 0.14.2 magic-string: 0.27.0 react: 18.2.0 react-docgen: 6.0.0-alpha.3 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) transitivePeerDependencies: - '@preact/preset-vite' - supports-color @@ -5920,7 +5903,7 @@ packages: file-system-cache: 2.0.2 dev: true - /@storybook/vue3-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.7)(vue@3.3.2): + /@storybook/vue3-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4): resolution: {integrity: sha512-SdAGfBRfm4cR9VNLRcBCLo3rTzeUTvZfyh5ll0cgInCo9gTxwfs1Y4zEmmVqDDOWQ7qlpJanITNGFGiSsdvRmg==} engines: {node: ^14.18 || >=16} peerDependencies: @@ -5928,15 +5911,15 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.7) + '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.8) '@storybook/core-server': 7.0.12 - '@storybook/vue3': 7.0.12(vue@3.3.2) - '@vitejs/plugin-vue': 4.2.3(vite@4.3.7)(vue@3.3.2) + '@storybook/vue3': 7.0.12(vue@3.3.4) + '@vitejs/plugin-vue': 4.2.3(vite@4.3.8)(vue@3.3.4) magic-string: 0.27.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) - vue-docgen-api: 4.64.1(vue@3.3.2) + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vue-docgen-api: 4.64.1(vue@3.3.4) transitivePeerDependencies: - '@preact/preset-vite' - bufferutil @@ -5948,7 +5931,7 @@ packages: - vue dev: true - /@storybook/vue3@7.0.12(vue@3.3.2): + /@storybook/vue3@7.0.12(vue@3.3.4): resolution: {integrity: sha512-zxRhuuNcM9hT1/s968iHL+diqFqRmpwvEoI7rF1yje09saMck+PFStlE8b/ohQeDtm0GdwVqjbzfHZIdPbivYg==} engines: {node: '>=16.0.0'} peerDependencies: @@ -5961,12 +5944,12 @@ packages: '@storybook/types': 7.0.12 ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.3.2 + vue: 3.3.4 transitivePeerDependencies: - supports-color dev: true - /@swc/cli@0.1.62(@swc/core@1.3.56)(chokidar@3.5.3): + /@swc/cli@0.1.62(@swc/core@1.3.59)(chokidar@3.5.3): resolution: {integrity: sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==} engines: {node: '>= 12.13'} hasBin: true @@ -5978,11 +5961,11 @@ packages: optional: true dependencies: '@mole-inc/bin-wrapper': 8.0.1 - '@swc/core': 1.3.56 + '@swc/core': 1.3.59 chokidar: 3.5.3 commander: 7.2.0 fast-glob: 3.2.12 - semver: 7.5.0 + semver: 7.5.1 slash: 3.0.0 source-map: 0.7.4 dev: false @@ -6006,6 +5989,14 @@ packages: requiresBuild: true optional: true + /@swc/core-darwin-arm64@1.3.59: + resolution: {integrity: sha512-AnqWFBgEKHP0jb4iZqx7eVQT9/rX45+DE4Ox7GpwCahUKxxrsDLyXzKhwLwQuAjUvtu5JcSB77szKpPGDM49fQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + /@swc/core-darwin-x64@1.3.56: resolution: {integrity: sha512-VH5saqYFasdRXJy6RAT+MXm0+IjkMZvOkohJwUei+oA65cKJofQwrJ1jZro8yOJFYvUSI3jgNRGsdBkmo/4hMw==} engines: {node: '>=10'} @@ -6014,6 +6005,14 @@ packages: requiresBuild: true optional: true + /@swc/core-darwin-x64@1.3.59: + resolution: {integrity: sha512-iqDs+yii9mOsmpJez82SEi4d4prWDRlapHxKnDVJ0x1AqRo41vIq8t3fujrvCHYU5VQgOYGh4ooXQpaP2H3B2A==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + /@swc/core-linux-arm-gnueabihf@1.3.56: resolution: {integrity: sha512-LWwPo6NnJkH01+ukqvkoNIOpMdw+Zundm4vBeicwyVrkP+mC3kwVfi03TUFpQUz3kRKdw/QEnxGTj+MouCPbtw==} engines: {node: '>=10'} @@ -6022,6 +6021,14 @@ packages: requiresBuild: true optional: true + /@swc/core-linux-arm-gnueabihf@1.3.59: + resolution: {integrity: sha512-PB0PP+SgkCSd/kYmltnPiGv42cOSaih1OjXCEjxvNwUFEmWqluW6uGdWaNiR1LoYMxhcHZTc336jL2+O3l6p0Q==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + /@swc/core-linux-arm64-gnu@1.3.56: resolution: {integrity: sha512-GzsUy/4egJ4cMlxbM+Ub7AMi5CKAc+pxBxrh8MUPQbyStW8jGgnQsJouTnGy0LHawtdEnsCOl6PcO6OgvktXuQ==} engines: {node: '>=10'} @@ -6030,6 +6037,14 @@ packages: requiresBuild: true optional: true + /@swc/core-linux-arm64-gnu@1.3.59: + resolution: {integrity: sha512-Ol/JPszWZ+OZ44FOdJe35TfJ1ckG4pYaisZJ4E7PzfwfVe2ygX85C5WWR4e5L0Y1zFvzpcI7gdyC2wzcXk4Cig==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + /@swc/core-linux-arm64-musl@1.3.56: resolution: {integrity: sha512-9gxL09BIiAv8zY0DjfnFf19bo8+P4T9tdhzPwcm+1yPJcY5yr1+YFWLNFzz01agtOj6VlZ2/wUJTaOfdjjtc+A==} engines: {node: '>=10'} @@ -6038,6 +6053,14 @@ packages: requiresBuild: true optional: true + /@swc/core-linux-arm64-musl@1.3.59: + resolution: {integrity: sha512-PtTTtGbj9GiY5gJdoSFL2A0vL6BRaS1haAhp6g3hZvLDkTTg+rJURmzwBMMjaQlnGC62x/lLf6MoszHG/05//Q==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + /@swc/core-linux-x64-gnu@1.3.56: resolution: {integrity: sha512-n0ORNknl50vMRkll3BDO1E4WOqY6iISlPV1ZQCRLWQ6YQ2q8/WAryBxc2OAybcGHBUFkxyACpJukeU1QZ/9tNw==} engines: {node: '>=10'} @@ -6046,6 +6069,14 @@ packages: requiresBuild: true optional: true + /@swc/core-linux-x64-gnu@1.3.59: + resolution: {integrity: sha512-XBW9AGi0YsIN76IfesnDSBn/5sjR69J75KUNte8sH6seYlHJ0/kblqUMbUcfr0CiGoJadbzAZeKZZmfN7EsHpg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + /@swc/core-linux-x64-musl@1.3.56: resolution: {integrity: sha512-r+D34WLAOAlJtfw1gaVWpHRwCncU9nzW9i7w9kSw4HpWYnHJOz54jLGSEmNsrhdTCz1VK2ar+V2ktFUsrlGlDA==} engines: {node: '>=10'} @@ -6054,6 +6085,14 @@ packages: requiresBuild: true optional: true + /@swc/core-linux-x64-musl@1.3.59: + resolution: {integrity: sha512-Cy5E939SdWPQ34cg6UABNO0RyEe0FuWqzZ/GLKtK11Ir4fjttVlucZiY59uQNyUVUc8T2qE0VBFCyD/zYGuHtg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + /@swc/core-win32-arm64-msvc@1.3.56: resolution: {integrity: sha512-29Yt75Is6X24z3x8h/xZC1HnDPkPpyLH9mDQiM6Cuc0I9mVr1XSriPEUB2N/awf5IE4SA8c+3IVq1DtKWbkJIw==} engines: {node: '>=10'} @@ -6062,6 +6101,14 @@ packages: requiresBuild: true optional: true + /@swc/core-win32-arm64-msvc@1.3.59: + resolution: {integrity: sha512-z5ZJxizRvRoSAaevRIi3YjQh74OFWEIhonSDWNdqDL7RbjEivcatYcG7OikH6s+rtPhOcwNm3PbGV2Prcgh/gg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + /@swc/core-win32-ia32-msvc@1.3.56: resolution: {integrity: sha512-mplp0zbYDrcHtfvkniXlXdB04e2qIjz2Gq/XHKr4Rnc6xVORJjjXF91IemXKpavx2oZYJws+LNJL7UFQ8jyCdQ==} engines: {node: '>=10'} @@ -6070,6 +6117,14 @@ packages: requiresBuild: true optional: true + /@swc/core-win32-ia32-msvc@1.3.59: + resolution: {integrity: sha512-vxpsn+hrKAhi5YusQfB/JXUJJVX40rIRE/L49ilBEqdbH8Khkoego6AD+2vWqTdJcUHo1WiAIAEZ0rTsjyorLQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + /@swc/core-win32-x64-msvc@1.3.56: resolution: {integrity: sha512-zp8MBnrw/bjdLenO/ifYzHrImSjKunqL0C2IF4LXYNRfcbYFh2NwobsVQMZ20IT0474lKRdlP8Oxdt+bHuXrzA==} engines: {node: '>=10'} @@ -6078,6 +6133,14 @@ packages: requiresBuild: true optional: true + /@swc/core-win32-x64-msvc@1.3.59: + resolution: {integrity: sha512-Ris/cJbURylcLwqz4RZUUBCEGsuaIHOJsvf69W5pGKHKBryVoOTNhBKpo3Km2hoAi5qFQ/ou0trAT4hBsVPZvQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + /@swc/core@1.3.56: resolution: {integrity: sha512-yz/EeXT+PMZucUNrYceRUaTfuNS4IIu5EDZSOlvCEvm4jAmZi7CYH1B/kvzEzoAOzr7zkQiDPNJftcQXLkjbjA==} engines: {node: '>=10'} @@ -6099,6 +6162,27 @@ packages: '@swc/core-win32-ia32-msvc': 1.3.56 '@swc/core-win32-x64-msvc': 1.3.56 + /@swc/core@1.3.59: + resolution: {integrity: sha512-ZBw31zd2E5SXiodwGvjQdx5ZC90b2uyX/i2LeMMs8LKfXD86pfOfQac+JVrnyEKDhASXj9icgsF9NXBhaMr3Kw==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': ^0.5.0 + peerDependenciesMeta: + '@swc/helpers': + optional: true + optionalDependencies: + '@swc/core-darwin-arm64': 1.3.59 + '@swc/core-darwin-x64': 1.3.59 + '@swc/core-linux-arm-gnueabihf': 1.3.59 + '@swc/core-linux-arm64-gnu': 1.3.59 + '@swc/core-linux-arm64-musl': 1.3.59 + '@swc/core-linux-x64-gnu': 1.3.59 + '@swc/core-linux-x64-musl': 1.3.59 + '@swc/core-win32-arm64-msvc': 1.3.59 + '@swc/core-win32-ia32-msvc': 1.3.59 + '@swc/core-win32-x64-msvc': 1.3.59 + /@swc/jest@0.2.26(@swc/core@1.3.56): resolution: {integrity: sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==} engines: {npm: '>= 7.0.0'} @@ -6110,6 +6194,17 @@ packages: jsonc-parser: 3.2.0 dev: true + /@swc/jest@0.2.26(@swc/core@1.3.59): + resolution: {integrity: sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==} + engines: {npm: '>= 7.0.0'} + peerDependencies: + '@swc/core': '*' + dependencies: + '@jest/create-cache-key-function': 27.5.1 + '@swc/core': 1.3.59 + jsonc-parser: 3.2.0 + dev: true + /@swc/wasm@1.2.130: resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==} requiresBuild: true @@ -6313,7 +6408,7 @@ packages: '@testing-library/dom': 8.20.0 dev: true - /@testing-library/vue@7.0.0(@vue/compiler-sfc@3.3.2)(vue@3.3.2): + /@testing-library/vue@7.0.0(@vue/compiler-sfc@3.3.4)(vue@3.3.4): resolution: {integrity: sha512-JU/q93HGo2qdm1dCgWymkeQlfpC0/0/DBZ2nAHgEAsVZxX11xVIxT7gbXdI7HACQpUbsUWt1zABGU075Fzt9XQ==} engines: {node: '>=14'} peerDependencies: @@ -6322,9 +6417,9 @@ packages: dependencies: '@babel/runtime': 7.21.0 '@testing-library/dom': 9.2.0 - '@vue/compiler-sfc': 3.3.2 - '@vue/test-utils': 2.3.2(vue@3.3.2) - vue: 3.3.2 + '@vue/compiler-sfc': 3.3.4 + '@vue/test-utils': 2.3.2(vue@3.3.4) + vue: 3.3.4 dev: true /@tokenizer/token@0.3.0: @@ -6343,7 +6438,7 @@ packages: /@types/accepts@1.3.5: resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/archiver@5.3.2: @@ -6397,7 +6492,7 @@ packages: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/braces@3.0.1: @@ -6417,7 +6512,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 20.1.7 + '@types/node': 20.2.1 '@types/responselike': 1.0.0 dev: false @@ -6430,11 +6525,11 @@ packages: /@types/chai-subset@1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: - '@types/chai': 4.3.4 + '@types/chai': 4.3.5 dev: true - /@types/chai@4.3.4: - resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} + /@types/chai@4.3.5: + resolution: {integrity: sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==} dev: true /@types/color-convert@2.0.0: @@ -6450,7 +6545,7 @@ packages: /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/content-disposition@0.5.5: @@ -6515,7 +6610,7 @@ packages: /@types/express-serve-static-core@4.17.33: resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: true @@ -6536,34 +6631,34 @@ packages: /@types/fluent-ffmpeg@2.1.21: resolution: {integrity: sha512-+n3dy/Tegt6n+YwGZUiGq6i8Jrnt8+MoyPiW1L6J5EWUl7GSt18a/VyReecfCsvTTNBXNMIKOMHDstiQM8nJLA==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/glob-stream@6.1.1: resolution: {integrity: sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==} dependencies: '@types/glob': 8.1.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/gulp-rename@2.0.1: @@ -6576,7 +6671,7 @@ packages: /@types/gulp-rename@2.0.2: resolution: {integrity: sha512-CQsXqTVtAXqrPd4IbrrlJEEzRkUR3RXsyZbrVoOVqjlchDDmnyRDatAUisjpQjjCg/wjJrSiNg8T1uAbJ/7Qqg==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 '@types/vinyl': 2.0.7 dev: true @@ -6631,7 +6726,7 @@ packages: /@types/jsdom@21.1.1: resolution: {integrity: sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 dev: true @@ -6655,7 +6750,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: false /@types/lodash@4.14.191: @@ -6703,7 +6798,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 form-data: 3.0.1 /@types/node-fetch@3.0.3: @@ -6731,17 +6826,13 @@ packages: resolution: {integrity: sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==} dev: true - /@types/node@20.1.3: - resolution: {integrity: sha512-NP2yfZpgmf2eDRPmgGq+fjGjSwFgYbihA8/gK+ey23qT9RkxsgNTZvGOEpXgzIGqesTYkElELLgtKoMQTys5vA==} - dev: true + /@types/node@20.2.1: + resolution: {integrity: sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==} - /@types/node@20.1.7: - resolution: {integrity: sha512-WCuw/o4GSwDGMoonES8rcvwsig77dGCMbZDrZr2x4ZZiNW4P/gcoZXe/0twgtobcTkmg9TuKflxYL/DuwDyJzg==} - - /@types/nodemailer@6.4.7: - resolution: {integrity: sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==} + /@types/nodemailer@6.4.8: + resolution: {integrity: sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/normalize-package-data@2.4.1: @@ -6755,7 +6846,7 @@ packages: /@types/oauth@0.9.1: resolution: {integrity: sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/offscreencanvas@2019.3.0: @@ -6769,7 +6860,7 @@ packages: /@types/pg@8.6.6: resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 pg-protocol: 1.5.0 pg-types: 2.2.0 dev: true @@ -6797,7 +6888,7 @@ packages: /@types/qrcode@1.5.0: resolution: {integrity: sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/qs@6.9.7: @@ -6827,7 +6918,7 @@ packages: /@types/readdir-glob@1.1.1: resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/redis@4.0.11: @@ -6843,7 +6934,7 @@ packages: /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: false /@types/sanitize-html@2.9.0: @@ -6871,7 +6962,7 @@ packages: resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} dependencies: '@types/mime': 3.0.1 - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/serviceworker@0.0.67: @@ -6881,7 +6972,7 @@ packages: /@types/set-cookie-parser@2.4.2: resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /@types/sharp@0.32.0: @@ -6946,7 +7037,7 @@ packages: /@types/undertaker@1.2.8: resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 '@types/undertaker-registry': 1.0.1 async-done: 1.3.2 dev: true @@ -6958,7 +7049,7 @@ packages: /@types/unzipper@0.10.5: resolution: {integrity: sha512-NrLJb29AdnBARpg9S/4ktfPEisbJ0AvaaAr3j7Q1tg8AgcEUsq2HqbNzvgLRoWyRtjzeLEv7vuL39u1mrNIyNA==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/uuid@9.0.1: @@ -6968,14 +7059,14 @@ packages: /@types/vary@1.1.0: resolution: {integrity: sha512-LQWqrIa0dvEOOH37lGksMEXbypRLUFqu6Gx0pmX7zIUisD2I/qaVgEX/vJ/PSVSW0Hk6yz1BNkFpqg6dZm3Wug==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/vinyl-fs@2.4.12: resolution: {integrity: sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==} dependencies: '@types/glob-stream': 6.1.1 - '@types/node': 20.1.7 + '@types/node': 20.2.1 '@types/vinyl': 2.0.7 dev: true @@ -6983,12 +7074,12 @@ packages: resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} dependencies: '@types/expect': 1.20.4 - '@types/node': 20.1.7 + '@types/node': 20.2.1 /@types/web-push@3.3.2: resolution: {integrity: sha512-JxWGVL/m7mWTIg4mRYO+A6s0jPmBkr4iJr39DqJpRJAc+jrPiEe1/asmkwerzRon8ZZDxaZJpsxpv0Z18Wo9gw==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/webgl-ext@0.0.30: @@ -7002,13 +7093,13 @@ packages: /@types/websocket@1.0.5: resolution: {integrity: sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/ws@8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 20.1.3 + '@types/node': 20.2.1 dev: true /@types/yargs-parser@21.0.0: @@ -7031,7 +7122,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true optional: true @@ -7130,7 +7221,7 @@ packages: debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.0 + semver: 7.5.1 tsutils: 3.21.0(typescript@5.0.4) typescript: 5.0.4 transitivePeerDependencies: @@ -7151,7 +7242,7 @@ packages: '@typescript-eslint/typescript-estree': 5.59.5(typescript@5.0.4) eslint: 8.40.0 eslint-scope: 5.1.1 - semver: 7.5.0 + semver: 7.5.1 transitivePeerDependencies: - supports-color - typescript @@ -7165,7 +7256,7 @@ packages: eslint-visitor-keys: 3.4.1 dev: true - /@vitejs/plugin-react@3.1.0(vite@4.3.7): + /@vitejs/plugin-react@3.1.0(vite@4.3.8): resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -7176,67 +7267,67 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.3) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true - /@vitejs/plugin-vue@4.2.3(vite@4.3.7)(vue@3.3.2): + /@vitejs/plugin-vue@4.2.3(vite@4.3.8)(vue@3.3.4): resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.0.0 vue: ^3.2.25 dependencies: - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) - vue: 3.3.2 + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vue: 3.3.4 - /@vitest/coverage-c8@0.31.0(vitest@0.31.0): - resolution: {integrity: sha512-h72qN1D962AO7UefQVulm9JFP5ACS7OfhCdBHioXU8f7ohH/+NTZCgAqmgcfRNHHO/8wLFxx+93YVxhodkEJVA==} + /@vitest/coverage-c8@0.31.1(vitest@0.31.1): + resolution: {integrity: sha512-6TkjQpmgYez7e3dbAUoYdRXxWN81BojCmUILJwgCy39uZFG33DsQ0rSRSZC9beAEdCZTpxR63nOvd9hxDQcJ0g==} peerDependencies: vitest: '>=0.30.0 <1' dependencies: - '@ampproject/remapping': 2.2.0 + '@ampproject/remapping': 2.2.1 c8: 7.13.0 magic-string: 0.30.0 picocolors: 1.0.0 std-env: 3.3.2 - vitest: 0.31.0(happy-dom@9.18.3)(sass@1.62.1) + vitest: 0.31.1(happy-dom@9.19.2)(sass@1.62.1) dev: true - /@vitest/expect@0.31.0: - resolution: {integrity: sha512-Jlm8ZTyp6vMY9iz9Ny9a0BHnCG4fqBa8neCF6Pk/c/6vkUk49Ls6UBlgGAU82QnzzoaUs9E/mUhq/eq9uMOv/g==} + /@vitest/expect@0.31.1: + resolution: {integrity: sha512-BV1LyNvhnX+eNYzJxlHIGPWZpwJFZaCcOIzp2CNG0P+bbetenTupk6EO0LANm4QFt0TTit+yqx7Rxd1qxi/SQA==} dependencies: - '@vitest/spy': 0.31.0 - '@vitest/utils': 0.31.0 + '@vitest/spy': 0.31.1 + '@vitest/utils': 0.31.1 chai: 4.3.7 dev: true - /@vitest/runner@0.31.0: - resolution: {integrity: sha512-H1OE+Ly7JFeBwnpHTrKyCNm/oZgr+16N4qIlzzqSG/YRQDATBYmJb/KUn3GrZaiQQyL7GwpNHVZxSQd6juLCgw==} + /@vitest/runner@0.31.1: + resolution: {integrity: sha512-imWuc82ngOtxdCUpXwtEzZIuc1KMr+VlQ3Ondph45VhWoQWit5yvG/fFcldbnCi8DUuFi+NmNx5ehMUw/cGLUw==} dependencies: - '@vitest/utils': 0.31.0 + '@vitest/utils': 0.31.1 concordance: 5.0.4 p-limit: 4.0.0 pathe: 1.1.0 dev: true - /@vitest/snapshot@0.31.0: - resolution: {integrity: sha512-5dTXhbHnyUMTMOujZPB0wjFjQ6q5x9c8TvAsSPUNKjp1tVU7i9pbqcKPqntyu2oXtmVxKbuHCqrOd+Ft60r4tg==} + /@vitest/snapshot@0.31.1: + resolution: {integrity: sha512-L3w5uU9bMe6asrNzJ8WZzN+jUTX4KSgCinEJPXyny0o90fG4FPQMV0OWsq7vrCWfQlAilMjDnOF9nP8lidsJ+g==} dependencies: magic-string: 0.30.0 pathe: 1.1.0 pretty-format: 27.5.1 dev: true - /@vitest/spy@0.31.0: - resolution: {integrity: sha512-IzCEQ85RN26GqjQNkYahgVLLkULOxOm5H/t364LG0JYb3Apg0PsYCHLBYGA006+SVRMWhQvHlBBCyuByAMFmkg==} + /@vitest/spy@0.31.1: + resolution: {integrity: sha512-1cTpt2m9mdo3hRLDyCG2hDQvRrePTDgEJBFQQNz1ydHHZy03EiA6EpFxY+7ODaY7vMRCie+WlFZBZ0/dQWyssQ==} dependencies: tinyspy: 2.1.0 dev: true - /@vitest/utils@0.31.0: - resolution: {integrity: sha512-kahaRyLX7GS1urekRXN2752X4gIgOGVX4Wo8eDUGUkTWlGpXzf5ZS6N9RUUS+Re3XEE8nVGqNyxkSxF5HXlGhQ==} + /@vitest/utils@0.31.1: + resolution: {integrity: sha512-yFyRD5ilwojsZfo3E0BnH72pSVSuLg2356cN1tCEe/0RtDzxTPYwOomIC+eQbot7m6DRy4tPZw+09mB7NkbMmA==} dependencies: concordance: 5.0.4 loupe: 2.3.6 @@ -7269,10 +7360,10 @@ packages: dependencies: '@volar/language-core': 1.4.1 '@volar/source-map': 1.4.1 - '@vue/compiler-dom': 3.3.2 - '@vue/compiler-sfc': 3.3.2 - '@vue/reactivity': 3.3.2 - '@vue/shared': 3.3.2 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-sfc': 3.3.4 + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 minimatch: 9.0.0 muggle-string: 0.2.2 vue-template-compiler: 2.7.14 @@ -7288,7 +7379,7 @@ packages: typescript: 5.0.4 dev: true - /@vue-macros/common@1.3.1(rollup@3.22.0)(vue@3.3.2): + /@vue-macros/common@1.3.1(rollup@3.22.0)(vue@3.3.4): resolution: {integrity: sha512-Lc5aP/8HNJD1XrnvpeNuWcCf82bZdR3auN/chA1b/1rKZgSnmQkH9f33tKO9qLwXSy+u4hpCi8Rw+oUuF1KCeg==} engines: {node: '>=14.19.0'} peerDependencies: @@ -7299,27 +7390,27 @@ packages: dependencies: '@babel/types': 7.21.5 '@rollup/pluginutils': 5.0.2(rollup@3.22.0) - '@vue/compiler-sfc': 3.3.2 + '@vue/compiler-sfc': 3.3.4 local-pkg: 0.4.3 magic-string-ast: 0.1.2 - vue: 3.3.2 + vue: 3.3.4 transitivePeerDependencies: - rollup dev: false - /@vue-macros/reactivity-transform@0.3.7(rollup@3.22.0)(vue@3.3.2): + /@vue-macros/reactivity-transform@0.3.7(rollup@3.22.0)(vue@3.3.4): resolution: {integrity: sha512-o+u5qstvUjNoaZjr4lUtNf5MuLgQHikvurnk6b2DFd9nB52j+BqOhI22uyn6K6TTAU0i0/PxT5YgwDlwVdvEUw==} engines: {node: '>=14.19.0'} peerDependencies: vue: ^2.7.0 || ^3.2.25 dependencies: '@babel/parser': 7.21.8 - '@vue-macros/common': 1.3.1(rollup@3.22.0)(vue@3.3.2) + '@vue-macros/common': 1.3.1(rollup@3.22.0)(vue@3.3.4) '@vue/compiler-core': 3.3.1 '@vue/shared': 3.3.2 magic-string: 0.30.0 unplugin: 1.3.1 - vue: 3.3.2 + vue: 3.3.4 transitivePeerDependencies: - rollup dev: false @@ -7333,19 +7424,19 @@ packages: source-map-js: 1.0.2 dev: false - /@vue/compiler-core@3.3.2: - resolution: {integrity: sha512-CKZWo1dzsQYTNTft7whzjL0HsrEpMfiK7pjZ2WFE3bC1NA7caUjWioHSK+49y/LK7Bsm4poJZzAMnvZMQ7OTeg==} + /@vue/compiler-core@3.3.4: + resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} dependencies: '@babel/parser': 7.21.8 - '@vue/shared': 3.3.2 + '@vue/shared': 3.3.4 estree-walker: 2.0.2 source-map-js: 1.0.2 - /@vue/compiler-dom@3.3.2: - resolution: {integrity: sha512-6gS3auANuKXLw0XH6QxkWqyPYPunziS2xb6VRenM3JY7gVfZcJvkCBHkb5RuNY1FCbBO3lkIi0CdXUCW1c7SXw==} + /@vue/compiler-dom@3.3.4: + resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==} dependencies: - '@vue/compiler-core': 3.3.2 - '@vue/shared': 3.3.2 + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 /@vue/compiler-sfc@2.7.14: resolution: {integrity: sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==} @@ -7355,61 +7446,61 @@ packages: source-map: 0.6.1 dev: false - /@vue/compiler-sfc@3.3.2: - resolution: {integrity: sha512-jG4jQy28H4BqzEKsQqqW65BZgmo3vzdLHTBjF+35RwtDdlFE+Fk1VWJYUnDMMqkFBo6Ye1ltSKVOMPgkzYj7SQ==} + /@vue/compiler-sfc@3.3.4: + resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} dependencies: '@babel/parser': 7.21.8 - '@vue/compiler-core': 3.3.2 - '@vue/compiler-dom': 3.3.2 - '@vue/compiler-ssr': 3.3.2 - '@vue/reactivity-transform': 3.3.2 - '@vue/shared': 3.3.2 + '@vue/compiler-core': 3.3.4 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-ssr': 3.3.4 + '@vue/reactivity-transform': 3.3.4 + '@vue/shared': 3.3.4 estree-walker: 2.0.2 magic-string: 0.30.0 postcss: 8.4.23 source-map-js: 1.0.2 - /@vue/compiler-ssr@3.3.2: - resolution: {integrity: sha512-K8OfY5FQtZaSOJHHe8xhEfIfLrefL/Y9frv4k4NsyQL3+0lRKxr9QuJhfdBDjkl7Fhz8CzKh63mULvmOfx3l2w==} + /@vue/compiler-ssr@3.3.4: + resolution: {integrity: sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==} dependencies: - '@vue/compiler-dom': 3.3.2 - '@vue/shared': 3.3.2 + '@vue/compiler-dom': 3.3.4 + '@vue/shared': 3.3.4 - /@vue/reactivity-transform@3.3.2: - resolution: {integrity: sha512-iu2WaQvlJHdnONrsyv4ibIEnSsuKF+aHFngGj/y1lwpHQtalpVhKg9wsKMoiKXS9zPNjG9mNKzJS9vudvjzvyg==} + /@vue/reactivity-transform@3.3.4: + resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} dependencies: '@babel/parser': 7.21.8 - '@vue/compiler-core': 3.3.2 - '@vue/shared': 3.3.2 + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 estree-walker: 2.0.2 magic-string: 0.30.0 - /@vue/reactivity@3.3.2: - resolution: {integrity: sha512-yX8C4uTgg2Tdj+512EEMnMKbLveoITl7YdQX35AYgx8vBvQGszKiiCN46g4RY6/deeo/5DLbeUUGxCq1qWMf5g==} + /@vue/reactivity@3.3.4: + resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} dependencies: - '@vue/shared': 3.3.2 + '@vue/shared': 3.3.4 - /@vue/runtime-core@3.3.2: - resolution: {integrity: sha512-qSl95qj0BvKfcsO+hICqFEoLhJn6++HtsPxmTkkadFbuhe3uQfJ8HmQwvEr7xbxBd2rcJB6XOJg7nWAn/ymC5A==} + /@vue/runtime-core@3.3.4: + resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==} dependencies: - '@vue/reactivity': 3.3.2 - '@vue/shared': 3.3.2 + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 - /@vue/runtime-dom@3.3.2: - resolution: {integrity: sha512-+drStsJT+0mtgHdarT7cXZReCcTFfm6ptxMrz0kAW5hms6UNBd8Q1pi4JKlncAhu+Ld/TevsSp7pqAZxBBoGng==} + /@vue/runtime-dom@3.3.4: + resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==} dependencies: - '@vue/runtime-core': 3.3.2 - '@vue/shared': 3.3.2 + '@vue/runtime-core': 3.3.4 + '@vue/shared': 3.3.4 csstype: 3.1.1 - /@vue/server-renderer@3.3.2(vue@3.3.2): - resolution: {integrity: sha512-QCwh6OGwJg6GDLE0fbQhRTR6tnU+XDJ1iCsTYHXBiezCXAhqMygFRij7BiLF4ytvvHcg5kX9joX5R5vP85++wg==} + /@vue/server-renderer@3.3.4(vue@3.3.4): + resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==} peerDependencies: - vue: 3.3.2 + vue: 3.3.4 dependencies: - '@vue/compiler-ssr': 3.3.2 - '@vue/shared': 3.3.2 - vue: 3.3.2 + '@vue/compiler-ssr': 3.3.4 + '@vue/shared': 3.3.4 + vue: 3.3.4 /@vue/shared@3.3.1: resolution: {integrity: sha512-ybDBtQ+479HL/bkeIOIAwgpeAEACzztkvulJLbK3JMFuTOv4qDivmV3AIsR8RHYJ+RD9tQxcHWBsX4GqEcYrfw==} @@ -7417,17 +7508,21 @@ packages: /@vue/shared@3.3.2: resolution: {integrity: sha512-0rFu3h8JbclbnvvKrs7Fe5FNGV9/5X2rPD7KmOzhLSUAiQH5//Hq437Gv0fR5Mev3u/nbtvmLl8XgwCU20/ZfQ==} + dev: false - /@vue/test-utils@2.3.2(vue@3.3.2): + /@vue/shared@3.3.4: + resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} + + /@vue/test-utils@2.3.2(vue@3.3.4): resolution: {integrity: sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==} peerDependencies: vue: ^3.0.1 dependencies: js-beautify: 1.14.6 - vue: 3.3.2 + vue: 3.3.4 optionalDependencies: - '@vue/compiler-dom': 3.3.2 - '@vue/server-renderer': 3.3.2(vue@3.3.2) + '@vue/compiler-dom': 3.3.4 + '@vue/server-renderer': 3.3.4(vue@3.3.4) dev: true /@webgpu/types@0.1.30: @@ -7468,7 +7563,7 @@ packages: p-limit: 2.3.0 pluralize: 7.0.0 pretty-bytes: 5.6.0 - semver: 7.5.0 + semver: 7.5.1 stream-to-promise: 2.2.0 tar-stream: 2.2.0 treeify: 1.1.0 @@ -8368,7 +8463,7 @@ packages: engines: {node: '>=12'} dependencies: bin-version: 6.0.0 - semver: 7.5.0 + semver: 7.5.1 semver-truncate: 2.0.0 dev: false @@ -8628,7 +8723,7 @@ packages: ioredis: 5.3.2 lodash: 4.17.21 msgpackr: 1.8.1 - semver: 7.5.0 + semver: 7.5.1 uuid: 8.3.2 transitivePeerDependencies: - supports-color @@ -9421,7 +9516,7 @@ packages: js-string-escape: 1.0.1 lodash: 4.17.21 md5-hex: 3.0.1 - semver: 7.5.0 + semver: 7.5.1 well-known-symbols: 2.0.0 dev: true @@ -10569,7 +10664,7 @@ packages: natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.11 - semver: 7.5.0 + semver: 7.5.1 vue-eslint-parser: 9.3.0(eslint@8.40.0) xml-name-validator: 4.0.0 transitivePeerDependencies: @@ -11098,7 +11193,7 @@ packages: proxy-addr: 2.0.7 rfdc: 1.3.0 secure-json-parse: 2.7.0 - semver: 7.5.0 + semver: 7.5.1 tiny-lru: 11.0.1 transitivePeerDependencies: - supports-color @@ -12048,8 +12143,8 @@ packages: uglify-js: 3.17.4 dev: true - /happy-dom@9.16.0: - resolution: {integrity: sha512-goq7grRjIiV2Svb251LWQOo/xm04za2mJ9+assbZJx1KnaVOX1gZBBp4MHbiFNkR6JW7UL81iCtZxCVu+qU5ng==} + /happy-dom@9.19.2: + resolution: {integrity: sha512-WBey64FErn5niCLddcjXxkgDk6burN/5doiJpMUQXpgEG3TUJdbygJV1bzcj1Ey+pz+0QGCZH1pwe24uPW+WnQ==} dependencies: css.escape: 1.5.1 entities: 4.5.0 @@ -12057,18 +12152,6 @@ packages: webidl-conversions: 7.0.0 whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 - dev: false - - /happy-dom@9.18.3: - resolution: {integrity: sha512-b7iMGYeIXvUryNultA0AHEVU0FPpb2djJ/xSVlMDfP7HG4z7FomdqkCEpWtSv1zDL+t1gRUoBbpqFCoUBvjYtg==} - dependencies: - css.escape: 1.5.1 - entities: 4.5.0 - iconv-lite: 0.6.3 - webidl-conversions: 7.0.0 - whatwg-encoding: 2.0.0 - whatwg-mimetype: 3.0.0 - dev: true /har-schema@2.0.0: resolution: {integrity: sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==} @@ -13149,7 +13232,7 @@ packages: '@jest/expect': 29.5.0 '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -13197,7 +13280,7 @@ packages: - ts-node dev: true - /jest-cli@29.5.0(@types/node@20.1.3): + /jest-cli@29.5.0(@types/node@20.2.1): resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -13214,7 +13297,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 29.5.0(@types/node@20.1.3) + jest-config: 29.5.0(@types/node@20.2.1) jest-util: 29.5.0 jest-validate: 29.5.0 prompts: 2.4.2 @@ -13264,7 +13347,7 @@ packages: - supports-color dev: true - /jest-config@29.5.0(@types/node@20.1.3): + /jest-config@29.5.0(@types/node@20.2.1): resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -13279,46 +13362,7 @@ packages: '@babel/core': 7.21.3 '@jest/test-sequencer': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.3 - babel-jest: 29.5.0(@babel/core@7.21.3) - chalk: 4.1.2 - ci-info: 3.7.1 - deepmerge: 4.2.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.5.0 - jest-environment-node: 29.5.0 - jest-get-type: 29.4.3 - jest-regex-util: 29.4.3 - jest-resolve: 29.5.0 - jest-runner: 29.5.0 - jest-util: 29.5.0 - jest-validate: 29.5.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.5.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-config@29.5.0(@types/node@20.1.7): - resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.21.3 - '@jest/test-sequencer': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 babel-jest: 29.5.0(@babel/core@7.21.3) chalk: 4.1.2 ci-info: 3.7.1 @@ -13387,7 +13431,7 @@ packages: '@jest/environment': 29.5.0 '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 jest-mock: 29.5.0 jest-util: 29.5.0 dev: true @@ -13417,7 +13461,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@types/graceful-fs': 4.1.6 - '@types/node': 20.1.7 + '@types/node': 20.2.1 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13468,7 +13512,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 20.1.7 + '@types/node': 20.2.1 dev: true /jest-mock@29.5.0: @@ -13476,7 +13520,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.1.3 + '@types/node': 20.2.1 jest-util: 29.5.0 dev: true @@ -13531,7 +13575,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13562,7 +13606,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -13590,7 +13634,7 @@ packages: '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.21.3) '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.21.3) '@babel/traverse': 7.21.3 - '@babel/types': 7.21.4 + '@babel/types': 7.21.5 '@jest/expect-utils': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 @@ -13607,7 +13651,7 @@ packages: jest-util: 29.5.0 natural-compare: 1.4.0 pretty-format: 29.5.0 - semver: 7.5.0 + semver: 7.5.1 transitivePeerDependencies: - supports-color dev: true @@ -13617,7 +13661,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 chalk: 4.1.2 ci-info: 3.7.1 graceful-fs: 4.2.11 @@ -13642,7 +13686,7 @@ packages: dependencies: '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.1.7 + '@types/node': 20.2.1 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13661,7 +13705,7 @@ packages: resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 jest-util: 29.5.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -13687,7 +13731,7 @@ packages: - ts-node dev: true - /jest@29.5.0(@types/node@20.1.3): + /jest@29.5.0(@types/node@20.2.1): resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -13700,7 +13744,7 @@ packages: '@jest/core': 29.5.0 '@jest/types': 29.5.0 import-local: 3.1.0 - jest-cli: 29.5.0(@types/node@20.1.3) + jest-cli: 29.5.0(@types/node@20.2.1) transitivePeerDependencies: - '@types/node' - supports-color @@ -15112,7 +15156,7 @@ packages: resolution: {integrity: sha512-eSKV6s+APenqVh8ubJyiu/YhZgxQpGP66ntzUb3lY1xB9ukSRaGnx0AIxI+IM+1+IVYC1oWobgG5L3Lt9ARykQ==} engines: {node: '>=10'} dependencies: - semver: 7.5.0 + semver: 7.5.1 /node-addon-api@5.0.0: resolution: {integrity: sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==} @@ -15179,7 +15223,7 @@ packages: nopt: 6.0.0 npmlog: 6.0.2 rimraf: 3.0.2 - semver: 7.5.0 + semver: 7.5.1 tar: 6.1.13 which: 2.0.2 transitivePeerDependencies: @@ -15242,7 +15286,7 @@ packages: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.11.0 - semver: 7.5.0 + semver: 7.5.1 validate-npm-package-license: 3.0.4 dev: true @@ -15914,20 +15958,26 @@ packages: /performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - /pg-connection-string@2.5.0: - resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} + /pg-cloudflare@1.1.0: + resolution: {integrity: sha512-tGM8/s6frwuAIyRcJ6nWcIvd3+3NmUKIs6OjviIm1HPPFEt5MzQDOTBQyhPWg/m0kCl95M6gA1JaIXtS8KovOA==} + requiresBuild: true + dev: false + optional: true + + /pg-connection-string@2.6.0: + resolution: {integrity: sha512-x14ibktcwlHKoHxx9X3uTVW9zIGR41ZB6QNhHb21OPNdCCO3NaRnpJuwKIQSR4u+Yqjx4HCvy7Hh7VSy1U4dGg==} dev: false /pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} - /pg-pool@3.6.0(pg@8.10.0): + /pg-pool@3.6.0(pg@8.11.0): resolution: {integrity: sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==} peerDependencies: pg: '>=8.0' dependencies: - pg: 8.10.0 + pg: 8.11.0 dev: false /pg-protocol@1.5.0: @@ -15948,8 +15998,8 @@ packages: postgres-date: 1.0.7 postgres-interval: 1.2.0 - /pg@8.10.0: - resolution: {integrity: sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==} + /pg@8.11.0: + resolution: {integrity: sha512-meLUVPn2TWgJyLmy7el3fQQVwft4gU5NGyvV0XbD41iU9Jbg8lCH4zexhIkihDzVHJStlt6r088G6/fWeNjhXA==} engines: {node: '>= 8.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -15959,11 +16009,13 @@ packages: dependencies: buffer-writer: 2.0.0 packet-reader: 1.0.0 - pg-connection-string: 2.5.0 - pg-pool: 3.6.0(pg@8.10.0) + pg-connection-string: 2.6.0 + pg-pool: 3.6.0(pg@8.11.0) pg-protocol: 1.6.0 pg-types: 2.2.0 pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.0 dev: false /pgpass@1.0.5: @@ -17675,6 +17727,14 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 + dev: true + + /semver@7.5.1: + resolution: {integrity: sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} @@ -17766,7 +17826,7 @@ packages: detect-libc: 2.0.1 node-addon-api: 5.0.0 prebuild-install: 7.1.1 - semver: 7.5.0 + semver: 7.5.1 simple-get: 4.0.1 tar-fs: 2.1.1 tunnel-agent: 0.6.0 @@ -17781,7 +17841,7 @@ packages: detect-libc: 2.0.1 node-addon-api: 6.1.0 prebuild-install: 7.1.1 - semver: 7.5.0 + semver: 7.5.1 simple-get: 4.0.1 tar-fs: 2.1.1 tunnel-agent: 0.6.0 @@ -17883,6 +17943,15 @@ packages: dev: false optional: true + /slacc-android-arm-eabi@0.0.9: + resolution: {integrity: sha512-T5P5kJ5UwW3UMoPXqqHh9TpCnuCJDCoivoiuONDXrYPYKF8sKDPMVVg1x/KU9/m7e562x9vAMBrIyqFFbEW0Jw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + /slacc-android-arm64@0.0.7: resolution: {integrity: sha512-aol/9Rg0Hfqu81hpK+HXcx9sGYu4qqYU+djBCgLtb8I6ZMdWUdE0dp8ACBoTOmYn34hYGcUu4FlJUZ8r7Utucg==} engines: {node: '>= 10'} @@ -17892,6 +17961,15 @@ packages: dev: false optional: true + /slacc-android-arm64@0.0.9: + resolution: {integrity: sha512-bcKB3ukcI5wWJa2clK/5cy6a4TKp51DRkdRuFgKLG05gBj1jbH+7+8iBPojljeY28LC2frmwVHGj3vDmkFUeYg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + /slacc-darwin-arm64@0.0.7: resolution: {integrity: sha512-PkV7rO/c9AImNYDacP+kxtOjVuxjy06IIOAxbWerIWvoeqsCNRtiF/dh+OqIACRFBuHIDe0oAyUCEMGUTnzjyQ==} engines: {node: '>= 10'} @@ -17901,6 +17979,15 @@ packages: dev: false optional: true + /slacc-darwin-arm64@0.0.9: + resolution: {integrity: sha512-EspX0Hj6t0Afxbsyc6rY9mTOUQQrPVtWPwwNRaljGRorPyRDDefrU1OnJXRcwcIp0oCZrRrivRYlO7lai63EMw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /slacc-darwin-universal@0.0.7: resolution: {integrity: sha512-Y9zXpL40m4Yq3dE5vdnAgfmn0Fxc0Bf0ixC9TSl96gKeIZEd6drkjfpHFdsIDNImzOksIAUo0HHiDdbEfE7zdQ==} engines: {node: '>= 10'} @@ -17909,6 +17996,14 @@ packages: dev: false optional: true + /slacc-darwin-universal@0.0.9: + resolution: {integrity: sha512-oQySg+9MPyKI9rwwwhmSZQkPks2/rq3k1P5HKwUgnaFZDvDtS/hpDycB3BxSDqWdD5kVA8PLCVa8pt9T5KyKfg==} + engines: {node: '>= 10'} + os: [darwin] + requiresBuild: true + dev: false + optional: true + /slacc-darwin-x64@0.0.7: resolution: {integrity: sha512-yKaGjX2YJl1QHe4NgqQVsY83jees3hjFxEUPoKpuZEQzWbMNn0XSyceFRGXIk1oDqiKU40UcsdcCedjYjSEd0Q==} engines: {node: '>= 10'} @@ -17918,6 +18013,24 @@ packages: dev: false optional: true + /slacc-darwin-x64@0.0.9: + resolution: {integrity: sha512-9Xp7mVKKF2QvDiIZOBgwsDdL/+95KBiFTdbo+XtH6YKoh6zNw0aPpkA3JojsdSMYdGHUrxl8b7avhzI0USqeEg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /slacc-freebsd-x64@0.0.9: + resolution: {integrity: sha512-jRd8WmXZLU2mcxV7SN8CzZzGiwbpxtaTjLwrYMTryQZ2TFr1xd1r5mQfTN5sBiwu3tnyK5dmHnRAPy+215mOkQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /slacc-linux-arm-gnueabihf@0.0.7: resolution: {integrity: sha512-pdWMdQeX6uA9JfSoWo9EHH0yRiwXKMbaKoS9gflDSyt/hjeR3Qx/KK7Wihd7HeXx7njlNdpr9ycTRmm5NgapQQ==} engines: {node: '>= 10'} @@ -17927,6 +18040,15 @@ packages: dev: false optional: true + /slacc-linux-arm-gnueabihf@0.0.9: + resolution: {integrity: sha512-nhP6+jgd30sq+zFxFW7fGhnPwCfCCU0l1JKk3ORGFMl7wH7ippTDd1xGapKq7N+zgdgURbyj83P3wWb2gcRZ1w==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + /slacc-linux-arm64-gnu@0.0.7: resolution: {integrity: sha512-hz9TK/w6fxeNZXyFzuLq5cJD/XRyJbo6BaIdW+VrKKnb9nkLnWlqDQtdtJk7Fw7zHjdY3Uqufjwm0iT6qBVpUQ==} engines: {node: '>= 10'} @@ -17936,6 +18058,15 @@ packages: dev: false optional: true + /slacc-linux-arm64-gnu@0.0.9: + resolution: {integrity: sha512-x7v0rDe0KNVe1Hl6/XCtkCpqdT283pyVaUmk+af0AnoesNRjYEK8DBc8i53N4nhotionHzPIZfu5gPAFkf6RhA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /slacc-linux-arm64-musl@0.0.7: resolution: {integrity: sha512-wCDAYL7e+lh3XL7g87Ui/Bb2Ap9GcBqeJuj2yHIx6MYC8ontwFSXhqRTmd2zmPLmZA5Nc11aKGN11YNu0Pnwlw==} engines: {node: '>= 10'} @@ -17945,6 +18076,15 @@ packages: dev: false optional: true + /slacc-linux-arm64-musl@0.0.9: + resolution: {integrity: sha512-jyq/ylITHIXTQX5ZqAbi7Mn5SdRgYJi+uEoUCi5UhoXb9LjpNzhkFuY29Je3IkVIIV7AEcAxIlvjdymXdzcF5w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /slacc-linux-x64-gnu@0.0.7: resolution: {integrity: sha512-E5+2cveizpfHXCk/Hu5VfslWFeDVw47nywODiJ8CsofT2l5ITfYPMFEBXm9ORY25mGBTgsO6lJYiF9Hz4FlS9Q==} engines: {node: '>= 10'} @@ -17954,6 +18094,15 @@ packages: dev: false optional: true + /slacc-linux-x64-gnu@0.0.9: + resolution: {integrity: sha512-Xs/F81H7cKhlIBigFID6CJlgjy0NeDUGV1CI1MI5mSVHsVI8dUO8zXWETjo6o8krJPgfjT5Jd4tAgvUFct5hng==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /slacc-win32-arm64-msvc@0.0.7: resolution: {integrity: sha512-3a+qnkZbP+Pr5RZuzd0Vi1uCal137QiJajRAWT4r7qwu+Zidd50x2oikQ4rAegqZVTm8qTwVmWA+WmH8WHI7iw==} engines: {node: '>= 10'} @@ -17963,6 +18112,15 @@ packages: dev: false optional: true + /slacc-win32-arm64-msvc@0.0.9: + resolution: {integrity: sha512-C+H0VkKbEEnRbcXRIG5rIaXlg7IZw3o1BbvqA71B8ouQRCu/dNRuH9EQsOYXWltndY42zZi8IupNIwydTUg+Mg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /slacc-win32-x64-msvc@0.0.7: resolution: {integrity: sha512-ydFdZ7wEXQPsw2Tg+yG9uJdCGTehyPtrWBVUMa7fojr3j1gbtThXS2l9Ad/6fYYi2VwdaYPLWbwV3GYElPGL8g==} engines: {node: '>= 10'} @@ -17972,21 +18130,31 @@ packages: dev: false optional: true - /slacc@0.0.7: - resolution: {integrity: sha512-rwi2F3oJaGPST9JdCoUd5fnSZaoZFgTL00GFKhKufT48uwtUEAHlOL0t8gEVmon71X+53f9nEdsGWhwtOutJTQ==} + /slacc-win32-x64-msvc@0.0.9: + resolution: {integrity: sha512-bElMnBbeMatCtVp2/+hBS6Z+846nQImEul9nBEr4gfezHotOM6MqR6PI7UQQzGhozpgwiDg2l1ub1MdOIgYizg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /slacc@0.0.9: + resolution: {integrity: sha512-BwhjD3daQB3VIx7GxkComMYrnkWuMt4YmDAueMMchblfUUBbP8EcuonJ1Bz9nqtRn1mAH2YPrrRDP95akM+ZuQ==} engines: {node: '>= 10'} optionalDependencies: - slacc-android-arm-eabi: 0.0.7 - slacc-android-arm64: 0.0.7 - slacc-darwin-arm64: 0.0.7 - slacc-darwin-universal: 0.0.7 - slacc-darwin-x64: 0.0.7 - slacc-linux-arm-gnueabihf: 0.0.7 - slacc-linux-arm64-gnu: 0.0.7 - slacc-linux-arm64-musl: 0.0.7 - slacc-linux-x64-gnu: 0.0.7 - slacc-win32-arm64-msvc: 0.0.7 - slacc-win32-x64-msvc: 0.0.7 + slacc-android-arm-eabi: 0.0.9 + slacc-android-arm64: 0.0.9 + slacc-darwin-arm64: 0.0.9 + slacc-darwin-universal: 0.0.9 + slacc-darwin-x64: 0.0.9 + slacc-freebsd-x64: 0.0.9 + slacc-linux-arm-gnueabihf: 0.0.9 + slacc-linux-arm64-gnu: 0.0.9 + slacc-linux-arm64-musl: 0.0.9 + slacc-linux-x64-gnu: 0.0.9 + slacc-win32-arm64-msvc: 0.0.9 + slacc-win32-x64-msvc: 0.0.9 dev: false /slash@3.0.0: @@ -18078,7 +18246,7 @@ packages: lodash.topairs: 4.3.0 micromatch: 4.0.5 p-map: 4.0.0 - semver: 7.5.0 + semver: 7.5.1 snyk-config: 5.1.0 tslib: 1.14.1 uuid: 8.3.2 @@ -18825,8 +18993,8 @@ packages: engines: {node: '>=12'} dev: false - /tinybench@2.4.0: - resolution: {integrity: sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==} + /tinybench@2.5.0: + resolution: {integrity: sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==} dev: true /tinycolor2@1.6.0: @@ -19140,7 +19308,7 @@ packages: /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - /typeorm@0.3.16(ioredis@5.3.2)(pg@8.10.0): + /typeorm@0.3.16(ioredis@5.3.2)(pg@8.11.0): resolution: {integrity: sha512-wJ4Qy1oqRKNDdZiBTTaVMqwo/XxC52Q7uNPTjltPgLhvIW173bL6Iad0lhptMOsFlpixFPaUu3PNziaRBwX2Zw==} engines: {node: '>= 12.9.0'} hasBin: true @@ -19209,7 +19377,7 @@ packages: glob: 8.1.0 ioredis: 5.3.2 mkdirp: 2.1.6 - pg: 8.10.0 + pg: 8.11.0 reflect-metadata: 0.1.13 sha.js: 2.4.11 tslib: 2.5.0 @@ -19656,8 +19824,8 @@ packages: replace-ext: 1.0.1 dev: false - /vite-node@0.31.0(@types/node@20.1.7)(sass@1.62.1): - resolution: {integrity: sha512-8x1x1LNuPvE2vIvkSB7c1mApX5oqlgsxzHQesYF7l5n1gKrEmrClIiZuOFbFDQcjLsmcWSwwmrWrcGWm9Fxc/g==} + /vite-node@0.31.1(@types/node@20.2.1)(sass@1.62.1): + resolution: {integrity: sha512-BajE/IsNQ6JyizPzu9zRgHrBwczkAs0erQf/JRpgTIESpKvNj9/Gd0vxX905klLkb0I0SJVCKbdrl5c6FnqYKA==} engines: {node: '>=v14.18.0'} hasBin: true dependencies: @@ -19666,7 +19834,7 @@ packages: mlly: 1.2.0 pathe: 1.1.0 picocolors: 1.0.0 - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) transitivePeerDependencies: - '@types/node' - less @@ -19681,8 +19849,8 @@ packages: resolution: {integrity: sha512-irjKcKXRn7v5bPAg4mAbsS6DgibpP1VUFL9tlgxU6lloK6V9yw9qCZkS+s2PtbkZpWNzr3TN3zVJAc6J7gJZmA==} dev: true - /vite@4.3.7(@types/node@20.1.7)(sass@1.62.1): - resolution: {integrity: sha512-MTIFpbIm9v7Hh5b0wSBgkcWzSBz7SAa6K/cBTwS4kUiQJfQLFlZZRJRQgqunCVzhTPCk674tW+0Qaqh3Q00dBg==} + /vite@4.3.8(@types/node@20.2.1)(sass@1.62.1): + resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -19706,7 +19874,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.1.7 + '@types/node': 20.2.1 esbuild: 0.17.18 postcss: 8.4.23 rollup: 3.22.0 @@ -19714,20 +19882,20 @@ packages: optionalDependencies: fsevents: 2.3.2 - /vitest-fetch-mock@0.2.2(vitest@0.31.0): + /vitest-fetch-mock@0.2.2(vitest@0.31.1): resolution: {integrity: sha512-XmH6QgTSjCWrqXoPREIdbj40T7i1xnGmAsTAgfckoO75W1IEHKR8hcPCQ7SO16RsdW1t85oUm6pcQRLeBgjVYQ==} engines: {node: '>=14.14.0'} peerDependencies: vitest: '>=0.16.0' dependencies: cross-fetch: 3.1.5 - vitest: 0.31.0(happy-dom@9.18.3)(sass@1.62.1) + vitest: 0.31.1(happy-dom@9.19.2)(sass@1.62.1) transitivePeerDependencies: - encoding dev: true - /vitest@0.31.0(happy-dom@9.18.3)(sass@1.62.1): - resolution: {integrity: sha512-JwWJS9p3GU9GxkG7eBSmr4Q4x4bvVBSswaCFf1PBNHiPx00obfhHRJfgHcnI0ffn+NMlIh9QGvG75FlaIBdKGA==} + /vitest@0.31.1(happy-dom@9.19.2)(sass@1.62.1): + resolution: {integrity: sha512-/dOoOgzoFk/5pTvg1E65WVaobknWREN15+HF+0ucudo3dDG/vCZoXTQrjIfEaWvQXmqScwkRodrTbM/ScMpRcQ==} engines: {node: '>=v14.18.0'} hasBin: true peerDependencies: @@ -19757,31 +19925,31 @@ packages: webdriverio: optional: true dependencies: - '@types/chai': 4.3.4 + '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 - '@types/node': 20.1.7 - '@vitest/expect': 0.31.0 - '@vitest/runner': 0.31.0 - '@vitest/snapshot': 0.31.0 - '@vitest/spy': 0.31.0 - '@vitest/utils': 0.31.0 + '@types/node': 20.2.1 + '@vitest/expect': 0.31.1 + '@vitest/runner': 0.31.1 + '@vitest/snapshot': 0.31.1 + '@vitest/spy': 0.31.1 + '@vitest/utils': 0.31.1 acorn: 8.8.2 acorn-walk: 8.2.0 cac: 6.7.14 chai: 4.3.7 concordance: 5.0.4 debug: 4.3.4(supports-color@8.1.1) - happy-dom: 9.18.3 + happy-dom: 9.19.2 local-pkg: 0.4.3 magic-string: 0.30.0 pathe: 1.1.0 picocolors: 1.0.0 std-env: 3.3.2 strip-literal: 1.0.1 - tinybench: 2.4.0 + tinybench: 2.5.0 tinypool: 0.5.0 - vite: 4.3.7(@types/node@20.1.7)(sass@1.62.1) - vite-node: 0.31.0(@types/node@20.1.7)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite-node: 0.31.1(@types/node@20.2.1)(sass@1.62.1) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -19796,20 +19964,20 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} - /vue-docgen-api@4.64.1(vue@3.3.2): + /vue-docgen-api@4.64.1(vue@3.3.4): resolution: {integrity: sha512-jbOf7ByE3Zvtuk+429Jorl+eIeh2aB2Fx1GUo3xJd1aByJWE8KDlSEa6b11PB1ze8f0sRUBraRDinICCk0KY7g==} dependencies: '@babel/parser': 7.21.8 '@babel/types': 7.21.5 - '@vue/compiler-dom': 3.3.2 - '@vue/compiler-sfc': 3.3.2 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-sfc': 3.3.4 ast-types: 0.14.2 hash-sum: 2.0.0 lru-cache: 8.0.4 pug: 3.0.2 recast: 0.22.0 ts-map: 1.0.3 - vue-inbrowser-compiler-independent-utils: 4.64.1(vue@3.3.2) + vue-inbrowser-compiler-independent-utils: 4.64.1(vue@3.3.4) transitivePeerDependencies: - vue dev: true @@ -19827,17 +19995,17 @@ packages: espree: 9.5.2 esquery: 1.4.2 lodash: 4.17.21 - semver: 7.5.0 + semver: 7.5.1 transitivePeerDependencies: - supports-color dev: true - /vue-inbrowser-compiler-independent-utils@4.64.1(vue@3.3.2): + /vue-inbrowser-compiler-independent-utils@4.64.1(vue@3.3.4): resolution: {integrity: sha512-Hn32n07XZ8j9W8+fmOXPQL+i+W2e/8i6mkH4Ju3H6nR0+cfvmWM95GhczYi5B27+Y8JlCKgAo04IUiYce4mKAw==} peerDependencies: vue: '>=2' dependencies: - vue: 3.3.2 + vue: 3.3.4 dev: true /vue-plyr@7.0.0: @@ -19847,13 +20015,13 @@ packages: vue: 2.7.14 dev: false - /vue-prism-editor@2.0.0-alpha.2(vue@3.3.2): + /vue-prism-editor@2.0.0-alpha.2(vue@3.3.4): resolution: {integrity: sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==} engines: {node: '>=10'} peerDependencies: vue: ^3.0.0 dependencies: - vue: 3.3.2 + vue: 3.3.4 dev: false /vue-template-compiler@2.7.14: @@ -19871,7 +20039,7 @@ packages: dependencies: '@volar/vue-language-core': 1.6.5 '@volar/vue-typescript': 1.6.5(typescript@5.0.4) - semver: 7.5.0 + semver: 7.5.1 typescript: 5.0.4 dev: true @@ -19882,22 +20050,22 @@ packages: csstype: 3.1.1 dev: false - /vue@3.3.2: - resolution: {integrity: sha512-98hJcAhyDwZoOo2flAQBSPVYG/o0HA9ivIy2ktHshjE+6/q8IMQ+kvDKQzOZTFPxvnNMcGM+zS2A00xeZMA7tA==} + /vue@3.3.4: + resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} dependencies: - '@vue/compiler-dom': 3.3.2 - '@vue/compiler-sfc': 3.3.2 - '@vue/runtime-dom': 3.3.2 - '@vue/server-renderer': 3.3.2(vue@3.3.2) - '@vue/shared': 3.3.2 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-sfc': 3.3.4 + '@vue/runtime-dom': 3.3.4 + '@vue/server-renderer': 3.3.4(vue@3.3.4) + '@vue/shared': 3.3.4 - /vuedraggable@4.1.0(vue@3.3.2): + /vuedraggable@4.1.0(vue@3.3.4): resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} peerDependencies: vue: ^3.0.1 dependencies: sortablejs: 1.14.0 - vue: 3.3.2 + vue: 3.3.4 dev: false /w3c-xmlserializer@4.0.0: From 02715f5d14d00172c71bf289a2bde4c770495de8 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Fri, 19 May 2023 07:36:47 +0000 Subject: [PATCH 059/213] update pnpm to 8.5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a8e1e7b20..53604fb866 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/misskey-dev/misskey.git" }, - "packageManager": "pnpm@8.3.1", + "packageManager": "pnpm@8.5.1", "workspaces": [ "packages/frontend", "packages/backend", From bd6666173a266dbcc10221a049f518443ed8f25b Mon Sep 17 00:00:00 2001 From: nenohi <kimutipartylove@gmail.com> Date: Fri, 19 May 2023 17:12:22 +0900 Subject: [PATCH 060/213] =?UTF-8?q?fix:=E3=83=AD=E3=83=BC=E3=83=AB?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=A4=E3=83=B3=E7=84=A1?= =?UTF-8?q?=E5=8A=B9=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20(#10843)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修正 * note visibility change * public投稿のみ * update changelog * RN非表示機能がうごかないところだった --- CHANGELOG.md | 2 ++ packages/backend/src/core/RoleService.ts | 8 ++++++++ .../backend/src/server/api/endpoints/roles/notes.ts | 1 + .../src/server/api/stream/channels/role-timeline.ts | 11 ++++++++++- .../frontend/src/ui/deck/role-timeline-column.vue | 2 +- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 454974ca23..4b462783de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ - AiScriptを0.13.3に更新 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 - Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正 +- fix:ロールタイムラインが無効でも投稿が流れてしまう問題の修正 +- fix:ロールタイムラインにて全ての投稿が流れてしまう問題の修正 ## 13.12.2 diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 68087ccc3b..130ec5ec8c 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -306,6 +306,14 @@ export class RoleService implements OnApplicationShutdown { return user.isRoot || (await this.getUserRoles(user.id)).some(r => r.isAdministrator); } + @bindThis + public async isExplorable(role: { id: Role['id']} | null): Promise<boolean> { + if (role == null) return false; + const check = await this.rolesRepository.findOneBy({ id: role.id }); + if (check == null) return false; + return check.isExplorable; + } + @bindThis public async getModeratorIds(includeAdmins = true): Promise<User['id'][]> { const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({})); diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts index 6202c740f1..42e36cb04a 100644 --- a/packages/backend/src/server/api/endpoints/roles/notes.ts +++ b/packages/backend/src/server/api/endpoints/roles/notes.ts @@ -93,6 +93,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { const query = this.notesRepository.createQueryBuilder('note') .where('note.id IN (:...noteIds)', { noteIds: noteIds }) + .andWhere('(note.visibility = \'public\')') .innerJoinAndSelect('note.user', 'user') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') diff --git a/packages/backend/src/server/api/stream/channels/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts index 9d106c8b2f..ab9c1aa0b5 100644 --- a/packages/backend/src/server/api/stream/channels/role-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts @@ -5,15 +5,17 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { bindThis } from '@/decorators.js'; import Channel from '../channel.js'; import { StreamMessages } from '../types.js'; +import { RoleService } from '@/core/RoleService.js'; class RoleTimelineChannel extends Channel { public readonly chName = 'roleTimeline'; public static shouldShare = false; public static requireCredential = false; private roleId: string; - + constructor( private noteEntityService: NoteEntityService, + private roleservice: RoleService, id: string, connection: Channel['connection'], @@ -34,6 +36,11 @@ class RoleTimelineChannel extends Channel { if (data.type === 'note') { const note = data.body; + if (!(await this.roleservice.isExplorable({ id: this.roleId }))) { + return; + } + if (note.visibility !== 'public') return; + // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.userIdsWhoMeMuting)) return; // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する @@ -61,6 +68,7 @@ export class RoleTimelineChannelService { constructor( private noteEntityService: NoteEntityService, + private roleservice: RoleService, ) { } @@ -68,6 +76,7 @@ export class RoleTimelineChannelService { public create(id: string, connection: Channel['connection']): RoleTimelineChannel { return new RoleTimelineChannel( this.noteEntityService, + this.roleservice, id, connection, ); diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue index 5783b3f071..e375a5884f 100644 --- a/packages/frontend/src/ui/deck/role-timeline-column.vue +++ b/packages/frontend/src/ui/deck/role-timeline-column.vue @@ -35,7 +35,7 @@ onMounted(() => { }); async function setRole() { - const roles = await os.api('roles/list'); + const roles = (await os.api('roles/list')).filter(x => x.isExplorable); const { canceled, result: role } = await os.select({ title: i18n.ts.role, items: roles.map(x => ({ From c713af8e23eef585dc3468806d5be8acfd608d8d Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 18:16:26 +0900 Subject: [PATCH 061/213] refactor --- .../frontend/src/components/MkUserInfo.vue | 2 +- packages/frontend/src/pages/clip.vue | 45 +++++++++---------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue index f560ebcd8a..fea3842a5b 100644 --- a/packages/frontend/src/components/MkUserInfo.vue +++ b/packages/frontend/src/components/MkUserInfo.vue @@ -105,7 +105,7 @@ defineProps<{ .mfm { display: -webkit-box; -webkit-line-clamp: 3; - -webkit-box-orient: vertical; + -webkit-box-orient: vertical; overflow: hidden; } diff --git a/packages/frontend/src/pages/clip.vue b/packages/frontend/src/pages/clip.vue index 654c44ae02..d5313099da 100644 --- a/packages/frontend/src/pages/clip.vue +++ b/packages/frontend/src/pages/clip.vue @@ -2,15 +2,15 @@ <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions"/></template> <MkSpacer :contentMax="800"> - <div v-if="clip"> - <div class="okzinsic _panel"> - <div v-if="clip.description" class="description"> + <div v-if="clip" class="_gaps"> + <div class="_panel"> + <div v-if="clip.description" :class="$style.description"> <Mfm :text="clip.description" :isNote="false" :i="$i"/> </div> - <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike class="button" rounded primary @click="unfavorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> - <MkButton v-else v-tooltip="i18n.ts.favorite" asLike class="button" rounded @click="favorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> - <div class="user"> - <MkAvatar :user="clip.user" class="avatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/> + <MkButton v-if="favorited" v-tooltip="i18n.ts.unfavorite" asLike rounded primary @click="unfavorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> + <MkButton v-else v-tooltip="i18n.ts.favorite" asLike rounded @click="favorite()"><i class="ti ti-heart"></i><span v-if="clip.favoritedCount > 0" style="margin-left: 6px;">{{ clip.favoritedCount }}</span></MkButton> + <div :class="$style.user"> + <MkAvatar :user="clip.user" :class="$style.avatar" indicator link preview/> <MkUserName :user="clip.user" :nowrap="false"/> </div> </div> @@ -147,25 +147,20 @@ definePageMetadata(computed(() => clip ? { } : null)); </script> -<style lang="scss" scoped> -.okzinsic { - position: relative; - margin-bottom: var(--margin); +<style lang="scss" module> +.description { + padding: 16px; +} - > .description { - padding: 16px; - } +.user { + --height: 32px; + padding: 16px; + border-top: solid 0.5px var(--divider); + line-height: var(--height); +} - > .user { - $height: 32px; - padding: 16px; - border-top: solid 0.5px var(--divider); - line-height: $height; - - > .avatar { - width: $height; - height: $height; - } - } +.avatar { + width: var(--height); + height: var(--height); } </style> From 1b78c6a3095965672c684a956b7787e1d7bf8a0f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 20:52:15 +0900 Subject: [PATCH 062/213] refactor --- packages/frontend/src/pages/admin/abuses.vue | 2 +- packages/frontend/src/pages/admin/ads.vue | 18 ++-- .../src/pages/admin/announcements.vue | 2 +- .../frontend/src/pages/admin/database.vue | 2 +- .../src/pages/admin/email-settings.vue | 8 +- .../frontend/src/pages/admin/federation.vue | 27 +++--- packages/frontend/src/pages/admin/files.vue | 4 +- packages/frontend/src/pages/admin/index.vue | 2 +- .../src/pages/admin/instance-block.vue | 2 +- .../frontend/src/pages/admin/moderation.vue | 4 +- .../src/pages/admin/object-storage.vue | 6 +- .../src/pages/admin/overview.instances.vue | 24 +++--- .../frontend/src/pages/admin/overview.vue | 2 +- .../src/pages/admin/proxy-account.vue | 2 +- .../frontend/src/pages/admin/queue.chart.vue | 84 +++++++++---------- packages/frontend/src/pages/admin/queue.vue | 2 +- packages/frontend/src/pages/admin/relays.vue | 2 +- .../frontend/src/pages/admin/roles.edit.vue | 4 +- .../frontend/src/pages/admin/roles.editor.vue | 40 ++++----- .../frontend/src/pages/admin/server-rules.vue | 4 +- packages/frontend/src/pages/admin/users.vue | 6 +- .../frontend/src/pages/flash/flash-edit.vue | 2 +- .../frontend/src/pages/flash/flash-index.vue | 2 +- packages/frontend/src/pages/flash/flash.vue | 8 +- .../frontend/src/pages/my-antennas/create.vue | 2 +- .../frontend/src/pages/my-antennas/editor.vue | 2 +- .../frontend/src/pages/my-antennas/index.vue | 26 +++--- .../frontend/src/pages/my-clips/index.vue | 2 +- .../frontend/src/pages/my-lists/index.vue | 4 +- .../pages/page-editor/page-editor.blocks.vue | 4 +- .../src/pages/page-editor/page-editor.vue | 2 +- .../src/pages/settings/2fa.qrdialog.vue | 4 +- packages/frontend/src/pages/settings/2fa.vue | 2 +- .../frontend/src/pages/settings/accounts.vue | 2 +- .../src/pages/settings/custom-css.vue | 2 +- .../frontend/src/pages/settings/drive.vue | 6 +- .../frontend/src/pages/settings/email.vue | 4 +- .../frontend/src/pages/settings/index.vue | 2 +- .../frontend/src/pages/settings/migration.vue | 10 +-- .../frontend/src/pages/settings/navbar.vue | 4 +- .../src/pages/settings/notifications.vue | 2 +- .../frontend/src/pages/settings/plugin.vue | 2 +- .../frontend/src/pages/settings/privacy.vue | 20 ++--- .../frontend/src/pages/settings/reaction.vue | 2 +- .../frontend/src/pages/settings/roles.vue | 2 +- .../frontend/src/pages/settings/security.vue | 2 +- .../src/pages/settings/sounds.sound.vue | 2 +- .../frontend/src/pages/settings/sounds.vue | 2 +- .../pages/settings/statusbar.statusbar.vue | 10 +-- .../frontend/src/pages/settings/statusbar.vue | 2 +- .../src/pages/settings/theme.manage.vue | 6 +- .../frontend/src/pages/user/achievements.vue | 4 +- packages/frontend/src/pages/user/activity.vue | 2 +- packages/frontend/src/pages/user/clips.vue | 32 ++++--- .../frontend/src/pages/user/follow-list.vue | 18 ++-- .../frontend/src/pages/user/followers.vue | 2 +- .../frontend/src/pages/user/following.vue | 2 +- packages/frontend/src/pages/user/gallery.vue | 8 +- packages/frontend/src/pages/user/home.vue | 8 +- .../src/pages/user/index.timeline.vue | 4 +- packages/frontend/src/pages/user/index.vue | 2 +- packages/frontend/src/pages/user/pages.vue | 6 +- .../frontend/src/pages/user/reactions.vue | 52 ++++++------ packages/frontend/src/ui/_common_/common.vue | 10 +-- .../src/ui/_common_/navbar-for-mobile.vue | 8 +- packages/frontend/src/ui/_common_/navbar.vue | 8 +- .../frontend/src/ui/_common_/statusbars.vue | 6 +- packages/frontend/src/ui/classic.header.vue | 8 +- packages/frontend/src/ui/classic.sidebar.vue | 8 +- packages/frontend/src/ui/classic.vue | 4 +- packages/frontend/src/ui/deck.vue | 22 ++--- .../frontend/src/ui/deck/antenna-column.vue | 2 +- .../frontend/src/ui/deck/channel-column.vue | 4 +- packages/frontend/src/ui/deck/column-core.vue | 20 ++--- .../frontend/src/ui/deck/direct-column.vue | 2 +- packages/frontend/src/ui/deck/list-column.vue | 2 +- packages/frontend/src/ui/deck/main-column.vue | 2 +- .../frontend/src/ui/deck/mentions-column.vue | 2 +- .../src/ui/deck/notifications-column.vue | 4 +- .../src/ui/deck/role-timeline-column.vue | 2 +- packages/frontend/src/ui/deck/tl-column.vue | 2 +- .../frontend/src/ui/deck/widgets-column.vue | 4 +- packages/frontend/src/ui/universal.vue | 34 ++++---- .../frontend/src/ui/universal.widgets.vue | 2 +- packages/frontend/src/ui/visitor.vue | 24 +++--- 85 files changed, 341 insertions(+), 368 deletions(-) diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index f8200570f9..3bc5ee9723 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="900"> + <MkSpacer :contentMax="900"> <div> <div class="reports"> <div class=""> diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index 803e8cb7b0..2c9e18b0bf 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -1,9 +1,9 @@ <template> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="900"> - <div class="uqshojas"> - <div v-for="ad in ads" class="_panel _gaps_m ad"> + <MkSpacer :contentMax="900"> + <div> + <div v-for="ad in ads" class="_panel _gaps_m" :class="$style.ad"> <MkAd v-if="ad.url" :specify="ad"/> <MkInput v-model="ad.url" type="url"> <template #label>URL</template> @@ -196,14 +196,12 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.uqshojas { - > .ad { - padding: 32px; +<style lang="scss" module> +.ad { + padding: 32px; - &:not(:last-child) { - margin-bottom: var(--margin); - } + &:not(:last-child) { + margin-bottom: var(--margin); } } </style> diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue index 638b193c11..3cb32c1d9d 100644 --- a/packages/frontend/src/pages/admin/announcements.vue +++ b/packages/frontend/src/pages/admin/announcements.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="900"> + <MkSpacer :contentMax="900"> <div class="_gaps_m"> <section v-for="announcement in announcements" class=""> <div class="_panel _gaps_m" style="padding: 24px;"> diff --git a/packages/frontend/src/pages/admin/database.vue b/packages/frontend/src/pages/admin/database.vue index 5a0d3d5e51..131e586afd 100644 --- a/packages/frontend/src/pages/admin/database.vue +++ b/packages/frontend/src/pages/admin/database.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="800" :marginMin="16" :marginMax="32"> <FormSuspense v-slot="{ result: database }" :p="databasePromiseFactory"> <MkKeyValue v-for="table in database" :key="table[0]" oneline style="margin: 1em 0;"> <template #key>{{ table[0] }}</template> diff --git a/packages/frontend/src/pages/admin/email-settings.vue b/packages/frontend/src/pages/admin/email-settings.vue index d51bf6230a..4f5bb379ad 100644 --- a/packages/frontend/src/pages/admin/email-settings.vue +++ b/packages/frontend/src/pages/admin/email-settings.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <div class="_gaps_m"> <MkSwitch v-model="enableEmail"> @@ -18,7 +18,7 @@ <template #label>{{ i18n.ts.smtpConfig }}</template> <div class="_gaps_m"> - <FormSplit :min-width="280"> + <FormSplit :minWidth="280"> <MkInput v-model="smtpHost"> <template #label>{{ i18n.ts.smtpHost }}</template> </MkInput> @@ -26,7 +26,7 @@ <template #label>{{ i18n.ts.smtpPort }}</template> </MkInput> </FormSplit> - <FormSplit :min-width="280"> + <FormSplit :minWidth="280"> <MkInput v-model="smtpUser"> <template #label>{{ i18n.ts.smtpUser }}</template> </MkInput> @@ -47,7 +47,7 @@ </MkSpacer> <template #footer> <div :class="$style.footer"> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="16"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="16"> <div class="_buttons"> <MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> <MkButton rounded @click="testEmail"><i class="ti ti-send"></i> {{ i18n.ts.testEmail }}</MkButton> diff --git a/packages/frontend/src/pages/admin/federation.vue b/packages/frontend/src/pages/admin/federation.vue index 6af1610431..b2a7ef6685 100644 --- a/packages/frontend/src/pages/admin/federation.vue +++ b/packages/frontend/src/pages/admin/federation.vue @@ -2,9 +2,9 @@ <div> <MkStickyContainer> <template #header><XHeader :actions="headerActions"/></template> - <MkSpacer :content-max="900"> - <div class="taeiyrib"> - <div class="query"> + <MkSpacer :contentMax="900"> + <div> + <div> <MkInput v-model="host" :debounce="true" class=""> <template #prefix><i class="ti ti-search"></i></template> <template #label>{{ i18n.ts.host }}</template> @@ -39,8 +39,8 @@ </div> <MkPagination v-slot="{items}" ref="instances" :key="host + state" :pagination="pagination"> - <div class="dqokceoj"> - <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" class="instance" :to="`/instance-info/${instance.host}`"> + <div :class="$style.instances"> + <MkA v-for="instance in items" :key="instance.id" v-tooltip.mfm="`Status: ${getStatus(instance)}`" :class="$style.instance" :to="`/instance-info/${instance.host}`"> <MkInstanceCardMini :instance="instance"/> </MkA> </div> @@ -100,21 +100,14 @@ definePageMetadata(computed(() => ({ }))); </script> -<style lang="scss" scoped> -.taeiyrib { - > .query { - background: var(--bg); - margin-bottom: 16px; - } -} - -.dqokceoj { +<style lang="scss" module> +.instances { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); grid-gap: 12px; +} - > .instance:hover { - text-decoration: none; - } +.instance:hover { + text-decoration: none; } </style> diff --git a/packages/frontend/src/pages/admin/files.vue b/packages/frontend/src/pages/admin/files.vue index 2b13a7c80c..a8ebb7f108 100644 --- a/packages/frontend/src/pages/admin/files.vue +++ b/packages/frontend/src/pages/admin/files.vue @@ -2,7 +2,7 @@ <div> <MkStickyContainer> <template #header><XHeader :actions="headerActions"/></template> - <MkSpacer :content-max="900"> + <MkSpacer :contentMax="900"> <div> <div> <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap;"> @@ -24,7 +24,7 @@ <template #label>MIME type</template> </MkInput> </div> - <MkFileListForAdmin :pagination="pagination" :view-mode="viewMode"/> + <MkFileListForAdmin :pagination="pagination" :viewMode="viewMode"/> </div> </div> </MkSpacer> diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 963393d7e5..5cbbcaa44c 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -1,7 +1,7 @@ <template> <div ref="el" class="hiyeyicy" :class="{ wide: !narrow }"> <div v-if="!narrow || currentPage?.route.name == null" class="nav"> - <MkSpacer :content-max="700" :margin-min="16"> + <MkSpacer :contentMax="700" :marginMin="16"> <div class="lxpfedzu"> <div class="banner"> <img :src="instance.iconUrl || '/favicon.ico'" alt="" class="icon"/> diff --git a/packages/frontend/src/pages/admin/instance-block.vue b/packages/frontend/src/pages/admin/instance-block.vue index 7a4937093e..e5f3816c82 100644 --- a/packages/frontend/src/pages/admin/instance-block.vue +++ b/packages/frontend/src/pages/admin/instance-block.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <MkTextarea v-model="blockedHosts"> <span>{{ i18n.ts.blockedInstances }}</span> diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue index bf788e3609..e36c9ac91d 100644 --- a/packages/frontend/src/pages/admin/moderation.vue +++ b/packages/frontend/src/pages/admin/moderation.vue @@ -2,7 +2,7 @@ <div> <MkStickyContainer> <template #header><XHeader :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <div class="_gaps_m"> <MkSwitch v-model="enableRegistration"> @@ -34,7 +34,7 @@ </MkSpacer> <template #footer> <div :class="$style.footer"> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="16"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="16"> <MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> </MkSpacer> </div> diff --git a/packages/frontend/src/pages/admin/object-storage.vue b/packages/frontend/src/pages/admin/object-storage.vue index 704b27c174..e569aad1b8 100644 --- a/packages/frontend/src/pages/admin/object-storage.vue +++ b/packages/frontend/src/pages/admin/object-storage.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <div class="_gaps_m"> <MkSwitch v-model="useObjectStorage">{{ i18n.ts.useObjectStorage }}</MkSwitch> @@ -33,7 +33,7 @@ <template #caption>{{ i18n.ts.objectStorageRegionDesc }}</template> </MkInput> - <FormSplit :min-width="280"> + <FormSplit :minWidth="280"> <MkInput v-model="objectStorageAccessKey"> <template #prefix><i class="ti ti-key"></i></template> <template #label>Access key</template> @@ -69,7 +69,7 @@ </MkSpacer> <template #footer> <div :class="$style.footer"> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="16"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="16"> <MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> </MkSpacer> </div> diff --git a/packages/frontend/src/pages/admin/overview.instances.vue b/packages/frontend/src/pages/admin/overview.instances.vue index 6c2ffd4742..d349b32322 100644 --- a/packages/frontend/src/pages/admin/overview.instances.vue +++ b/packages/frontend/src/pages/admin/overview.instances.vue @@ -1,9 +1,9 @@ <template> -<div class="wbrkwale"> +<div> <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in"> <MkLoading v-if="fetching"/> - <div v-else class="instances"> - <MkA v-for="(instance, i) in instances" :key="instance.id" v-tooltip.mfm.noDelay="`${instance.name}\n${instance.host}\n${instance.softwareName} ${instance.softwareVersion}`" :to="`/instance-info/${instance.host}`" class="instance"> + <div v-else :class="$style.instances"> + <MkA v-for="(instance, i) in instances" :key="instance.id" v-tooltip.mfm.noDelay="`${instance.name}\n${instance.host}\n${instance.softwareName} ${instance.softwareVersion}`" :to="`/instance-info/${instance.host}`" :class="$style.instance"> <MkInstanceCardMini :instance="instance"/> </MkA> </div> @@ -36,16 +36,14 @@ useInterval(fetch, 1000 * 60, { }); </script> -<style lang="scss" scoped> -.wbrkwale { - > .instances { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); - grid-gap: 12px; +<style lang="scss" module> +.instances { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + grid-gap: 12px; +} - > .instance:hover { - text-decoration: none; - } - } +.instance:hover { + text-decoration: none; } </style> diff --git a/packages/frontend/src/pages/admin/overview.vue b/packages/frontend/src/pages/admin/overview.vue index 46a93ac5d8..e8295c81b5 100644 --- a/packages/frontend/src/pages/admin/overview.vue +++ b/packages/frontend/src/pages/admin/overview.vue @@ -1,5 +1,5 @@ <template> -<MkSpacer :content-max="1000"> +<MkSpacer :contentMax="1000"> <div ref="rootEl" :class="$style.root"> <MkFoldableSection class="item"> <template #header>Stats</template> diff --git a/packages/frontend/src/pages/admin/proxy-account.vue b/packages/frontend/src/pages/admin/proxy-account.vue index 6ad566187a..c81f50a0d2 100644 --- a/packages/frontend/src/pages/admin/proxy-account.vue +++ b/packages/frontend/src/pages/admin/proxy-account.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <MkInfo>{{ i18n.ts.proxyAccountDescription }}</MkInfo> <MkKeyValue> diff --git a/packages/frontend/src/pages/admin/queue.chart.vue b/packages/frontend/src/pages/admin/queue.chart.vue index 728f3b2c80..3ad8324d63 100644 --- a/packages/frontend/src/pages/admin/queue.chart.vue +++ b/packages/frontend/src/pages/admin/queue.chart.vue @@ -1,30 +1,30 @@ <template> -<div class="pumxzjhg _gaps"> +<div class="_gaps"> <div :class="$style.status"> - <div class="item _panel"><div class="label">Process</div>{{ number(activeSincePrevTick) }}</div> - <div class="item _panel"><div class="label">Active</div>{{ number(active) }}</div> - <div class="item _panel"><div class="label">Waiting</div>{{ number(waiting) }}</div> - <div class="item _panel"><div class="label">Delayed</div>{{ number(delayed) }}</div> + <div :class="$style.statusItem" class="_panel"><div :class="$style.statusLabel">Process</div>{{ number(activeSincePrevTick) }}</div> + <div :class="$style.statusItem" class="_panel"><div :class="$style.statusLabel">Active</div>{{ number(active) }}</div> + <div :class="$style.statusItem" class="_panel"><div :class="$style.statusLabel">Waiting</div>{{ number(waiting) }}</div> + <div :class="$style.statusItem" class="_panel"><div :class="$style.statusLabel">Delayed</div>{{ number(delayed) }}</div> </div> - <div class="charts"> - <div class="chart"> - <div class="title">Process</div> + <div :class="$style.charts"> + <div :class="$style.chart"> + <div :class="$style.chartTitle">Process</div> <XChart ref="chartProcess" type="process"/> </div> - <div class="chart"> - <div class="title">Active</div> + <div :class="$style.chart"> + <div :class="$style.chartTitle">Active</div> <XChart ref="chartActive" type="active"/> </div> - <div class="chart"> - <div class="title">Delayed</div> + <div :class="$style.chart"> + <div :class="$style.chartTitle">Delayed</div> <XChart ref="chartDelayed" type="delayed"/> </div> - <div class="chart"> - <div class="title">Waiting</div> + <div :class="$style.chart"> + <div :class="$style.chartTitle">Waiting</div> <XChart ref="chartWaiting" type="waiting"/> </div> </div> - <MkFolder :default-open="true" :max-height="250"> + <MkFolder :defaultOpen="true" :max-height="250"> <template #icon><i class="ti ti-alert-triangle"></i></template> <template #label>Errored instances</template> <template #suffix>({{ number(jobs.reduce((a, b) => a + b[1], 0)) }} jobs)</template> @@ -118,43 +118,37 @@ onUnmounted(() => { }); </script> -<style lang="scss" scoped> -.pumxzjhg { - > .charts { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; - - > .chart { - min-width: 0; - padding: 16px; - background: var(--panel); - border-radius: var(--radius); - - > .title { - margin-bottom: 8px; - } - } - } -} -</style> - <style lang="scss" module> +.charts { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; +} + +.chart { + min-width: 0; + padding: 16px; + background: var(--panel); + border-radius: var(--radius); +} + +.chartTitle { + margin-bottom: 8px; +} + .status { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); grid-gap: 10px; +} - &:global { - > .item { - padding: 12px 16px; +.statusItem { + padding: 12px 16px; +} - > .label { - font-size: 80%; - opacity: 0.6; - } - } - } +.statusLabel { + font-size: 80%; + opacity: 0.6; } .jobs { diff --git a/packages/frontend/src/pages/admin/queue.vue b/packages/frontend/src/pages/admin/queue.vue index 509d329eb1..1282a4b49f 100644 --- a/packages/frontend/src/pages/admin/queue.vue +++ b/packages/frontend/src/pages/admin/queue.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <XQueue v-if="tab === 'deliver'" domain="deliver"/> <XQueue v-else-if="tab === 'inbox'" domain="inbox"/> <br> diff --git a/packages/frontend/src/pages/admin/relays.vue b/packages/frontend/src/pages/admin/relays.vue index 7ebcdfc583..c82e7e1e00 100644 --- a/packages/frontend/src/pages/admin/relays.vue +++ b/packages/frontend/src/pages/admin/relays.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800"> + <MkSpacer :contentMax="800"> <div class="_gaps"> <div v-for="relay in relays" :key="relay.inbox" class="relaycxt _panel" style="padding: 16px;"> <div>{{ relay.inbox }}</div> diff --git a/packages/frontend/src/pages/admin/roles.edit.vue b/packages/frontend/src/pages/admin/roles.edit.vue index c211ef2f05..c7a34ac77b 100644 --- a/packages/frontend/src/pages/admin/roles.edit.vue +++ b/packages/frontend/src/pages/admin/roles.edit.vue @@ -2,12 +2,12 @@ <div> <MkStickyContainer> <template #header><XHeader :tabs="headerTabs"/></template> - <MkSpacer :content-max="600" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="600" :marginMin="16" :marginMax="32"> <XEditor v-if="data" v-model="data"/> </MkSpacer> <template #footer> <div :class="$style.footer"> - <MkSpacer :content-max="600" :margin-min="16" :margin-max="16"> + <MkSpacer :contentMax="600" :marginMin="16" :marginMax="16"> <MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> </MkSpacer> </div> diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index 49942c87ce..a1fa9d2932 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -36,7 +36,7 @@ <option value="conditional">{{ i18n.ts._role.conditional }}</option> </MkSelect> - <MkFolder v-if="role.target === 'conditional'" default-open> + <MkFolder v-if="role.target === 'conditional'" defaultOpen> <template #label>{{ i18n.ts._role.condition }}</template> <div class="_gaps"> <RolesEditorFormula v-model="role.condFormula"/> @@ -81,11 +81,11 @@ <MkSwitch v-model="role.policies.rateLimitFactor.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts._role.useBaseValue }}</template> </MkSwitch> - <MkRange :model-value="role.policies.rateLimitFactor.value * 100" :min="0" :max="400" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => role.policies.rateLimitFactor.value = (v / 100)"> + <MkRange :modelValue="role.policies.rateLimitFactor.value * 100" :min="0" :max="400" :step="10" :textConverter="(v) => `${v}%`" @update:modelValue="v => role.policies.rateLimitFactor.value = (v / 100)"> <template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template> <template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template> </MkRange> - <MkRange v-model="role.policies.rateLimitFactor.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.rateLimitFactor.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -105,7 +105,7 @@ <MkSwitch v-model="role.policies.gtlAvailable.value" :disabled="role.policies.gtlAvailable.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.gtlAvailable.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.gtlAvailable.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -125,7 +125,7 @@ <MkSwitch v-model="role.policies.ltlAvailable.value" :disabled="role.policies.ltlAvailable.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.ltlAvailable.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.ltlAvailable.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -145,7 +145,7 @@ <MkSwitch v-model="role.policies.canPublicNote.value" :disabled="role.policies.canPublicNote.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.canPublicNote.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.canPublicNote.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -165,7 +165,7 @@ <MkSwitch v-model="role.policies.canInvite.value" :disabled="role.policies.canInvite.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.canInvite.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.canInvite.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -185,7 +185,7 @@ <MkSwitch v-model="role.policies.canManageCustomEmojis.value" :disabled="role.policies.canManageCustomEmojis.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.canManageCustomEmojis.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.canManageCustomEmojis.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -205,7 +205,7 @@ <MkSwitch v-model="role.policies.canSearchNotes.value" :disabled="role.policies.canSearchNotes.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.canSearchNotes.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.canSearchNotes.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -225,7 +225,7 @@ <MkInput v-model="role.policies.driveCapacityMb.value" :disabled="role.policies.driveCapacityMb.useDefault" type="number" :readonly="readonly"> <template #suffix>MB</template> </MkInput> - <MkRange v-model="role.policies.driveCapacityMb.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.driveCapacityMb.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -245,7 +245,7 @@ <MkSwitch v-model="role.policies.alwaysMarkNsfw.value" :disabled="role.policies.alwaysMarkNsfw.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.alwaysMarkNsfw.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.alwaysMarkNsfw.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -264,7 +264,7 @@ </MkSwitch> <MkInput v-model="role.policies.pinLimit.value" :disabled="role.policies.pinLimit.useDefault" type="number" :readonly="readonly"> </MkInput> - <MkRange v-model="role.policies.pinLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.pinLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -283,7 +283,7 @@ </MkSwitch> <MkInput v-model="role.policies.antennaLimit.value" :disabled="role.policies.antennaLimit.useDefault" type="number" :readonly="readonly"> </MkInput> - <MkRange v-model="role.policies.antennaLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.antennaLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -303,7 +303,7 @@ <MkInput v-model="role.policies.wordMuteLimit.value" :disabled="role.policies.wordMuteLimit.useDefault" type="number" :readonly="readonly"> <template #suffix>chars</template> </MkInput> - <MkRange v-model="role.policies.wordMuteLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.wordMuteLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -322,7 +322,7 @@ </MkSwitch> <MkInput v-model="role.policies.webhookLimit.value" :disabled="role.policies.webhookLimit.useDefault" type="number" :readonly="readonly"> </MkInput> - <MkRange v-model="role.policies.webhookLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.webhookLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -341,7 +341,7 @@ </MkSwitch> <MkInput v-model="role.policies.clipLimit.value" :disabled="role.policies.clipLimit.useDefault" type="number" :readonly="readonly"> </MkInput> - <MkRange v-model="role.policies.clipLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.clipLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -360,7 +360,7 @@ </MkSwitch> <MkInput v-model="role.policies.noteEachClipsLimit.value" :disabled="role.policies.noteEachClipsLimit.useDefault" type="number" :readonly="readonly"> </MkInput> - <MkRange v-model="role.policies.noteEachClipsLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.noteEachClipsLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -379,7 +379,7 @@ </MkSwitch> <MkInput v-model="role.policies.userListLimit.value" :disabled="role.policies.userListLimit.useDefault" type="number" :readonly="readonly"> </MkInput> - <MkRange v-model="role.policies.userListLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.userListLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -398,7 +398,7 @@ </MkSwitch> <MkInput v-model="role.policies.userEachUserListsLimit.value" :disabled="role.policies.userEachUserListsLimit.useDefault" type="number" :readonly="readonly"> </MkInput> - <MkRange v-model="role.policies.userEachUserListsLimit.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.userEachUserListsLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> @@ -418,7 +418,7 @@ <MkSwitch v-model="role.policies.canHideAds.value" :disabled="role.policies.canHideAds.useDefault" :readonly="readonly"> <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> - <MkRange v-model="role.policies.canHideAds.priority" :min="0" :max="2" :step="1" easing :text-converter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> + <MkRange v-model="role.policies.canHideAds.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''"> <template #label>{{ i18n.ts._role.priority }}</template> </MkRange> </div> diff --git a/packages/frontend/src/pages/admin/server-rules.vue b/packages/frontend/src/pages/admin/server-rules.vue index 85781c0bd0..2e4aba5fe4 100644 --- a/packages/frontend/src/pages/admin/server-rules.vue +++ b/packages/frontend/src/pages/admin/server-rules.vue @@ -2,13 +2,13 @@ <div> <MkStickyContainer> <template #header><XHeader :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <div class="_gaps_m"> <div>{{ i18n.ts._serverRules.description }}</div> <Sortable v-model="serverRules" class="_gaps_m" - :item-key="(_, i) => i" + :itemKey="(_, i) => i" :animation="150" :handle="'.' + $style.itemHandle" @start="e => e.item.classList.add('active')" diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index 819ced826d..1af661a475 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -2,7 +2,7 @@ <div> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="900"> + <MkSpacer :contentMax="900"> <div class="_gaps"> <div :class="$style.inputs"> <MkSelect v-model="sort" style="flex: 1;"> @@ -28,11 +28,11 @@ </MkSelect> </div> <div :class="$style.inputs"> - <MkInput v-model="searchUsername" style="flex: 1;" type="text" :spellcheck="false" @update:model-value="$refs.users.reload()"> + <MkInput v-model="searchUsername" style="flex: 1;" type="text" :spellcheck="false" @update:modelValue="$refs.users.reload()"> <template #prefix>@</template> <template #label>{{ i18n.ts.username }}</template> </MkInput> - <MkInput v-model="searchHost" style="flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params.origin === 'local'" @update:model-value="$refs.users.reload()"> + <MkInput v-model="searchHost" style="flex: 1;" type="text" :spellcheck="false" :disabled="pagination.params.origin === 'local'" @update:modelValue="$refs.users.reload()"> <template #prefix>@</template> <template #label>{{ i18n.ts.host }}</template> </MkInput> diff --git a/packages/frontend/src/pages/flash/flash-edit.vue b/packages/frontend/src/pages/flash/flash-edit.vue index a3daa8ea46..6a16cd1c4a 100644 --- a/packages/frontend/src/pages/flash/flash-edit.vue +++ b/packages/frontend/src/pages/flash/flash-edit.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div class="_gaps"> <MkInput v-model="title"> <template #label>{{ i18n.ts._play.title }}</template> diff --git a/packages/frontend/src/pages/flash/flash-index.vue b/packages/frontend/src/pages/flash/flash-index.vue index f1dca5f240..0fd5527a85 100644 --- a/packages/frontend/src/pages/flash/flash-index.vue +++ b/packages/frontend/src/pages/flash/flash-index.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div v-if="tab === 'featured'" class=""> <MkPagination v-slot="{items}" :pagination="featuredFlashsPagination"> <div class="_gaps_s"> diff --git a/packages/frontend/src/pages/flash/flash.vue b/packages/frontend/src/pages/flash/flash.vue index 961ef4b751..2e1532b9f3 100644 --- a/packages/frontend/src/pages/flash/flash.vue +++ b/packages/frontend/src/pages/flash/flash.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in"> <div v-if="flash" :key="flash.id"> <Transition :name="defaultStore.state.animation ? 'zoom' : ''" mode="out-in"> @@ -10,8 +10,8 @@ <MkAsUi v-if="root" :component="root" :components="components"/> </div> <div class="actions _panel"> - <MkButton v-if="flash.isLiked" v-tooltip="i18n.ts.unlike" as-like class="button" rounded primary @click="unlike()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton> - <MkButton v-else v-tooltip="i18n.ts.like" as-like class="button" rounded @click="like()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton> + <MkButton v-if="flash.isLiked" v-tooltip="i18n.ts.unlike" asLike class="button" rounded primary @click="unlike()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton> + <MkButton v-else v-tooltip="i18n.ts.like" asLike class="button" rounded @click="like()"><i class="ti ti-heart"></i><span v-if="flash.likedCount > 0" style="margin-left: 6px;">{{ flash.likedCount }}</span></MkButton> <MkButton v-tooltip="i18n.ts.shareWithNote" class="button" rounded @click="shareWithNote"><i class="ti ti-repeat ti-fw"></i></MkButton> <MkButton v-tooltip="i18n.ts.share" class="button" rounded @click="share"><i class="ti ti-share ti-fw"></i></MkButton> </div> @@ -27,7 +27,7 @@ </div> </div> </Transition> - <MkFolder :default-open="false" :max-height="280" class="_margin"> + <MkFolder :defaultOpen="false" :max-height="280" class="_margin"> <template #icon><i class="ti ti-code"></i></template> <template #label>{{ i18n.ts._play.viewSource }}</template> diff --git a/packages/frontend/src/pages/my-antennas/create.vue b/packages/frontend/src/pages/my-antennas/create.vue index 14ab18a3df..355d18fdb5 100644 --- a/packages/frontend/src/pages/my-antennas/create.vue +++ b/packages/frontend/src/pages/my-antennas/create.vue @@ -1,5 +1,5 @@ <template> -<div class="geegznzt"> +<div> <XAntenna :antenna="draft" @created="onAntennaCreated"/> </div> </template> diff --git a/packages/frontend/src/pages/my-antennas/editor.vue b/packages/frontend/src/pages/my-antennas/editor.vue index dd5f3222af..ed92208c42 100644 --- a/packages/frontend/src/pages/my-antennas/editor.vue +++ b/packages/frontend/src/pages/my-antennas/editor.vue @@ -1,5 +1,5 @@ <template> -<MkSpacer :content-max="700"> +<MkSpacer :contentMax="700"> <div> <div class="_gaps_m"> <MkInput v-model="name"> diff --git a/packages/frontend/src/pages/my-antennas/index.vue b/packages/frontend/src/pages/my-antennas/index.vue index f1764b1aad..2ca026b9a1 100644 --- a/packages/frontend/src/pages/my-antennas/index.vue +++ b/packages/frontend/src/pages/my-antennas/index.vue @@ -1,18 +1,20 @@ -<template><MkStickyContainer> +<template> +<MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> - <div class="ieepwinx"> - <MkButton :link="true" to="/my/antennas/create" primary class="add"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> + <MkSpacer :contentMax="700"> + <div class="ieepwinx"> + <MkButton :link="true" to="/my/antennas/create" primary class="add"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> - <div class=""> - <MkPagination v-slot="{items}" ref="list" :pagination="pagination"> - <MkA v-for="antenna in items" :key="antenna.id" class="ljoevbzj" :to="`/my/antennas/${antenna.id}`"> - <div class="name">{{ antenna.name }}</div> - </MkA> - </MkPagination> + <div class=""> + <MkPagination v-slot="{items}" ref="list" :pagination="pagination"> + <MkA v-for="antenna in items" :key="antenna.id" class="ljoevbzj" :to="`/my/antennas/${antenna.id}`"> + <div class="name">{{ antenna.name }}</div> + </MkA> + </MkPagination> + </div> </div> - </div> -</MkSpacer></MkStickyContainer> + </MkSpacer> +</MkStickyContainer> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/pages/my-clips/index.vue b/packages/frontend/src/pages/my-clips/index.vue index ccffa7b563..a769f8ee97 100644 --- a/packages/frontend/src/pages/my-clips/index.vue +++ b/packages/frontend/src/pages/my-clips/index.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div v-if="tab === 'my'" class="_gaps"> <MkButton primary rounded class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> diff --git a/packages/frontend/src/pages/my-lists/index.vue b/packages/frontend/src/pages/my-lists/index.vue index 6068e375ea..e4b6f0e5bc 100644 --- a/packages/frontend/src/pages/my-lists/index.vue +++ b/packages/frontend/src/pages/my-lists/index.vue @@ -1,14 +1,14 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div class="qkcjvfiv"> <MkButton primary class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton> <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="lists"> <MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`"> <div class="name">{{ list.name }}</div> - <MkAvatars :user-ids="list.userIds"/> + <MkAvatars :userIds="list.userIds"/> </MkA> </MkPagination> </div> diff --git a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue index 2c3d59256c..24b9cb4065 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue @@ -1,9 +1,9 @@ <template> -<Sortable :model-value="modelValue" tag="div" item-key="id" handle=".drag-handle" :group="{ name: 'blocks' }" :animation="150" :swap-threshold="0.5" @update:model-value="v => $emit('update:modelValue', v)"> +<Sortable :modelValue="modelValue" tag="div" itemKey="id" handle=".drag-handle" :group="{ name: 'blocks' }" :animation="150" :swapThreshold="0.5" @update:modelValue="v => $emit('update:modelValue', v)"> <template #item="{element}"> <div :class="$style.item"> <!-- divが無いとエラーになる https://github.com/SortableJS/vue.draggable.next/issues/189 --> - <component :is="'x-' + element.type" :model-value="element" @update:model-value="updateItem" @remove="() => removeItem(element)"/> + <component :is="'x-' + element.type" :modelValue="element" @update:modelValue="updateItem" @remove="() => removeItem(element)"/> </div> </template> </Sortable> diff --git a/packages/frontend/src/pages/page-editor/page-editor.vue b/packages/frontend/src/pages/page-editor/page-editor.vue index bcf30e23a7..bd54699dc4 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div class="jqqmcavi"> <MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="ti ti-external-link"></i> {{ i18n.ts._pages.viewPage }}</MkButton> <MkButton v-if="!readonly" inline primary class="button" @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> diff --git a/packages/frontend/src/pages/settings/2fa.qrdialog.vue b/packages/frontend/src/pages/settings/2fa.qrdialog.vue index 1d836db5f5..6a798b5626 100644 --- a/packages/frontend/src/pages/settings/2fa.qrdialog.vue +++ b/packages/frontend/src/pages/settings/2fa.qrdialog.vue @@ -1,8 +1,8 @@ <template> <MkModal ref="dialogEl" - :prefer-type="'dialog'" - :z-priority="'low'" + :preferType="'dialog'" + :zPriority="'low'" @click="cancel" @close="cancel" @closed="emit('closed')" diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue index 891934d706..aff7765ed5 100644 --- a/packages/frontend/src/pages/settings/2fa.vue +++ b/packages/frontend/src/pages/settings/2fa.vue @@ -51,7 +51,7 @@ </div> </MkFolder> - <MkSwitch :disabled="!$i.twoFactorEnabled || $i.securityKeysList.length === 0" :model-value="usePasswordLessLogin" @update:model-value="v => updatePasswordLessLogin(v)"> + <MkSwitch :disabled="!$i.twoFactorEnabled || $i.securityKeysList.length === 0" :modelValue="usePasswordLessLogin" @update:modelValue="v => updatePasswordLessLogin(v)"> <template #label>{{ i18n.ts.passwordLessLogin }}</template> <template #caption>{{ i18n.ts.passwordLessLoginDescription }}</template> </MkSwitch> diff --git a/packages/frontend/src/pages/settings/accounts.vue b/packages/frontend/src/pages/settings/accounts.vue index a58e74fe69..78479be973 100644 --- a/packages/frontend/src/pages/settings/accounts.vue +++ b/packages/frontend/src/pages/settings/accounts.vue @@ -15,13 +15,13 @@ <script lang="ts" setup> import { defineAsyncComponent, ref } from 'vue'; +import type * as Misskey from 'misskey-js'; import FormSuspense from '@/components/form/suspense.vue'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os'; import { getAccounts, addAccount as addAccounts, removeAccount as _removeAccount, login, $i } from '@/account'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; -import type * as Misskey from 'misskey-js'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; const storedAccounts = ref<any>(null); diff --git a/packages/frontend/src/pages/settings/custom-css.vue b/packages/frontend/src/pages/settings/custom-css.vue index 456c3742c5..970d5689b4 100644 --- a/packages/frontend/src/pages/settings/custom-css.vue +++ b/packages/frontend/src/pages/settings/custom-css.vue @@ -2,7 +2,7 @@ <div class="_gaps_m"> <FormInfo warn>{{ i18n.ts.customCssWarn }}</FormInfo> - <MkTextarea v-model="localCustomCss" manual-save tall class="_monospace" style="tab-size: 2;"> + <MkTextarea v-model="localCustomCss" manualSave tall class="_monospace" style="tab-size: 2;"> <template #label>CSS</template> </MkTextarea> </div> diff --git a/packages/frontend/src/pages/settings/drive.vue b/packages/frontend/src/pages/settings/drive.vue index 73c2b2e604..6ff98bc977 100644 --- a/packages/frontend/src/pages/settings/drive.vue +++ b/packages/frontend/src/pages/settings/drive.vue @@ -22,7 +22,7 @@ <FormSection> <template #label>{{ i18n.ts.statistics }}</template> - <MkChart src="per-user-drive" :args="{ user: $i }" span="day" :limit="7 * 5" :bar="true" :stacked="true" :detailed="false" :aspect-ratio="6"/> + <MkChart src="per-user-drive" :args="{ user: $i }" span="day" :limit="7 * 5" :bar="true" :stacked="true" :detailed="false" :aspectRatio="6"/> </FormSection> <FormSection> @@ -39,10 +39,10 @@ <template #label>{{ i18n.ts.keepOriginalUploading }}</template> <template #caption>{{ i18n.ts.keepOriginalUploadingDescription }}</template> </MkSwitch> - <MkSwitch v-model="alwaysMarkNsfw" @update:model-value="saveProfile()"> + <MkSwitch v-model="alwaysMarkNsfw" @update:modelValue="saveProfile()"> <template #label>{{ i18n.ts.alwaysMarkSensitive }}</template> </MkSwitch> - <MkSwitch v-model="autoSensitive" @update:model-value="saveProfile()"> + <MkSwitch v-model="autoSensitive" @update:modelValue="saveProfile()"> <template #label>{{ i18n.ts.enableAutoSensitive }}<span class="_beta">{{ i18n.ts.beta }}</span></template> <template #caption>{{ i18n.ts.enableAutoSensitiveDescription }}</template> </MkSwitch> diff --git a/packages/frontend/src/pages/settings/email.vue b/packages/frontend/src/pages/settings/email.vue index b1e6f223b6..d015cec154 100644 --- a/packages/frontend/src/pages/settings/email.vue +++ b/packages/frontend/src/pages/settings/email.vue @@ -2,7 +2,7 @@ <div v-if="instance.enableEmail" class="_gaps_m"> <FormSection first> <template #label>{{ i18n.ts.emailAddress }}</template> - <MkInput v-model="emailAddress" type="email" manual-save> + <MkInput v-model="emailAddress" type="email" manualSave> <template #prefix><i class="ti ti-mail"></i></template> <template v-if="$i.email && !$i.emailVerified" #caption>{{ i18n.ts.verificationEmailSent }}</template> <template v-else-if="emailAddress === $i.email && $i.emailVerified" #caption><i class="ti ti-check" style="color: var(--success);"></i> {{ i18n.ts.emailVerified }}</template> @@ -10,7 +10,7 @@ </FormSection> <FormSection> - <MkSwitch :model-value="$i.receiveAnnouncementEmail" @update:model-value="onChangeReceiveAnnouncementEmail"> + <MkSwitch :modelValue="$i.receiveAnnouncementEmail" @update:modelValue="onChangeReceiveAnnouncementEmail"> {{ i18n.ts.receiveAnnouncementFromInstance }} </MkSwitch> </FormSection> diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index 34a962ef4c..b4f056d8a6 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="900" :margin-min="20" :margin-max="32"> + <MkSpacer :contentMax="900" :marginMin="20" :marginMax="32"> <div ref="el" class="vvcocwet" :class="{ wide: !narrow }"> <div class="body"> <div v-if="!narrow || currentPage?.route.name == null" class="nav"> diff --git a/packages/frontend/src/pages/settings/migration.vue b/packages/frontend/src/pages/settings/migration.vue index 541992875e..102bc68523 100644 --- a/packages/frontend/src/pages/settings/migration.vue +++ b/packages/frontend/src/pages/settings/migration.vue @@ -3,7 +3,7 @@ <FormInfo warn> {{ i18n.ts.thisIsExperimentalFeature }} </FormInfo> - <MkFolder :default-open="true"> + <MkFolder :defaultOpen="true"> <template #icon><i class="ti ti-plane-arrival"></i></template> <template #label>{{ i18n.ts._accountMigration.moveFrom }}</template> <template #caption>{{ i18n.ts._accountMigration.moveFromSub }}</template> @@ -25,7 +25,7 @@ </div> </MkFolder> - <MkFolder :default-open="!!$i?.movedTo"> + <MkFolder :defaultOpen="!!$i?.movedTo"> <template #icon><i class="ti ti-plane-departure"></i></template> <template #label>{{ i18n.ts._accountMigration.moveTo }}</template> @@ -48,7 +48,7 @@ <FormInfo>{{ i18n.ts._accountMigration.postMigrationNote }}</FormInfo> <FormInfo warn>{{ i18n.ts._accountMigration.movedAndCannotBeUndone }}</FormInfo> <div>{{ i18n.ts._accountMigration.movedTo }}</div> - <MkUserInfo v-if="movedTo" :user="movedTo" class="_panel _shadow" /> + <MkUserInfo v-if="movedTo" :user="movedTo" class="_panel _shadow"/> </template> </div> </MkFolder> @@ -57,6 +57,8 @@ <script lang="ts" setup> import { ref } from 'vue'; +import { toString } from 'misskey-js/built/acct'; +import { UserDetailed } from 'misskey-js/built/entities'; import FormInfo from '@/components/MkInfo.vue'; import MkInput from '@/components/MkInput.vue'; import MkButton from '@/components/MkButton.vue'; @@ -66,8 +68,6 @@ import * as os from '@/os'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import { $i } from '@/account'; -import { toString } from 'misskey-js/built/acct'; -import { UserDetailed } from 'misskey-js/built/entities'; import { unisonReload } from '@/scripts/unison-reload'; const moveToAccount = ref(''); diff --git a/packages/frontend/src/pages/settings/navbar.vue b/packages/frontend/src/pages/settings/navbar.vue index b3b33b8026..8780bfbc1e 100644 --- a/packages/frontend/src/pages/settings/navbar.vue +++ b/packages/frontend/src/pages/settings/navbar.vue @@ -2,10 +2,10 @@ <div class="_gaps_m"> <FormSlot> <template #label>{{ i18n.ts.navbar }}</template> - <MkContainer :show-header="false"> + <MkContainer :showHeader="false"> <Sortable v-model="items" - item-key="id" + itemKey="id" :animation="150" :handle="'.' + $style.itemHandle" @start="e => e.item.classList.add('active')" diff --git a/packages/frontend/src/pages/settings/notifications.vue b/packages/frontend/src/pages/settings/notifications.vue index 2cf2f6d7f6..2552db4198 100644 --- a/packages/frontend/src/pages/settings/notifications.vue +++ b/packages/frontend/src/pages/settings/notifications.vue @@ -12,7 +12,7 @@ <div class="_gaps_m"> <MkPushNotificationAllowButton ref="allowButton"/> - <MkSwitch :disabled="!pushRegistrationInServer" :model-value="sendReadMessage" @update:model-value="onChangeSendReadMessage"> + <MkSwitch :disabled="!pushRegistrationInServer" :modelValue="sendReadMessage" @update:modelValue="onChangeSendReadMessage"> <template #label>{{ i18n.ts.sendPushNotificationReadMessage }}</template> <template #caption> <I18n :src="i18n.ts.sendPushNotificationReadMessageCaption"> diff --git a/packages/frontend/src/pages/settings/plugin.vue b/packages/frontend/src/pages/settings/plugin.vue index f90ca737e9..75fae014f8 100644 --- a/packages/frontend/src/pages/settings/plugin.vue +++ b/packages/frontend/src/pages/settings/plugin.vue @@ -8,7 +8,7 @@ <div v-for="plugin in plugins" :key="plugin.id" class="_panel _gaps_s" style="padding: 20px;"> <span style="display: flex;"><b>{{ plugin.name }}</b><span style="margin-left: auto;">v{{ plugin.version }}</span></span> - <MkSwitch :model-value="plugin.active" @update:model-value="changeActive(plugin, $event)">{{ i18n.ts.makeActive }}</MkSwitch> + <MkSwitch :modelValue="plugin.active" @update:modelValue="changeActive(plugin, $event)">{{ i18n.ts.makeActive }}</MkSwitch> <MkKeyValue> <template #key>{{ i18n.ts.author }}</template> diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue index a1af0ba80b..7fd4d6d34e 100644 --- a/packages/frontend/src/pages/settings/privacy.vue +++ b/packages/frontend/src/pages/settings/privacy.vue @@ -1,14 +1,14 @@ <template> <div class="_gaps_m"> - <MkSwitch v-model="isLocked" @update:model-value="save()">{{ i18n.ts.makeFollowManuallyApprove }}<template #caption>{{ i18n.ts.lockedAccountInfo }}</template></MkSwitch> - <MkSwitch v-if="isLocked" v-model="autoAcceptFollowed" @update:model-value="save()">{{ i18n.ts.autoAcceptFollowed }}</MkSwitch> + <MkSwitch v-model="isLocked" @update:modelValue="save()">{{ i18n.ts.makeFollowManuallyApprove }}<template #caption>{{ i18n.ts.lockedAccountInfo }}</template></MkSwitch> + <MkSwitch v-if="isLocked" v-model="autoAcceptFollowed" @update:modelValue="save()">{{ i18n.ts.autoAcceptFollowed }}</MkSwitch> - <MkSwitch v-model="publicReactions" @update:model-value="save()"> + <MkSwitch v-model="publicReactions" @update:modelValue="save()"> {{ i18n.ts.makeReactionsPublic }} <template #caption>{{ i18n.ts.makeReactionsPublicDescription }}</template> </MkSwitch> - <MkSelect v-model="ffVisibility" @update:model-value="save()"> + <MkSelect v-model="ffVisibility" @update:modelValue="save()"> <template #label>{{ i18n.ts.ffVisibility }}</template> <option value="public">{{ i18n.ts._ffVisibility.public }}</option> <option value="followers">{{ i18n.ts._ffVisibility.followers }}</option> @@ -16,26 +16,26 @@ <template #caption>{{ i18n.ts.ffVisibilityDescription }}</template> </MkSelect> - <MkSwitch v-model="hideOnlineStatus" @update:model-value="save()"> + <MkSwitch v-model="hideOnlineStatus" @update:modelValue="save()"> {{ i18n.ts.hideOnlineStatus }} <template #caption>{{ i18n.ts.hideOnlineStatusDescription }}</template> </MkSwitch> - <MkSwitch v-model="noCrawle" @update:model-value="save()"> + <MkSwitch v-model="noCrawle" @update:modelValue="save()"> {{ i18n.ts.noCrawle }} <template #caption>{{ i18n.ts.noCrawleDescription }}</template> </MkSwitch> - <MkSwitch v-model="preventAiLearning" @update:model-value="save()"> + <MkSwitch v-model="preventAiLearning" @update:modelValue="save()"> {{ i18n.ts.preventAiLearning }}<span class="_beta">{{ i18n.ts.beta }}</span> <template #caption>{{ i18n.ts.preventAiLearningDescription }}</template> </MkSwitch> - <MkSwitch v-model="isExplorable" @update:model-value="save()"> + <MkSwitch v-model="isExplorable" @update:modelValue="save()"> {{ i18n.ts.makeExplorable }} <template #caption>{{ i18n.ts.makeExplorableDescription }}</template> </MkSwitch> <FormSection> <div class="_gaps_m"> - <MkSwitch v-model="rememberNoteVisibility" @update:model-value="save()">{{ i18n.ts.rememberNoteVisibility }}</MkSwitch> + <MkSwitch v-model="rememberNoteVisibility" @update:modelValue="save()">{{ i18n.ts.rememberNoteVisibility }}</MkSwitch> <MkFolder v-if="!rememberNoteVisibility"> <template #label>{{ i18n.ts.defaultNoteVisibility }}</template> <template v-if="defaultNoteVisibility === 'public'" #suffix>{{ i18n.ts._visibility.public }}</template> @@ -56,7 +56,7 @@ </div> </FormSection> - <MkSwitch v-model="keepCw" @update:model-value="save()">{{ i18n.ts.keepCw }}</MkSwitch> + <MkSwitch v-model="keepCw" @update:modelValue="save()">{{ i18n.ts.keepCw }}</MkSwitch> </div> </template> diff --git a/packages/frontend/src/pages/settings/reaction.vue b/packages/frontend/src/pages/settings/reaction.vue index 10169ccf18..cb483e34b5 100644 --- a/packages/frontend/src/pages/settings/reaction.vue +++ b/packages/frontend/src/pages/settings/reaction.vue @@ -3,7 +3,7 @@ <FromSlot> <template #label>{{ i18n.ts.reactionSettingDescription }}</template> <div v-panel style="border-radius: 6px;"> - <Sortable v-model="reactions" :class="$style.reactions" :item-key="item => item" :animation="150" :delay="100" :delay-on-touch-only="true"> + <Sortable v-model="reactions" :class="$style.reactions" :itemKey="item => item" :animation="150" :delay="100" :delayOnTouchOnly="true"> <template #item="{element}"> <button class="_button" :class="$style.reactionsItem" @click="remove(element, $event)"> <MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true"/> diff --git a/packages/frontend/src/pages/settings/roles.vue b/packages/frontend/src/pages/settings/roles.vue index ba510dced3..05753c9b60 100644 --- a/packages/frontend/src/pages/settings/roles.vue +++ b/packages/frontend/src/pages/settings/roles.vue @@ -3,7 +3,7 @@ <FormSection first> <template #label>{{ i18n.ts.rolesAssignedToMe }}</template> <div class="_gaps_s"> - <MkRolePreview v-for="role in $i.roles" :key="role.id" :role="role" :for-moderation="false"/> + <MkRolePreview v-for="role in $i.roles" :key="role.id" :role="role" :forModeration="false"/> </div> </FormSection> <FormSection> diff --git a/packages/frontend/src/pages/settings/security.vue b/packages/frontend/src/pages/settings/security.vue index 0cc2df09c5..2da84763a3 100644 --- a/packages/frontend/src/pages/settings/security.vue +++ b/packages/frontend/src/pages/settings/security.vue @@ -9,7 +9,7 @@ <FormSection> <template #label>{{ i18n.ts.signinHistory }}</template> - <MkPagination :pagination="pagination" disable-auto-load> + <MkPagination :pagination="pagination" disableAutoLoad> <template #default="{items}"> <div> <div v-for="item in items" :key="item.id" v-panel class="timnmucd"> diff --git a/packages/frontend/src/pages/settings/sounds.sound.vue b/packages/frontend/src/pages/settings/sounds.sound.vue index aa9f528006..c1a333548d 100644 --- a/packages/frontend/src/pages/settings/sounds.sound.vue +++ b/packages/frontend/src/pages/settings/sounds.sound.vue @@ -4,7 +4,7 @@ <template #label>{{ i18n.ts.sound }}</template> <option v-for="x in soundsTypes" :key="x" :value="x">{{ x == null ? i18n.ts.none : x }}</option> </MkSelect> - <MkRange v-model="volume" :min="0" :max="1" :step="0.05" :text-converter="(v) => `${Math.floor(v * 100)}%`"> + <MkRange v-model="volume" :min="0" :max="1" :step="0.05" :textConverter="(v) => `${Math.floor(v * 100)}%`"> <template #label>{{ i18n.ts.volume }}</template> </MkRange> diff --git a/packages/frontend/src/pages/settings/sounds.vue b/packages/frontend/src/pages/settings/sounds.vue index 724fe43478..c2bf3f8cd5 100644 --- a/packages/frontend/src/pages/settings/sounds.vue +++ b/packages/frontend/src/pages/settings/sounds.vue @@ -1,6 +1,6 @@ <template> <div class="_gaps_m"> - <MkRange v-model="masterVolume" :min="0" :max="1" :step="0.05" :text-converter="(v) => `${Math.floor(v * 100)}%`"> + <MkRange v-model="masterVolume" :min="0" :max="1" :step="0.05" :textConverter="(v) => `${Math.floor(v * 100)}%`"> <template #label>{{ i18n.ts.masterVolume }}</template> </MkRange> diff --git a/packages/frontend/src/pages/settings/statusbar.statusbar.vue b/packages/frontend/src/pages/settings/statusbar.statusbar.vue index 81ff873e9e..c73ff7c075 100644 --- a/packages/frontend/src/pages/settings/statusbar.statusbar.vue +++ b/packages/frontend/src/pages/settings/statusbar.statusbar.vue @@ -7,7 +7,7 @@ <option value="userList">User list timeline</option> </MkSelect> - <MkInput v-model="statusbar.name" manual-save> + <MkInput v-model="statusbar.name" manualSave> <template #label>{{ i18n.ts.label }}</template> </MkInput> @@ -25,13 +25,13 @@ </MkRadios> <template v-if="statusbar.type === 'rss'"> - <MkInput v-model="statusbar.props.url" manual-save type="url"> + <MkInput v-model="statusbar.props.url" manualSave type="url"> <template #label>URL</template> </MkInput> <MkSwitch v-model="statusbar.props.shuffle"> <template #label>{{ i18n.ts.shuffle }}</template> </MkSwitch> - <MkInput v-model="statusbar.props.refreshIntervalSec" manual-save type="number"> + <MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number"> <template #label>{{ i18n.ts.refreshInterval }}</template> </MkInput> <MkRange v-model="statusbar.props.marqueeDuration" :min="5" :max="150" :step="1"> @@ -43,7 +43,7 @@ </MkSwitch> </template> <template v-else-if="statusbar.type === 'federation'"> - <MkInput v-model="statusbar.props.refreshIntervalSec" manual-save type="number"> + <MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number"> <template #label>{{ i18n.ts.refreshInterval }}</template> </MkInput> <MkRange v-model="statusbar.props.marqueeDuration" :min="5" :max="150" :step="1"> @@ -62,7 +62,7 @@ <template #label>{{ i18n.ts.userList }}</template> <option v-for="list in userLists" :value="list.id">{{ list.name }}</option> </MkSelect> - <MkInput v-model="statusbar.props.refreshIntervalSec" manual-save type="number"> + <MkInput v-model="statusbar.props.refreshIntervalSec" manualSave type="number"> <template #label>{{ i18n.ts.refreshInterval }}</template> </MkInput> <MkRange v-model="statusbar.props.marqueeDuration" :min="5" :max="150" :step="1"> diff --git a/packages/frontend/src/pages/settings/statusbar.vue b/packages/frontend/src/pages/settings/statusbar.vue index f5a090a63b..bfb69936e1 100644 --- a/packages/frontend/src/pages/settings/statusbar.vue +++ b/packages/frontend/src/pages/settings/statusbar.vue @@ -3,7 +3,7 @@ <MkFolder v-for="x in statusbars" :key="x.id"> <template #label>{{ x.type ?? i18n.ts.notSet }}</template> <template #suffix>{{ x.name }}</template> - <XStatusbar :_id="x.id" :user-lists="userLists"/> + <XStatusbar :_id="x.id" :userLists="userLists"/> </MkFolder> <MkButton primary @click="add">{{ i18n.ts.add }}</MkButton> </div> diff --git a/packages/frontend/src/pages/settings/theme.manage.vue b/packages/frontend/src/pages/settings/theme.manage.vue index d1821a00d4..0255435112 100644 --- a/packages/frontend/src/pages/settings/theme.manage.vue +++ b/packages/frontend/src/pages/settings/theme.manage.vue @@ -10,13 +10,13 @@ </optgroup> </MkSelect> <template v-if="selectedTheme"> - <MkInput readonly :model-value="selectedTheme.author"> + <MkInput readonly :modelValue="selectedTheme.author"> <template #label>{{ i18n.ts.author }}</template> </MkInput> - <MkTextarea v-if="selectedTheme.desc" readonly :model-value="selectedTheme.desc"> + <MkTextarea v-if="selectedTheme.desc" readonly :modelValue="selectedTheme.desc"> <template #label>{{ i18n.ts._theme.description }}</template> </MkTextarea> - <MkTextarea readonly tall :model-value="selectedThemeCode"> + <MkTextarea readonly tall :modelValue="selectedThemeCode"> <template #label>{{ i18n.ts._theme.code }}</template> <template #caption><button class="_textButton" @click="copyThemeCode()">{{ i18n.ts.copy }}</button></template> </MkTextarea> diff --git a/packages/frontend/src/pages/user/achievements.vue b/packages/frontend/src/pages/user/achievements.vue index 1b3a6e24b3..7d5993c265 100644 --- a/packages/frontend/src/pages/user/achievements.vue +++ b/packages/frontend/src/pages/user/achievements.vue @@ -1,6 +1,6 @@ <template> -<MkSpacer :content-max="1200"> - <MkAchievements :user="user" :with-locked="false" :with-description="$i != null && (props.user.id === $i.id)"/> +<MkSpacer :contentMax="1200"> + <MkAchievements :user="user" :withLocked="false" :withDescription="$i != null && (props.user.id === $i.id)"/> </MkSpacer> </template> diff --git a/packages/frontend/src/pages/user/activity.vue b/packages/frontend/src/pages/user/activity.vue index cd538ad61f..dfdd7edb7d 100644 --- a/packages/frontend/src/pages/user/activity.vue +++ b/packages/frontend/src/pages/user/activity.vue @@ -1,5 +1,5 @@ <template> -<MkSpacer :content-max="700"> +<MkSpacer :contentMax="700"> <div class="_gaps"> <MkFoldableSection class="item"> <template #header><i class="ti ti-activity"></i> Heatmap</template> diff --git a/packages/frontend/src/pages/user/clips.vue b/packages/frontend/src/pages/user/clips.vue index 95f8cbc296..08b7b9a71f 100644 --- a/packages/frontend/src/pages/user/clips.vue +++ b/packages/frontend/src/pages/user/clips.vue @@ -1,10 +1,10 @@ <template> -<MkSpacer :content-max="700"> - <div class="pages-user-clips"> - <MkPagination v-slot="{items}" ref="list" :pagination="pagination" class="list"> - <MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _margin"> +<MkSpacer :contentMax="700"> + <div> + <MkPagination v-slot="{items}" ref="list" :pagination="pagination"> + <MkA v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" :class="$style.item" class="_panel _margin"> <b>{{ item.name }}</b> - <div v-if="item.description" class="description">{{ item.description }}</div> + <div v-if="item.description" :class="$style.description">{{ item.description }}</div> </MkA> </MkPagination> </div> @@ -29,19 +29,15 @@ const pagination = { }; </script> -<style lang="scss" scoped> -.pages-user-clips { - > .list { - > .item { - display: block; - padding: 16px; +<style lang="scss" module> +.item { + display: block; + padding: 16px; +} - > .description { - margin-top: 8px; - padding-top: 8px; - border-top: solid 0.5px var(--divider); - } - } - } +.description { + margin-top: 8px; + padding-top: 8px; + border-top: solid 0.5px var(--divider); } </style> diff --git a/packages/frontend/src/pages/user/follow-list.vue b/packages/frontend/src/pages/user/follow-list.vue index d42acd838f..4e76ddfe79 100644 --- a/packages/frontend/src/pages/user/follow-list.vue +++ b/packages/frontend/src/pages/user/follow-list.vue @@ -1,8 +1,8 @@ <template> <div> - <MkPagination v-slot="{items}" ref="list" :pagination="type === 'following' ? followingPagination : followersPagination" class="mk-following-or-followers"> - <div class="users"> - <MkUserInfo v-for="user in items.map(x => type === 'following' ? x.followee : x.follower)" :key="user.id" class="user" :user="user"/> + <MkPagination v-slot="{items}" ref="list" :pagination="type === 'following' ? followingPagination : followersPagination"> + <div :class="$style.users"> + <MkUserInfo v-for="user in items.map(x => type === 'following' ? x.followee : x.follower)" :key="user.id" :user="user"/> </div> </MkPagination> </div> @@ -36,12 +36,10 @@ const followersPagination = { }; </script> -<style lang="scss" scoped> -.mk-following-or-followers { - > .users { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); - grid-gap: var(--margin); - } +<style lang="scss" module> +.users { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + grid-gap: var(--margin); } </style> diff --git a/packages/frontend/src/pages/user/followers.vue b/packages/frontend/src/pages/user/followers.vue index 20573e67e9..7cbc5bee12 100644 --- a/packages/frontend/src/pages/user/followers.vue +++ b/packages/frontend/src/pages/user/followers.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="1000"> + <MkSpacer :contentMax="1000"> <Transition name="fade" mode="out-in"> <div v-if="user"> <XFollowList :user="user" type="followers"/> diff --git a/packages/frontend/src/pages/user/following.vue b/packages/frontend/src/pages/user/following.vue index 3825f138cf..c36bc0b839 100644 --- a/packages/frontend/src/pages/user/following.vue +++ b/packages/frontend/src/pages/user/following.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="1000"> + <MkSpacer :contentMax="1000"> <Transition name="fade" mode="out-in"> <div v-if="user"> <XFollowList :user="user" type="following"/> diff --git a/packages/frontend/src/pages/user/gallery.vue b/packages/frontend/src/pages/user/gallery.vue index b80e83fb11..b4bbab16fd 100644 --- a/packages/frontend/src/pages/user/gallery.vue +++ b/packages/frontend/src/pages/user/gallery.vue @@ -1,7 +1,7 @@ <template> -<MkSpacer :content-max="700"> +<MkSpacer :contentMax="700"> <MkPagination v-slot="{items}" :pagination="pagination"> - <div class="jrnovfpt"> + <div :class="$style.root"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> </div> </MkPagination> @@ -28,8 +28,8 @@ const pagination = { }; </script> -<style lang="scss" scoped> -.jrnovfpt { +<style lang="scss" module> +.root { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); grid-gap: 12px; diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index a39f206863..2e69eb367b 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -1,5 +1,5 @@ <template> -<MkSpacer :content-max="narrow ? 800 : 1100"> +<MkSpacer :contentMax="narrow ? 800 : 1100"> <div ref="rootEl" class="ftskorzw" :class="{ wide: !narrow }" style="container-type: inline-size;"> <div class="main _gaps"> <!-- TODO --> @@ -7,7 +7,7 @@ <!-- <div class="punished" v-if="user.isSilenced"><i class="ti ti-alert-triangle" style="margin-right: 8px;"></i> {{ i18n.ts.userSilenced }}</div> --> <div class="profile _gaps"> - <MkAccountMoved v-if="user.movedTo" :moved-to="user.movedTo"/> + <MkAccountMoved v-if="user.movedTo" :movedTo="user.movedTo"/> <MkRemoteCaution v-if="user.host != null" :href="user.url ?? user.uri!" class="warn"/> <div :key="user.id" class="main _panel"> @@ -49,7 +49,7 @@ </span> </div> <div v-if="iAmModerator" class="moderationNote"> - <MkTextarea v-if="editModerationNote || (moderationNote != null && moderationNote !== '')" v-model="moderationNote" manual-save> + <MkTextarea v-if="editModerationNote || (moderationNote != null && moderationNote !== '')" v-model="moderationNote" manualSave> <template #label>Moderation note</template> </MkTextarea> <div v-else> @@ -123,7 +123,7 @@ <XPhotos :key="user.id" :user="user"/> <XActivity :key="user.id" :user="user"/> </template> - <MkNotes v-if="!disableNotes" :class="$style.tl" :no-gap="true" :pagination="pagination"/> + <MkNotes v-if="!disableNotes" :class="$style.tl" :noGap="true" :pagination="pagination"/> </div> </div> <div v-if="!narrow" class="sub _gaps" style="container-type: inline-size;"> diff --git a/packages/frontend/src/pages/user/index.timeline.vue b/packages/frontend/src/pages/user/index.timeline.vue index d8fc253910..91c580ce96 100644 --- a/packages/frontend/src/pages/user/index.timeline.vue +++ b/packages/frontend/src/pages/user/index.timeline.vue @@ -1,5 +1,5 @@ <template> -<MkSpacer :content-max="800" style="padding-top: 0"> +<MkSpacer :contentMax="800" style="padding-top: 0"> <MkStickyContainer> <template #header> <MkTab v-model="include" :class="$style.tab"> @@ -8,7 +8,7 @@ <option value="files">{{ i18n.ts.withFiles }}</option> </MkTab> </template> - <MkNotes :no-gap="true" :pagination="pagination" :class="$style.tl"/> + <MkNotes :noGap="true" :pagination="pagination" :class="$style.tl"/> </MkStickyContainer> </MkSpacer> </template> diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index 07f7d30f0c..9fe94d68f6 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -5,7 +5,7 @@ <Transition name="fade" mode="out-in"> <div v-if="user"> <XHome v-if="tab === 'home'" :user="user"/> - <XTimeline v-else-if="tab === 'notes'" :user="user" /> + <XTimeline v-else-if="tab === 'notes'" :user="user"/> <XActivity v-else-if="tab === 'activity'" :user="user"/> <XAchievements v-else-if="tab === 'achievements'" :user="user"/> <XReactions v-else-if="tab === 'reactions'" :user="user"/> diff --git a/packages/frontend/src/pages/user/pages.vue b/packages/frontend/src/pages/user/pages.vue index 7ea1d75f43..a2975c7079 100644 --- a/packages/frontend/src/pages/user/pages.vue +++ b/packages/frontend/src/pages/user/pages.vue @@ -1,5 +1,5 @@ <template> -<MkSpacer :content-max="700"> +<MkSpacer :contentMax="700"> <MkPagination v-slot="{items}" ref="list" :pagination="pagination"> <MkPagePreview v-for="page in items" :key="page.id" :page="page" class="_margin"/> </MkPagination> @@ -24,7 +24,3 @@ const pagination = { })), }; </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/user/reactions.vue b/packages/frontend/src/pages/user/reactions.vue index 24129ec024..2281603394 100644 --- a/packages/frontend/src/pages/user/reactions.vue +++ b/packages/frontend/src/pages/user/reactions.vue @@ -1,11 +1,11 @@ <template> -<MkSpacer :content-max="700"> +<MkSpacer :contentMax="700"> <MkPagination v-slot="{items}" ref="list" :pagination="pagination"> - <div v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _margin afdcfbfb"> - <div class="header"> - <MkAvatar class="avatar" :user="user"/> - <MkReactionIcon class="reaction" :reaction="item.type" :no-style="true"/> - <MkTime :time="item.createdAt" class="createdAt"/> + <div v-for="item in items" :key="item.id" :to="`/clips/${item.id}`" class="_panel _margin"> + <div :class="$style.header"> + <MkAvatar :class="$style.avatar" :user="user"/> + <MkReactionIcon :class="$style.reaction" :reaction="item.type" :noStyle="true"/> + <MkTime :time="item.createdAt" :class="$style.createdAt"/> </div> <MkNote :key="item.id" :note="item.note"/> </div> @@ -33,29 +33,27 @@ const pagination = { }; </script> -<style lang="scss" scoped> -.afdcfbfb { - > .header { - display: flex; - align-items: center; - padding: 8px 16px; - margin-bottom: 8px; - border-bottom: solid 2px var(--divider); +<style lang="scss" module> +.header { + display: flex; + align-items: center; + padding: 8px 16px; + margin-bottom: 8px; + border-bottom: solid 2px var(--divider); +} - > .avatar { - width: 24px; - height: 24px; - margin-right: 8px; - } +.avatar { + width: 24px; + height: 24px; + margin-right: 8px; +} - > .reaction { - width: 32px; - height: 32px; - } +.reaction { + width: 32px; + height: 32px; +} - > .createdAt { - margin-left: auto; - } - } +.createdAt { + margin-left: auto; } </style> diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue index 2beebb0390..4600d2af8e 100644 --- a/packages/frontend/src/ui/_common_/common.vue +++ b/packages/frontend/src/ui/_common_/common.vue @@ -11,11 +11,11 @@ <TransitionGroup tag="div" :class="[$style.notifications, $style[`notificationsPosition-${defaultStore.state.notificationPosition}`], $style[`notificationsStackAxis-${defaultStore.state.notificationStackAxis}`]]" - :move-class="defaultStore.state.animation ? $style.transition_notification_move : ''" - :enter-active-class="defaultStore.state.animation ? $style.transition_notification_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_notification_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_notification_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_notification_leaveTo : ''" + :moveClass="defaultStore.state.animation ? $style.transition_notification_move : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_notification_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_notification_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_notification_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_notification_leaveTo : ''" > <div v-for="notification in notifications" :key="notification.id" :class="$style.notification"> <XNotification :notification="notification"/> diff --git a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue index 7a94a0c3ee..6aacdd0150 100644 --- a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue +++ b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue @@ -8,25 +8,25 @@ </button> </div> <div class="middle"> - <MkA v-click-anime class="item index" active-class="active" to="/" exact> + <MkA v-click-anime class="item index" activeClass="active" to="/" exact> <i class="icon ti ti-home ti-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> </MkA> <template v-for="item in menu"> <div v-if="item === '-'" class="divider"></div> - <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: navbarItemDef[item].active }]" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> + <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: navbarItemDef[item].active }]" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <i class="icon ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon _indicatorCircle"></i></span> </component> </template> <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" active-class="active" to="/admin"> + <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" activeClass="active" to="/admin"> <i class="icon ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> </MkA> <button v-click-anime class="item _button" @click="more"> <i class="icon ti ti-grid-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> <span v-if="otherMenuItemIndicated" class="indicator"><i class="icon _indicatorCircle"></i></span> </button> - <MkA v-click-anime class="item" active-class="active" to="/settings"> + <MkA v-click-anime class="item" activeClass="active" to="/settings"> <i class="icon ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> </MkA> </div> diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index 3b4b161422..2daff868a9 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -8,7 +8,7 @@ </button> </div> <div class="middle"> - <MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.timeline" class="item index" active-class="active" to="/" exact> + <MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.timeline" class="item index" activeClass="active" to="/" exact> <i class="icon ti ti-home ti-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> </MkA> <template v-for="item in menu"> @@ -20,7 +20,7 @@ v-tooltip.noDelay.right="navbarItemDef[item].title" class="item _button" :class="[item, { active: navbarItemDef[item].active }]" - active-class="active" + activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}" > @@ -29,14 +29,14 @@ </component> </template> <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.noDelay.right="i18n.ts.controlPanel" class="item" active-class="active" to="/admin"> + <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.noDelay.right="i18n.ts.controlPanel" class="item" activeClass="active" to="/admin"> <i class="icon ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> </MkA> <button v-click-anime class="item _button" @click="more"> <i class="icon ti ti-grid-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> <span v-if="otherMenuItemIndicated" class="indicator"><i class="icon _indicatorCircle"></i></span> </button> - <MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.settings" class="item" active-class="active" to="/settings"> + <MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.settings" class="item" activeClass="active" to="/settings"> <i class="icon ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> </MkA> </div> diff --git a/packages/frontend/src/ui/_common_/statusbars.vue b/packages/frontend/src/ui/_common_/statusbars.vue index f84695c15f..b1e2c80f10 100644 --- a/packages/frontend/src/ui/_common_/statusbars.vue +++ b/packages/frontend/src/ui/_common_/statusbars.vue @@ -10,9 +10,9 @@ }]" > <span class="name">{{ x.name }}</span> - <XRss v-if="x.type === 'rss'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :url="x.props.url" :shuffle="x.props.shuffle"/> - <XFederation v-else-if="x.type === 'federation'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :colored="x.props.colored"/> - <XUserList v-else-if="x.type === 'userList'" class="body" :refresh-interval-sec="x.props.refreshIntervalSec" :marquee-duration="x.props.marqueeDuration" :marquee-reverse="x.props.marqueeReverse" :display="x.props.display" :user-list-id="x.props.userListId"/> + <XRss v-if="x.type === 'rss'" class="body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :url="x.props.url" :shuffle="x.props.shuffle"/> + <XFederation v-else-if="x.type === 'federation'" class="body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :colored="x.props.colored"/> + <XUserList v-else-if="x.type === 'userList'" class="body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :userListId="x.props.userListId"/> </div> </div> </template> diff --git a/packages/frontend/src/ui/classic.header.vue b/packages/frontend/src/ui/classic.header.vue index daea775552..233d5b2644 100644 --- a/packages/frontend/src/ui/classic.header.vue +++ b/packages/frontend/src/ui/classic.header.vue @@ -5,18 +5,18 @@ <button v-click-anime class="item _button instance" @click="openInstanceMenu"> <img :src="instance.iconUrl ?? instance.faviconUrl ?? '/favicon.ico'" class="_ghost"/> </button> - <MkA v-click-anime v-tooltip="i18n.ts.timeline" class="item index" active-class="active" to="/" exact> + <MkA v-click-anime v-tooltip="i18n.ts.timeline" class="item index" activeClass="active" to="/" exact> <i class="ti ti-home ti-fw"></i> </MkA> <template v-for="item in menu"> <div v-if="item === '-'" class="divider"></div> - <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-tooltip="navbarItemDef[item].title" class="item _button" :class="item" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> + <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-tooltip="navbarItemDef[item].title" class="item _button" :class="item" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <i class="ti-fw" :class="navbarItemDef[item].icon"></i> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="_indicatorCircle"></i></span> </component> </template> <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip="i18n.ts.controlPanel" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip="i18n.ts.controlPanel" class="item" activeClass="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null"> <i class="ti ti-dashboard ti-fw"></i> </MkA> <button v-click-anime class="item _button" @click="more"> @@ -25,7 +25,7 @@ </button> </div> <div class="right"> - <MkA v-click-anime v-tooltip="i18n.ts.settings" class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-click-anime v-tooltip="i18n.ts.settings" class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null"> <i class="ti ti-settings ti-fw"></i> </MkA> <button v-click-anime class="item _button account" @click="openAccountMenu"> diff --git a/packages/frontend/src/ui/classic.sidebar.vue b/packages/frontend/src/ui/classic.sidebar.vue index 73db14c65e..e5755e87c9 100644 --- a/packages/frontend/src/ui/classic.sidebar.vue +++ b/packages/frontend/src/ui/classic.sidebar.vue @@ -9,25 +9,25 @@ </MkButton> </div> <div class="divider"></div> - <MkA v-click-anime class="item index" active-class="active" to="/" exact> + <MkA v-click-anime class="item index" activeClass="active" to="/" exact> <i class="ti ti-home ti-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> </MkA> <template v-for="item in menu"> <div v-if="item === '-'" class="divider"></div> - <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="item" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> + <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="item" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <i class="ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span> <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="_indicatorCircle"></i></span> </component> </template> <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" activeClass="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null"> <i class="ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> </MkA> <button v-click-anime class="item _button" @click="more"> <i class="ti ti-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> <span v-if="otherNavItemIndicated" class="indicator"><i class="_indicatorCircle"></i></span> </button> - <MkA v-click-anime class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-click-anime class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null"> <i class="ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> </MkA> <div class="divider"></div> diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index c17450f6ed..d50f2b0454 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -7,7 +7,7 @@ <XSidebar/> </div> <div v-else ref="widgetsLeft" class="widgets left"> - <XWidgets place="left" :margin-top="'var(--margin)'" @mounted="attachSticky(widgetsLeft)"/> + <XWidgets place="left" :marginTop="'var(--margin)'" @mounted="attachSticky(widgetsLeft)"/> </div> <main class="main" @contextmenu.stop="onContextmenu"> @@ -17,7 +17,7 @@ </main> <div v-if="isDesktop" ref="widgetsRight" class="widgets right"> - <XWidgets :place="showMenuOnTop ? 'right' : null" :margin-top="showMenuOnTop ? '0' : 'var(--margin)'" @mounted="attachSticky(widgetsRight)"/> + <XWidgets :place="showMenuOnTop ? 'right' : null" :marginTop="showMenuOnTop ? '0' : 'var(--margin)'" @mounted="attachSticky(widgetsRight)"/> </div> </div> diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 33e752513b..585f727698 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -12,7 +12,7 @@ :class="$style.folder" :style="columns.filter(c => ids.includes(c.id)).some(c => c.flexible) ? { flex: 1, minWidth: '350px' } : { width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }" > - <DeckColumnCore v-for="id in ids" :ref="id" :key="id" :column="columns.find(c => c.id === id)" :is-stacked="true" @parent-focus="moveFocus(id, $event)"/> + <DeckColumnCore v-for="id in ids" :ref="id" :key="id" :column="columns.find(c => c.id === id)" :isStacked="true" @parentFocus="moveFocus(id, $event)"/> </section> <DeckColumnCore v-else @@ -20,9 +20,9 @@ :key="ids[0]" :class="$style.column" :column="columns.find(c => c.id === ids[0])" - :is-stacked="false" + :isStacked="false" :style="columns.find(c => c.id === ids[0])!.flexible ? { flex: 1, minWidth: '350px' } : { width: columns.find(c => c.id === ids[0])!.width + 'px' }" - @parent-focus="moveFocus(ids[0], $event)" + @parentFocus="moveFocus(ids[0], $event)" /> </template> <div v-if="layout.length === 0" class="_panel" :class="$style.onboarding"> @@ -53,10 +53,10 @@ </div> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''" > <div v-if="drawerMenuShowing" @@ -68,10 +68,10 @@ </Transition> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_menuDrawer_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_menuDrawer_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_menuDrawer_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_menuDrawer_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveTo : ''" > <div v-if="drawerMenuShowing" :class="$style.menu"> <XDrawerMenu/> diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue index 76a8b6e760..661f4cab82 100644 --- a/packages/frontend/src/ui/deck/antenna-column.vue +++ b/packages/frontend/src/ui/deck/antenna-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header> <i class="ti ti-antenna"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue index 9605d1b22e..14858750d5 100644 --- a/packages/frontend/src/ui/deck/channel-column.vue +++ b/packages/frontend/src/ui/deck/channel-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header> <i class="ti ti-device-tv"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> @@ -14,13 +14,13 @@ </template> <script lang="ts" setup> +import * as misskey from 'misskey-js'; import XColumn from './column.vue'; import { updateColumn, Column } from './deck-store'; import MkTimeline from '@/components/MkTimeline.vue'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os'; import { i18n } from '@/i18n'; -import * as misskey from 'misskey-js'; const props = defineProps<{ column: Column; diff --git a/packages/frontend/src/ui/deck/column-core.vue b/packages/frontend/src/ui/deck/column-core.vue index 8e7addf359..29299cdcdb 100644 --- a/packages/frontend/src/ui/deck/column-core.vue +++ b/packages/frontend/src/ui/deck/column-core.vue @@ -1,16 +1,16 @@ <template> <!-- TODO: リファクタの余地がありそう --> <div v-if="!column">たぶん見えちゃいけないやつ</div> -<XMainColumn v-else-if="column.type === 'main'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XWidgetsColumn v-else-if="column.type === 'widgets'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XNotificationsColumn v-else-if="column.type === 'notifications'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XTlColumn v-else-if="column.type === 'tl'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XListColumn v-else-if="column.type === 'list'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XChannelColumn v-else-if="column.type === 'channel'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XAntennaColumn v-else-if="column.type === 'antenna'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XMentionsColumn v-else-if="column.type === 'mentions'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XDirectColumn v-else-if="column.type === 'direct'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> -<XRoleTimelineColumn v-else-if="column.type === 'roleTimeline'" :column="column" :is-stacked="isStacked" @parent-focus="emit('parent-focus', $event)"/> +<XMainColumn v-else-if="column.type === 'main'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XWidgetsColumn v-else-if="column.type === 'widgets'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XNotificationsColumn v-else-if="column.type === 'notifications'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XTlColumn v-else-if="column.type === 'tl'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XListColumn v-else-if="column.type === 'list'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XChannelColumn v-else-if="column.type === 'channel'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XAntennaColumn v-else-if="column.type === 'antenna'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XMentionsColumn v-else-if="column.type === 'mentions'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XDirectColumn v-else-if="column.type === 'direct'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> +<XRoleTimelineColumn v-else-if="column.type === 'roleTimeline'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/ui/deck/direct-column.vue b/packages/frontend/src/ui/deck/direct-column.vue index 15b76c4d92..5f76ea6d86 100644 --- a/packages/frontend/src/ui/deck/direct-column.vue +++ b/packages/frontend/src/ui/deck/direct-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header><i class="ti ti-mail" style="margin-right: 8px;"></i>{{ column.name }}</template> <MkNotes :pagination="pagination"/> diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue index 352c1d246a..165b654514 100644 --- a/packages/frontend/src/ui/deck/list-column.vue +++ b/packages/frontend/src/ui/deck/list-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header> <i class="ti ti-list"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> diff --git a/packages/frontend/src/ui/deck/main-column.vue b/packages/frontend/src/ui/deck/main-column.vue index f3826a8d31..5448e3d2f3 100644 --- a/packages/frontend/src/ui/deck/main-column.vue +++ b/packages/frontend/src/ui/deck/main-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn v-if="deckStore.state.alwaysShowMainColumn || mainRouter.currentRoute.value.name !== 'index'" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn v-if="deckStore.state.alwaysShowMainColumn || mainRouter.currentRoute.value.name !== 'index'" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header> <template v-if="pageMetadata?.value"> <i :class="pageMetadata?.value.icon"></i> diff --git a/packages/frontend/src/ui/deck/mentions-column.vue b/packages/frontend/src/ui/deck/mentions-column.vue index 852d7a8f7e..d6f9d88043 100644 --- a/packages/frontend/src/ui/deck/mentions-column.vue +++ b/packages/frontend/src/ui/deck/mentions-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header><i class="ti ti-at" style="margin-right: 8px;"></i>{{ column.name }}</template> <MkNotes :pagination="pagination"/> diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue index 9d133035fe..48d88aa6cf 100644 --- a/packages/frontend/src/ui/deck/notifications-column.vue +++ b/packages/frontend/src/ui/deck/notifications-column.vue @@ -1,8 +1,8 @@ <template> -<XColumn :column="column" :is-stacked="isStacked" :menu="menu" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :column="column" :isStacked="isStacked" :menu="menu" @parentFocus="$event => emit('parent-focus', $event)"> <template #header><i class="ti ti-bell" style="margin-right: 8px;"></i>{{ column.name }}</template> - <XNotifications :include-types="column.includingTypes"/> + <XNotifications :includeTypes="column.includingTypes"/> </XColumn> </template> diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue index e375a5884f..cb189cae4b 100644 --- a/packages/frontend/src/ui/deck/role-timeline-column.vue +++ b/packages/frontend/src/ui/deck/role-timeline-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header> <i class="ti ti-badge"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue index c23943d4db..a4fea6564b 100644 --- a/packages/frontend/src/ui/deck/tl-column.vue +++ b/packages/frontend/src/ui/deck/tl-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header> <i v-if="column.tl === 'home'" class="ti ti-home"></i> <i v-else-if="column.tl === 'local'" class="ti ti-planet"></i> diff --git a/packages/frontend/src/ui/deck/widgets-column.vue b/packages/frontend/src/ui/deck/widgets-column.vue index 3b5b727991..af35d3ac13 100644 --- a/packages/frontend/src/ui/deck/widgets-column.vue +++ b/packages/frontend/src/ui/deck/widgets-column.vue @@ -1,10 +1,10 @@ <template> -<XColumn :menu="menu" :naked="true" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :naked="true" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> <template #header><i class="ti ti-apps" style="margin-right: 8px;"></i>{{ column.name }}</template> <div :class="$style.root"> <div v-if="!(column.widgets && column.widgets.length > 0) && !edit" :class="$style.intro">{{ i18n.ts._deck.widgetsIntroduction }}</div> - <XWidgets :edit="edit" :widgets="column.widgets ?? []" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="edit = false"/> + <XWidgets :edit="edit" :widgets="column.widgets ?? []" @addWidget="addWidget" @removeWidget="removeWidget" @updateWidget="updateWidget" @updateWidgets="updateWidgets" @exit="edit = false"/> </div> </XColumn> </template> diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index f755dda627..d3fd0403d2 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -13,7 +13,7 @@ </MkStickyContainer> <div v-if="isDesktop" ref="widgetsEl" :class="$style.widgets"> - <XWidgets :margin-top="'var(--margin)'" @mounted="attachSticky"/> + <XWidgets :marginTop="'var(--margin)'" @mounted="attachSticky"/> </div> <button v-if="!isDesktop && !isMobile" :class="$style.widgetButton" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button> @@ -27,10 +27,10 @@ </div> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''" > <div v-if="drawerMenuShowing" @@ -42,10 +42,10 @@ </Transition> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_menuDrawer_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_menuDrawer_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_menuDrawer_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_menuDrawer_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveTo : ''" > <div v-if="drawerMenuShowing" :class="$style.menuDrawer"> <XDrawerMenu/> @@ -53,10 +53,10 @@ </Transition> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_leaveTo : ''" > <div v-if="widgetsShowing" @@ -68,10 +68,10 @@ </Transition> <Transition - :enter-active-class="defaultStore.state.animation ? $style.transition_widgetsDrawer_enterActive : ''" - :leave-active-class="defaultStore.state.animation ? $style.transition_widgetsDrawer_leaveActive : ''" - :enter-from-class="defaultStore.state.animation ? $style.transition_widgetsDrawer_enterFrom : ''" - :leave-to-class="defaultStore.state.animation ? $style.transition_widgetsDrawer_leaveTo : ''" + :enterActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_enterActive : ''" + :leaveActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_leaveActive : ''" + :enterFromClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_enterFrom : ''" + :leaveToClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_leaveTo : ''" > <div v-if="widgetsShowing" :class="$style.widgetsDrawer"> <button class="_button" :class="$style.widgetsCloseButton" @click="widgetsShowing = false"><i class="ti ti-x"></i></button> diff --git a/packages/frontend/src/ui/universal.widgets.vue b/packages/frontend/src/ui/universal.widgets.vue index 3e0c38bb83..a3e34ed181 100644 --- a/packages/frontend/src/ui/universal.widgets.vue +++ b/packages/frontend/src/ui/universal.widgets.vue @@ -1,6 +1,6 @@ <template> <div :class="$style.root" :style="{ paddingTop: marginTop }"> - <XWidgets :class="$style.widgets" :edit="editMode" :widgets="widgets" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/> + <XWidgets :class="$style.widgets" :edit="editMode" :widgets="widgets" @addWidget="addWidget" @removeWidget="removeWidget" @updateWidget="updateWidget" @updateWidgets="updateWidgets" @exit="editMode = false"/> <button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button> <button v-else class="_textButton" data-cy-widget-edit :class="$style.edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button> diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue index 623abbda39..d6de145edb 100644 --- a/packages/frontend/src/ui/visitor.vue +++ b/packages/frontend/src/ui/visitor.vue @@ -12,10 +12,10 @@ <div class="main"> <div v-if="!root" class="header"> <div v-if="narrow === false" class="wide"> - <MkA to="/" class="link" active-class="active"><i class="ti ti-home icon"></i> {{ i18n.ts.home }}</MkA> - <MkA v-if="isTimelineAvailable" to="/timeline" class="link" active-class="active"><i class="ti ti-message icon"></i> {{ i18n.ts.timeline }}</MkA> - <MkA to="/explore" class="link" active-class="active"><i class="ti ti-hash icon"></i> {{ i18n.ts.explore }}</MkA> - <MkA to="/channels" class="link" active-class="active"><i class="ti ti-device-tv icon"></i> {{ i18n.ts.channel }}</MkA> + <MkA to="/" class="link" activeClass="active"><i class="ti ti-home icon"></i> {{ i18n.ts.home }}</MkA> + <MkA v-if="isTimelineAvailable" to="/timeline" class="link" activeClass="active"><i class="ti ti-message icon"></i> {{ i18n.ts.timeline }}</MkA> + <MkA to="/explore" class="link" activeClass="active"><i class="ti ti-hash icon"></i> {{ i18n.ts.explore }}</MkA> + <MkA to="/channels" class="link" activeClass="active"><i class="ti ti-device-tv icon"></i> {{ i18n.ts.channel }}</MkA> </div> <div v-else-if="narrow === true" class="narrow"> <button class="menu _button" @click="showMenu = true"> @@ -44,15 +44,15 @@ <Transition :name="'tray'"> <div v-if="showMenu" class="menu"> - <MkA to="/" class="link" active-class="active"><i class="ti ti-home icon"></i>{{ i18n.ts.home }}</MkA> - <MkA v-if="isTimelineAvailable" to="/timeline" class="link" active-class="active"><i class="ti ti-message icon"></i>{{ i18n.ts.timeline }}</MkA> - <MkA to="/explore" class="link" active-class="active"><i class="ti ti-hash icon"></i>{{ i18n.ts.explore }}</MkA> - <MkA to="/announcements" class="link" active-class="active"><i class="ti ti-speakerphone icon"></i>{{ i18n.ts.announcements }}</MkA> - <MkA to="/channels" class="link" active-class="active"><i class="ti ti-device-tv icon"></i>{{ i18n.ts.channel }}</MkA> + <MkA to="/" class="link" activeClass="active"><i class="ti ti-home icon"></i>{{ i18n.ts.home }}</MkA> + <MkA v-if="isTimelineAvailable" to="/timeline" class="link" activeClass="active"><i class="ti ti-message icon"></i>{{ i18n.ts.timeline }}</MkA> + <MkA to="/explore" class="link" activeClass="active"><i class="ti ti-hash icon"></i>{{ i18n.ts.explore }}</MkA> + <MkA to="/announcements" class="link" activeClass="active"><i class="ti ti-speakerphone icon"></i>{{ i18n.ts.announcements }}</MkA> + <MkA to="/channels" class="link" activeClass="active"><i class="ti ti-device-tv icon"></i>{{ i18n.ts.channel }}</MkA> <div class="divider"></div> - <MkA to="/pages" class="link" active-class="active"><i class="ti ti-news icon"></i>{{ i18n.ts.pages }}</MkA> - <MkA to="/play" class="link" active-class="active"><i class="ti ti-player-play icon"></i>Play</MkA> - <MkA to="/gallery" class="link" active-class="active"><i class="ti ti-icons icon"></i>{{ i18n.ts.gallery }}</MkA> + <MkA to="/pages" class="link" activeClass="active"><i class="ti ti-news icon"></i>{{ i18n.ts.pages }}</MkA> + <MkA to="/play" class="link" activeClass="active"><i class="ti ti-player-play icon"></i>Play</MkA> + <MkA to="/gallery" class="link" activeClass="active"><i class="ti ti-icons icon"></i>{{ i18n.ts.gallery }}</MkA> <div class="action"> <button class="_buttonPrimary" @click="signup()">{{ i18n.ts.signup }}</button> <button class="_button" @click="signin()">{{ i18n.ts.login }}</button> From 15db0b8812f269d71e232f37cb7f066ad4a9b6db Mon Sep 17 00:00:00 2001 From: Nanashia <nanashia.128@gmail.com> Date: Fri, 19 May 2023 20:53:20 +0900 Subject: [PATCH 063/213] test(backend): Add tests for antennas (#10868) --- packages/backend/test/e2e/antennas.ts | 653 ++++++++++++++++++++++++++ packages/backend/test/utils.ts | 97 ++++ 2 files changed, 750 insertions(+) create mode 100644 packages/backend/test/e2e/antennas.ts diff --git a/packages/backend/test/e2e/antennas.ts b/packages/backend/test/e2e/antennas.ts new file mode 100644 index 0000000000..dd3b09f85a --- /dev/null +++ b/packages/backend/test/e2e/antennas.ts @@ -0,0 +1,653 @@ +process.env.NODE_ENV = 'test'; + +import * as assert from 'assert'; +import { inspect } from 'node:util'; +import { DEFAULT_POLICIES } from '@/core/RoleService.js'; +import type { Packed } from '@/misc/json-schema.js'; +import { + signup, + post, + userList, + page, + role, + startServer, + api, + successfulApiCall, + failedApiCall, + uploadFile, + testPaginationConsistency, +} from '../utils.js'; +import type * as misskey from 'misskey-js'; +import type { INestApplicationContext } from '@nestjs/common'; + +const compareBy = <T extends { id: string }>(selector: (s: T) => string = (s: T): string => s.id) => (a: T, b: T): number => { + return selector(a).localeCompare(selector(b)); +}; + +describe('アンテナ', () => { + // エンティティとしてのアンテナを主眼においたテストを記述する + // (Antennaを返すエンドポイント、Antennaエンティティを書き換えるエンドポイント、Antennaからノートを取得するエンドポイントをテストする) + + // BUG misskey-jsとjson-schemaが一致していない。 + // - srcのenumにgroupが残っている + // - userGroupIdが残っている, isActiveがない + type Antenna = misskey.entities.Antenna | Packed<'Antenna'>; + type User = misskey.entities.MeDetailed & { token: string }; + type Note = misskey.entities.Note; + + // アンテナを作成できる最小のパラメタ + const defaultParam = { + caseSensitive: false, + excludeKeywords: [['']], + keywords: [['keyword']], + name: 'test', + notify: false, + src: 'all' as const, + userListId: null, + users: [''], + withFile: false, + withReplies: false, + }; + + let app: INestApplicationContext; + + let root: User; + let alice: User; + let bob: User; + let carol: User; + + let alicePost: Note; + let aliceList: misskey.entities.UserList; + let bobFile: misskey.entities.DriveFile; + let bobList: misskey.entities.UserList; + + let userNotExplorable: User; + let userLocking: User; + let userSilenced: User; + let userSuspended: User; + let userDeletedBySelf: User; + let userDeletedByAdmin: User; + let userFollowingAlice: User; + let userFollowedByAlice: User; + let userBlockingAlice: User; + let userBlockedByAlice: User; + let userMutingAlice: User; + let userMutedByAlice: User; + + beforeAll(async () => { + app = await startServer(); + }, 1000 * 60 * 2); + + beforeAll(async () => { + root = await signup({ username: 'root' }); + alice = await signup({ username: 'alice' }); + alicePost = await post(alice, { text: 'test' }); + aliceList = await userList(alice, {}); + bob = await signup({ username: 'bob' }); + aliceList = await userList(alice, {}); + bobFile = (await uploadFile(bob)).body; + bobList = await userList(bob); + carol = await signup({ username: 'carol' }); + await api('users/lists/push', { listId: aliceList.id, userId: bob.id }, alice); + await api('users/lists/push', { listId: aliceList.id, userId: carol.id }, alice); + + userNotExplorable = await signup({ username: 'userNotExplorable' }); + await post(userNotExplorable, { text: 'test' }); + await api('i/update', { isExplorable: false }, userNotExplorable); + userLocking = await signup({ username: 'userLocking' }); + await post(userLocking, { text: 'test' }); + await api('i/update', { isLocked: true }, userLocking); + userSilenced = await signup({ username: 'userSilenced' }); + await post(userSilenced, { text: 'test' }); + const roleSilenced = await role(root, {}, { canPublicNote: { priority: 0, useDefault: false, value: false } }); + await api('admin/roles/assign', { userId: userSilenced.id, roleId: roleSilenced.id }, root); + userSuspended = await signup({ username: 'userSuspended' }); + await post(userSuspended, { text: 'test' }); + await successfulApiCall({ endpoint: 'i/update', parameters: { description: '#user_testuserSuspended' }, user: userSuspended }); + await api('admin/suspend-user', { userId: userSuspended.id }, root); + userDeletedBySelf = await signup({ username: 'userDeletedBySelf', password: 'userDeletedBySelf' }); + await post(userDeletedBySelf, { text: 'test' }); + await api('i/delete-account', { password: 'userDeletedBySelf' }, userDeletedBySelf); + userDeletedByAdmin = await signup({ username: 'userDeletedByAdmin' }); + await post(userDeletedByAdmin, { text: 'test' }); + await api('admin/delete-account', { userId: userDeletedByAdmin.id }, root); + userFollowedByAlice = await signup({ username: 'userFollowedByAlice' }); + await post(userFollowedByAlice, { text: 'test' }); + await api('following/create', { userId: userFollowedByAlice.id }, alice); + userFollowingAlice = await signup({ username: 'userFollowingAlice' }); + await post(userFollowingAlice, { text: 'test' }); + await api('following/create', { userId: alice.id }, userFollowingAlice); + userBlockingAlice = await signup({ username: 'userBlockingAlice' }); + await post(userBlockingAlice, { text: 'test' }); + await api('blocking/create', { userId: alice.id }, userBlockingAlice); + userBlockedByAlice = await signup({ username: 'userBlockedByAlice' }); + await post(userBlockedByAlice, { text: 'test' }); + await api('blocking/create', { userId: userBlockedByAlice.id }, alice); + userMutingAlice = await signup({ username: 'userMutingAlice' }); + await post(userMutingAlice, { text: 'test' }); + await api('mute/create', { userId: alice.id }, userMutingAlice); + userMutedByAlice = await signup({ username: 'userMutedByAlice' }); + await post(userMutedByAlice, { text: 'test' }); + await api('mute/create', { userId: userMutedByAlice.id }, alice); + }, 1000 * 60 * 10); + + afterAll(async () => { + await app.close(); + }); + + beforeEach(async () => { + // テスト間で影響し合わないように毎回全部消す。 + for (const user of [alice, bob]) { + const list = await api('/antennas/list', {}, user); + for (const antenna of list.body) { + await api('/antennas/delete', { antennaId: antenna.id }, user); + } + } + }); + + //#region 作成(antennas/create) + + test('が作成できること、キーが過不足なく入っていること。', async () => { + const response = await successfulApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam }, + user: alice, + }); + assert.match(response.id, /[0-9a-z]{10}/); + const expected = { + id: response.id, + caseSensitive: false, + createdAt: new Date(response.createdAt).toISOString(), + excludeKeywords: [['']], + hasUnreadNote: false, + isActive: true, + keywords: [['keyword']], + name: 'test', + notify: false, + src: 'all', + userListId: null, + users: [''], + withFile: false, + withReplies: false, + } as Antenna; + assert.deepStrictEqual(response, expected); + }); + + test('が上限いっぱいまで作成できること', async () => { + // antennaLimit + 1まで作れるのがキモ + const response = await Promise.all([...Array(DEFAULT_POLICIES.antennaLimit + 1)].map(() => successfulApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam }, + user: alice, + }))); + + const expected = await successfulApiCall({ endpoint: 'antennas/list', parameters: {}, user: alice }); + assert.deepStrictEqual( + response.sort(compareBy(s => s.id)), + expected.sort(compareBy(s => s.id))); + + failedApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam }, + user: alice, + }, { + status: 400, + code: 'TOO_MANY_ANTENNAS', + id: 'faf47050-e8b5-438c-913c-db2b1576fde4', + }); + }); + + test('を作成するとき他人のリストを指定したらエラーになる', async () => { + failedApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam, src: 'list', userListId: bobList.id }, + user: alice, + }, { + status: 400, + code: 'NO_SUCH_USER_LIST', + id: '95063e93-a283-4b8b-9aa5-bcdb8df69a7f', + }); + }); + + const antennaParamPattern = [ + { parameters: (): object => ({ name: 'x'.repeat(100) }) }, + { parameters: (): object => ({ name: 'x' }) }, + { parameters: (): object => ({ src: 'home' }) }, + { parameters: (): object => ({ src: 'all' }) }, + { parameters: (): object => ({ src: 'users' }) }, + { parameters: (): object => ({ src: 'list' }) }, + { parameters: (): object => ({ userListId: null }) }, + { parameters: (): object => ({ src: 'list', userListId: aliceList.id }) }, + { parameters: (): object => ({ keywords: [['x']] }) }, + { parameters: (): object => ({ keywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) }, + { parameters: (): object => ({ excludeKeywords: [['a', 'b', 'c'], ['x'], ['y'], ['z']] }) }, + { parameters: (): object => ({ users: [alice.username] }) }, + { parameters: (): object => ({ users: [alice.username, bob.username, carol.username] }) }, + { parameters: (): object => ({ caseSensitive: false }) }, + { parameters: (): object => ({ caseSensitive: true }) }, + { parameters: (): object => ({ withReplies: false }) }, + { parameters: (): object => ({ withReplies: true }) }, + { parameters: (): object => ({ withFile: false }) }, + { parameters: (): object => ({ withFile: true }) }, + { parameters: (): object => ({ notify: false }) }, + { parameters: (): object => ({ notify: true }) }, + ]; + test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => { + const response = await successfulApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam, ...parameters() }, + user: alice, + }); + const expected = { ...response, ...parameters() }; + assert.deepStrictEqual(response, expected); + }); + + //#endregion + //#region 更新(antennas/update) + + test.each(antennaParamPattern)('を変更できること($#)', async ({ parameters }) => { + const antenna = await successfulApiCall({ endpoint: 'antennas/create', parameters: defaultParam, user: alice }); + const response = await successfulApiCall({ + endpoint: 'antennas/update', + parameters: { antennaId: antenna.id, ...defaultParam, ...parameters() }, + user: alice, + }); + const expected = { ...response, ...parameters() }; + assert.deepStrictEqual(response, expected); + }); + test.todo('は他人のものは変更できない'); + + test('を変更するとき他人のリストを指定したらエラーになる', async () => { + const antenna = await successfulApiCall({ endpoint: 'antennas/create', parameters: defaultParam, user: alice }); + failedApiCall({ + endpoint: 'antennas/update', + parameters: { antennaId: antenna.id, ...defaultParam, src: 'list', userListId: bobList.id }, + user: alice, + }, { + status: 400, + code: 'NO_SUCH_USER_LIST', + id: '1c6b35c9-943e-48c2-81e4-2844989407f7', + }); + }); + + //#endregion + //#region 表示(antennas/show) + + test('をID指定で表示できること。', async () => { + const antenna = await successfulApiCall({ endpoint: 'antennas/create', parameters: defaultParam, user: alice }); + const response = await successfulApiCall({ + endpoint: 'antennas/show', + parameters: { antennaId: antenna.id }, + user: alice, + }); + const expected = { ...antenna }; + assert.deepStrictEqual(response, expected); + }); + test.todo('は他人のものをID指定で表示できない'); + + //#endregion + //#region 一覧(antennas/list) + + test('をリスト形式で取得できること。', async () => { + const antenna = await successfulApiCall({ endpoint: 'antennas/create', parameters: defaultParam, user: alice }); + await successfulApiCall({ endpoint: 'antennas/create', parameters: defaultParam, user: bob }); + const response = await successfulApiCall({ + endpoint: 'antennas/list', + parameters: {}, + user: alice, + }); + const expected = [{ ...antenna }]; + assert.deepStrictEqual(response, expected); + }); + + //#endregion + //#region 削除(antennas/delete) + + test('を削除できること。', async () => { + const antenna = await successfulApiCall({ endpoint: 'antennas/create', parameters: defaultParam, user: alice }); + const response = await successfulApiCall({ + endpoint: 'antennas/delete', + parameters: { antennaId: antenna.id }, + user: alice, + }); + assert.deepStrictEqual(response, null); + const list = await successfulApiCall({ endpoint: 'antennas/list', parameters: {}, user: alice }); + assert.deepStrictEqual(list, []); + }); + test.todo('は他人のものを削除できない'); + + //#endregion + + describe('のノート', () => { + //#region アンテナのノート取得(antennas/notes) + + test('を取得できること。', async () => { + const keyword = 'キーワード'; + await post(bob, { text: `test ${keyword} beforehand` }); + const antenna = await successfulApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam, keywords: [[keyword]] }, + user: alice, + }); + const note = await post(bob, { text: `test ${keyword}` }); + const response = await successfulApiCall({ + endpoint: 'antennas/notes', + parameters: { antennaId: antenna.id }, + user: alice, + }); + const expected = [note]; + assert.deepStrictEqual(response, expected); + }); + + const keyword = 'キーワード'; + test.each([ + { + label: '全体から', + parameters: (): object => ({ src: 'all' }), + posts: [ + { note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true }, + { note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true }, + { note: (): Promise<Note> => post(carol, { text: `test ${keyword}` }), included: true }, + ], + }, + { + // BUG e4144a1 以降home指定は壊れている(allと同じ) + label: 'ホーム指定はallと同じ', + parameters: (): object => ({ src: 'home' }), + posts: [ + { note: (): Promise<Note> => post(alice, { text: `${keyword}` }), included: true }, + { note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true }, + { note: (): Promise<Note> => post(carol, { text: `test ${keyword}` }), included: true }, + ], + }, + { + // https://github.com/misskey-dev/misskey/issues/9025 + label: 'ただし、フォロワー限定投稿とDM投稿を含まない。フォロワーであっても。', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'public' }), included: true }, + { note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'home' }), included: true }, + { note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'followers' }) }, + { note: (): Promise<Note> => post(userFollowedByAlice, { text: `${keyword}`, visibility: 'specified', visibleUserIds: [alice.id] }) }, + ], + }, + { + label: 'ブロックしているユーザーのノートは含む', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userBlockedByAlice, { text: `${keyword}` }), included: true }, + ], + }, + { + label: 'ブロックされているユーザーのノートは含まない', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userBlockingAlice, { text: `${keyword}` }) }, + ], + }, + { + label: 'ミュートしているユーザーのノートは含まない', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userMutedByAlice, { text: `${keyword}` }) }, + ], + }, + { + label: 'ミュートされているユーザーのノートは含む', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userMutingAlice, { text: `${keyword}` }), included: true }, + ], + }, + { + label: '「見つけやすくする」がOFFのユーザーのノートも含まれる', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userNotExplorable, { text: `${keyword}` }), included: true }, + ], + }, + { + label: '鍵付きユーザーのノートも含まれる', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userLocking, { text: `${keyword}` }), included: true }, + ], + }, + { + label: 'サイレンスのノートも含まれる', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userSilenced, { text: `${keyword}` }), included: true }, + ], + }, + { + label: '削除ユーザーのノートも含まれる', + parameters: (): object => ({}), + posts: [ + { note: (): Promise<Note> => post(userDeletedBySelf, { text: `${keyword}` }), included: true }, + { note: (): Promise<Note> => post(userDeletedByAdmin, { text: `${keyword}` }), included: true }, + ], + }, + { + label: 'ユーザー指定で', + parameters: (): object => ({ src: 'users', users: [`@${bob.username}`, `@${carol.username}`] }), + posts: [ + { note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true }, + { note: (): Promise<Note> => post(carol, { text: `test ${keyword}` }), included: true }, + ], + }, + { + label: 'リスト指定で', + parameters: (): object => ({ src: 'list', userListId: aliceList.id }), + posts: [ + { note: (): Promise<Note> => post(alice, { text: `test ${keyword}` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true }, + { note: (): Promise<Note> => post(carol, { text: `test ${keyword}` }), included: true }, + ], + }, + { + label: 'CWにもマッチする', + parameters: (): object => ({ keywords: [[keyword]] }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: 'test', cw: `cw ${keyword}` }), included: true }, + ], + }, + { + label: 'キーワード1つ', + parameters: (): object => ({ keywords: [[keyword]] }), + posts: [ + { note: (): Promise<Note> => post(alice, { text: 'test' }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true }, + { note: (): Promise<Note> => post(carol, { text: 'test' }) }, + ], + }, + { + label: 'キーワード3つ(AND)', + parameters: (): object => ({ keywords: [['A', 'B', 'C']] }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: 'test A' }) }, + { note: (): Promise<Note> => post(bob, { text: 'test A B' }) }, + { note: (): Promise<Note> => post(bob, { text: 'test B C' }) }, + { note: (): Promise<Note> => post(bob, { text: 'test A B C' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'test C B A A B C' }), included: true }, + ], + }, + { + label: 'キーワード3つ(OR)', + parameters: (): object => ({ keywords: [['A'], ['B'], ['C']] }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: 'test' }) }, + { note: (): Promise<Note> => post(bob, { text: 'test A' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'test A B' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'test B C' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'test B C A' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'test C B' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'test C' }), included: true }, + ], + }, + { + label: '除外ワード3つ(AND)', + parameters: (): object => ({ excludeKeywords: [['A', 'B', 'C']] }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} A B` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} B C` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} B C A` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} C B` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} C` }), included: true }, + ], + }, + { + label: '除外ワード3つ(OR)', + parameters: (): object => ({ excludeKeywords: [['A'], ['B'], ['C']] }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `test ${keyword}` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} A` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} A B` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} B C` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} B C A` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} C B` }) }, + { note: (): Promise<Note> => post(bob, { text: `test ${keyword} C` }) }, + ], + }, + { + label: 'キーワード1つ(大文字小文字区別する)', + parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: true }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: 'keyword' }) }, + { note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }) }, + { note: (): Promise<Note> => post(bob, { text: 'KEYWORD' }), included: true }, + ], + }, + { + label: 'キーワード1つ(大文字小文字区別しない)', + parameters: (): object => ({ keywords: [['KEYWORD']], caseSensitive: false }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: 'keyword' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'kEyWoRd' }), included: true }, + { note: (): Promise<Note> => post(bob, { text: 'KEYWORD' }), included: true }, + ], + }, + { + label: '除外ワード1つ(大文字小文字区別する)', + parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: true }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `${keyword} kEyWoRd` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `${keyword} KEYWORD` }) }, + ], + }, + { + label: '除外ワード1つ(大文字小文字区別しない)', + parameters: (): object => ({ excludeKeywords: [['KEYWORD']], caseSensitive: false }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `${keyword} keyword` }) }, + { note: (): Promise<Note> => post(bob, { text: `${keyword} kEyWoRd` }) }, + { note: (): Promise<Note> => post(bob, { text: `${keyword} KEYWORD` }) }, + ], + }, + { + label: '添付ファイルを問わない', + parameters: (): object => ({ withFile: false }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true }, + ], + }, + { + label: '添付ファイル付きのみ', + parameters: (): object => ({ withFile: true }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `${keyword}`, fileIds: [bobFile.id] }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `${keyword}` }) }, + ], + }, + { + label: 'リプライ以外', + parameters: (): object => ({ withReplies: false }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }) }, + { note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true }, + ], + }, + { + label: 'リプライも含む', + parameters: (): object => ({ withReplies: true }), + posts: [ + { note: (): Promise<Note> => post(bob, { text: `${keyword}`, replyId: alicePost.id }), included: true }, + { note: (): Promise<Note> => post(bob, { text: `${keyword}` }), included: true }, + ], + }, + ])('が取得できること($label)', async ({ parameters, posts }) => { + const antenna = await successfulApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam, keywords: [[keyword]], ...parameters() }, + user: alice, + }); + + const notes = await posts.reduce(async (prev, current) => { + // includedに関わらずnote()は評価して投稿する。 + const p = await prev; + const n = await current.note(); + if (current.included) return p.concat(n); + return p; + }, Promise.resolve([] as Note[])); + + // alice視点でNoteを取り直す + const expected = await Promise.all(notes.reverse().map(s => successfulApiCall({ + endpoint: 'notes/show', + parameters: { noteId: s.id }, + user: alice, + }))); + + const response = await successfulApiCall({ + endpoint: 'antennas/notes', + parameters: { antennaId: antenna.id }, + user: alice, + }); + assert.deepStrictEqual( + response.map(({ userId, id, text }) => ({ userId, id, text })), + expected.map(({ userId, id, text }) => ({ userId, id, text }))); + assert.deepStrictEqual(response, expected); + }); + + test.skip('が取得でき、日付指定のPaginationに一貫性があること', async () => { }); + test.each([ + { label: 'ID指定', offsetBy: 'id' }, + + // BUG sinceDate, untilDateはsinceIdや他のエンドポイントとは異なり、その時刻に一致するレコードを含んでしまう。 + // { label: '日付指定', offsetBy: 'createdAt' }, + ] as const)('が取得でき、$labelのPaginationに一貫性があること', async ({ offsetBy }) => { + const antenna = await successfulApiCall({ + endpoint: 'antennas/create', + parameters: { ...defaultParam, keywords: [[keyword]] }, + user: alice, + }); + const notes = await [...Array(30)].reduce(async (prev, current, index) => { + const p = await prev; + const n = await post(alice, { text: `${keyword} (${index})` }); + return [n].concat(p); + }, Promise.resolve([] as Note[])); + + // antennas/notesは降順のみで、昇順をサポートしない。 + await testPaginationConsistency(notes, async (paginationParam) => { + return successfulApiCall({ + endpoint: 'antennas/notes', + parameters: { antennaId: antenna.id, ...paginationParam }, + user: alice, + }) as any as Note[]; + }, offsetBy, 'desc'); + }); + + // BUG 7日過ぎると作り直すしかない。 https://github.com/misskey-dev/misskey/issues/10476 + test.todo('を取得したときActiveに戻る'); + + //#endregion + }); +}); diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index 809ed2c66c..1a4a0b3545 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -124,6 +124,13 @@ export const react = async (user: any, note: any, reaction: string): Promise<any }, user); }; +export const userList = async (user: any, userList: any = {}): Promise<any> => { + const res = await api('users/lists/create', { + name: 'test', + }, user); + return res.body; +}; + export const page = async (user: any, page: any = {}): Promise<any> => { const res = await api('pages/create', { alignCenter: false, @@ -380,6 +387,96 @@ export const simpleGet = async (path: string, accept = '*/*', cookie: any = unde }; }; +/** + * あるAPIエンドポイントのPaginationが複数の条件で一貫した挙動であることをテストします。 + * (sinceId, untilId, sinceDate, untilDate, offset, limit) + * @param expected 期待値となるEntityの並び(例:Note[])昇順降順が一致している必要がある + * @param fetchEntities Entity[]を返却するテスト対象のAPIを呼び出す関数 + * @param offsetBy 何をキーとしてPaginationするか。 + * @param ordering 昇順・降順 + */ +export async function testPaginationConsistency<Entity extends { id: string, createdAt?: string }>( + expected: Entity[], + fetchEntities: (paginationParam: { + limit?: number, + offset?: number, + sinceId?: string, + untilId?: string, + sinceDate?: number, + untilDate?: number, + }) => Promise<Entity[]>, + offsetBy: 'offset' | 'id' | 'createdAt' = 'id', + ordering: 'desc' | 'asc' = 'desc'): Promise<void> { + const rangeToParam = (p: { limit?: number, until?: Entity, since?: Entity }): object => { + if (offsetBy === 'id') { + return { limit: p.limit, sinceId: p.since?.id, untilId: p.until?.id }; + } else { + const sinceDate = p.since?.createdAt !== undefined ? new Date(p.since.createdAt).getTime() : undefined; + const untilDate = p.until?.createdAt !== undefined ? new Date(p.until.createdAt).getTime() : undefined; + return { limit: p.limit, sinceDate, untilDate }; + } + }; + + for (const limit of [1, 5, 10, 100, undefined]) { + // 1. sinceId/DateとuntilId/Dateで両端を指定して取得した結果が期待通りになっていること + if (ordering === 'desc') { + const end = expected[expected.length - 1]; + let last = await fetchEntities(rangeToParam({ limit, since: end })); + const actual: Entity[] = []; + while (last.length !== 0) { + actual.push(...last); + last = await fetchEntities(rangeToParam({ limit, until: last[last.length - 1], since: end })); + } + actual.push(end); + assert.deepStrictEqual( + actual.map(({ id, createdAt }) => id + ':' + createdAt), + expected.map(({ id, createdAt }) => id + ':' + createdAt)); + } + + // 2. sinceId/Date指定+limitで取得してつなぎ合わせた結果が期待通りになっていること + if (ordering === 'asc') { + // 昇順にしたときの先頭(一番古いもの)をもってくる(expected[1]を基準に降順にして0番目) + let last = await fetchEntities({ limit: 1, untilId: expected[1].id }); + const actual: Entity[] = []; + while (last.length !== 0) { + actual.push(...last); + last = await fetchEntities(rangeToParam({ limit, since: last[last.length - 1] })); + } + assert.deepStrictEqual( + actual.map(({ id, createdAt }) => id + ':' + createdAt), + expected.map(({ id, createdAt }) => id + ':' + createdAt)); + } + + // 3. untilId指定+limitで取得してつなぎ合わせた結果が期待通りになっていること + if (ordering === 'desc') { + let last = await fetchEntities({ limit }); + const actual: Entity[] = []; + while (last.length !== 0) { + actual.push(...last); + last = await fetchEntities(rangeToParam({ limit, until: last[last.length - 1] })); + } + assert.deepStrictEqual( + actual.map(({ id, createdAt }) => id + ':' + createdAt), + expected.map(({ id, createdAt }) => id + ':' + createdAt)); + } + + // 4. offset指定+limitで取得してつなぎ合わせた結果が期待通りになっていること + if (offsetBy === 'offset') { + let last = await fetchEntities({ limit, offset: 0 }); + let offset = limit ?? 10; + const actual: Entity[] = []; + while (last.length !== 0) { + actual.push(...last); + last = await fetchEntities({ limit, offset }); + offset += limit ?? 10; + } + assert.deepStrictEqual( + actual.map(({ id, createdAt }) => id + ':' + createdAt), + expected.map(({ id, createdAt }) => id + ':' + createdAt)); + } + } +} + export async function initTestDb(justBorrow = false, initEntities?: any[]) { if (process.env.NODE_ENV !== 'test') throw 'NODE_ENV is not a test'; From 1eb35dd5bc647825ab9b4706ccb38ba00e3d8060 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 19 May 2023 20:59:21 +0900 Subject: [PATCH 064/213] delete /docs --- docs/DONATORS.md | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 docs/DONATORS.md diff --git a/docs/DONATORS.md b/docs/DONATORS.md deleted file mode 100644 index 9da5c1a94e..0000000000 --- a/docs/DONATORS.md +++ /dev/null @@ -1,25 +0,0 @@ -DONATORS -======== -The list of people who have sent donation for Misskey. - -(In random order, honorific titles are omitted.) - -* らふぁ -* 俺様 -* なぎうり -* スルメ https://surume.tk/ -* 藍 -* 音船 https://otofune.me/ -* aqz https://misskey.xyz/aqz -* kotodu "虚無創作中" -* Maya Minatsuki -* Knzk https://knzk.me/@Knzk -* ねじりわさび https://knzk.me/@y -* NCLS https://knzk.me/@imncls] -* こじま @skoji@sandbox.skoji.jp - -:heart: Thanks for donating, guys! - ---- - -If your name is missing, please contact us! From ee3f408c7d25accb5812c4f442ba7f4531e4b681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Sat, 20 May 2023 03:38:07 +0900 Subject: [PATCH 065/213] feat: impl IdlingRenderScheduler (#10547) * feat: impl IdleRender * test: pin time on Chromatic * test: pin time on Chromatic * fix: typo * style: rename * style: rename * chore: back to setTimeout * style: linebreak * refactor: remove unused budget option * refactor: use raw unix time * fix: conflict error * fix: floor * fix: subtract * Revert "fix: subtract" This reverts commit 2ef4afaafc69d2fb8329b04c1b124dfa97b7e863. * Revert "fix: floor" This reverts commit bef8ecdf45c6afc52138921d16e2caca78cfd38d. * Revert "refactor: use raw unix time" This reverts commit 5199e13cb2829f3036101f95445cca3cb9c83703. --- packages/frontend/.storybook/generate.tsx | 1 + .../components/MkAnalogClock.stories.impl.ts | 2 +- .../frontend/src/components/MkAnalogClock.vue | 34 ++++++++--------- .../components/MkDigitalClock.stories.impl.ts | 32 ++++++++++++++++ .../src/components/MkDigitalClock.vue | 21 +++++----- .../frontend/src/components/global/MkTime.vue | 1 - packages/frontend/src/scripts/idle-render.ts | 38 +++++++++++++++++++ 7 files changed, 100 insertions(+), 29 deletions(-) create mode 100644 packages/frontend/src/components/MkDigitalClock.stories.impl.ts create mode 100644 packages/frontend/src/scripts/idle-render.ts diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index 7c51d4c00c..f442422109 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -397,6 +397,7 @@ function toStories(component: string): string { Promise.all([ glob('src/components/global/*.vue'), glob('src/components/Mk{A,B}*.vue'), + glob('src/components/MkDigitalClock.vue'), glob('src/components/MkGalleryPostPreview.vue'), glob('src/components/MkSignupServerRules.vue'), glob('src/components/MkUserSetupDialog.vue'), diff --git a/packages/frontend/src/components/MkAnalogClock.stories.impl.ts b/packages/frontend/src/components/MkAnalogClock.stories.impl.ts index e7fbb47284..0aebdccf4f 100644 --- a/packages/frontend/src/components/MkAnalogClock.stories.impl.ts +++ b/packages/frontend/src/components/MkAnalogClock.stories.impl.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ import { StoryObj } from '@storybook/vue3'; +import isChromatic from 'chromatic/isChromatic'; import MkAnalogClock from './MkAnalogClock.vue'; -import isChromatic from 'chromatic'; export const Default = { render(args) { return { diff --git a/packages/frontend/src/components/MkAnalogClock.vue b/packages/frontend/src/components/MkAnalogClock.vue index f12020f810..05caffe7d0 100644 --- a/packages/frontend/src/components/MkAnalogClock.vue +++ b/packages/frontend/src/components/MkAnalogClock.vue @@ -39,6 +39,7 @@ --> <line + ref="sLine" :class="[$style.s, { [$style.animate]: !disableSAnimate && sAnimation !== 'none', [$style.elastic]: sAnimation === 'elastic', [$style.easeOut]: sAnimation === 'easeOut' }]" :x1="5 - (0 * (sHandLengthRatio * handsTailLength))" :y1="5 + (1 * (sHandLengthRatio * handsTailLength))" @@ -73,9 +74,10 @@ </template> <script lang="ts" setup> -import { computed, onMounted, onBeforeUnmount } from 'vue'; +import { computed, onMounted, onBeforeUnmount, ref } from 'vue'; import tinycolor from 'tinycolor2'; import { globalEvents } from '@/events.js'; +import { defaultIdlingRenderScheduler } from '@/scripts/idle-render.js'; // https://stackoverflow.com/questions/1878907/how-can-i-find-the-difference-between-two-angles const angleDiff = (a: number, b: number) => { @@ -145,6 +147,7 @@ let mAngle = $ref<number>(0); let sAngle = $ref<number>(0); let disableSAnimate = $ref(false); let sOneRound = false; +const sLine = ref<SVGPathElement>(); function tick() { const now = props.now(); @@ -160,17 +163,21 @@ function tick() { } hAngle = Math.PI * (h % (props.twentyfour ? 24 : 12) + (m + s / 60) / 60) / (props.twentyfour ? 12 : 6); mAngle = Math.PI * (m + s / 60) / 30; - if (sOneRound) { // 秒針が一周した際のアニメーションをよしなに処理する(これが無いと秒が59->0になったときに期待したアニメーションにならない) + if (sOneRound && sLine.value) { // 秒針が一周した際のアニメーションをよしなに処理する(これが無いと秒が59->0になったときに期待したアニメーションにならない) sAngle = Math.PI * 60 / 30; - window.setTimeout(() => { + defaultIdlingRenderScheduler.delete(tick); + sLine.value.addEventListener('transitionend', () => { disableSAnimate = true; - window.setTimeout(() => { + requestAnimationFrame(() => { sAngle = 0; - window.setTimeout(() => { + requestAnimationFrame(() => { disableSAnimate = false; - }, 100); - }, 100); - }, 700); + if (enabled) { + defaultIdlingRenderScheduler.add(tick); + } + }); + }); + }, { once: true }); } else { sAngle = Math.PI * s / 30; } @@ -194,20 +201,13 @@ function calcColors() { calcColors(); onMounted(() => { - const update = () => { - if (enabled) { - tick(); - window.setTimeout(update, 1000); - } - }; - update(); - + defaultIdlingRenderScheduler.add(tick); globalEvents.on('themeChanged', calcColors); }); onBeforeUnmount(() => { enabled = false; - + defaultIdlingRenderScheduler.delete(tick); globalEvents.off('themeChanged', calcColors); }); </script> diff --git a/packages/frontend/src/components/MkDigitalClock.stories.impl.ts b/packages/frontend/src/components/MkDigitalClock.stories.impl.ts new file mode 100644 index 0000000000..344f6de47c --- /dev/null +++ b/packages/frontend/src/components/MkDigitalClock.stories.impl.ts @@ -0,0 +1,32 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { StoryObj } from '@storybook/vue3'; +import isChromatic from 'chromatic/isChromatic'; +import MkDigitalClock from './MkDigitalClock.vue'; +export const Default = { + render(args) { + return { + components: { + MkDigitalClock, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '<MkDigitalClock v-bind="props" />', + }; + }, + args: { + now: isChromatic() ? () => new Date('2023-01-01T10:10:30') : undefined, + }, + parameters: { + layout: 'centered', + }, +} satisfies StoryObj<typeof MkDigitalClock>; diff --git a/packages/frontend/src/components/MkDigitalClock.vue b/packages/frontend/src/components/MkDigitalClock.vue index 278dc8a5e7..aea20f2489 100644 --- a/packages/frontend/src/components/MkDigitalClock.vue +++ b/packages/frontend/src/components/MkDigitalClock.vue @@ -11,19 +11,21 @@ </template> <script lang="ts" setup> -import { onUnmounted, ref, watch } from 'vue'; +import { onMounted, onUnmounted, ref, watch } from 'vue'; +import { defaultIdlingRenderScheduler } from '@/scripts/idle-render.js'; const props = withDefaults(defineProps<{ showS?: boolean; showMs?: boolean; offset?: number; + now?: () => Date; }>(), { showS: true, showMs: false, offset: 0 - new Date().getTimezoneOffset(), + now: () => new Date(), }); -let intervalId; const hh = ref(''); const mm = ref(''); const ss = ref(''); @@ -39,9 +41,9 @@ watch(showColon, (v) => { } }); -const tick = () => { - const now = new Date(); - now.setMinutes(now.getMinutes() + (new Date().getTimezoneOffset() + props.offset)); +const tick = (): void => { + const now = props.now(); + now.setMinutes(now.getMinutes() + now.getTimezoneOffset() + props.offset); hh.value = now.getHours().toString().padStart(2, '0'); mm.value = now.getMinutes().toString().padStart(2, '0'); ss.value = now.getSeconds().toString().padStart(2, '0'); @@ -52,13 +54,12 @@ const tick = () => { tick(); -watch(() => props.showMs, () => { - if (intervalId) window.clearInterval(intervalId); - intervalId = window.setInterval(tick, props.showMs ? 10 : 1000); -}, { immediate: true }); +onMounted(() => { + defaultIdlingRenderScheduler.add(tick); +}); onUnmounted(() => { - window.clearInterval(intervalId); + defaultIdlingRenderScheduler.delete(tick); }); </script> diff --git a/packages/frontend/src/components/global/MkTime.vue b/packages/frontend/src/components/global/MkTime.vue index 261cc0ee18..dfc3c89798 100644 --- a/packages/frontend/src/components/global/MkTime.vue +++ b/packages/frontend/src/components/global/MkTime.vue @@ -58,7 +58,6 @@ function tick() { if (props.mode === 'relative' || props.mode === 'detail') { tick(); - onUnmounted(() => { window.clearTimeout(tickId); }); diff --git a/packages/frontend/src/scripts/idle-render.ts b/packages/frontend/src/scripts/idle-render.ts new file mode 100644 index 0000000000..ccce8b02bf --- /dev/null +++ b/packages/frontend/src/scripts/idle-render.ts @@ -0,0 +1,38 @@ +class IdlingRenderScheduler { + #renderers: Set<FrameRequestCallback>; + #rafId: number; + #ricId: number; + + constructor() { + this.#renderers = new Set(); + this.#rafId = 0; + this.#ricId = requestIdleCallback((deadline) => this.#schedule(deadline)); + } + + #schedule(deadline: IdleDeadline): void { + if (deadline.timeRemaining()) { + this.#rafId = requestAnimationFrame((time) => { + for (const renderer of this.#renderers) { + renderer(time); + } + }); + } + this.#ricId = requestIdleCallback((arg) => this.#schedule(arg)); + } + + add(renderer: FrameRequestCallback): void { + this.#renderers.add(renderer); + } + + delete(renderer: FrameRequestCallback): void { + this.#renderers.delete(renderer); + } + + dispose(): void { + this.#renderers.clear(); + cancelAnimationFrame(this.#rafId); + cancelIdleCallback(this.#ricId); + } +} + +export const defaultIdlingRenderScheduler = new IdlingRenderScheduler(); From c685989e670b1945bb0ba2391a49ebcf3ee484aa Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 20 May 2023 10:05:35 +0900 Subject: [PATCH 066/213] refactor --- packages/frontend/src/ui/deck.vue | 77 +++++++++++-------- packages/frontend/src/ui/deck/column-core.vue | 38 --------- 2 files changed, 46 insertions(+), 69 deletions(-) delete mode 100644 packages/frontend/src/ui/deck/column-core.vue diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 585f727698..df695b9f4b 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -4,27 +4,24 @@ <div :class="$style.main"> <XStatusBars/> - <div ref="columnsEl" :class="[$style.columns, deckStore.reactiveState.columnAlign.value, { [$style.snapScroll]: snapScroll }]" @contextmenu.self.prevent="onContextmenu"> - <template v-for="ids in layout"> - <!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため --> - <section - v-if="ids.length > 1" - :class="$style.folder" - :style="columns.filter(c => ids.includes(c.id)).some(c => c.flexible) ? { flex: 1, minWidth: '350px' } : { width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }" - > - <DeckColumnCore v-for="id in ids" :ref="id" :key="id" :column="columns.find(c => c.id === id)" :isStacked="true" @parentFocus="moveFocus(id, $event)"/> - </section> - <DeckColumnCore - v-else - :ref="ids[0]" - :key="ids[0]" + <div ref="columnsEl" :class="[$style.sections, deckStore.reactiveState.columnAlign.value, { [$style.snapScroll]: snapScroll }]" @contextmenu.self.prevent="onContextmenu"> + <!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため --> + <section + v-for="ids in layout" + :class="$style.section" + :style="columns.filter(c => ids.includes(c.id)).some(c => c.flexible) ? { flex: 1, minWidth: '350px' } : { width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }" + > + <component + :is="columnComponents[columns.find(c => c.id === id)!.type] ?? XTlColumn" + v-for="id in ids" + :ref="id" + :key="id" :class="$style.column" - :column="columns.find(c => c.id === ids[0])" - :isStacked="false" - :style="columns.find(c => c.id === ids[0])!.flexible ? { flex: 1, minWidth: '350px' } : { width: columns.find(c => c.id === ids[0])!.width + 'px' }" - @parentFocus="moveFocus(ids[0], $event)" + :column="columns.find(c => c.id === id)" + :isStacked="ids.length > 1" + @parentFocus="moveFocus(id, $event)" /> - </template> + </section> <div v-if="layout.length === 0" class="_panel" :class="$style.onboarding"> <div>{{ i18n.ts._deck.introduction }}</div> <MkButton primary style="margin: 1em auto;" @click="addColumn">{{ i18n.ts._deck.addColumn }}</MkButton> @@ -87,7 +84,6 @@ import { computed, defineAsyncComponent, ref, watch } from 'vue'; import { v4 as uuid } from 'uuid'; import XCommon from './_common_/common.vue'; import { deckStore, addColumn as addColumnToStore, loadDeck, getProfiles, deleteProfile as deleteProfile_ } from './deck/deck-store'; -import DeckColumnCore from '@/ui/deck/column-core.vue'; import XSidebar from '@/ui/_common_/navbar.vue'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; import MkButton from '@/components/MkButton.vue'; @@ -100,8 +96,31 @@ import { mainRouter } from '@/router'; import { unisonReload } from '@/scripts/unison-reload'; import { deviceKind } from '@/scripts/device-kind'; import { defaultStore } from '@/store'; +import XMainColumn from '@/ui/deck/main-column.vue'; +import XTlColumn from '@/ui/deck/tl-column.vue'; +import XAntennaColumn from '@/ui/deck/antenna-column.vue'; +import XListColumn from '@/ui/deck/list-column.vue'; +import XChannelColumn from '@/ui/deck/channel-column.vue'; +import XNotificationsColumn from '@/ui/deck/notifications-column.vue'; +import XWidgetsColumn from '@/ui/deck/widgets-column.vue'; +import XMentionsColumn from '@/ui/deck/mentions-column.vue'; +import XDirectColumn from '@/ui/deck/direct-column.vue'; +import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue'; const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); +const columnComponents = { + main: XMainColumn, + widgets: XWidgetsColumn, + notifications: XNotificationsColumn, + tl: XTlColumn, + list: XListColumn, + channel: XChannelColumn, + antenna: XAntennaColumn, + mentions: XMentionsColumn, + direct: XDirectColumn, + roleTimeline: XRoleTimelineColumn, +}; + mainRouter.navHook = (path, flag): boolean => { if (flag === 'forcePage') return false; const noMainColumn = !deckStore.state.columns.some(x => x.type === 'main'); @@ -286,18 +305,18 @@ async function deleteProfile() { flex-direction: column; } -.columns { +.sections { flex: 1; display: flex; overflow-x: auto; overflow-y: clip; &.center { - > .column:first-of-type { + > .section:first-of-type { margin-left: auto; } - > .column:last-of-type { + > .section:last-of-type { margin-right: auto; } } @@ -307,7 +326,9 @@ async function deleteProfile() { } } -.column { +.section { + display: flex; + flex-direction: column; scroll-snap-align: start; flex-shrink: 0; border-right: solid var(--deckDividerThickness) var(--deckDivider); @@ -315,14 +336,8 @@ async function deleteProfile() { &:first-of-type { border-left: solid var(--deckDividerThickness) var(--deckDivider); } -} -.folder { - composes: column; - display: flex; - flex-direction: column; - - > *:not(:last-of-type) { + > .column:not(:last-of-type) { border-bottom: solid var(--deckDividerThickness) var(--deckDivider); } } diff --git a/packages/frontend/src/ui/deck/column-core.vue b/packages/frontend/src/ui/deck/column-core.vue deleted file mode 100644 index 29299cdcdb..0000000000 --- a/packages/frontend/src/ui/deck/column-core.vue +++ /dev/null @@ -1,38 +0,0 @@ -<template> -<!-- TODO: リファクタの余地がありそう --> -<div v-if="!column">たぶん見えちゃいけないやつ</div> -<XMainColumn v-else-if="column.type === 'main'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XWidgetsColumn v-else-if="column.type === 'widgets'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XNotificationsColumn v-else-if="column.type === 'notifications'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XTlColumn v-else-if="column.type === 'tl'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XListColumn v-else-if="column.type === 'list'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XChannelColumn v-else-if="column.type === 'channel'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XAntennaColumn v-else-if="column.type === 'antenna'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XMentionsColumn v-else-if="column.type === 'mentions'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XDirectColumn v-else-if="column.type === 'direct'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -<XRoleTimelineColumn v-else-if="column.type === 'roleTimeline'" :column="column" :isStacked="isStacked" @parentFocus="emit('parent-focus', $event)"/> -</template> - -<script lang="ts" setup> -import { } from 'vue'; -import XMainColumn from './main-column.vue'; -import XTlColumn from './tl-column.vue'; -import XAntennaColumn from './antenna-column.vue'; -import XListColumn from './list-column.vue'; -import XChannelColumn from './channel-column.vue'; -import XNotificationsColumn from './notifications-column.vue'; -import XWidgetsColumn from './widgets-column.vue'; -import XMentionsColumn from './mentions-column.vue'; -import XDirectColumn from './direct-column.vue'; -import XRoleTimelineColumn from './role-timeline-column.vue'; -import { Column } from './deck-store'; - -defineProps<{ - column?: Column; - isStacked: boolean; -}>(); - -const emit = defineEmits<{ - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; -}>(); -</script> From d177f97928c7223349f65820b931c6884dafe2f7 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 20 May 2023 10:12:18 +0900 Subject: [PATCH 067/213] refactor --- packages/frontend/src/ui/deck.vue | 6 +--- .../frontend/src/ui/deck/antenna-column.vue | 3 +- .../frontend/src/ui/deck/channel-column.vue | 3 +- packages/frontend/src/ui/deck/column.vue | 33 ++++++------------- .../frontend/src/ui/deck/direct-column.vue | 3 +- packages/frontend/src/ui/deck/list-column.vue | 3 +- packages/frontend/src/ui/deck/main-column.vue | 3 +- .../frontend/src/ui/deck/mentions-column.vue | 3 +- .../src/ui/deck/notifications-column.vue | 3 +- .../src/ui/deck/role-timeline-column.vue | 3 +- packages/frontend/src/ui/deck/tl-column.vue | 3 +- .../frontend/src/ui/deck/widgets-column.vue | 3 +- 12 files changed, 21 insertions(+), 48 deletions(-) diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index df695b9f4b..b91d6d7675 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -19,7 +19,6 @@ :class="$style.column" :column="columns.find(c => c.id === id)" :isStacked="ids.length > 1" - @parentFocus="moveFocus(id, $event)" /> </section> <div v-if="layout.length === 0" class="_panel" :class="$style.onboarding"> @@ -206,11 +205,8 @@ window.addEventListener('wheel', (ev) => { columnsEl.scrollLeft += ev.deltaY; } }); -loadDeck(); -function moveFocus(id: string, direction: 'up' | 'down' | 'left' | 'right') { - // TODO?? -} +loadDeck(); function changeProfile(ev: MouseEvent) { const items = ref([{ diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue index 661f4cab82..d35fa58638 100644 --- a/packages/frontend/src/ui/deck/antenna-column.vue +++ b/packages/frontend/src/ui/deck/antenna-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked"> <template #header> <i class="ti ti-antenna"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> @@ -23,7 +23,6 @@ const props = defineProps<{ const emit = defineEmits<{ (ev: 'loaded'): void; - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue index 14858750d5..a967d9f08e 100644 --- a/packages/frontend/src/ui/deck/channel-column.vue +++ b/packages/frontend/src/ui/deck/channel-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked"> <template #header> <i class="ti ti-device-tv"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> @@ -29,7 +29,6 @@ const props = defineProps<{ const emit = defineEmits<{ (ev: 'loaded'): void; - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 402bbe0352..e2c651beca 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -1,7 +1,5 @@ <template> -<!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため --> -<section - v-hotkey="keymap" +<div :class="[$style.root, { [$style.paged]: isMainColumn, [$style.naked]: naked, [$style.active]: active, [$style.isStacked]: isStacked, [$style.draghover]: draghover, [$style.dragging]: dragging, [$style.dropready]: dropready }]" @dragover.prevent.stop="onDragover" @dragleave="onDragleave" @@ -22,10 +20,10 @@ <span :class="$style.title"><slot name="header"></slot></span> <button v-tooltip="i18n.ts.settings" :class="$style.menu" class="_button" @click.stop="showSettingsMenu"><i class="ti ti-dots"></i></button> </header> - <div v-show="active" ref="body" :class="$style.body"> + <div v-if="active" ref="body" :class="$style.body"> <slot></slot> </div> -</section> +</div> </template> <script lang="ts" setup> @@ -49,12 +47,7 @@ const props = withDefaults(defineProps<{ naked: false, }); -const emit = defineEmits<{ - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; - (ev: 'change-active-state', v: boolean): void; -}>(); - -let body = $shallowRef<HTMLDivElement>(); +let body = $shallowRef<HTMLDivElement | null>(); let dragging = $ref(false); watch($$(dragging), v => os.deckGlobalEvents.emit(v ? 'column.dragStart' : 'column.dragEnd')); @@ -64,14 +57,6 @@ let dropready = $ref(false); const isMainColumn = $computed(() => props.column.type === 'main'); const active = $computed(() => props.column.active !== false); -watch($$(active), v => emit('change-active-state', v)); - -const keymap = $computed(() => ({ - 'shift+up': () => emit('parent-focus', 'up'), - 'shift+down': () => emit('parent-focus', 'down'), - 'shift+left': () => emit('parent-focus', 'left'), - 'shift+right': () => emit('parent-focus', 'right'), -})); onMounted(() => { os.deckGlobalEvents.on('column.dragStart', onOtherDragStart); @@ -190,10 +175,12 @@ function onContextmenu(ev: MouseEvent) { } function goTop() { - body.scrollTo({ - top: 0, - behavior: 'smooth', - }); + if (body) { + body.scrollTo({ + top: 0, + behavior: 'smooth', + }); + } } function onDragstart(ev) { diff --git a/packages/frontend/src/ui/deck/direct-column.vue b/packages/frontend/src/ui/deck/direct-column.vue index 5f76ea6d86..f3397ceae6 100644 --- a/packages/frontend/src/ui/deck/direct-column.vue +++ b/packages/frontend/src/ui/deck/direct-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :column="column" :isStacked="isStacked"> <template #header><i class="ti ti-mail" style="margin-right: 8px;"></i>{{ column.name }}</template> <MkNotes :pagination="pagination"/> @@ -18,7 +18,6 @@ defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); const pagination = { diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue index 165b654514..439db8815a 100644 --- a/packages/frontend/src/ui/deck/list-column.vue +++ b/packages/frontend/src/ui/deck/list-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked"> <template #header> <i class="ti ti-list"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> @@ -23,7 +23,6 @@ const props = defineProps<{ const emit = defineEmits<{ (ev: 'loaded'): void; - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); diff --git a/packages/frontend/src/ui/deck/main-column.vue b/packages/frontend/src/ui/deck/main-column.vue index 5448e3d2f3..b2b558b308 100644 --- a/packages/frontend/src/ui/deck/main-column.vue +++ b/packages/frontend/src/ui/deck/main-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn v-if="deckStore.state.alwaysShowMainColumn || mainRouter.currentRoute.value.name !== 'index'" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn v-if="deckStore.state.alwaysShowMainColumn || mainRouter.currentRoute.value.name !== 'index'" :column="column" :isStacked="isStacked"> <template #header> <template v-if="pageMetadata?.value"> <i :class="pageMetadata?.value.icon"></i> @@ -26,7 +26,6 @@ defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); diff --git a/packages/frontend/src/ui/deck/mentions-column.vue b/packages/frontend/src/ui/deck/mentions-column.vue index d6f9d88043..63fc57db74 100644 --- a/packages/frontend/src/ui/deck/mentions-column.vue +++ b/packages/frontend/src/ui/deck/mentions-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :column="column" :isStacked="isStacked"> <template #header><i class="ti ti-at" style="margin-right: 8px;"></i>{{ column.name }}</template> <MkNotes :pagination="pagination"/> @@ -18,7 +18,6 @@ defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); const pagination = { diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue index 48d88aa6cf..e10b496447 100644 --- a/packages/frontend/src/ui/deck/notifications-column.vue +++ b/packages/frontend/src/ui/deck/notifications-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :column="column" :isStacked="isStacked" :menu="menu" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :column="column" :isStacked="isStacked" :menu="menu"> <template #header><i class="ti ti-bell" style="margin-right: 8px;"></i>{{ column.name }}</template> <XNotifications :includeTypes="column.includingTypes"/> @@ -20,7 +20,6 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); function func() { diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue index cb189cae4b..df21fff431 100644 --- a/packages/frontend/src/ui/deck/role-timeline-column.vue +++ b/packages/frontend/src/ui/deck/role-timeline-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked"> <template #header> <i class="ti ti-badge"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> @@ -23,7 +23,6 @@ const props = defineProps<{ const emit = defineEmits<{ (ev: 'loaded'): void; - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue index a4fea6564b..c0840f9d98 100644 --- a/packages/frontend/src/ui/deck/tl-column.vue +++ b/packages/frontend/src/ui/deck/tl-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :column="column" :isStacked="isStacked"> <template #header> <i v-if="column.tl === 'home'" class="ti ti-home"></i> <i v-else-if="column.tl === 'local'" class="ti ti-planet"></i> @@ -36,7 +36,6 @@ const props = defineProps<{ const emit = defineEmits<{ (ev: 'loaded'): void; - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); let disabled = $ref(false); diff --git a/packages/frontend/src/ui/deck/widgets-column.vue b/packages/frontend/src/ui/deck/widgets-column.vue index af35d3ac13..2c4095ac4e 100644 --- a/packages/frontend/src/ui/deck/widgets-column.vue +++ b/packages/frontend/src/ui/deck/widgets-column.vue @@ -1,5 +1,5 @@ <template> -<XColumn :menu="menu" :naked="true" :column="column" :isStacked="isStacked" @parentFocus="$event => emit('parent-focus', $event)"> +<XColumn :menu="menu" :naked="true" :column="column" :isStacked="isStacked"> <template #header><i class="ti ti-apps" style="margin-right: 8px;"></i>{{ column.name }}</template> <div :class="$style.root"> @@ -22,7 +22,6 @@ const props = defineProps<{ }>(); const emit = defineEmits<{ - (ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void; }>(); let edit = $ref(false); From 05507a4beaf6340d42f806621aa685a73dbebeaf Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 20 May 2023 10:31:53 +0900 Subject: [PATCH 068/213] =?UTF-8?q?enhance(frontend):=20Deck=20UI=E3=82=92?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E3=81=97=E3=81=A6=E3=81=84=E3=82=8B=E5=A0=B4?= =?UTF-8?q?=E5=90=88=E3=80=81`/`=E4=BB=A5=E5=A4=96=E3=81=AB=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=82=BB=E3=82=B9=E3=81=97=E3=81=9F=E9=9A=9B=E3=81=AB?= =?UTF-8?q?Zen=20UI=E3=81=A7=E8=A1=A8=E7=A4=BA=E3=81=99=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve #10871 --- CHANGELOG.md | 2 ++ packages/frontend/src/boot/main-boot.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b462783de..53f903c64b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ - リアクションの取り消し/変更時に確認ダイアログを出すように - 開発者モードを追加 - AiScriptを0.13.3に更新 +- Deck UIを使用している場合、`/`以外にアクセスした際にZen UIで表示するように + - メインカラムを設置していない場合の問題を解決 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 - Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正 - fix:ロールタイムラインが無効でも投稿が流れてしまう問題の修正 diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index c0bfa4603e..76e8c50724 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -16,7 +16,7 @@ import { initializeSw } from '@/scripts/initialize-sw'; export async function mainBoot() { const { isClientUpdated } = await common(() => createApp( - new URLSearchParams(window.location.search).has('zen') ? defineAsyncComponent(() => import('@/ui/zen.vue')) : + new URLSearchParams(window.location.search).has('zen') || (ui === 'deck' && location.pathname !== '/') ? defineAsyncComponent(() => import('@/ui/zen.vue')) : !$i ? defineAsyncComponent(() => import('@/ui/visitor.vue')) : ui === 'deck' ? defineAsyncComponent(() => import('@/ui/deck.vue')) : ui === 'classic' ? defineAsyncComponent(() => import('@/ui/classic.vue')) : From 81fd94e6352ab3f565c4f54485b4a7369faf914f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Sat, 20 May 2023 10:34:31 +0900 Subject: [PATCH 069/213] chore: update slacc (#10867) Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> --- packages/backend/package.json | 23 +++--- pnpm-lock.yaml | 145 ++++++---------------------------- 2 files changed, 37 insertions(+), 131 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 89a1a986b7..1fca0cdefe 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -35,17 +35,18 @@ "@swc/core-win32-x64-msvc": "1.3.56", "@tensorflow/tfjs": "4.4.0", "@tensorflow/tfjs-node": "4.4.0", - "slacc-android-arm-eabi": "0.0.7", - "slacc-android-arm64": "0.0.7", - "slacc-darwin-arm64": "0.0.7", - "slacc-darwin-universal": "0.0.7", - "slacc-darwin-x64": "0.0.7", - "slacc-linux-arm-gnueabihf": "0.0.7", - "slacc-linux-arm64-gnu": "0.0.7", - "slacc-linux-arm64-musl": "0.0.7", - "slacc-linux-x64-gnu": "0.0.7", - "slacc-win32-arm64-msvc": "0.0.7", - "slacc-win32-x64-msvc": "0.0.7" + "slacc-android-arm-eabi": "0.0.9", + "slacc-android-arm64": "0.0.9", + "slacc-darwin-arm64": "0.0.9", + "slacc-darwin-universal": "0.0.9", + "slacc-darwin-x64": "0.0.9", + "slacc-freebsd-x64": "0.0.9", + "slacc-linux-arm-gnueabihf": "0.0.9", + "slacc-linux-arm64-gnu": "0.0.9", + "slacc-linux-arm64-musl": "0.0.9", + "slacc-linux-x64-gnu": "0.0.9", + "slacc-win32-arm64-msvc": "0.0.9", + "slacc-win32-x64-msvc": "0.0.9" }, "dependencies": { "@aws-sdk/client-s3": "3.321.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3c6f08ba4..9214dadb01 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -438,38 +438,41 @@ importers: specifier: 4.4.0 version: 4.4.0(seedrandom@3.0.5) slacc-android-arm-eabi: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-android-arm64: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-darwin-arm64: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-darwin-universal: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-darwin-x64: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 + slacc-freebsd-x64: + specifier: 0.0.9 + version: 0.0.9 slacc-linux-arm-gnueabihf: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-linux-arm64-gnu: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-linux-arm64-musl: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-linux-x64-gnu: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-win32-arm64-msvc: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 slacc-win32-x64-msvc: - specifier: 0.0.7 - version: 0.0.7 + specifier: 0.0.9 + version: 0.0.9 devDependencies: '@jest/globals': specifier: 29.5.0 @@ -17934,15 +17937,6 @@ packages: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true - /slacc-android-arm-eabi@0.0.7: - resolution: {integrity: sha512-6TikZlR1jsQscxwphhrf0U4xbsRy6zKJ0zmEULopTzbohgo5OLdZ7L3tQazkYlaaFe3YjGnVLW3FfGhhrajVog==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] - requiresBuild: true - dev: false - optional: true - /slacc-android-arm-eabi@0.0.9: resolution: {integrity: sha512-T5P5kJ5UwW3UMoPXqqHh9TpCnuCJDCoivoiuONDXrYPYKF8sKDPMVVg1x/KU9/m7e562x9vAMBrIyqFFbEW0Jw==} engines: {node: '>= 10'} @@ -17952,15 +17946,6 @@ packages: dev: false optional: true - /slacc-android-arm64@0.0.7: - resolution: {integrity: sha512-aol/9Rg0Hfqu81hpK+HXcx9sGYu4qqYU+djBCgLtb8I6ZMdWUdE0dp8ACBoTOmYn34hYGcUu4FlJUZ8r7Utucg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: false - optional: true - /slacc-android-arm64@0.0.9: resolution: {integrity: sha512-bcKB3ukcI5wWJa2clK/5cy6a4TKp51DRkdRuFgKLG05gBj1jbH+7+8iBPojljeY28LC2frmwVHGj3vDmkFUeYg==} engines: {node: '>= 10'} @@ -17970,15 +17955,6 @@ packages: dev: false optional: true - /slacc-darwin-arm64@0.0.7: - resolution: {integrity: sha512-PkV7rO/c9AImNYDacP+kxtOjVuxjy06IIOAxbWerIWvoeqsCNRtiF/dh+OqIACRFBuHIDe0oAyUCEMGUTnzjyQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - /slacc-darwin-arm64@0.0.9: resolution: {integrity: sha512-EspX0Hj6t0Afxbsyc6rY9mTOUQQrPVtWPwwNRaljGRorPyRDDefrU1OnJXRcwcIp0oCZrRrivRYlO7lai63EMw==} engines: {node: '>= 10'} @@ -17988,14 +17964,6 @@ packages: dev: false optional: true - /slacc-darwin-universal@0.0.7: - resolution: {integrity: sha512-Y9zXpL40m4Yq3dE5vdnAgfmn0Fxc0Bf0ixC9TSl96gKeIZEd6drkjfpHFdsIDNImzOksIAUo0HHiDdbEfE7zdQ==} - engines: {node: '>= 10'} - os: [darwin] - requiresBuild: true - dev: false - optional: true - /slacc-darwin-universal@0.0.9: resolution: {integrity: sha512-oQySg+9MPyKI9rwwwhmSZQkPks2/rq3k1P5HKwUgnaFZDvDtS/hpDycB3BxSDqWdD5kVA8PLCVa8pt9T5KyKfg==} engines: {node: '>= 10'} @@ -18004,15 +17972,6 @@ packages: dev: false optional: true - /slacc-darwin-x64@0.0.7: - resolution: {integrity: sha512-yKaGjX2YJl1QHe4NgqQVsY83jees3hjFxEUPoKpuZEQzWbMNn0XSyceFRGXIk1oDqiKU40UcsdcCedjYjSEd0Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false - optional: true - /slacc-darwin-x64@0.0.9: resolution: {integrity: sha512-9Xp7mVKKF2QvDiIZOBgwsDdL/+95KBiFTdbo+XtH6YKoh6zNw0aPpkA3JojsdSMYdGHUrxl8b7avhzI0USqeEg==} engines: {node: '>= 10'} @@ -18031,15 +17990,6 @@ packages: dev: false optional: true - /slacc-linux-arm-gnueabihf@0.0.7: - resolution: {integrity: sha512-pdWMdQeX6uA9JfSoWo9EHH0yRiwXKMbaKoS9gflDSyt/hjeR3Qx/KK7Wihd7HeXx7njlNdpr9ycTRmm5NgapQQ==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false - optional: true - /slacc-linux-arm-gnueabihf@0.0.9: resolution: {integrity: sha512-nhP6+jgd30sq+zFxFW7fGhnPwCfCCU0l1JKk3ORGFMl7wH7ippTDd1xGapKq7N+zgdgURbyj83P3wWb2gcRZ1w==} engines: {node: '>= 10'} @@ -18049,15 +17999,6 @@ packages: dev: false optional: true - /slacc-linux-arm64-gnu@0.0.7: - resolution: {integrity: sha512-hz9TK/w6fxeNZXyFzuLq5cJD/XRyJbo6BaIdW+VrKKnb9nkLnWlqDQtdtJk7Fw7zHjdY3Uqufjwm0iT6qBVpUQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /slacc-linux-arm64-gnu@0.0.9: resolution: {integrity: sha512-x7v0rDe0KNVe1Hl6/XCtkCpqdT283pyVaUmk+af0AnoesNRjYEK8DBc8i53N4nhotionHzPIZfu5gPAFkf6RhA==} engines: {node: '>= 10'} @@ -18067,15 +18008,6 @@ packages: dev: false optional: true - /slacc-linux-arm64-musl@0.0.7: - resolution: {integrity: sha512-wCDAYL7e+lh3XL7g87Ui/Bb2Ap9GcBqeJuj2yHIx6MYC8ontwFSXhqRTmd2zmPLmZA5Nc11aKGN11YNu0Pnwlw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /slacc-linux-arm64-musl@0.0.9: resolution: {integrity: sha512-jyq/ylITHIXTQX5ZqAbi7Mn5SdRgYJi+uEoUCi5UhoXb9LjpNzhkFuY29Je3IkVIIV7AEcAxIlvjdymXdzcF5w==} engines: {node: '>= 10'} @@ -18085,15 +18017,6 @@ packages: dev: false optional: true - /slacc-linux-x64-gnu@0.0.7: - resolution: {integrity: sha512-E5+2cveizpfHXCk/Hu5VfslWFeDVw47nywODiJ8CsofT2l5ITfYPMFEBXm9ORY25mGBTgsO6lJYiF9Hz4FlS9Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false - optional: true - /slacc-linux-x64-gnu@0.0.9: resolution: {integrity: sha512-Xs/F81H7cKhlIBigFID6CJlgjy0NeDUGV1CI1MI5mSVHsVI8dUO8zXWETjo6o8krJPgfjT5Jd4tAgvUFct5hng==} engines: {node: '>= 10'} @@ -18103,15 +18026,6 @@ packages: dev: false optional: true - /slacc-win32-arm64-msvc@0.0.7: - resolution: {integrity: sha512-3a+qnkZbP+Pr5RZuzd0Vi1uCal137QiJajRAWT4r7qwu+Zidd50x2oikQ4rAegqZVTm8qTwVmWA+WmH8WHI7iw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: false - optional: true - /slacc-win32-arm64-msvc@0.0.9: resolution: {integrity: sha512-C+H0VkKbEEnRbcXRIG5rIaXlg7IZw3o1BbvqA71B8ouQRCu/dNRuH9EQsOYXWltndY42zZi8IupNIwydTUg+Mg==} engines: {node: '>= 10'} @@ -18121,15 +18035,6 @@ packages: dev: false optional: true - /slacc-win32-x64-msvc@0.0.7: - resolution: {integrity: sha512-ydFdZ7wEXQPsw2Tg+yG9uJdCGTehyPtrWBVUMa7fojr3j1gbtThXS2l9Ad/6fYYi2VwdaYPLWbwV3GYElPGL8g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: false - optional: true - /slacc-win32-x64-msvc@0.0.9: resolution: {integrity: sha512-bElMnBbeMatCtVp2/+hBS6Z+846nQImEul9nBEr4gfezHotOM6MqR6PI7UQQzGhozpgwiDg2l1ub1MdOIgYizg==} engines: {node: '>= 10'} From 915ed39715b3e424cb252d303765d92f7effd283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Sat, 20 May 2023 10:35:23 +0900 Subject: [PATCH 070/213] feat: support summary_large_image (#10862) * feat: use summary_large_image * chore: add video * chore: ignore sensitive image on note --- packages/backend/src/server/web/views/base.pug | 2 +- .../backend/src/server/web/views/channel.pug | 1 + packages/backend/src/server/web/views/clip.pug | 1 + packages/backend/src/server/web/views/flash.pug | 1 + .../src/server/web/views/gallery-post.pug | 1 + packages/backend/src/server/web/views/note.pug | 16 +++++++++++++++- packages/backend/src/server/web/views/page.pug | 1 + packages/backend/src/server/web/views/user.pug | 1 + 8 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index cb5d05a403..25513cc4cc 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -25,7 +25,6 @@ html meta(name='referrer' content='origin') meta(name='theme-color' content= themeColor || '#86b300') meta(name='theme-color-orig' content= themeColor || '#86b300') - meta(property='twitter:card' content='summary') meta(property='og:site_name' content= instanceName || 'Misskey') meta(name='viewport' content='width=device-width, initial-scale=1') link(rel='icon' href= icon || '/favicon.ico') @@ -59,6 +58,7 @@ html meta(property='og:title' content= title || 'Misskey') meta(property='og:description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨') meta(property='og:image' content= img) + meta(property='twitter:card' content='summary') style include ../style.css diff --git a/packages/backend/src/server/web/views/channel.pug b/packages/backend/src/server/web/views/channel.pug index 486f0ecc47..c514025e0b 100644 --- a/packages/backend/src/server/web/views/channel.pug +++ b/packages/backend/src/server/web/views/channel.pug @@ -16,3 +16,4 @@ block og meta(property='og:description' content= channel.description) meta(property='og:url' content= url) meta(property='og:image' content= channel.bannerUrl) + meta(property='twitter:card' content='summary') diff --git a/packages/backend/src/server/web/views/clip.pug b/packages/backend/src/server/web/views/clip.pug index 74dc62f1e7..5a0018803a 100644 --- a/packages/backend/src/server/web/views/clip.pug +++ b/packages/backend/src/server/web/views/clip.pug @@ -17,6 +17,7 @@ block og meta(property='og:description' content= clip.description) meta(property='og:url' content= url) meta(property='og:image' content= avatarUrl) + meta(property='twitter:card' content='summary') block meta if profile.noCrawle diff --git a/packages/backend/src/server/web/views/flash.pug b/packages/backend/src/server/web/views/flash.pug index 5594fcdfbf..1549aa7906 100644 --- a/packages/backend/src/server/web/views/flash.pug +++ b/packages/backend/src/server/web/views/flash.pug @@ -17,6 +17,7 @@ block og meta(property='og:description' content= flash.summary) meta(property='og:url' content= url) meta(property='og:image' content= avatarUrl) + meta(property='twitter:card' content='summary') block meta if profile.noCrawle diff --git a/packages/backend/src/server/web/views/gallery-post.pug b/packages/backend/src/server/web/views/gallery-post.pug index 10f2d269bc..a458d7f8c7 100644 --- a/packages/backend/src/server/web/views/gallery-post.pug +++ b/packages/backend/src/server/web/views/gallery-post.pug @@ -17,6 +17,7 @@ block og meta(property='og:description' content= post.description) meta(property='og:url' content= url) meta(property='og:image' content= post.files[0].thumbnailUrl) + meta(property='twitter:card' content='summary_large_image') block meta if user.host || profile.noCrawle diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index badfcccd61..874c48c602 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -5,6 +5,8 @@ block vars - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`; - const url = `${config.url}/notes/${note.id}`; - const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null; + - const image = (note.files || []).find(file => file.type.startsWith('image/') && !file.type.isSensitive) + - const video = (note.files || []).find(file => file.type.startsWith('video/') && !file.type.isSensitive) block title = `${title} | ${instanceName}` @@ -17,7 +19,19 @@ block og meta(property='og:title' content= title) meta(property='og:description' content= summary) meta(property='og:url' content= url) - meta(property='og:image' content= avatarUrl) + if video + meta(property='og:video:url' content= video.url) + meta(property='og:video:secure_url' content= video.url) + meta(property='og:video:type' content= video.type) + // FIXME: add width and height + // FIXME: add embed player for Twitter + if image + meta(property='twitter:card' content='summary_large_image') + meta(property='og:image' content= image.url) + else + meta(property='twitter:card' content='summary') + meta(property='og:image' content= avatarUrl) + block meta if user.host || isRenote || profile.noCrawle diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug index ddffc361c8..08bb08ffe7 100644 --- a/packages/backend/src/server/web/views/page.pug +++ b/packages/backend/src/server/web/views/page.pug @@ -17,6 +17,7 @@ block og meta(property='og:description' content= page.summary) meta(property='og:url' content= url) meta(property='og:image' content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : avatarUrl) + meta(property='twitter:card' content= page.eyeCatchingImage ? 'summary_large_image' : 'summary') block meta if profile.noCrawle diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug index f4c83aa89d..83d57349a6 100644 --- a/packages/backend/src/server/web/views/user.pug +++ b/packages/backend/src/server/web/views/user.pug @@ -16,6 +16,7 @@ block og meta(property='og:description' content= profile.description) meta(property='og:url' content= url) meta(property='og:image' content= avatarUrl) + meta(property='twitter:card' content='summary') block meta if user.host || profile.noCrawle From ca75afe06593ac261c998687316a5d2dc0c62d9a Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 20 May 2023 10:35:56 +0900 Subject: [PATCH 071/213] 13.13.0-beta.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 53604fb866..7b5d729b73 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0-beta.2", + "version": "13.13.0-beta.3", "codename": "nasubi", "repository": { "type": "git", From 38e6f3f77656d431675dfeb1a6215f240382d46b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 20 May 2023 12:32:51 +0900 Subject: [PATCH 072/213] :art: --- .../frontend/src/pages/admin/federation.vue | 2 +- packages/frontend/src/pages/admin/files.vue | 42 +++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/frontend/src/pages/admin/federation.vue b/packages/frontend/src/pages/admin/federation.vue index b2a7ef6685..a8d6dcf3de 100644 --- a/packages/frontend/src/pages/admin/federation.vue +++ b/packages/frontend/src/pages/admin/federation.vue @@ -3,7 +3,7 @@ <MkStickyContainer> <template #header><XHeader :actions="headerActions"/></template> <MkSpacer :contentMax="900"> - <div> + <div class="_gaps"> <div> <MkInput v-model="host" :debounce="true" class=""> <template #prefix><i class="ti ti-search"></i></template> diff --git a/packages/frontend/src/pages/admin/files.vue b/packages/frontend/src/pages/admin/files.vue index a8ebb7f108..b204a1a64a 100644 --- a/packages/frontend/src/pages/admin/files.vue +++ b/packages/frontend/src/pages/admin/files.vue @@ -3,29 +3,27 @@ <MkStickyContainer> <template #header><XHeader :actions="headerActions"/></template> <MkSpacer :contentMax="900"> - <div> - <div> - <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap;"> - <MkSelect v-model="origin" style="margin: 0; flex: 1;"> - <template #label>{{ i18n.ts.instance }}</template> - <option value="combined">{{ i18n.ts.all }}</option> - <option value="local">{{ i18n.ts.local }}</option> - <option value="remote">{{ i18n.ts.remote }}</option> - </MkSelect> - <MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="pagination.params.origin === 'local'"> - <template #label>{{ i18n.ts.host }}</template> - </MkInput> - </div> - <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap; padding-top: 1.2em;"> - <MkInput v-model="userId" :debounce="true" type="search" style="margin: 0; flex: 1;"> - <template #label>User ID</template> - </MkInput> - <MkInput v-model="type" :debounce="true" type="search" style="margin: 0; flex: 1;"> - <template #label>MIME type</template> - </MkInput> - </div> - <MkFileListForAdmin :pagination="pagination" :viewMode="viewMode"/> + <div class="_gaps"> + <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap;"> + <MkSelect v-model="origin" style="margin: 0; flex: 1;"> + <template #label>{{ i18n.ts.instance }}</template> + <option value="combined">{{ i18n.ts.all }}</option> + <option value="local">{{ i18n.ts.local }}</option> + <option value="remote">{{ i18n.ts.remote }}</option> + </MkSelect> + <MkInput v-model="searchHost" :debounce="true" type="search" style="margin: 0; flex: 1;" :disabled="pagination.params.origin === 'local'"> + <template #label>{{ i18n.ts.host }}</template> + </MkInput> </div> + <div class="inputs" style="display: flex; gap: var(--margin); flex-wrap: wrap;"> + <MkInput v-model="userId" :debounce="true" type="search" style="margin: 0; flex: 1;"> + <template #label>User ID</template> + </MkInput> + <MkInput v-model="type" :debounce="true" type="search" style="margin: 0; flex: 1;"> + <template #label>MIME type</template> + </MkInput> + </div> + <MkFileListForAdmin :pagination="pagination" :viewMode="viewMode"/> </div> </MkSpacer> </MkStickyContainer> From 22a6bd6b22314185319f4d092a277fbf8ac07ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Sat, 20 May 2023 14:03:05 +0000 Subject: [PATCH 073/213] ci: fix branch name --- .github/workflows/storybook.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index a9a5be7588..19a03e5dea 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -86,7 +86,7 @@ jobs: if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then echo "skip=true" >> $GITHUB_OUTPUT fi - pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static $(echo "$CHROMATIC_PARAMETER") + pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name ${{ github.event.pull_request.head.ref }} $(echo "$CHROMATIC_PARAMETER") env: CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - name: Notify that Chromatic detects changes From 9a6ce1e86786756c73286b08d0ad275eaaad09d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Sat, 20 May 2023 18:52:08 +0000 Subject: [PATCH 074/213] ci: fix head user --- .github/workflows/storybook.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 19a03e5dea..6cb1b34997 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -86,7 +86,11 @@ jobs: if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then echo "skip=true" >> $GITHUB_OUTPUT fi - pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name ${{ github.event.pull_request.head.ref }} $(echo "$CHROMATIC_PARAMETER") + BRANCH="${{ github.event.pull_request.head.user.login }}:${{ github.event.pull_request.head.ref }}" + if [ "$BRANCH" = "misskey-dev:${{ github.event.pull_request.head.ref }}" ]; then + BRANCH="${{ github.event.pull_request.head.ref }}" + fi + pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name $BRANCH $(echo "$CHROMATIC_PARAMETER") env: CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - name: Notify that Chromatic detects changes From acdcd7c623fccf6a3e02caebafac1c53cd180c20 Mon Sep 17 00:00:00 2001 From: Caipira <caipira@libnare.net> Date: Wed, 24 May 2023 09:43:38 +0900 Subject: [PATCH 075/213] enhance(frontend): improve signup complete ui (#10876) * enhance(frontend): improve signup complete ui * relocation * tweak * Update _boot_.ts --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> --- packages/frontend/src/_boot_.ts | 4 +- .../frontend/src/pages/signup-complete.vue | 90 ++++++++++++++----- 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/packages/frontend/src/_boot_.ts b/packages/frontend/src/_boot_.ts index a8efafca61..921c161765 100644 --- a/packages/frontend/src/_boot_.ts +++ b/packages/frontend/src/_boot_.ts @@ -5,7 +5,9 @@ import '@/style.scss'; import { mainBoot } from './boot/main-boot'; import { subBoot } from './boot/sub-boot'; -if (['/share', '/auth', '/miauth'].includes(location.pathname)) { +const subBootPaths = ['/share', '/auth', '/miauth', '/signup-complete']; + +if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) { subBoot(); } else { mainBoot(); diff --git a/packages/frontend/src/pages/signup-complete.vue b/packages/frontend/src/pages/signup-complete.vue index 079cbb3d33..2700601c44 100644 --- a/packages/frontend/src/pages/signup-complete.vue +++ b/packages/frontend/src/pages/signup-complete.vue @@ -1,37 +1,83 @@ <template> -<div> - {{ i18n.ts.processing }} +<div :class="$style.root"> + <MkAnimBg style="position: fixed; top: 0;"/> + <div :class="$style.formContainer"> + <form :class="$style.form" class="_panel" @submit.prevent="submit()"> + <div :class="$style.banner"> + <i class="ti ti-user-check"></i> + </div> + <div class="_gaps_m" style="padding: 32px;"> + <div>{{ i18n.t('clickToFinishEmailVerification', { ok: i18n.ts.gotIt }) }}</div> + <div> + <MkButton gradate large rounded type="submit" :disabled="submitting" data-cy-admin-ok style="margin: 0 auto;"> + {{ submitting ? i18n.ts.processing : i18n.ts.gotIt }}<MkEllipsis v-if="submitting"/> + </MkButton> + </div> + </div> + </form> + </div> </div> </template> <script lang="ts" setup> -import { onMounted } from 'vue'; -import * as os from '@/os'; +import { } from 'vue'; +import MkButton from '@/components/MkButton.vue'; +import MkAnimBg from '@/components/MkAnimBg.vue'; import { login } from '@/account'; import { i18n } from '@/i18n'; -import { definePageMetadata } from '@/scripts/page-metadata'; +import * as os from '@/os'; + +let submitting = $ref(false); const props = defineProps<{ code: string; }>(); -onMounted(async () => { - await os.alert({ - type: 'info', - text: i18n.t('clickToFinishEmailVerification', { ok: i18n.ts.gotIt }), - }); - const res = await os.apiWithDialog('signup-pending', { +function submit() { + if (submitting) return; + submitting = true; + + os.api('signup-pending', { code: props.code, + }).then(res => { + return login(res.i, '/'); + }).catch(() => { + submitting = false; + + os.alert({ + type: 'error', + text: i18n.ts.somethingHappened, + }); }); - login(res.i, '/'); -}); - -const headerActions = $computed(() => []); - -const headerTabs = $computed(() => []); - -definePageMetadata({ - title: i18n.ts.signup, - icon: 'ti ti-user', -}); +} </script> + +<style lang="scss" module> +.root { +} + +.formContainer { + min-height: 100svh; + padding: 32px 32px 64px 32px; + box-sizing: border-box; +display: grid; +place-content: center; +} + +.form { + position: relative; + z-index: 10; + border-radius: var(--radius); + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); + overflow: clip; + max-width: 500px; +} + +.banner { + padding: 16px; + text-align: center; + font-size: 26px; + background-color: var(--accentedBg); + color: var(--accent); +} +</style> From ed902658a97802942d0d823dfaa9ff46fa4c7598 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 24 May 2023 09:59:30 +0900 Subject: [PATCH 076/213] refactor --- packages/backend/src/GlobalModule.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts index 5fb4e8ef3c..564787392f 100644 --- a/packages/backend/src/GlobalModule.ts +++ b/packages/backend/src/GlobalModule.ts @@ -4,7 +4,7 @@ import * as Redis from 'ioredis'; import { DataSource } from 'typeorm'; import { MeiliSearch } from 'meilisearch'; import { DI } from './di-symbols.js'; -import { loadConfig } from './config.js'; +import { Config, loadConfig } from './config.js'; import { createPostgresDataSource } from './postgres.js'; import { RepositoryModule } from './models/RepositoryModule.js'; import type { Provider, OnApplicationShutdown } from '@nestjs/common'; @@ -25,7 +25,7 @@ const $db: Provider = { const $meilisearch: Provider = { provide: DI.meilisearch, - useFactory: (config) => { + useFactory: (config: Config) => { if (config.meilisearch) { return new MeiliSearch({ host: `${config.meilisearch.ssl ? 'https' : 'http' }://${config.meilisearch.host}:${config.meilisearch.port}`, @@ -40,7 +40,7 @@ const $meilisearch: Provider = { const $redis: Provider = { provide: DI.redis, - useFactory: (config) => { + useFactory: (config: Config) => { return new Redis.Redis({ port: config.redis.port, host: config.redis.host, @@ -55,7 +55,7 @@ const $redis: Provider = { const $redisForPub: Provider = { provide: DI.redisForPub, - useFactory: (config) => { + useFactory: (config: Config) => { const redis = new Redis.Redis({ port: config.redisForPubsub.port, host: config.redisForPubsub.host, @@ -71,7 +71,7 @@ const $redisForPub: Provider = { const $redisForSub: Provider = { provide: DI.redisForSub, - useFactory: (config) => { + useFactory: (config: Config) => { const redis = new Redis.Redis({ port: config.redisForPubsub.port, host: config.redisForPubsub.host, From 1de774fa3d39beef4fee1b3b1287745194e577f1 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 24 May 2023 10:16:42 +0900 Subject: [PATCH 077/213] update deps --- package.json | 2 +- packages/backend/package.json | 14 +- packages/frontend/package.json | 50 +- pnpm-lock.yaml | 1303 +++++++++++++++++--------------- 4 files changed, 716 insertions(+), 653 deletions(-) diff --git a/package.json b/package.json index 7b5d729b73..7723623198 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@typescript-eslint/eslint-plugin": "5.59.5", "@typescript-eslint/parser": "5.59.5", "cross-env": "7.0.3", - "cypress": "12.12.0", + "cypress": "12.13.0", "eslint": "8.40.0", "start-server-and-test": "2.0.0" }, diff --git a/packages/backend/package.json b/packages/backend/package.json index 1fca0cdefe..4aa79222f0 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -63,9 +63,9 @@ "@fastify/multipart": "7.6.0", "@fastify/static": "6.10.1", "@fastify/view": "7.4.1", - "@nestjs/common": "9.4.1", - "@nestjs/core": "9.4.1", - "@nestjs/testing": "9.4.1", + "@nestjs/common": "9.4.2", + "@nestjs/core": "9.4.2", + "@nestjs/testing": "9.4.2", "@peertube/http-signature": "1.7.0", "@sinonjs/fake-timers": "10.0.2", "@swc/cli": "0.1.62", @@ -103,7 +103,7 @@ "jsdom": "21.1.1", "json5": "2.2.3", "jsonld": "8.1.1", - "meilisearch": "0.32.3", + "meilisearch": "0.32.4", "jsrsasign": "10.8.6", "mfm-js": "0.23.3", "mime-types": "2.1.35", @@ -179,11 +179,11 @@ "@types/jsonld": "1.5.8", "@types/jsrsasign": "10.5.8", "@types/mime-types": "2.1.1", - "@types/node": "20.2.1", + "@types/node": "20.2.3", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.8", "@types/oauth": "0.9.1", - "@types/pg": "8.6.6", + "@types/pg": "8.10.1", "@types/pug": "2.0.6", "@types/punycode": "2.1.0", "@types/qrcode": "1.5.0", @@ -197,7 +197,7 @@ "@types/sinonjs__fake-timers": "8.1.2", "@types/tinycolor2": "1.4.3", "@types/tmp": "0.2.3", - "@types/unzipper": "0.10.5", + "@types/unzipper": "0.10.6", "@types/uuid": "9.0.1", "@types/vary": "1.1.0", "@types/web-push": "3.3.2", diff --git a/packages/frontend/package.json b/packages/frontend/package.json index a32cfbd8a7..9a471c9c07 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -22,7 +22,7 @@ "@syuilo/aiscript": "0.13.3", "@tabler/icons-webfont": "2.17.0", "@vitejs/plugin-vue": "4.2.3", - "@vue-macros/reactivity-transform": "0.3.7", + "@vue-macros/reactivity-transform": "0.3.8", "@vue/compiler-sfc": "3.3.4", "autosize": "6.0.1", "broadcast-channel": "4.20.2", @@ -53,7 +53,7 @@ "punycode": "2.3.0", "querystring": "0.2.1", "rndstr": "1.0.0", - "rollup": "3.22.0", + "rollup": "3.23.0", "s-age": "1.1.2", "sanitize-html": "2.10.0", "sass": "1.62.1", @@ -77,37 +77,37 @@ "vuedraggable": "next" }, "devDependencies": { - "@storybook/addon-actions": "7.0.12", - "@storybook/addon-essentials": "7.0.12", - "@storybook/addon-interactions": "7.0.12", - "@storybook/addon-links": "7.0.12", - "@storybook/addon-storysource": "7.0.12", - "@storybook/addons": "7.0.12", - "@storybook/blocks": "7.0.12", - "@storybook/core-events": "7.0.12", + "@storybook/addon-actions": "7.0.15", + "@storybook/addon-essentials": "7.0.15", + "@storybook/addon-interactions": "7.0.15", + "@storybook/addon-links": "7.0.15", + "@storybook/addon-storysource": "7.0.15", + "@storybook/addons": "7.0.15", + "@storybook/blocks": "7.0.15", + "@storybook/core-events": "7.0.15", "@storybook/jest": "0.1.0", - "@storybook/manager-api": "7.0.12", - "@storybook/preview-api": "7.0.12", - "@storybook/react": "7.0.12", - "@storybook/react-vite": "7.0.12", + "@storybook/manager-api": "7.0.15", + "@storybook/preview-api": "7.0.15", + "@storybook/react": "7.0.15", + "@storybook/react-vite": "7.0.15", "@storybook/testing-library": "0.1.0", - "@storybook/theming": "7.0.12", - "@storybook/types": "7.0.12", - "@storybook/vue3": "7.0.12", - "@storybook/vue3-vite": "7.0.12", + "@storybook/theming": "7.0.15", + "@storybook/types": "7.0.15", + "@storybook/vue3": "7.0.15", + "@storybook/vue3-vite": "7.0.15", "@testing-library/jest-dom": "5.16.5", "@testing-library/vue": "7.0.0", "@types/escape-regexp": "0.0.1", "@types/estree": "1.0.1", "@types/gulp": "4.0.10", "@types/gulp-rename": "2.0.2", - "@types/matter-js": "0.18.3", + "@types/matter-js": "0.18.4", "@types/micromatch": "4.0.2", - "@types/node": "20.2.1", + "@types/node": "20.2.3", "@types/punycode": "2.1.0", "@types/sanitize-html": "2.9.0", "@types/seedrandom": "3.0.5", - "@types/testing-library__jest-dom": "^5.14.5", + "@types/testing-library__jest-dom": "^5.14.6", "@types/throttle-debounce": "5.0.0", "@types/tinycolor2": "1.4.3", "@types/uuid": "9.0.1", @@ -117,13 +117,13 @@ "@typescript-eslint/parser": "5.59.5", "@vitest/coverage-c8": "0.31.1", "@vue/runtime-core": "3.3.4", - "astring": "1.8.4", + "astring": "1.8.5", "chokidar-cli": "3.0.0", "cross-env": "7.0.3", - "cypress": "12.12.0", + "cypress": "12.13.0", "eslint": "8.40.0", "eslint-plugin-import": "2.27.5", - "eslint-plugin-vue": "9.13.0", + "eslint-plugin-vue": "9.14.0", "fast-glob": "3.2.12", "happy-dom": "9.19.2", "micromatch": "3.1.10", @@ -133,7 +133,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "start-server-and-test": "2.0.0", - "storybook": "7.0.12", + "storybook": "7.0.15", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "summaly": "github:misskey-dev/summaly", "vite-plugin-turbosnap": "1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9214dadb01..2ab17897f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,8 +53,8 @@ importers: specifier: 7.0.3 version: 7.0.3 cypress: - specifier: 12.12.0 - version: 12.12.0 + specifier: 12.13.0 + version: 12.13.0 eslint: specifier: 8.40.0 version: 8.40.0 @@ -107,14 +107,14 @@ importers: specifier: 7.4.1 version: 7.4.1 '@nestjs/common': - specifier: 9.4.1 - version: 9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1) + specifier: 9.4.2 + version: 9.4.2(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/core': - specifier: 9.4.1 - version: 9.4.1(@nestjs/common@9.4.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) + specifier: 9.4.2 + version: 9.4.2(@nestjs/common@9.4.2)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/testing': - specifier: 9.4.1 - version: 9.4.1(@nestjs/common@9.4.1)(@nestjs/core@9.4.1) + specifier: 9.4.2 + version: 9.4.2(@nestjs/common@9.4.2)(@nestjs/core@9.4.2) '@peertube/http-signature': specifier: 1.7.0 version: 1.7.0 @@ -230,8 +230,8 @@ importers: specifier: 10.8.6 version: 10.8.6 meilisearch: - specifier: 0.32.3 - version: 0.32.3 + specifier: 0.32.4 + version: 0.32.4 mfm-js: specifier: 0.23.3 version: 0.23.3 @@ -526,8 +526,8 @@ importers: specifier: 2.1.1 version: 2.1.1 '@types/node': - specifier: 20.2.1 - version: 20.2.1 + specifier: 20.2.3 + version: 20.2.3 '@types/node-fetch': specifier: 3.0.3 version: 3.0.3 @@ -538,8 +538,8 @@ importers: specifier: 0.9.1 version: 0.9.1 '@types/pg': - specifier: 8.6.6 - version: 8.6.6 + specifier: 8.10.1 + version: 8.10.1 '@types/pug': specifier: 2.0.6 version: 2.0.6 @@ -580,8 +580,8 @@ importers: specifier: 0.2.3 version: 0.2.3 '@types/unzipper': - specifier: 0.10.5 - version: 0.10.5 + specifier: 0.10.6 + version: 0.10.6 '@types/uuid': specifier: 9.0.1 version: 9.0.1 @@ -620,7 +620,7 @@ importers: version: 6.1.0 jest: specifier: 29.5.0 - version: 29.5.0(@types/node@20.2.1) + version: 29.5.0(@types/node@20.2.3) jest-mock: specifier: 29.5.0 version: 29.5.0 @@ -632,16 +632,16 @@ importers: version: 14.1.2 '@rollup/plugin-alias': specifier: 5.0.0 - version: 5.0.0(rollup@3.22.0) + version: 5.0.0(rollup@3.23.0) '@rollup/plugin-json': specifier: 6.0.0 - version: 6.0.0(rollup@3.22.0) + version: 6.0.0(rollup@3.23.0) '@rollup/plugin-replace': specifier: 5.0.2 - version: 5.0.2(rollup@3.22.0) + version: 5.0.2(rollup@3.23.0) '@rollup/pluginutils': specifier: 5.0.2 - version: 5.0.2(rollup@3.22.0) + version: 5.0.2(rollup@3.23.0) '@syuilo/aiscript': specifier: 0.13.3 version: 0.13.3 @@ -652,8 +652,8 @@ importers: specifier: 4.2.3 version: 4.2.3(vite@4.3.8)(vue@3.3.4) '@vue-macros/reactivity-transform': - specifier: 0.3.7 - version: 0.3.7(rollup@3.22.0)(vue@3.3.4) + specifier: 0.3.8 + version: 0.3.8(rollup@3.23.0)(vue@3.3.4) '@vue/compiler-sfc': specifier: 3.3.4 version: 3.3.4 @@ -745,8 +745,8 @@ importers: specifier: 1.0.0 version: 1.0.0 rollup: - specifier: 3.22.0 - version: 3.22.0 + specifier: 3.23.0 + version: 3.23.0 s-age: specifier: 1.1.2 version: 1.1.2 @@ -797,7 +797,7 @@ importers: version: 1.8.0 vite: specifier: 4.3.8 - version: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + version: 4.3.8(@types/node@20.2.3)(sass@1.62.1) vue: specifier: 3.3.4 version: 3.3.4 @@ -812,59 +812,59 @@ importers: version: 4.1.0(vue@3.3.4) devDependencies: '@storybook/addon-actions': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-essentials': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-interactions': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-links': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-storysource': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/addons': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/blocks': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/core-events': - specifier: 7.0.12 - version: 7.0.12 + specifier: 7.0.15 + version: 7.0.15 '@storybook/jest': specifier: 0.1.0 version: 0.1.0 '@storybook/manager-api': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/preview-api': - specifier: 7.0.12 - version: 7.0.12 + specifier: 7.0.15 + version: 7.0.15 '@storybook/react': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) '@storybook/react-vite': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8) '@storybook/testing-library': specifier: 0.1.0 version: 0.1.0 '@storybook/theming': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0) '@storybook/types': - specifier: 7.0.12 - version: 7.0.12 + specifier: 7.0.15 + version: 7.0.15 '@storybook/vue3': - specifier: 7.0.12 - version: 7.0.12(vue@3.3.4) + specifier: 7.0.15 + version: 7.0.15(vue@3.3.4) '@storybook/vue3-vite': - specifier: 7.0.12 - version: 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4) + specifier: 7.0.15 + version: 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4) '@testing-library/jest-dom': specifier: 5.16.5 version: 5.16.5 @@ -884,14 +884,14 @@ importers: specifier: 2.0.2 version: 2.0.2 '@types/matter-js': - specifier: 0.18.3 - version: 0.18.3 + specifier: 0.18.4 + version: 0.18.4 '@types/micromatch': specifier: 4.0.2 version: 4.0.2 '@types/node': - specifier: 20.2.1 - version: 20.2.1 + specifier: 20.2.3 + version: 20.2.3 '@types/punycode': specifier: 2.1.0 version: 2.1.0 @@ -902,8 +902,8 @@ importers: specifier: 3.0.5 version: 3.0.5 '@types/testing-library__jest-dom': - specifier: ^5.14.5 - version: 5.14.5 + specifier: ^5.14.6 + version: 5.14.6 '@types/throttle-debounce': specifier: 5.0.0 version: 5.0.0 @@ -932,8 +932,8 @@ importers: specifier: 3.3.4 version: 3.3.4 astring: - specifier: 1.8.4 - version: 1.8.4 + specifier: 1.8.5 + version: 1.8.5 chokidar-cli: specifier: 3.0.0 version: 3.0.0 @@ -941,8 +941,8 @@ importers: specifier: 7.0.3 version: 7.0.3 cypress: - specifier: 12.12.0 - version: 12.12.0 + specifier: 12.13.0 + version: 12.13.0 eslint: specifier: 8.40.0 version: 8.40.0 @@ -950,8 +950,8 @@ importers: specifier: 2.27.5 version: 2.27.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0) eslint-plugin-vue: - specifier: 9.13.0 - version: 9.13.0(eslint@8.40.0) + specifier: 9.14.0 + version: 9.14.0(eslint@8.40.0) fast-glob: specifier: 3.2.12 version: 3.2.12 @@ -980,11 +980,11 @@ importers: specifier: 2.0.0 version: 2.0.0 storybook: - specifier: 7.0.12 - version: 7.0.12 + specifier: 7.0.15 + version: 7.0.15 storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.12)(@storybook/components@7.0.12)(@storybook/core-events@7.0.12)(@storybook/manager-api@7.0.12)(@storybook/preview-api@7.0.12)(@storybook/theming@7.0.12)(@storybook/types@7.0.12)(react-dom@18.2.0)(react@18.2.0) + version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.15)(@storybook/components@7.0.15)(@storybook/core-events@7.0.15)(@storybook/manager-api@7.0.15)(@storybook/preview-api@7.0.15)(@storybook/theming@7.0.15)(@storybook/types@7.0.15)(react-dom@18.2.0)(react@18.2.0) summaly: specifier: github:misskey-dev/summaly version: github.com/misskey-dev/summaly/77dd5654bb82280b38c1f50e51a771c33f3df503 @@ -1188,13 +1188,13 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/chunked-blob-reader@3.310.0: resolution: {integrity: sha512-CrJS3exo4mWaLnWxfCH+w88Ou0IcAZSIkk4QbmxiHl/5Dq705OLoxf4385MVyExpqpeVJYOYQ2WaD8i/pQZ2fg==} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/client-s3@3.321.1: @@ -1295,7 +1295,7 @@ packages: '@aws-sdk/util-user-agent-browser': 3.310.0 '@aws-sdk/util-user-agent-node': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 transitivePeerDependencies: - aws-crt dev: false @@ -1335,7 +1335,7 @@ packages: '@aws-sdk/util-user-agent-browser': 3.310.0 '@aws-sdk/util-user-agent-node': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 transitivePeerDependencies: - aws-crt dev: false @@ -1379,7 +1379,7 @@ packages: '@aws-sdk/util-user-agent-node': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 fast-xml-parser: 4.1.2 - tslib: 2.5.0 + tslib: 2.5.2 transitivePeerDependencies: - aws-crt dev: false @@ -1391,7 +1391,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-config-provider': 3.310.0 '@aws-sdk/util-middleware': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/credential-provider-env@3.310.0: @@ -1400,7 +1400,7 @@ packages: dependencies: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/credential-provider-imds@3.310.0: @@ -1411,7 +1411,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 '@aws-sdk/url-parser': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/credential-provider-ini@3.321.1: @@ -1426,7 +1426,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 transitivePeerDependencies: - aws-crt dev: false @@ -1444,7 +1444,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 transitivePeerDependencies: - aws-crt dev: false @@ -1456,7 +1456,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/credential-provider-sso@3.321.1: @@ -1468,7 +1468,7 @@ packages: '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/token-providers': 3.321.1 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 transitivePeerDependencies: - aws-crt dev: false @@ -1479,7 +1479,7 @@ packages: dependencies: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/eventstream-codec@3.310.0: @@ -1488,7 +1488,7 @@ packages: '@aws-crypto/crc32': 3.0.0 '@aws-sdk/types': 3.310.0 '@aws-sdk/util-hex-encoding': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/eventstream-serde-browser@3.310.0: @@ -1497,7 +1497,7 @@ packages: dependencies: '@aws-sdk/eventstream-serde-universal': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/eventstream-serde-config-resolver@3.310.0: @@ -1505,7 +1505,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/eventstream-serde-node@3.310.0: @@ -1514,7 +1514,7 @@ packages: dependencies: '@aws-sdk/eventstream-serde-universal': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/eventstream-serde-universal@3.310.0: @@ -1523,7 +1523,7 @@ packages: dependencies: '@aws-sdk/eventstream-codec': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/fetch-http-handler@3.310.0: @@ -1533,7 +1533,7 @@ packages: '@aws-sdk/querystring-builder': 3.310.0 '@aws-sdk/types': 3.310.0 '@aws-sdk/util-base64': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/hash-blob-browser@3.310.0: @@ -1541,7 +1541,7 @@ packages: dependencies: '@aws-sdk/chunked-blob-reader': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/hash-node@3.310.0: @@ -1551,7 +1551,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-buffer-from': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/hash-stream-node@3.310.0: @@ -1560,21 +1560,21 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/invalid-dependency@3.310.0: resolution: {integrity: sha512-1s5RG5rSPXoa/aZ/Kqr5U/7lqpx+Ry81GprQ2bxWqJvWQIJ0IRUwo5pk8XFxbKVr/2a+4lZT/c3OGoBOM1yRRA==} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/is-array-buffer@3.310.0: resolution: {integrity: sha512-urnbcCR+h9NWUnmOtet/s4ghvzsidFmspfhYaHAmSRdy9yDjdjBJMFjjsn85A1ODUktztm+cVncXjQ38WCMjMQ==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/lib-storage@3.321.1(@aws-sdk/abort-controller@3.310.0)(@aws-sdk/client-s3@3.321.1): @@ -1599,7 +1599,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-bucket-endpoint@3.310.0: @@ -1610,7 +1610,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-arn-parser': 3.310.0 '@aws-sdk/util-config-provider': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-content-length@3.310.0: @@ -1619,7 +1619,7 @@ packages: dependencies: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-endpoint@3.310.0: @@ -1630,7 +1630,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/url-parser': 3.310.0 '@aws-sdk/util-middleware': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-expect-continue@3.310.0: @@ -1639,7 +1639,7 @@ packages: dependencies: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-flexible-checksums@3.310.0: @@ -1652,7 +1652,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-host-header@3.310.0: @@ -1661,7 +1661,7 @@ packages: dependencies: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-location-constraint@3.310.0: @@ -1669,7 +1669,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-logger@3.310.0: @@ -1677,7 +1677,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-recursion-detection@3.310.0: @@ -1686,7 +1686,7 @@ packages: dependencies: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-retry@3.310.0: @@ -1698,7 +1698,7 @@ packages: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-middleware': 3.310.0 '@aws-sdk/util-retry': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 uuid: 8.3.2 dev: false @@ -1709,7 +1709,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 '@aws-sdk/util-arn-parser': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-sdk-sts@3.310.0: @@ -1718,7 +1718,7 @@ packages: dependencies: '@aws-sdk/middleware-signing': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-serde@3.310.0: @@ -1726,7 +1726,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-signing@3.310.0: @@ -1738,7 +1738,7 @@ packages: '@aws-sdk/signature-v4': 3.310.0 '@aws-sdk/types': 3.310.0 '@aws-sdk/util-middleware': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-ssec@3.310.0: @@ -1746,14 +1746,14 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-stack@3.310.0: resolution: {integrity: sha512-010O1PD+UAcZVKRvqEusE1KJqN96wwrf6QsqbRM0ywsKQ21NDweaHvEDlds2VHpgmofxkRLRu/IDrlPkKRQrRg==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/middleware-user-agent@3.319.0: @@ -1763,7 +1763,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/types': 3.310.0 '@aws-sdk/util-endpoints': 3.319.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/node-config-provider@3.310.0: @@ -1773,7 +1773,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/node-http-handler@3.321.1: @@ -1792,7 +1792,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/protocol-http@3.310.0: @@ -1800,7 +1800,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/querystring-builder@3.310.0: @@ -1809,7 +1809,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 '@aws-sdk/util-uri-escape': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/querystring-parser@3.310.0: @@ -1817,7 +1817,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/service-error-classification@3.310.0: @@ -1830,7 +1830,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/signature-v4-multi-region@3.310.0: @@ -1845,7 +1845,7 @@ packages: '@aws-sdk/protocol-http': 3.310.0 '@aws-sdk/signature-v4': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/signature-v4@3.310.0: @@ -1858,7 +1858,7 @@ packages: '@aws-sdk/util-middleware': 3.310.0 '@aws-sdk/util-uri-escape': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/smithy-client@3.316.0: @@ -1867,7 +1867,7 @@ packages: dependencies: '@aws-sdk/middleware-stack': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/token-providers@3.321.1: @@ -1878,7 +1878,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/shared-ini-file-loader': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 transitivePeerDependencies: - aws-crt dev: false @@ -1887,7 +1887,7 @@ packages: resolution: {integrity: sha512-j8eamQJ7YcIhw7fneUfs8LYl3t01k4uHi4ZDmNRgtbmbmTTG3FZc2MotStZnp3nZB6vLiPF1o5aoJxWVvkzS6A==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/url-parser@3.310.0: @@ -1895,14 +1895,14 @@ packages: dependencies: '@aws-sdk/querystring-parser': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-arn-parser@3.310.0: resolution: {integrity: sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-base64@3.310.0: @@ -1910,20 +1910,20 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/util-buffer-from': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-body-length-browser@3.310.0: resolution: {integrity: sha512-sxsC3lPBGfpHtNTUoGXMQXLwjmR0zVpx0rSvzTPAuoVILVsp5AU/w5FphNPxD5OVIjNbZv9KsKTuvNTiZjDp9g==} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-body-length-node@3.310.0: resolution: {integrity: sha512-2tqGXdyKhyA6w4zz7UPoS8Ip+7sayOg9BwHNidiGm2ikbDxm1YrCfYXvCBdwaJxa4hJfRVz+aL9e+d3GqPI9pQ==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-buffer-from@3.310.0: @@ -1931,14 +1931,14 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/is-array-buffer': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-config-provider@3.310.0: resolution: {integrity: sha512-xIBaYo8dwiojCw8vnUcIL4Z5tyfb1v3yjqyJKJWV/dqKUFOOS0U591plmXbM+M/QkXyML3ypon1f8+BoaDExrg==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-defaults-mode-browser@3.316.0: @@ -1948,7 +1948,7 @@ packages: '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 bowser: 2.11.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-defaults-mode-node@3.316.0: @@ -1960,7 +1960,7 @@ packages: '@aws-sdk/node-config-provider': 3.310.0 '@aws-sdk/property-provider': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-endpoints@3.319.0: @@ -1968,28 +1968,28 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-hex-encoding@3.310.0: resolution: {integrity: sha512-sVN7mcCCDSJ67pI1ZMtk84SKGqyix6/0A1Ab163YKn+lFBQRMKexleZzpYzNGxYzmQS6VanP/cfU7NiLQOaSfA==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-locate-window@3.208.0: resolution: {integrity: sha512-iua1A2+P7JJEDHVgvXrRJSvsnzG7stYSGQnBVphIUlemwl6nN5D+QrgbjECtrbxRz8asYFHSzhdhECqN+tFiBg==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-middleware@3.310.0: resolution: {integrity: sha512-FTSUKL/eRb9X6uEZClrTe27QFXUNNp7fxYrPndZwk1hlaOP5ix+MIHBcI7pIiiY/JPfOUmPyZOu+HetlFXjWog==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-retry@3.310.0: @@ -1997,7 +1997,7 @@ packages: engines: {node: '>= 14.0.0'} dependencies: '@aws-sdk/service-error-classification': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-stream-browser@3.310.0: @@ -2008,7 +2008,7 @@ packages: '@aws-sdk/util-base64': 3.310.0 '@aws-sdk/util-hex-encoding': 3.310.0 '@aws-sdk/util-utf8': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-stream-node@3.321.1: @@ -2018,14 +2018,14 @@ packages: '@aws-sdk/node-http-handler': 3.321.1 '@aws-sdk/types': 3.310.0 '@aws-sdk/util-buffer-from': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-uri-escape@3.310.0: resolution: {integrity: sha512-drzt+aB2qo2LgtDoiy/3sVG8w63cgLkqFIa2NFlGpUgHFWTXkqtbgf4L5QdjRGKWhmZsnqkbtL7vkSWEcYDJ4Q==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-user-agent-browser@3.310.0: @@ -2033,7 +2033,7 @@ packages: dependencies: '@aws-sdk/types': 3.310.0 bowser: 2.11.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-user-agent-node@3.310.0: @@ -2047,13 +2047,13 @@ packages: dependencies: '@aws-sdk/node-config-provider': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-utf8-browser@3.259.0: resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-utf8@3.310.0: @@ -2061,7 +2061,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@aws-sdk/util-buffer-from': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/util-waiter@3.310.0: @@ -2070,14 +2070,14 @@ packages: dependencies: '@aws-sdk/abort-controller': 3.310.0 '@aws-sdk/types': 3.310.0 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@aws-sdk/xml-builder@3.310.0: resolution: {integrity: sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@babel/code-frame@7.18.6: @@ -2102,7 +2102,7 @@ packages: '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) '@babel/helper-module-transforms': 7.21.2 '@babel/helpers': 7.21.0 - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/template': 7.20.7 '@babel/traverse': 7.21.3 '@babel/types': 7.21.5 @@ -2371,6 +2371,13 @@ packages: dependencies: '@babel/types': 7.21.5 + /@babel/parser@7.21.9: + resolution: {integrity: sha512-q5PNg/Bi1OpGgx5jYlvWZwAorZepEudDMCLtj967aeS7WMont7dUZI46M2XwcIQqvUlMxWfdLFu4S/qSxeUu5g==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.21.5 + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} engines: {node: '>=6.9.0'} @@ -3345,7 +3352,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/types': 7.21.5 dev: true @@ -3359,7 +3366,7 @@ packages: '@babel/helper-function-name': 7.21.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/types': 7.21.5 debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 @@ -3971,7 +3978,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 chalk: 4.1.2 jest-message-util: 29.5.0 jest-util: 29.5.0 @@ -3992,14 +3999,14 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.5.0 - jest-config: 29.5.0(@types/node@20.2.1) + jest-config: 29.5.0(@types/node@20.2.3) jest-haste-map: 29.5.0 jest-message-util: 29.5.0 jest-regex-util: 29.4.3 @@ -4033,7 +4040,7 @@ packages: dependencies: '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 jest-mock: 29.5.0 dev: true @@ -4060,7 +4067,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@sinonjs/fake-timers': 10.0.2 - '@types/node': 20.2.1 + '@types/node': 20.2.3 jest-message-util: 29.5.0 jest-mock: 29.5.0 jest-util: 29.5.0 @@ -4093,7 +4100,7 @@ packages: '@jest/transform': 29.5.0 '@jest/types': 29.5.0 '@jridgewell/trace-mapping': 0.3.17 - '@types/node': 20.2.1 + '@types/node': 20.2.3 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -4187,7 +4194,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: true @@ -4199,7 +4206,7 @@ packages: '@jest/schemas': 29.4.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/yargs': 17.0.19 chalk: 4.1.2 dev: true @@ -4218,7 +4225,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.0.4) typescript: 5.0.4 - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) dev: true /@jridgewell/gen-mapping@0.3.2: @@ -4431,8 +4438,8 @@ packages: tar-fs: 2.1.1 dev: true - /@nestjs/common@9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1): - resolution: {integrity: sha512-VA5XXLAvXG3vY4GqvvuevL7Ooi5RRsov+ydMlgc1rPswgxkSVWaPTqNibsP4C6y5XJtKfc4Ol+zoe2w/LeYJTQ==} + /@nestjs/common@9.4.2(reflect-metadata@0.1.13)(rxjs@7.8.1): + resolution: {integrity: sha512-sea+qZnbD5x3YWZDVQT/wbVJ2NiABaM1tyZTLuW9hpkcM2KFA96xKtK3VaCxyz49zoXIgSOefsyK7HuUMCe27Q==} peerDependencies: cache-manager: <=5 class-transformer: '*' @@ -4450,12 +4457,12 @@ packages: iterare: 1.2.1 reflect-metadata: 0.1.13 rxjs: 7.8.1 - tslib: 2.5.0 + tslib: 2.5.2 uid: 2.0.2 dev: false - /@nestjs/core@9.4.1(@nestjs/common@9.4.1)(reflect-metadata@0.1.13)(rxjs@7.8.1): - resolution: {integrity: sha512-KbG0L5UVaI9kjZv3QkSyCf8Cz5lj11hy60n+NPoO0GZmJbhWkfsjletwKpwlpMeGbi7jLGTsU+HPDgprANSNEA==} + /@nestjs/core@9.4.2(@nestjs/common@9.4.2)(reflect-metadata@0.1.13)(rxjs@7.8.1): + resolution: {integrity: sha512-S5K9GTpjBqEJtu5VxRsVaaGEBZ1bkY+Ht4+2hqZSKsI+rzcEB5hcvR+5KiMsMY1VGYvlZ99lxYz72p4h8B0mKw==} requiresBuild: true peerDependencies: '@nestjs/common': ^9.0.0 @@ -4472,21 +4479,21 @@ packages: '@nestjs/websockets': optional: true dependencies: - '@nestjs/common': 9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1) + '@nestjs/common': 9.4.2(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 path-to-regexp: 3.2.0 reflect-metadata: 0.1.13 rxjs: 7.8.1 - tslib: 2.5.0 + tslib: 2.5.2 uid: 2.0.2 transitivePeerDependencies: - encoding dev: false - /@nestjs/testing@9.4.1(@nestjs/common@9.4.1)(@nestjs/core@9.4.1): - resolution: {integrity: sha512-DErwymDxsY80dH2v3eZDVOhjDv6oY6YsaI3GnUEU+gUrYa8qxxKPHfOofAsFF7SExfeJo5c8RQRfazW3bQupJA==} + /@nestjs/testing@9.4.2(@nestjs/common@9.4.2)(@nestjs/core@9.4.2): + resolution: {integrity: sha512-4WZPJz85zLVZkhmWYq+Unr43MixISelg/TyuX1YFZYOeukIN+O6fRtAAPIKLqRQsiY0rE/h8FAEbYGWhNrRfSA==} peerDependencies: '@nestjs/common': ^9.0.0 '@nestjs/core': ^9.0.0 @@ -4498,9 +4505,9 @@ packages: '@nestjs/platform-express': optional: true dependencies: - '@nestjs/common': 9.4.1(reflect-metadata@0.1.13)(rxjs@7.8.1) - '@nestjs/core': 9.4.1(@nestjs/common@9.4.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) - tslib: 2.5.0 + '@nestjs/common': 9.4.2(reflect-metadata@0.1.13)(rxjs@7.8.1) + '@nestjs/core': 9.4.2(@nestjs/common@9.4.2)(reflect-metadata@0.1.13)(rxjs@7.8.1) + tslib: 2.5.2 dev: false /@nodelib/fs.scandir@2.1.5: @@ -4629,7 +4636,7 @@ packages: '@redis/client': 1.4.2 dev: true - /@rollup/plugin-alias@5.0.0(rollup@3.22.0): + /@rollup/plugin-alias@5.0.0(rollup@3.23.0): resolution: {integrity: sha512-l9hY5chSCjuFRPsnRm16twWBiSApl2uYFLsepQYwtBuAxNMQ/1dJqADld40P0Jkqm65GRTLy/AC6hnpVebtLsA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4638,11 +4645,11 @@ packages: rollup: optional: true dependencies: - rollup: 3.22.0 + rollup: 3.23.0 slash: 4.0.0 dev: false - /@rollup/plugin-json@6.0.0(rollup@3.22.0): + /@rollup/plugin-json@6.0.0(rollup@3.23.0): resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4651,11 +4658,11 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.22.0) - rollup: 3.22.0 + '@rollup/pluginutils': 5.0.2(rollup@3.23.0) + rollup: 3.23.0 dev: false - /@rollup/plugin-replace@5.0.2(rollup@3.22.0): + /@rollup/plugin-replace@5.0.2(rollup@3.23.0): resolution: {integrity: sha512-M9YXNekv/C/iHHK+cvORzfRYfPbq0RDD8r0G+bMiTXjNGKulPnCT9O3Ss46WfhI6ZOCgApOP7xAdmCQJ+U2LAA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4664,9 +4671,9 @@ packages: rollup: optional: true dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.22.0) + '@rollup/pluginutils': 5.0.2(rollup@3.23.0) magic-string: 0.27.0 - rollup: 3.22.0 + rollup: 3.23.0 dev: false /@rollup/pluginutils@4.2.1: @@ -4677,7 +4684,7 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/pluginutils@5.0.2(rollup@3.22.0): + /@rollup/pluginutils@5.0.2(rollup@3.23.0): resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} engines: {node: '>=14.0.0'} peerDependencies: @@ -4689,7 +4696,7 @@ packages: '@types/estree': 1.0.1 estree-walker: 2.0.2 picomatch: 2.3.1 - rollup: 3.22.0 + rollup: 3.23.0 dev: false /@rushstack/node-core-library@3.58.0(@types/node@18.16.3): @@ -4813,7 +4820,7 @@ packages: object-hash: 3.0.0 packageurl-js: 1.0.1 semver: 7.5.1 - tslib: 2.5.0 + tslib: 2.5.2 dev: false /@snyk/graphlib@2.1.9-patch.3: @@ -4840,8 +4847,8 @@ packages: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} dev: false - /@storybook/addon-actions@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-f07Mc3qwcG9heGsuUUTIJbWF2nw/Ite3mvyIZY2VbgwhMUMVHj4knY4fh/LojwcUmmmc7CNZu3sJN/wIqpaHCQ==} + /@storybook/addon-actions@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-1urDxJpG5BTmZCbda+93iuCNwzj7AiPt/VlmpDpd9Mc/WTOKBg0cXo8oBLibOZgCTLEx+4sq5eVgdMVybBa87g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4851,14 +4858,14 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 dequal: 2.0.3 lodash: 4.17.21 polished: 4.2.2 @@ -4871,8 +4878,8 @@ packages: uuid: 9.0.0 dev: true - /@storybook/addon-backgrounds@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-sAZSxsbj3CcabowALKTafpdnqXMBZB8C42s4Uxv11FCP50GqrP8jp2TqsIiDZxUbeXwI094W/gHnw41MSphG8Q==} + /@storybook/addon-backgrounds@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-cUb5i3dn4MhXFtCuA8p/ax6dtFaJ52+q6Dex8L40DtWC/fPrC2igAXN4o7WhRHztY6utZSLy4invEjqAFCEYRw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4882,22 +4889,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-controls@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-/+yBhswN1N7ttR1NGN94HE/25VELm4YuBtrkh+LJeKP/eQ5CZpLjexASN2GZcfmdnkwIYZAEH0X/AImLaCJAWA==} + /@storybook/addon-controls@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sLLYVgprrsC6k0/2ErKJSa6Jtlxo+lHSO41K6nB0WQmQ8Moroe2kBaNTP6C9+zhGuI427Eueuzs3cKHwn/eIKw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4907,15 +4914,15 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.12 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.0.12 - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/blocks': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.15 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.0.15 + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 lodash: 4.17.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4924,8 +4931,8 @@ packages: - supports-color dev: true - /@storybook/addon-docs@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-zgg4sq34Zz8TN74+kSogxRHsIZ5gsIazJpa0osZp91nJQvsKUEfldjBtQWbBWzjVCrWmzOhW5/RLCnmCNm9y/w==} + /@storybook/addon-docs@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-FBXHFwm6wH3SYsv73SmVQMs+FxP8eSoWlDFBEZ1lulCK7f0NKflhzTTimyh9m+aRCsbvC2Vm+7/9CJ5OZU+GEQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4934,19 +4941,19 @@ packages: '@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.21.3) '@jest/transform': 29.5.0 '@mdx-js/react': 2.3.0(react@18.2.0) - '@storybook/blocks': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/csf-plugin': 7.0.12 - '@storybook/csf-tools': 7.0.12 + '@storybook/blocks': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/csf-plugin': 7.0.15 + '@storybook/csf-tools': 7.0.15 '@storybook/global': 5.0.0 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.0.12 - '@storybook/postinstall': 7.0.12 - '@storybook/preview-api': 7.0.12 - '@storybook/react-dom-shim': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/node-logger': 7.0.15 + '@storybook/postinstall': 7.0.15 + '@storybook/preview-api': 7.0.15 + '@storybook/react-dom-shim': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 fs-extra: 11.1.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4957,25 +4964,25 @@ packages: - supports-color dev: true - /@storybook/addon-essentials@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Js2cxvauAf8fkA5D0QrqPPe/FvpY1DbJp61VNGh82Xu0zZrczCGYP3jkWG79vl0zllJNs7hnkV8W6xY1JWgLoA==} + /@storybook/addon-essentials@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-YfacNHFOkXu3Ela/Bo7VIJ4cA7/KUFrSzQ463R9GxKsUpBOoXEowbZnur/Aa6ipX7arckdzpc7vXkPFGiRlsdw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/addon-actions': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-backgrounds': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-controls': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-docs': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-highlight': 7.0.12 - '@storybook/addon-measure': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-outline': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-toolbars': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-viewport': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.12 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.0.12 - '@storybook/preview-api': 7.0.12 + '@storybook/addon-actions': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-backgrounds': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-controls': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-docs': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-highlight': 7.0.15 + '@storybook/addon-measure': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-outline': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-toolbars': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-viewport': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.15 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.0.15 + '@storybook/preview-api': 7.0.15 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 @@ -4983,16 +4990,16 @@ packages: - supports-color dev: true - /@storybook/addon-highlight@7.0.12: - resolution: {integrity: sha512-ccIsBVjUlZ7cM1adSSFTqqWXiELPdDqfZLz4dWfDbiLyG3InC953ugtvoUWCIZpC2OOnjVLpF7Rbshq2O/QoMw==} + /@storybook/addon-highlight@7.0.15: + resolution: {integrity: sha512-lqf2rZkCpbxse0DXWjlRbCUTjCbUDNTh0aqt1L2NJkZKN2UrHjKbCXOHdtbMJewTLCuatKmjpHNbYp3sAzVq7w==} dependencies: - '@storybook/core-events': 7.0.12 + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.12 + '@storybook/preview-api': 7.0.15 dev: true - /@storybook/addon-interactions@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Rb1mv1RQrTd3sA/WwNTdv00rW+7APfvZEeZks6+8+kS1C4EFMDmLnVBZlPllFdo1BOnTCyer4GZZ5ncVkWNLyQ==} + /@storybook/addon-interactions@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-yhPhGMGdYwjYOaSLIp8iol9owpo5Dwk4UcH7WS7z4GwYgQwZ1GYBty1NcVpmxvFA429WQp0grqhJ+Q2xaJYstw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5002,16 +5009,16 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.12 - '@storybook/core-events': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.15 + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 7.0.12 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/instrumenter': 7.0.15 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 jest-mock: 27.5.1 polished: 4.2.2 react: 18.2.0 @@ -5021,8 +5028,8 @@ packages: - supports-color dev: true - /@storybook/addon-links@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-6kGClsIpX9dRKc5bUAPNcp/4wlgPIxMrieUV+6k1dTsRQqbaEfxih/Fq259D5+yVBDNi3YAnvRjMiIibl8fa5A==} + /@storybook/addon-links@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-rr2L46GeqX/4tvINzFTwe2TCq1gTFsOqMXPIgpsoiIA7A6Kj8AMGya3tWr7GPCK23MZxkuquyj+jTbO4kZjCwQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5032,22 +5039,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/core-events': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/core-events': 7.0.15 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/router': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/router': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-measure@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Uq9cj9QmN7WKBQ6wqeneFmTqo1UQKXIc4CpGBEtJtfsYNLsERrVzOs/tRUf66Zl3lWgfFZxs1B5Ij6RDsYEjRw==} + /@storybook/addon-measure@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-jnLh/Kyb6DWL5wdtqcR8Quuf25GzU6bmAJfMbQ/WUbf60M2fXK4d6h6YiFY9HSiAzc/UaH66tiAvqwe+ztgf4A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5057,19 +5064,19 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/types': 7.0.15 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addon-outline@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-eZPkm3mECdqx1EDJ0S6DAzZ9WZLPIsZH7fRy6vdJJuAgvnOSzkt7AEpA0hlgiNyXcFpE1Cav6/g12FUf4Zo82g==} + /@storybook/addon-outline@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-fc4P5f9bk0m8g5MDyj5V4MFsyNlMWEk1wPD6oBoi7VluTBZxfeLRaNrj9Ek6uDcuilTz2KBAf9aOMgluhEKEYw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5079,20 +5086,20 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/types': 7.0.15 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-storysource@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-drWG7mY76eL8BwkD5KFMSxnErqF6iOZCk3bpUFGqT5uzx6oVkjmOimZHTEuHtHEi6TtK8QN5KTUi6vXzsGSGpA==} + /@storybook/addon-storysource@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-62UHB6m/CA5+YfrdmHVzoI7yULaKXfrTK5ymNm8qV/zOx5QNYkldmtEfKZSDbeMlW740Awgd4QBD3neS2TNFXQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5102,13 +5109,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/router': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/source-loader': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/router': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/source-loader': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) estraverse: 5.3.0 prop-types: 15.8.1 react: 18.2.0 @@ -5116,8 +5123,8 @@ packages: react-syntax-highlighter: 15.5.0(react@18.2.0) dev: true - /@storybook/addon-toolbars@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-7xRxk+999NVdEwzn2z1O9Tg5iuUSEXQ5jo+hiyK934VvuyqUsZnflKbSvwVEHb2W+DroaaXu8bdHWxGSH+6moQ==} + /@storybook/addon-toolbars@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-DOyOHlChprAn/QLENBeu13MiGjNXHPJt+uOt+GlBY6b4oZbDUHC9l4uC+C/iDzuGBZ1hZ9VQlS2xM8GUcyy78w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5127,17 +5134,17 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addon-viewport@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-pMgqtDQF8e9AErnRKbbSK9m1lcKn1dFSOkk0PgSBwIIjmha6q+GeT45EHQrQGtkLdtWT0iTktC8ivzIiGKmHkg==} + /@storybook/addon-viewport@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-VIOEVKlgHlbzVz00aehSgFa8rSZZDBleadyGKm+XPtuZmY5ovyCYtp1CBtslTxmzJ/U1e2I++SCqeuT4bxNarw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5147,49 +5154,49 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) memoizerific: 1.11.3 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addons@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-yVADbWCFdb12cSpspeb+/6lfTNarPtZZLql49Bhu6E7PxECw/Q3kfHu0LXBLcSnU7f4QqQvQjp88ultt01ABBQ==} + /@storybook/addons@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7C9NlhFy9iJopulYhzUaxsNepOFG3tIMrzxfxkLVizlparffDybWfHtUa27wfMAnOu7G71jE7+PreJDz0Lyblg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/types': 7.0.15 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/blocks@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-MbJKjuTJ7xVbkUVwkEwb6vTYGrkRk4+Xtx1UGo+512o91ubqFs8hXwCHP+x/49RCIIQs5zl93Ig8fTtm+MejWw==} + /@storybook/blocks@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ygWH4UukbfEOdTnYs0uWVNQflR2ZEmX4izyLdDrbk3XCi8O5SdgAa4vb7/KW7sErIgkLWr/vo1INo/XXrX/Ceg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.0.12 - '@storybook/client-logger': 7.0.12 - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.12 + '@storybook/channels': 7.0.15 + '@storybook/client-logger': 7.0.15 + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.15 '@storybook/csf': 0.1.0 - '@storybook/docs-tools': 7.0.12 + '@storybook/docs-tools': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 '@types/lodash': 4.14.191 color-convert: 2.0.1 dequal: 2.0.3 @@ -5207,13 +5214,13 @@ packages: - supports-color dev: true - /@storybook/builder-manager@7.0.12: - resolution: {integrity: sha512-bkZPSDH38/dUSsO087oQ8+goyaEDP/xD0/O61QcQ8EbaVeT6s6Qt7mMhqsLrtmEZHvPMQwKeIXhOJlRNNXB+SA==} + /@storybook/builder-manager@7.0.15: + resolution: {integrity: sha512-NeEhrE6NTL8aOcxyH4TWazAI+6JyrhN+GUk+0ZPwzaraGfgAefMxATACHhDteU8DeSMQW3pymUOvU1uwjLrjWA==} dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 7.0.12 - '@storybook/manager': 7.0.12 - '@storybook/node-logger': 7.0.12 + '@storybook/core-common': 7.0.15 + '@storybook/manager': 7.0.15 + '@storybook/node-logger': 7.0.15 '@types/ejs': 3.1.2 '@types/find-cache-dir': 3.2.1 '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.17.18) @@ -5230,8 +5237,8 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.0.12(typescript@5.0.4)(vite@4.3.8): - resolution: {integrity: sha512-6FJNXis+dYs/KrhfRQgz8HcRw/Oq4FaEghCwsjngQDy4PcpQuxkDbvGJKlBaSr92vUL36FWSPq8u5+VGCHjh5Q==} + /@storybook/builder-vite@7.0.15(typescript@5.0.4)(vite@4.3.8): + resolution: {integrity: sha512-JLdStf1ykV54+FBfcO5GoPYJkhY413EhUNAFlZ04FqcVQjpRcRvWXZ/swiIFubAZo/2eHV8eGbRrlB/aNduq0w==} peerDependencies: '@preact/preset-vite': '*' typescript: '>= 4.3.x' @@ -5245,16 +5252,17 @@ packages: vite-plugin-glimmerx: optional: true dependencies: - '@storybook/channel-postmessage': 7.0.12 - '@storybook/channel-websocket': 7.0.12 - '@storybook/client-logger': 7.0.12 - '@storybook/core-common': 7.0.12 - '@storybook/csf-plugin': 7.0.12 + '@storybook/channel-postmessage': 7.0.15 + '@storybook/channel-websocket': 7.0.15 + '@storybook/client-logger': 7.0.15 + '@storybook/core-common': 7.0.15 + '@storybook/csf-plugin': 7.0.15 + '@storybook/global': 5.0.0 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.0.12 - '@storybook/preview': 7.0.12 - '@storybook/preview-api': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/node-logger': 7.0.15 + '@storybook/preview': 7.0.15 + '@storybook/preview-api': 7.0.15 + '@storybook/types': 7.0.15 browser-assert: 1.2.1 es-module-lexer: 0.9.3 express: 4.18.2 @@ -5264,19 +5272,19 @@ packages: magic-string: 0.27.0 remark-external-links: 8.0.0 remark-slug: 6.1.0 - rollup: 3.22.0 + rollup: 3.23.0 typescript: 5.0.4 - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true - /@storybook/channel-postmessage@7.0.12: - resolution: {integrity: sha512-Tc7kQZ5yxlZ44Nmmzec92JaDJ6UZ3Ze4cBfiHik4XcnM1PtN8hr8VFoC6a2AIm1ybfIRenfT5w9TH5yriiPIhw==} + /@storybook/channel-postmessage@7.0.15: + resolution: {integrity: sha512-5ZHIQI+Upb12C1lxeXHKVDBEtjjwtWN7XbTz+B1OQ09SRW4LEr8OMD/E9UHsQ2cuKrtBLPs8gkfYO+Ibvx5CkQ==} dependencies: - '@storybook/channels': 7.0.12 - '@storybook/client-logger': 7.0.12 - '@storybook/core-events': 7.0.12 + '@storybook/channels': 7.0.15 + '@storybook/client-logger': 7.0.15 + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 qs: 6.11.1 telejson: 7.0.4 @@ -5304,17 +5312,17 @@ packages: telejson: 7.0.4 dev: true - /@storybook/channel-websocket@7.0.12: - resolution: {integrity: sha512-UV6b9gX2mQLtXlKaFKCHcy+6MaK2od6BYqSJfainnBjDsMIXyhcf7fJaj0XQkJrbNnRBwGhw+6s8JxL98xp7Ew==} + /@storybook/channel-websocket@7.0.15: + resolution: {integrity: sha512-v+PWiSW0yLdDT+X8UXeacmWV9nmXu/AcWvodFEOj4/WUQnN2V5JJszbFm3lmFDrl1sGHEKZt8r3Q31yq3Jm5Lg==} dependencies: - '@storybook/channels': 7.0.12 - '@storybook/client-logger': 7.0.12 + '@storybook/channels': 7.0.15 + '@storybook/client-logger': 7.0.15 '@storybook/global': 5.0.0 telejson: 7.0.4 dev: true - /@storybook/channels@7.0.12: - resolution: {integrity: sha512-KDdDmDs8kxAJU+vndTqTNazjLO+XoIPiTRlfP7mk7cgHiQXSjMYy3JSCQ7W0of0Q+9VSl/ve9CNbnGbcQF7rNQ==} + /@storybook/channels@7.0.15: + resolution: {integrity: sha512-oCXop4qiikZPOWTeuBYyURszXUW81V4SkOJ1c76rU69DQzzMyTZArlGZCSk2OlwePjsLcKGj9bw+6410MaDtCA==} dev: true /@storybook/channels@7.0.2: @@ -5325,20 +5333,20 @@ packages: resolution: {integrity: sha512-+34cVmrXZ3lb1s5tDK+OWd5HLtEPSUMas0VKFJ0k9LBpFlVl9aiCZBJRvSYmWL7beauUfa+HSmJgjlD6228ChQ==} dev: true - /@storybook/cli@7.0.12: - resolution: {integrity: sha512-OABCRIujxsszIJ0CCpKg8Uj4C1UlAwBpBQhv2aMX3lA/pur6Od524syv2ypWu6J2FyvK/ooeyMbjoP7330cIuA==} + /@storybook/cli@7.0.15: + resolution: {integrity: sha512-BxnSAdxsgCFVsey7ASONVJQ7coOZARQou13w7Xleq6y+a7Wi6JQRXNEeNA6JHjMiceuq69BMkvBYr+sJ9Bzwhg==} hasBin: true dependencies: '@babel/core': 7.21.3 '@babel/preset-env': 7.21.4(@babel/core@7.21.3) '@ndelangen/get-tarball': 3.0.7 - '@storybook/codemod': 7.0.12 - '@storybook/core-common': 7.0.12 - '@storybook/core-server': 7.0.12 - '@storybook/csf-tools': 7.0.12 - '@storybook/node-logger': 7.0.12 - '@storybook/telemetry': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/codemod': 7.0.15 + '@storybook/core-common': 7.0.15 + '@storybook/core-server': 7.0.15 + '@storybook/csf-tools': 7.0.15 + '@storybook/node-logger': 7.0.15 + '@storybook/telemetry': 7.0.15 + '@storybook/types': 7.0.15 '@types/semver': 7.5.0 boxen: 5.1.2 chalk: 4.1.2 @@ -5356,6 +5364,7 @@ packages: globby: 11.1.0 jscodeshift: 0.14.0(@babel/preset-env@7.21.4) leven: 3.1.0 + ora: 5.4.1 prettier: 2.8.8 prompts: 2.4.2 puppeteer-core: 2.1.1 @@ -5374,8 +5383,8 @@ packages: - utf-8-validate dev: true - /@storybook/client-logger@7.0.12: - resolution: {integrity: sha512-MQMtIgGEgdixvxnBvZ2m8hhc0DGJWeCpHtxg7oqBLBEBmCYFueTqDZHl4Z6SoCrK0a2YS5X/BIXOcEtP1ulMKw==} + /@storybook/client-logger@7.0.15: + resolution: {integrity: sha512-ezy6i7e0PvNB+s+gAmE2vEHgdlFQZIzpFkNMZjM/lsJYX5+Q7Jgz/+i/fWEtFILUBPiRQGqcDsH7PAn2AfGRcw==} dependencies: '@storybook/global': 5.0.0 dev: true @@ -5392,16 +5401,16 @@ packages: '@storybook/global': 5.0.0 dev: true - /@storybook/codemod@7.0.12: - resolution: {integrity: sha512-eGbGZSglvbnY1omzRyEC4XP0FbpuCFKgjXmdHn9faGQUU5EJHwcGYYrRW8JZL3nEVIvNDuRAKzM3p0BVo1xeSQ==} + /@storybook/codemod@7.0.15: + resolution: {integrity: sha512-mUoOuqjiPVeMU+Z1J+3QycTwc8IPZlvY24mqdHy6Q2y7vKgozu1G/D/OkJBV+zlleguBpBxQkDLRB3CHA+LVkQ==} dependencies: '@babel/core': 7.21.3 '@babel/preset-env': 7.21.4(@babel/core@7.21.3) '@babel/types': 7.21.5 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.0.12 - '@storybook/node-logger': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/csf-tools': 7.0.15 + '@storybook/node-logger': 7.0.15 + '@storybook/types': 7.0.15 cross-spawn: 7.0.3 globby: 11.1.0 jscodeshift: 0.14.0(@babel/preset-env@7.21.4) @@ -5412,17 +5421,17 @@ packages: - supports-color dev: true - /@storybook/components@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-6TxByzYS4+LxwZRioGpP6Zh9If5ctjQs5OnR2UmQvP6HDjmMWYTntoHKIbDwAL9C6MrnQYpPOGCPkqrtODQ4/w==} + /@storybook/components@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aek4/F5h3DShxS17tUYzI2FBwDT8+IRkg3OnkvybJC2U0MizPjwNa8qUk0kt4lEzt1y1TwnXH7TFCjWYY5zS6A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.0.12 + '@storybook/client-logger': 7.0.15 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5430,18 +5439,18 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/core-client@7.0.12: - resolution: {integrity: sha512-m0r+Vl3LfU8cJl8UqIwzh0sEN9I//nMaT8UIIm481AINhQTNihQcnYi9jRw7USjfz2fv5CYkg8cEr4KhI8QlRA==} + /@storybook/core-client@7.0.15: + resolution: {integrity: sha512-h4/X597DnWp3Ocpli1B27fpKLXEU1qD4PYCnJW4Pl9DyJXBbzCo2VFZ7LyG3Wrod7ZjrmGOYjOiSisS3f8pcPA==} dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/preview-api': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/preview-api': 7.0.15 dev: true - /@storybook/core-common@7.0.12: - resolution: {integrity: sha512-PFVjYXHUxDQO1oqfqwQe7S3XoLNO0aZYEr9Zl0LiexlxxnU1v+TQjEfNd/H3T0xxpXlsgzhtEcagdzJeAKyh2g==} + /@storybook/core-common@7.0.15: + resolution: {integrity: sha512-uAgpAqGedA7oRXstkZJfJYzuQuK4IrbdfJmA+fVlQ8wdpOtV/BL9YVy80W+YJQCkgUYW7KDagpQ8OMqIpiWt2w==} dependencies: - '@storybook/node-logger': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/node-logger': 7.0.15 + '@storybook/types': 7.0.15 '@types/node': 16.18.16 '@types/pretty-hrtime': 1.0.1 chalk: 4.1.2 @@ -5463,8 +5472,8 @@ packages: - supports-color dev: true - /@storybook/core-events@7.0.12: - resolution: {integrity: sha512-VTmb/zjbz3o1bg+bATzLigVXMVDC/S1FP8CqIrz4mkiys52139FGzMandL2Y2AecPZPGss7ZRdfma28HKVYTRg==} + /@storybook/core-events@7.0.15: + resolution: {integrity: sha512-ffpOLFpDs1T/HVUpGNDyo7c81lfH3Vvga0Hl6uhxm6zi9PkayV3DCgtmZ/W7daC7DiJC+upG/ziMG+5Oj33PDQ==} dev: true /@storybook/core-events@7.0.2: @@ -5475,23 +5484,23 @@ packages: resolution: {integrity: sha512-kGrtjlYtjd4iTVk+Phb4CymZaVkB+MGscKAgcO8gfgJ/Q/gq8HQLVZSIzeoCDcDSHOGlBzbg2WVtdHIHhCKlOQ==} dev: true - /@storybook/core-server@7.0.12: - resolution: {integrity: sha512-X35Kmg7y35Ph4J+gCDJrnVgBwlz4/DzOQofUS6rAbi4KvrPWDJXeM2OzOgx6B0abKl4CeMmjuc0tjbg4vbUFuA==} + /@storybook/core-server@7.0.15: + resolution: {integrity: sha512-342wGx7uk4j2R8Zk03GLkiwONXUMV2Frpw2HG2HmGviWArN4B3UmU0YHj00GjFM51kyYtjhaJVyTMA20x+6/Yw==} dependencies: '@aw-web-design/x-default-browser': 1.4.88 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 7.0.12 - '@storybook/core-common': 7.0.12 - '@storybook/core-events': 7.0.12 + '@storybook/builder-manager': 7.0.15 + '@storybook/core-common': 7.0.15 + '@storybook/core-events': 7.0.15 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.0.12 + '@storybook/csf-tools': 7.0.15 '@storybook/docs-mdx': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager': 7.0.12 - '@storybook/node-logger': 7.0.12 - '@storybook/preview-api': 7.0.12 - '@storybook/telemetry': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/manager': 7.0.15 + '@storybook/node-logger': 7.0.15 + '@storybook/preview-api': 7.0.15 + '@storybook/telemetry': 7.0.15 + '@storybook/types': 7.0.15 '@types/detect-port': 1.3.2 '@types/node': 16.18.16 '@types/node-fetch': 2.6.2 @@ -5508,7 +5517,7 @@ packages: globby: 11.1.0 ip: 2.0.0 lodash: 4.17.21 - node-fetch: 2.6.7 + node-fetch: 2.6.11 open: 8.4.2 pretty-hrtime: 1.0.3 prompts: 2.4.2 @@ -5527,24 +5536,24 @@ packages: - utf-8-validate dev: true - /@storybook/csf-plugin@7.0.12: - resolution: {integrity: sha512-iiH0ynLQV5BYFc0o7RlSJS2S3GT/ffyfbV4rnCnPKdqyo4REEVvmhOuLhwzurtsXsjh+xF6VUYUDN+8/5mbkYw==} + /@storybook/csf-plugin@7.0.15: + resolution: {integrity: sha512-qJwZ6FhTt5HhsXY1rgwqwB1aMbuUSJYEVDM2Y5w0vOB+RHRT6JZpZgVlFz2C8qagX/F27seq6GF0VtfgOAJpaA==} dependencies: - '@storybook/csf-tools': 7.0.12 + '@storybook/csf-tools': 7.0.15 unplugin: 0.10.2 transitivePeerDependencies: - supports-color dev: true - /@storybook/csf-tools@7.0.12: - resolution: {integrity: sha512-EcDzKeENzs4awyjx0VxlONDLibiEtIPDP1XdOCcZGtv3nXXBFtS2WDsYhJHkwyvE37jWTyw2e4xKQmBi0Hjvbw==} + /@storybook/csf-tools@7.0.15: + resolution: {integrity: sha512-PTA8NJTWsAtHsmJcU18PJZA66vyiZtKJJwNL7bTkKuG5HJLer8En6OarJERomhnnr8k0I6dycfWmWgcfeTNoxg==} dependencies: '@babel/generator': 7.21.3 - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/traverse': 7.21.3 '@babel/types': 7.21.5 '@storybook/csf': 0.1.0 - '@storybook/types': 7.0.12 + '@storybook/types': 7.0.15 fs-extra: 11.1.0 recast: 0.23.1 ts-dedent: 2.2.0 @@ -5562,13 +5571,13 @@ packages: resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} dev: true - /@storybook/docs-tools@7.0.12: - resolution: {integrity: sha512-+HykeQLgjyDyF9G7HqY0FHXlX7X5YpQcmNjftJzBrc/GO1EeO0M78d54avcOPyyTfuWOh7oZtSJ0MzjA1qrqaQ==} + /@storybook/docs-tools@7.0.15: + resolution: {integrity: sha512-d2GP3UGSz3TS6c/wcB+ngXRNwXlZzyy3vQRAFdirLeTjTN07koyr3aagd5mdJwlMbO2vEIVjNetY4TFX1zfuSQ==} dependencies: '@babel/core': 7.21.3 - '@storybook/core-common': 7.0.12 - '@storybook/preview-api': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/core-common': 7.0.15 + '@storybook/preview-api': 7.0.15 + '@storybook/types': 7.0.15 '@types/doctrine': 0.0.3 doctrine: 3.0.0 lodash: 4.17.21 @@ -5586,14 +5595,14 @@ packages: resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} dev: true - /@storybook/instrumenter@7.0.12: - resolution: {integrity: sha512-jx4rb4AMT1YIOpE0HCdfyLvpYU+94wPkC9vt7sZGWAp7nnYG+KO/lx3XCJaR9qQPIxVYejJtWkeGn4RID79SoQ==} + /@storybook/instrumenter@7.0.15: + resolution: {integrity: sha512-vg+glFfRwk9LRBdFYoRQa6JQrTpdIZV35C24dm+tytnIoGqe5jexI+Lmkb+417JQsfdYKZ11IaL0Zj43CbC6vw==} dependencies: - '@storybook/channels': 7.0.12 - '@storybook/client-logger': 7.0.12 - '@storybook/core-events': 7.0.12 + '@storybook/channels': 7.0.15 + '@storybook/client-logger': 7.0.15 + '@storybook/core-events': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.12 + '@storybook/preview-api': 7.0.15 dev: true /@storybook/instrumenter@7.0.2: @@ -5625,20 +5634,20 @@ packages: jest-mock: 27.5.1 dev: true - /@storybook/manager-api@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-3QXARtxpc6Xxqf5pviUw2UuhK53+IsINSljeWhAqdQ1Gzbywl67TpibTd7xVN6NKxhUH5Bzo9bIZTAzMZGqaKw==} + /@storybook/manager-api@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-S5OZz8QB8pABLFV4hDJrZE5DLk/EJhn/i48xiycuAtBCVcU4jw4xOyrF4f2ZbtsaWQ5GLAAanOb8yTJcqKnItA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.0.12 - '@storybook/client-logger': 7.0.12 - '@storybook/core-events': 7.0.12 + '@storybook/channels': 7.0.15 + '@storybook/client-logger': 7.0.15 + '@storybook/core-events': 7.0.15 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/router': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/router': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 @@ -5650,16 +5659,16 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/manager@7.0.12: - resolution: {integrity: sha512-19BsDcwJOYXn6zEarxvNGDdYLUqZyhX92x6GPHSC4cf8BoxHuhmtnz5vOTZHusCxkKIu/C9W0H6wH2Ma47kDCg==} + /@storybook/manager@7.0.15: + resolution: {integrity: sha512-ixx+E2Vb34VIY9JqKoWA+Qv3soJhSWW0ETdMaPn+QmcSoicqM4I861hmxm37ROhwRpAMi2U0sS0m4L+6VeB0lQ==} dev: true /@storybook/mdx2-csf@1.0.0: resolution: {integrity: sha512-dBAnEL4HfxxJmv7LdEYUoZlQbWj9APZNIbOaq0tgF8XkxiIbzqvgB0jhL/9UOrysSDbQWBiCRTu2wOVxedGfmw==} dev: true - /@storybook/node-logger@7.0.12: - resolution: {integrity: sha512-VL+NXzc9NuOP6/9alg4Sofz9kh8tmlo3p+UtCIYCHH088yCsB3XsNhkG9lF1C5EZVWcuHxc2u6MMF3ezOjvKfQ==} + /@storybook/node-logger@7.0.15: + resolution: {integrity: sha512-h7kAbugjW4OqVIs5fd3Lme8+WBaEZYAULaNJ1zdvVpvWepG6iBaF/j8RlZdJzrPDdwQvZ2g9gVk5HySXpeXOjA==} dependencies: '@types/npmlog': 4.1.4 chalk: 4.1.2 @@ -5667,20 +5676,20 @@ packages: pretty-hrtime: 1.0.3 dev: true - /@storybook/postinstall@7.0.12: - resolution: {integrity: sha512-RKNvBLgABBTQwvGyF2jX4vP7OMLB3KvEEOQDoeOKjqyWfekDn5smI+eT714mtmKIH0YMcwmvzLgEdZkjmM/XhA==} + /@storybook/postinstall@7.0.15: + resolution: {integrity: sha512-oVw7E7iBDEN3toMJPH2bxkS/rLShSHNmK8cU8bO6kdxBVCmUdhqMME7TOzqy7bAZ+ODlFCqwdstp85pO6xarig==} dev: true - /@storybook/preview-api@7.0.12: - resolution: {integrity: sha512-YI/AfHszIOYt967fsRlc7j6I0zZB+RSsBwD/nMA8y9vszdpQ0MgRhxHgQxFf6cgqbuQcdCsnTIpT0iQ4GHjDXg==} + /@storybook/preview-api@7.0.15: + resolution: {integrity: sha512-ZjqMFsOYVklO1h4BfyNGpn4FM6lHgQ9RZ+LmUnd1qh/GdxpRHIGLKtsvd4nxaSJLHNE53WO+1yUeJPiglEeE4g==} dependencies: - '@storybook/channel-postmessage': 7.0.12 - '@storybook/channels': 7.0.12 - '@storybook/client-logger': 7.0.12 - '@storybook/core-events': 7.0.12 + '@storybook/channel-postmessage': 7.0.15 + '@storybook/channels': 7.0.15 + '@storybook/client-logger': 7.0.15 + '@storybook/core-events': 7.0.15 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/types': 7.0.12 + '@storybook/types': 7.0.15 '@types/qs': 6.9.7 dequal: 2.0.3 lodash: 4.17.21 @@ -5731,12 +5740,12 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/preview@7.0.12: - resolution: {integrity: sha512-za8El/nnkyAo/uqyqAg7PMuP6DSdPoEnDRyIk4LzY7sAGly6i4Uge377cdo1nUBQLS5S4kKIc4xf8TUegb3G1Q==} + /@storybook/preview@7.0.15: + resolution: {integrity: sha512-rTHgSCpKOnypMVQZdJ78Hlcnkm54UK6KTbQrM3LW41W5sbmTV3OpN6x0Ke7FY6tvrpWATJs26YrTTatDV8tbUA==} dev: true - /@storybook/react-dom-shim@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-4z9J54TD7uphxPqSuLEzeKTV4oF8Fmv8qFfnT0XZJ2mpYTC2NTbkYoYZQ8N0eYzvNOk6xgfpDqBdmIANf4NaYw==} + /@storybook/react-dom-shim@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Yi/1ZtzttAay3TMFyiF5oV317fUwdAT+Z595sBCMHEzhZWUA9zKxvR0KAQ2cBlCc6u7+tJvIMaGkcS/IZWVqPw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5745,8 +5754,8 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8): - resolution: {integrity: sha512-SIszevqIKOW+5TwzNposDI+3giSZNVZ7HSu7u2JEpu0Iw/CWyYI06rUgH2ft8Xluhb8vEorZKiZjsdiQDVo64w==} + /@storybook/react-vite@7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8): + resolution: {integrity: sha512-bPNvjHccYgXCskrW6CIpqcuZWsASdlOuFgJs1q/sxEHy5gGw+kMEm0XKmha4cTLlUAFd4EwhmKkC6BEgtSYVWw==} engines: {node: '>=16'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5755,15 +5764,15 @@ packages: dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.8) '@rollup/pluginutils': 4.2.1 - '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.8) - '@storybook/react': 7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + '@storybook/builder-vite': 7.0.15(typescript@5.0.4)(vite@4.3.8) + '@storybook/react': 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) '@vitejs/plugin-react': 3.1.0(vite@4.3.8) ast-types: 0.14.2 magic-string: 0.27.0 react: 18.2.0 react-docgen: 6.0.0-alpha.3 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) transitivePeerDependencies: - '@preact/preset-vite' - supports-color @@ -5771,8 +5780,8 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4): - resolution: {integrity: sha512-dKHKc02LSgn3St7U/xj/Rr2DFLbS4dWQka+pS/AOvPPvMAR2gGHVhkmoFuFMf176hUTuE5MCoWBoNJIRMz7ZiQ==} + /@storybook/react@7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4): + resolution: {integrity: sha512-YuqUyfbPr4mFsRAIUTmVgx5mCNK00fg/Mztwyg3PRN4SuRWhx5MJy6kMX2GV3DcKqyeC5U2aWKHlzjzrGwXymw==} engines: {node: '>=16.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5782,13 +5791,13 @@ packages: typescript: optional: true dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/core-client': 7.0.12 - '@storybook/docs-tools': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/core-client': 7.0.15 + '@storybook/docs-tools': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.12 - '@storybook/react-dom-shim': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/preview-api': 7.0.15 + '@storybook/react-dom-shim': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 '@types/node': 16.18.16 @@ -5810,27 +5819,27 @@ packages: - supports-color dev: true - /@storybook/router@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-dOtBiCBGeDem86BCWR7AlTVQjoBk0yw/XZLXS9qcpUfpe+UDjd0Rh21ZdEEMHG1Wfu4d2AhhG5l/JSJ1IE83jQ==} + /@storybook/router@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-iwW2bzoULMIHjzK7ok0l+4O5AafyZ1APMUcYv8S+lC1bOl7odAcV2dbUQ21M1D/L+no7LrcnfJBGOD8NKE4nTQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.0.12 + '@storybook/client-logger': 7.0.15 memoizerific: 1.11.3 qs: 6.11.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/source-loader@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-dIT4uHiEFgIX/W1aYpKazeu+8GN2OljQsB84oO6Ea887f3emmVJRBGwvoChSAZH+ps2zGput88Lby+W5Paesow==} + /@storybook/source-loader@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-bk+TbRx9WoUE6to39TjL5BYxZmaq4expM1OlgBabES+mJmdYIvNoDWNYufSv5Gdj25Rg6nG9vYGaf1iviTna9A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@storybook/csf': 0.1.0 - '@storybook/types': 7.0.12 + '@storybook/types': 7.0.15 estraverse: 5.3.0 lodash: 4.17.21 prettier: 2.8.8 @@ -5838,11 +5847,11 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/telemetry@7.0.12: - resolution: {integrity: sha512-oxqe15bn5W+1pLpLjXTfj3H+YPZq3jExjdJwTCUHtFrrsNs0k6dyqAUk8qTOUqOTclANHb6vlNBFJDvZ6qbfEQ==} + /@storybook/telemetry@7.0.15: + resolution: {integrity: sha512-Tuf6Oy1Lxr+bGT9rILT1oKlQtHrO9oCzk/6/wSSZnV08yzwqe5Tmc8OUd9ytc2BbQb67yObsT9Lb9YC+9+X3+g==} dependencies: - '@storybook/client-logger': 7.0.12 - '@storybook/core-common': 7.0.12 + '@storybook/client-logger': 7.0.15 + '@storybook/core-common': 7.0.15 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.4 @@ -5865,24 +5874,24 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/theming@7.0.12(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-frBkvH7LF8j23ODaywLK4m4LLscw49oKblkZ+30QZkBAzRf2o3a/QSZW2V1zfBo7ygcXiUJ5bIjh7Y17mMJqbQ==} + /@storybook/theming@7.0.15(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-oxy1jTt1lYLWCRXhSnjvxIzJHW+tQS4kqD/F8mr3/C0WbMXbSv/rKlS2fkIYbOecjqs0C/8ypa1KzEMcBTfIRQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) - '@storybook/client-logger': 7.0.12 + '@storybook/client-logger': 7.0.15 '@storybook/global': 5.0.0 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/types@7.0.12: - resolution: {integrity: sha512-nlvU4MyO2grwPCRQ8alA3AnY1bQxGJ6A4QgJu+1MhtjVenifFlxOQX4H1OiA+YXfjlV096oO5LrxvetJPFAKKQ==} + /@storybook/types@7.0.15: + resolution: {integrity: sha512-WjrTpRxCZDL7noDv7ziRdOsuYMppbKRsWlH53HY5GFXJZPYaFWs6lKZOo7+T8OxYXegD4Y5AcD8tGQrX8GtycQ==} dependencies: - '@storybook/channels': 7.0.12 + '@storybook/channels': 7.0.15 '@types/babel__core': 7.20.0 '@types/express': 4.17.17 file-system-cache: 2.0.2 @@ -5906,22 +5915,22 @@ packages: file-system-cache: 2.0.2 dev: true - /@storybook/vue3-vite@7.0.12(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4): - resolution: {integrity: sha512-SdAGfBRfm4cR9VNLRcBCLo3rTzeUTvZfyh5ll0cgInCo9gTxwfs1Y4zEmmVqDDOWQ7qlpJanITNGFGiSsdvRmg==} + /@storybook/vue3-vite@7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4): + resolution: {integrity: sha512-a5kjtOxVUTZ++QPYT294110OZA1xec8HB9XbF4Mq9xmMK4HAJ2Tv4yx1UtMA6bCanOOCpa1VyA0CQVje6RdgMQ==} engines: {node: ^14.18 || >=16} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@storybook/builder-vite': 7.0.12(typescript@5.0.4)(vite@4.3.8) - '@storybook/core-server': 7.0.12 - '@storybook/vue3': 7.0.12(vue@3.3.4) + '@storybook/builder-vite': 7.0.15(typescript@5.0.4)(vite@4.3.8) + '@storybook/core-server': 7.0.15 + '@storybook/vue3': 7.0.15(vue@3.3.4) '@vitejs/plugin-vue': 4.2.3(vite@4.3.8)(vue@3.3.4) magic-string: 0.27.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) vue-docgen-api: 4.64.1(vue@3.3.4) transitivePeerDependencies: - '@preact/preset-vite' @@ -5934,17 +5943,17 @@ packages: - vue dev: true - /@storybook/vue3@7.0.12(vue@3.3.4): - resolution: {integrity: sha512-zxRhuuNcM9hT1/s968iHL+diqFqRmpwvEoI7rF1yje09saMck+PFStlE8b/ohQeDtm0GdwVqjbzfHZIdPbivYg==} + /@storybook/vue3@7.0.15(vue@3.3.4): + resolution: {integrity: sha512-h38XFH2fpfZcflg2xifaiwiSfgZd7Ry+/HbwRRKPpvPsBsfXt79KC8H2vHLdMU2KNWpERMKw2eG1PTzYUGUr5w==} engines: {node: '>=16.0.0'} peerDependencies: vue: ^3.0.0 dependencies: - '@storybook/core-client': 7.0.12 - '@storybook/docs-tools': 7.0.12 + '@storybook/core-client': 7.0.15 + '@storybook/docs-tools': 7.0.15 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.12 - '@storybook/types': 7.0.12 + '@storybook/preview-api': 7.0.15 + '@storybook/types': 7.0.15 ts-dedent: 2.2.0 type-fest: 2.19.0 vue: 3.3.4 @@ -6303,7 +6312,7 @@ packages: dependencies: '@tensorflow/tfjs-core': 4.4.0 '@types/node-fetch': 2.6.2 - node-fetch: 2.6.7 + node-fetch: 2.6.11 seedrandom: 3.0.5 string_decoder: 1.3.0 transitivePeerDependencies: @@ -6392,7 +6401,7 @@ packages: dependencies: '@adobe/css-tools': 4.2.0 '@babel/runtime': 7.20.7 - '@types/testing-library__jest-dom': 5.14.5 + '@types/testing-library__jest-dom': 5.14.6 aria-query: 5.1.3 chalk: 3.0.0 css.escape: 1.5.1 @@ -6441,7 +6450,7 @@ packages: /@types/accepts@1.3.5: resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/archiver@5.3.2: @@ -6477,7 +6486,7 @@ packages: /@types/babel__template@7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/types': 7.21.5 dev: true @@ -6495,7 +6504,7 @@ packages: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/braces@3.0.1: @@ -6515,7 +6524,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/responselike': 1.0.0 dev: false @@ -6548,7 +6557,7 @@ packages: /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/content-disposition@0.5.5: @@ -6613,7 +6622,7 @@ packages: /@types/express-serve-static-core@4.17.33: resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: true @@ -6634,34 +6643,34 @@ packages: /@types/fluent-ffmpeg@2.1.21: resolution: {integrity: sha512-+n3dy/Tegt6n+YwGZUiGq6i8Jrnt8+MoyPiW1L6J5EWUl7GSt18a/VyReecfCsvTTNBXNMIKOMHDstiQM8nJLA==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/glob-stream@6.1.1: resolution: {integrity: sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==} dependencies: '@types/glob': 8.1.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/gulp-rename@2.0.1: @@ -6674,7 +6683,7 @@ packages: /@types/gulp-rename@2.0.2: resolution: {integrity: sha512-CQsXqTVtAXqrPd4IbrrlJEEzRkUR3RXsyZbrVoOVqjlchDDmnyRDatAUisjpQjjCg/wjJrSiNg8T1uAbJ/7Qqg==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/vinyl': 2.0.7 dev: true @@ -6729,7 +6738,7 @@ packages: /@types/jsdom@21.1.1: resolution: {integrity: sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 dev: true @@ -6753,7 +6762,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: false /@types/lodash@4.14.191: @@ -6764,8 +6773,8 @@ packages: resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} dev: false - /@types/matter-js@0.18.3: - resolution: {integrity: sha512-7DYI52ebEl6AD9+RV2jO/XHdlFlpozYbkURtYKKJ2tO34q49Y15cfl+JSJpoMglQCAL/PxBSHKVv3wkvfZZD7g==} + /@types/matter-js@0.18.4: + resolution: {integrity: sha512-7YgBqVLbLTCTMKmWfvPkohb5sTErBrLui3jRypFLCAxfTYc/HH+gaz10FT8Qw5XipWf7/Ns7Aksmo8nsIIL3lw==} dev: true /@types/mdx@2.0.3: @@ -6801,7 +6810,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 form-data: 3.0.1 /@types/node-fetch@3.0.3: @@ -6829,13 +6838,13 @@ packages: resolution: {integrity: sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==} dev: true - /@types/node@20.2.1: - resolution: {integrity: sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==} + /@types/node@20.2.3: + resolution: {integrity: sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==} /@types/nodemailer@6.4.8: resolution: {integrity: sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/normalize-package-data@2.4.1: @@ -6849,7 +6858,7 @@ packages: /@types/oauth@0.9.1: resolution: {integrity: sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/offscreencanvas@2019.3.0: @@ -6860,12 +6869,12 @@ packages: resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==} dev: false - /@types/pg@8.6.6: - resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} + /@types/pg@8.10.1: + resolution: {integrity: sha512-AmEHA/XxMxemQom5iDwP62FYNkv+gDDnetRG7v2N2dPtju7UKI7FknUimcZo7SodKTHtckYPzaTqUEvUKbVJEA==} dependencies: - '@types/node': 20.2.1 - pg-protocol: 1.5.0 - pg-types: 2.2.0 + '@types/node': 20.2.3 + pg-protocol: 1.6.0 + pg-types: 4.0.1 dev: true /@types/prettier@2.7.2: @@ -6891,7 +6900,7 @@ packages: /@types/qrcode@1.5.0: resolution: {integrity: sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/qs@6.9.7: @@ -6921,7 +6930,7 @@ packages: /@types/readdir-glob@1.1.1: resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/redis@4.0.11: @@ -6937,7 +6946,7 @@ packages: /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: false /@types/sanitize-html@2.9.0: @@ -6965,7 +6974,7 @@ packages: resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} dependencies: '@types/mime': 3.0.1 - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/serviceworker@0.0.67: @@ -6975,7 +6984,7 @@ packages: /@types/set-cookie-parser@2.4.2: resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/sharp@0.32.0: @@ -7007,8 +7016,8 @@ packages: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true - /@types/testing-library__jest-dom@5.14.5: - resolution: {integrity: sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==} + /@types/testing-library__jest-dom@5.14.6: + resolution: {integrity: sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==} dependencies: '@types/jest': 29.5.1 dev: true @@ -7040,7 +7049,7 @@ packages: /@types/undertaker@1.2.8: resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/undertaker-registry': 1.0.1 async-done: 1.3.2 dev: true @@ -7049,10 +7058,10 @@ packages: resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==} dev: true - /@types/unzipper@0.10.5: - resolution: {integrity: sha512-NrLJb29AdnBARpg9S/4ktfPEisbJ0AvaaAr3j7Q1tg8AgcEUsq2HqbNzvgLRoWyRtjzeLEv7vuL39u1mrNIyNA==} + /@types/unzipper@0.10.6: + resolution: {integrity: sha512-zcBj329AHgKLQyz209N/S9R0GZqXSkUQO4tJSYE3x02qg4JuDFpgKMj50r82Erk1natCWQDIvSccDddt7jPzjA==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/uuid@9.0.1: @@ -7062,14 +7071,14 @@ packages: /@types/vary@1.1.0: resolution: {integrity: sha512-LQWqrIa0dvEOOH37lGksMEXbypRLUFqu6Gx0pmX7zIUisD2I/qaVgEX/vJ/PSVSW0Hk6yz1BNkFpqg6dZm3Wug==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/vinyl-fs@2.4.12: resolution: {integrity: sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==} dependencies: '@types/glob-stream': 6.1.1 - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/vinyl': 2.0.7 dev: true @@ -7077,12 +7086,12 @@ packages: resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} dependencies: '@types/expect': 1.20.4 - '@types/node': 20.2.1 + '@types/node': 20.2.3 /@types/web-push@3.3.2: resolution: {integrity: sha512-JxWGVL/m7mWTIg4mRYO+A6s0jPmBkr4iJr39DqJpRJAc+jrPiEe1/asmkwerzRon8ZZDxaZJpsxpv0Z18Wo9gw==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/webgl-ext@0.0.30: @@ -7096,13 +7105,13 @@ packages: /@types/websocket@1.0.5: resolution: {integrity: sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/ws@8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /@types/yargs-parser@21.0.0: @@ -7125,7 +7134,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true optional: true @@ -7270,7 +7279,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.3) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true @@ -7282,7 +7291,7 @@ packages: vite: ^4.0.0 vue: ^3.2.25 dependencies: - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) vue: 3.3.4 /@vitest/coverage-c8@0.31.1(vitest@0.31.1): @@ -7382,9 +7391,9 @@ packages: typescript: 5.0.4 dev: true - /@vue-macros/common@1.3.1(rollup@3.22.0)(vue@3.3.4): - resolution: {integrity: sha512-Lc5aP/8HNJD1XrnvpeNuWcCf82bZdR3auN/chA1b/1rKZgSnmQkH9f33tKO9qLwXSy+u4hpCi8Rw+oUuF1KCeg==} - engines: {node: '>=14.19.0'} + /@vue-macros/common@1.3.2(rollup@3.23.0)(vue@3.3.4): + resolution: {integrity: sha512-D/hNU0+0HPGFpGf1TO2eKpBKVFTIsHMjzu7/IXe9+hz0TY+WJOGtnlpJyMWFWnM56mXvBOMiQ74zW8MTFlbMMQ==} + engines: {node: '>=16.14.0'} peerDependencies: vue: ^2.7.0 || ^3.2.25 peerDependenciesMeta: @@ -7392,7 +7401,7 @@ packages: optional: true dependencies: '@babel/types': 7.21.5 - '@rollup/pluginutils': 5.0.2(rollup@3.22.0) + '@rollup/pluginutils': 5.0.2(rollup@3.23.0) '@vue/compiler-sfc': 3.3.4 local-pkg: 0.4.3 magic-string-ast: 0.1.2 @@ -7401,16 +7410,16 @@ packages: - rollup dev: false - /@vue-macros/reactivity-transform@0.3.7(rollup@3.22.0)(vue@3.3.4): - resolution: {integrity: sha512-o+u5qstvUjNoaZjr4lUtNf5MuLgQHikvurnk6b2DFd9nB52j+BqOhI22uyn6K6TTAU0i0/PxT5YgwDlwVdvEUw==} - engines: {node: '>=14.19.0'} + /@vue-macros/reactivity-transform@0.3.8(rollup@3.23.0)(vue@3.3.4): + resolution: {integrity: sha512-a9GBGy7ZCJdbOvynGl+gBGy0EQlhbUkJxnpEPdxQDWKTEiqW3xQGPCaqonVvHFH1DxQrbfKyxsPy+72Ssr6tKA==} + engines: {node: '>=16.14.0'} peerDependencies: vue: ^2.7.0 || ^3.2.25 dependencies: - '@babel/parser': 7.21.8 - '@vue-macros/common': 1.3.1(rollup@3.22.0)(vue@3.3.4) - '@vue/compiler-core': 3.3.1 - '@vue/shared': 3.3.2 + '@babel/parser': 7.21.9 + '@vue-macros/common': 1.3.2(rollup@3.23.0)(vue@3.3.4) + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 magic-string: 0.30.0 unplugin: 1.3.1 vue: 3.3.4 @@ -7418,19 +7427,10 @@ packages: - rollup dev: false - /@vue/compiler-core@3.3.1: - resolution: {integrity: sha512-5le1qYSBgLWg2jdLrbydlhnPJkkzMw46UrRUvTnOKlfg6pThtm9ohhqBhNPHbr0RcM1MCbK5WZe/3Ghz0SZjpQ==} - dependencies: - '@babel/parser': 7.21.8 - '@vue/shared': 3.3.1 - estree-walker: 2.0.2 - source-map-js: 1.0.2 - dev: false - /@vue/compiler-core@3.3.4: resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@vue/shared': 3.3.4 estree-walker: 2.0.2 source-map-js: 1.0.2 @@ -7444,7 +7444,7 @@ packages: /@vue/compiler-sfc@2.7.14: resolution: {integrity: sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 postcss: 8.4.23 source-map: 0.6.1 dev: false @@ -7505,14 +7505,6 @@ packages: '@vue/shared': 3.3.4 vue: 3.3.4 - /@vue/shared@3.3.1: - resolution: {integrity: sha512-ybDBtQ+479HL/bkeIOIAwgpeAEACzztkvulJLbK3JMFuTOv4qDivmV3AIsR8RHYJ+RD9tQxcHWBsX4GqEcYrfw==} - dev: false - - /@vue/shared@3.3.2: - resolution: {integrity: sha512-0rFu3h8JbclbnvvKrs7Fe5FNGV9/5X2rPD7KmOzhLSUAiQH5//Hq437Gv0fR5Mev3u/nbtvmLl8XgwCU20/ZfQ==} - dev: false - /@vue/shared@3.3.4: resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} @@ -7581,7 +7573,7 @@ packages: esbuild: '>=0.10.0' dependencies: esbuild: 0.17.18 - tslib: 2.5.0 + tslib: 2.5.2 dev: true /@yarnpkg/fslib@2.10.2: @@ -8134,21 +8126,21 @@ packages: resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} engines: {node: '>=4'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: true /ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: true /ast-types@0.16.1: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: true /astral-regex@2.0.0: @@ -8156,8 +8148,8 @@ packages: engines: {node: '>=8'} dev: true - /astring@1.8.4: - resolution: {integrity: sha512-97a+l2LBU3Op3bBQEff79i/E4jMD2ZLFD8rHx9B6mXyB2uQwhJQYfiDqUwtfjF4QA1F2qs//N6Cw8LetMbQjcw==} + /astring@1.8.5: + resolution: {integrity: sha512-TuBbdn7jWVzf8dmFGTaRpW8qgANtWLi1qJLnkfGO5uVf6jf9f/F4B1H35tnOI+qVYZo3p3i8WZlbZOuPAE0wEA==} hasBin: true dev: true @@ -9540,7 +9532,7 @@ packages: /constantinople@4.0.1: resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/types': 7.21.5 /content-disposition@0.5.4: @@ -9641,6 +9633,15 @@ packages: node-fetch: 2.6.7 transitivePeerDependencies: - encoding + dev: true + + /cross-fetch@3.1.6: + resolution: {integrity: sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==} + dependencies: + node-fetch: 2.6.11 + transitivePeerDependencies: + - encoding + dev: false /cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} @@ -9754,8 +9755,8 @@ packages: uniq: 1.0.1 dev: false - /cypress@12.12.0: - resolution: {integrity: sha512-UU5wFQ7SMVCR/hyKok/KmzG6fpZgBHHfrXcHzDmPHWrT+UUetxFzQgt7cxCszlwfozckzwkd22dxMwl/vNkWRw==} + /cypress@12.13.0: + resolution: {integrity: sha512-QJlSmdPk+53Zhy69woJMySZQJoWfEWun3X5OOenGsXjRPVfByVTHorxNehbzhZrEzH9RDUDqVcck0ahtlS+N/Q==} engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} hasBin: true requiresBuild: true @@ -9797,7 +9798,7 @@ packages: pretty-bytes: 5.6.0 proxy-from-env: 1.0.0 request-progress: 3.0.0 - semver: 7.5.0 + semver: 7.5.1 supports-color: 8.1.1 tmp: 0.2.1 untildify: 4.0.0 @@ -10656,8 +10657,8 @@ packages: - supports-color dev: true - /eslint-plugin-vue@9.13.0(eslint@8.40.0): - resolution: {integrity: sha512-aBz9A8WB4wmpnVv0pYUt86cmH9EkcwWzgEwecBxMoRNhQjTL5i4sqadnwShv/hOdr8Hbl8XANGV7dtX9UQIAyA==} + /eslint-plugin-vue@9.14.0(eslint@8.40.0): + resolution: {integrity: sha512-4O7EuiqPGVQA1wYCzLvCzsBTv9JIPHLHhrf0k55DLzbwtmJbSw2TKS0G/l7pOwi9RWMSkjIT7ftChU5gZpgnJw==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 @@ -10817,7 +10818,7 @@ packages: /event-loop-spinner@2.2.0: resolution: {integrity: sha512-KB44sV4Mv7uLIkJHJ5qhiZe5um6th2g57nHQL/uqnPHKP2IswoTRWUteEXTJQL4gW++1zqWUni+H2hGkP51c9w==} dependencies: - tslib: 2.5.0 + tslib: 2.5.2 dev: false /event-stream@3.3.4: @@ -13141,7 +13142,7 @@ packages: /isomorphic-unfetch@3.1.0: resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} dependencies: - node-fetch: 2.6.7 + node-fetch: 2.6.11 unfetch: 4.2.0 transitivePeerDependencies: - encoding @@ -13160,7 +13161,7 @@ packages: engines: {node: '>=8'} dependencies: '@babel/core': 7.21.3 - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -13235,7 +13236,7 @@ packages: '@jest/expect': 29.5.0 '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -13283,7 +13284,7 @@ packages: - ts-node dev: true - /jest-cli@29.5.0(@types/node@20.2.1): + /jest-cli@29.5.0(@types/node@20.2.3): resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -13300,7 +13301,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 29.5.0(@types/node@20.2.1) + jest-config: 29.5.0(@types/node@20.2.3) jest-util: 29.5.0 jest-validate: 29.5.0 prompts: 2.4.2 @@ -13350,7 +13351,7 @@ packages: - supports-color dev: true - /jest-config@29.5.0(@types/node@20.2.1): + /jest-config@29.5.0(@types/node@20.2.3): resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: @@ -13365,7 +13366,7 @@ packages: '@babel/core': 7.21.3 '@jest/test-sequencer': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 babel-jest: 29.5.0(@babel/core@7.21.3) chalk: 4.1.2 ci-info: 3.7.1 @@ -13434,7 +13435,7 @@ packages: '@jest/environment': 29.5.0 '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 jest-mock: 29.5.0 jest-util: 29.5.0 dev: true @@ -13464,7 +13465,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@types/graceful-fs': 4.1.6 - '@types/node': 20.2.1 + '@types/node': 20.2.3 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13515,7 +13516,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: true /jest-mock@29.5.0: @@ -13523,7 +13524,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 jest-util: 29.5.0 dev: true @@ -13578,7 +13579,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13609,7 +13610,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -13664,7 +13665,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 chalk: 4.1.2 ci-info: 3.7.1 graceful-fs: 4.2.11 @@ -13689,7 +13690,7 @@ packages: dependencies: '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.1 + '@types/node': 20.2.3 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13708,7 +13709,7 @@ packages: resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 jest-util: 29.5.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -13734,7 +13735,7 @@ packages: - ts-node dev: true - /jest@29.5.0(@types/node@20.2.1): + /jest@29.5.0(@types/node@20.2.3): resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -13747,7 +13748,7 @@ packages: '@jest/core': 29.5.0 '@jest/types': 29.5.0 import-local: 3.1.0 - jest-cli: 29.5.0(@types/node@20.2.1) + jest-cli: 29.5.0(@types/node@20.2.3) transitivePeerDependencies: - '@types/node' - supports-color @@ -13850,7 +13851,7 @@ packages: '@babel/preset-env': ^7.1.6 dependencies: '@babel/core': 7.21.3 - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.21.3) '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.21.3) '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.3) @@ -14634,10 +14635,10 @@ packages: engines: {node: '>= 0.6'} dev: true - /meilisearch@0.32.3: - resolution: {integrity: sha512-EOgfBuRE5SiIPIpEDYe2HO0D7a4z5bexIgaAdJFma/dH5hx1kwO+u/qb2g3qKyjG+iA3l8MlmTj/Xd72uahaAw==} + /meilisearch@0.32.4: + resolution: {integrity: sha512-QvPtQ6F2TaqAT9fw072/MDjSCMpQifdtUBFeIk3M5jSnFpeSiv1iwfJWNfP6ByaCgR/s++K1Cqtf9vjcZe7prg==} dependencies: - cross-fetch: 3.1.5 + cross-fetch: 3.1.6 transitivePeerDependencies: - encoding dev: false @@ -15188,6 +15189,17 @@ packages: resolution: {integrity: sha512-KIkvH1jl6b3O7es/0ShyCgWLcfXxlBrLBbP3rOr23WArC66IMcU4DeZEeYEOwnopYhawLTn7/y+YtmASe8DFVQ==} dev: true + /node-fetch@2.6.11: + resolution: {integrity: sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + /node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -15509,6 +15521,10 @@ packages: resolution: {integrity: sha512-Oh+8fK09mgGmAshFdH6hSVco6KZmd1tTwNFWj35OvzdmJTMZtAkbn05zar2iG3v6sDs1JLEtOiBGNb6BHwkb2w==} dev: false + /obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + dev: true + /omggif@1.0.10: resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} dev: false @@ -15975,6 +15991,11 @@ packages: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} + /pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + dev: true + /pg-pool@3.6.0(pg@8.11.0): resolution: {integrity: sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==} peerDependencies: @@ -15983,13 +16004,8 @@ packages: pg: 8.11.0 dev: false - /pg-protocol@1.5.0: - resolution: {integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==} - dev: true - /pg-protocol@1.6.0: resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} - dev: false /pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} @@ -16000,6 +16016,20 @@ packages: postgres-bytea: 1.0.0 postgres-date: 1.0.7 postgres-interval: 1.2.0 + dev: false + + /pg-types@4.0.1: + resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==} + engines: {node: '>=10'} + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.0.1 + postgres-interval: 3.0.0 + postgres-range: 1.1.3 + dev: true /pg@8.11.0: resolution: {integrity: sha512-meLUVPn2TWgJyLmy7el3fQQVwft4gU5NGyvV0XbD41iU9Jbg8lCH4zexhIkihDzVHJStlt6r088G6/fWeNjhXA==} @@ -16415,20 +16445,50 @@ packages: /postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} + dev: false + + /postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + dev: true /postgres-bytea@1.0.0: resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} engines: {node: '>=0.10.0'} + dev: false + + /postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + dependencies: + obuf: 1.1.2 + dev: true /postgres-date@1.0.7: resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} engines: {node: '>=0.10.0'} + dev: false + + /postgres-date@2.0.1: + resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==} + engines: {node: '>=12'} + dev: true /postgres-interval@1.2.0: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} dependencies: xtend: 4.0.2 + dev: false + + /postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + dev: true + + /postgres-range@1.1.3: + resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==} + dev: true /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} @@ -17146,7 +17206,7 @@ packages: ast-types: 0.15.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.5.0 + tslib: 2.5.2 dev: true /recast@0.22.0: @@ -17157,7 +17217,7 @@ packages: ast-types: 0.15.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.5.0 + tslib: 2.5.2 dev: true /recast@0.23.1: @@ -17168,7 +17228,7 @@ packages: ast-types: 0.16.1 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.5.0 + tslib: 2.5.2 dev: true /rechoir@0.6.2: @@ -17557,8 +17617,8 @@ packages: seedrandom: 2.4.2 dev: false - /rollup@3.22.0: - resolution: {integrity: sha512-imsigcWor5Y/dC0rz2q0bBt9PabcL3TORry2hAa6O6BuMvY71bqHyfReAz5qyAqiQATD1m70qdntqBfBQjVWpQ==} + /rollup@3.23.0: + resolution: {integrity: sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -18379,11 +18439,11 @@ packages: resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} dev: true - /storybook@7.0.12: - resolution: {integrity: sha512-HKi7NQQTZhBGEU3KUFxTNGtIZcG8+hokiO5TwcIr7s7smAVKdvj9vY5YGsVkiWF39o+5UtafW1B/i9D8lBFsYg==} + /storybook@7.0.15: + resolution: {integrity: sha512-GYGRH20H2G0oUhoh40p0o0AGPXN/cKntpt/BX7NKB1Dr4OqbawBw/65yGhuFuYA+HFjBUonWixicOgPkrsyuKg==} hasBin: true dependencies: - '@storybook/cli': 7.0.12 + '@storybook/cli': 7.0.15 transitivePeerDependencies: - bufferutil - encoding @@ -19109,6 +19169,9 @@ packages: /tslib@2.5.0: resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==} + /tslib@2.5.2: + resolution: {integrity: sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA==} + /tsutils@3.21.0(typescript@5.0.4): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -19729,7 +19792,7 @@ packages: replace-ext: 1.0.1 dev: false - /vite-node@0.31.1(@types/node@20.2.1)(sass@1.62.1): + /vite-node@0.31.1(@types/node@20.2.3)(sass@1.62.1): resolution: {integrity: sha512-BajE/IsNQ6JyizPzu9zRgHrBwczkAs0erQf/JRpgTIESpKvNj9/Gd0vxX905klLkb0I0SJVCKbdrl5c6FnqYKA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -19739,7 +19802,7 @@ packages: mlly: 1.2.0 pathe: 1.1.0 picocolors: 1.0.0 - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) transitivePeerDependencies: - '@types/node' - less @@ -19754,7 +19817,7 @@ packages: resolution: {integrity: sha512-irjKcKXRn7v5bPAg4mAbsS6DgibpP1VUFL9tlgxU6lloK6V9yw9qCZkS+s2PtbkZpWNzr3TN3zVJAc6J7gJZmA==} dev: true - /vite@4.3.8(@types/node@20.2.1)(sass@1.62.1): + /vite@4.3.8(@types/node@20.2.3)(sass@1.62.1): resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -19779,10 +19842,10 @@ packages: terser: optional: true dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 esbuild: 0.17.18 postcss: 8.4.23 - rollup: 3.22.0 + rollup: 3.23.0 sass: 1.62.1 optionalDependencies: fsevents: 2.3.2 @@ -19832,7 +19895,7 @@ packages: dependencies: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@vitest/expect': 0.31.1 '@vitest/runner': 0.31.1 '@vitest/snapshot': 0.31.1 @@ -19853,8 +19916,8 @@ packages: strip-literal: 1.0.1 tinybench: 2.5.0 tinypool: 0.5.0 - vite: 4.3.8(@types/node@20.2.1)(sass@1.62.1) - vite-node: 0.31.1(@types/node@20.2.1)(sass@1.62.1) + vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite-node: 0.31.1(@types/node@20.2.3)(sass@1.62.1) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -19872,7 +19935,7 @@ packages: /vue-docgen-api@4.64.1(vue@3.3.4): resolution: {integrity: sha512-jbOf7ByE3Zvtuk+429Jorl+eIeh2aB2Fx1GUo3xJd1aByJWE8KDlSEa6b11PB1ze8f0sRUBraRDinICCk0KY7g==} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/types': 7.21.5 '@vue/compiler-dom': 3.3.4 '@vue/compiler-sfc': 3.3.4 @@ -20185,7 +20248,7 @@ packages: resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/types': 7.21.5 assert-never: 1.2.1 babel-walk: 3.0.0-canary-5 @@ -20499,7 +20562,7 @@ packages: sharp: 0.31.3 dev: false - github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.12)(@storybook/components@7.0.12)(@storybook/core-events@7.0.12)(@storybook/manager-api@7.0.12)(@storybook/preview-api@7.0.12)(@storybook/theming@7.0.12)(@storybook/types@7.0.12)(react-dom@18.2.0)(react@18.2.0): + github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.15)(@storybook/components@7.0.15)(@storybook/core-events@7.0.15)(@storybook/manager-api@7.0.15)(@storybook/preview-api@7.0.15)(@storybook/theming@7.0.15)(@storybook/types@7.0.15)(react-dom@18.2.0)(react@18.2.0): resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640 name: storybook-addon-misskey-theme @@ -20520,13 +20583,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/components': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.12 - '@storybook/manager-api': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.12 - '@storybook/theming': 7.0.12(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.12 + '@storybook/blocks': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.15 + '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.15 + '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.15 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true From d2eec3a9e457d4c8bab595c14b4f8e8b79099a26 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 24 May 2023 14:34:46 +0900 Subject: [PATCH 078/213] refactor --- .../src/components/MkPostFormAttaches.vue | 103 ++++++++---------- .../src/widgets/WidgetInstanceCloud.vue | 4 - .../src/widgets/WidgetOnlineUsers.vue | 26 ++--- 3 files changed, 59 insertions(+), 74 deletions(-) diff --git a/packages/frontend/src/components/MkPostFormAttaches.vue b/packages/frontend/src/components/MkPostFormAttaches.vue index 5227afee0d..ee4d439cc3 100644 --- a/packages/frontend/src/components/MkPostFormAttaches.vue +++ b/packages/frontend/src/components/MkPostFormAttaches.vue @@ -1,16 +1,16 @@ <template> -<div v-show="props.modelValue.length != 0" class="skeikyzd"> - <Sortable :modelValue="props.modelValue" class="files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)"> +<div v-show="props.modelValue.length != 0" :class="$style.root"> + <Sortable :modelValue="props.modelValue" :class="$style.files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)"> <template #item="{element}"> - <div class="file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)"> - <MkDriveFileThumbnail :data-id="element.id" class="thumbnail" :file="element" fit="cover"/> - <div v-if="element.isSensitive" class="sensitive"> - <i class="ti ti-alert-triangle icon"></i> + <div :class="$style.file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)"> + <MkDriveFileThumbnail :data-id="element.id" :class="$style.thumbnail" :file="element" fit="cover"/> + <div v-if="element.isSensitive" :class="$style.sensitive"> + <i class="ti ti-alert-triangle" style="margin: auto;"></i> </div> </div> </template> </Sortable> - <p class="remain">{{ 16 - props.modelValue.length }}/16</p> + <p :class="$style.remain">{{ 16 - props.modelValue.length }}/16</p> </div> </template> @@ -108,60 +108,53 @@ function showFileMenu(file, ev: MouseEvent) { } </script> -<style lang="scss" scoped> -.skeikyzd { +<style lang="scss" module> +.root { padding: 8px 16px; position: relative; +} - > .files { - display: flex; - flex-wrap: wrap; +.files { + display: flex; + flex-wrap: wrap; +} - > .file { - position: relative; - width: 64px; - height: 64px; - margin-right: 4px; - border-radius: 4px; - overflow: hidden; - cursor: move; +.file { + position: relative; + width: 64px; + height: 64px; + margin-right: 4px; + border-radius: 4px; + overflow: hidden; + cursor: move; +} - &:hover > .remove { - display: block; - } +.thumbnail { + width: 100%; + height: 100%; + z-index: 1; + color: var(--fg); +} - > .thumbnail { - width: 100%; - height: 100%; - z-index: 1; - color: var(--fg); - } +.sensitive { + display: flex; + position: absolute; + width: 64px; + height: 64px; + top: 0; + left: 0; + z-index: 2; + background: rgba(17, 17, 17, .7); + color: #fff; +} - > .sensitive { - display: flex; - position: absolute; - width: 64px; - height: 64px; - top: 0; - left: 0; - z-index: 2; - background: rgba(17, 17, 17, .7); - color: #fff; - - > .icon { - margin: auto; - } - } - } - } - - > .remain { - display: block; - position: absolute; - top: 8px; - right: 8px; - margin: 0; - padding: 0; - } +.remain { + display: block; + position: absolute; + top: 8px; + right: 8px; + margin: 0; + padding: 0; + font-size: 90%; } </style> diff --git a/packages/frontend/src/widgets/WidgetInstanceCloud.vue b/packages/frontend/src/widgets/WidgetInstanceCloud.vue index 79bd4b55fd..f8b811e6ba 100644 --- a/packages/frontend/src/widgets/WidgetInstanceCloud.vue +++ b/packages/frontend/src/widgets/WidgetInstanceCloud.vue @@ -72,7 +72,3 @@ defineExpose<WidgetComponentExpose>({ id: props.widget ? props.widget.id : null, }); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/widgets/WidgetOnlineUsers.vue b/packages/frontend/src/widgets/WidgetOnlineUsers.vue index f95103b0b9..c920c3ca53 100644 --- a/packages/frontend/src/widgets/WidgetOnlineUsers.vue +++ b/packages/frontend/src/widgets/WidgetOnlineUsers.vue @@ -1,8 +1,10 @@ <template> -<div data-cy-mkw-onlineUsers class="mkw-onlineUsers" :class="{ _panel: !widgetProps.transparent, pad: !widgetProps.transparent }"> - <I18n v-if="onlineUsersCount" :src="i18n.ts.onlineUsersCount" textTag="span" class="text"> - <template #n><b>{{ number(onlineUsersCount) }}</b></template> - </I18n> +<div data-cy-mkw-onlineUsers :class="[$style.root, { _panel: !widgetProps.transparent, [$style.pad]: !widgetProps.transparent }]"> + <span :class="$style.text"> + <I18n v-if="onlineUsersCount" :src="i18n.ts.onlineUsersCount" textTag="span"> + <template #n><b style="color: #41b781;">{{ number(onlineUsersCount) }}</b></template> + </I18n> + </span> </div> </template> @@ -55,22 +57,16 @@ defineExpose<WidgetComponentExpose>({ }); </script> -<style lang="scss" scoped> -.mkw-onlineUsers { +<style lang="scss" module> +.root { text-align: center; &.pad { padding: 16px 0; } +} - > .text { - ::v-deep(b) { - color: #41b781; - } - - ::v-deep(span) { - opacity: 0.7; - } - } +.text { + color: var(--fgTransparentWeak); } </style> From 38a1d6693a3295dc59cf82c57ccab96112affa2b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 24 May 2023 14:43:53 +0900 Subject: [PATCH 079/213] :art: --- packages/backend/src/server/web/boot.js | 70 ++++++++++++------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index fd7f54da54..825f02e835 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -160,37 +160,41 @@ <path d="M12 9v2m0 4v.01"></path> <path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path> </svg> - <h1>An error has occurred!</h1> - <button class="button-big" onclick="location.reload();"> - <span class="button-label-big">Refresh</span> + <h1>Failed to load<br>読み込みに失敗しました</h1> + <button class="button-big" onclick="location.reload(true);"> + <span class="button-label-big">Reload / リロード</span> </button> - <p class="dont-worry">Don't worry, it's (probably) not your fault.</p> - <p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p> - <p>Update your os and browser.</p> - <p>Disable an adblocker.</p> - <a href="/flush"> - <button class="button-small"> - <span class="button-label-small">Clear preferences and cache</span> - </button> - </a> - <br> - <a href="/cli"> - <button class="button-small"> - <span class="button-label-small">Start the simple client</span> - </button> - </a> - <br> - <a href="/bios"> - <button class="button-small"> - <span class="button-label-small">Start the repair tool</span> - </button> - </a> + <p><b>The following actions may solve the problem. / 以下を行うと解決する可能性があります。</b></p> + <p>Clear the browser cache / ブラウザのキャッシュをクリアする</p> + <p>Update your os and browser / ブラウザおよびOSを最新バージョンに更新する</p> + <p>Disable an adblocker / アドブロッカーを無効にする</p> + <details style="color: #86b300;"> + <summary>Other options / その他のオプション</summary> + <a href="/flush"> + <button class="button-small"> + <span class="button-label-small">Clear preferences and cache</span> + </button> + </a> + <br> + <a href="/cli"> + <button class="button-small"> + <span class="button-label-small">Start the simple client</span> + </button> + </a> + <br> + <a href="/bios"> + <button class="button-small"> + <span class="button-label-small">Start the repair tool</span> + </button> + </a> + </details> <br> <div id="errors"></div> `; errorsElement = document.getElementById('errors'); } const detailsElement = document.createElement('details'); + detailsElement.id = 'errorInfo'; detailsElement.innerHTML = ` <br> <summary> @@ -247,7 +251,7 @@ .button-label-big { color: #222; font-weight: bold; - font-size: 20px; + font-size: 1.2em; padding: 12px; } @@ -267,11 +271,6 @@ font-size: 16px; } - .dont-worry, - #msg { - font-size: 18px; - } - .icon-warning { color: #dec340; height: 4rem; @@ -279,14 +278,15 @@ } h1 { - font-size: 32px; + font-size: 1.5em; + margin: 1em; } code { font-family: Fira, FiraCode, monospace; } - details { + #errorInfo { background: #333; margin-bottom: 2rem; padding: 0.5rem 1rem; @@ -296,16 +296,16 @@ margin: auto; } - summary { + #errorInfo summary { cursor: pointer; } - summary > * { + #errorInfo summary > * { display: inline; } @media screen and (max-width: 500px) { - details { + #errorInfo { width: 50%; } `) From 62fe3bfb5470129a3c82ee17ce3200dddb9623f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Wed, 24 May 2023 17:12:38 +0900 Subject: [PATCH 080/213] refactor(#7598): add i18n dynamic typings (#10882) * refactor: add i18n dynamic typings * chore: tweak --- locales/generateDTS.js | 72 + locales/index.d.ts | 2145 +++++++++++++++++++++++++++++- packages/frontend/src/i18n.ts | 3 +- packages/frontend/vite.config.ts | 5 + 4 files changed, 2222 insertions(+), 3 deletions(-) create mode 100644 locales/generateDTS.js diff --git a/locales/generateDTS.js b/locales/generateDTS.js new file mode 100644 index 0000000000..5949aee7cd --- /dev/null +++ b/locales/generateDTS.js @@ -0,0 +1,72 @@ +const fs = require('fs'); +const yaml = require('js-yaml'); +const ts = require('typescript'); + +function createMembers(record) { + return Object.entries(record) + .map(([k, v]) => ts.factory.createPropertySignature( + undefined, + ts.factory.createStringLiteral(k), + undefined, + typeof v === 'string' + ? ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword) + : ts.factory.createTypeLiteralNode(createMembers(v)), + )); +} + +module.exports = function generateDTS() { + const locale = yaml.load(fs.readFileSync(`${__dirname}/ja-JP.yml`, 'utf-8')); + const members = createMembers(locale); + const elements = [ + ts.factory.createInterfaceDeclaration( + [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], + ts.factory.createIdentifier('Locale'), + undefined, + undefined, + members, + ), + ts.factory.createVariableStatement( + [ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)], + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration( + ts.factory.createIdentifier('locales'), + undefined, + ts.factory.createTypeLiteralNode([ts.factory.createIndexSignature( + undefined, + [ts.factory.createParameterDeclaration( + undefined, + undefined, + ts.factory.createIdentifier('lang'), + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + undefined, + )], + ts.factory.createTypeReferenceNode( + ts.factory.createIdentifier('Locale'), + undefined, + ), + )]), + undefined, + )], + ts.NodeFlags.Const | ts.NodeFlags.Ambient | ts.NodeFlags.ContextFlags, + ), + ), + ts.factory.createExportAssignment( + undefined, + true, + ts.factory.createIdentifier('locales'), + ), + ]; + const printed = ts.createPrinter({ + newLine: ts.NewLineKind.LineFeed, + }).printList( + ts.ListFormat.MultiLine, + ts.factory.createNodeArray(elements), + ts.createSourceFile('index.d.ts', '', ts.ScriptTarget.ESNext, true, ts.ScriptKind.TS), + ); + + fs.writeFileSync(`${__dirname}/index.d.ts`, `/* eslint-disable */ +// This file is generated by locales/generateDTS.js +// Do not edit this file directly. +${printed}`, 'utf-8'); +} diff --git a/locales/index.d.ts b/locales/index.d.ts index fe3edb445b..6e3edefabb 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1,3 +1,2144 @@ -declare const locales: { [lang: string]: any }; - +/* eslint-disable */ +// This file is generated by locales/generateDTS.js +// Do not edit this file directly. +export interface Locale { + "_lang_": string; + "headlineMisskey": string; + "introMisskey": string; + "poweredByMisskeyDescription": string; + "monthAndDay": string; + "search": string; + "notifications": string; + "username": string; + "password": string; + "forgotPassword": string; + "fetchingAsApObject": string; + "ok": string; + "gotIt": string; + "cancel": string; + "noThankYou": string; + "enterUsername": string; + "renotedBy": string; + "noNotes": string; + "noNotifications": string; + "instance": string; + "settings": string; + "notificationSettings": string; + "basicSettings": string; + "otherSettings": string; + "openInWindow": string; + "profile": string; + "timeline": string; + "noAccountDescription": string; + "login": string; + "loggingIn": string; + "logout": string; + "signup": string; + "uploading": string; + "save": string; + "users": string; + "addUser": string; + "favorite": string; + "favorites": string; + "unfavorite": string; + "favorited": string; + "alreadyFavorited": string; + "cantFavorite": string; + "pin": string; + "unpin": string; + "copyContent": string; + "copyLink": string; + "delete": string; + "deleteAndEdit": string; + "deleteAndEditConfirm": string; + "addToList": string; + "sendMessage": string; + "copyRSS": string; + "copyUsername": string; + "copyUserId": string; + "copyNoteId": string; + "searchUser": string; + "reply": string; + "loadMore": string; + "showMore": string; + "showLess": string; + "youGotNewFollower": string; + "receiveFollowRequest": string; + "followRequestAccepted": string; + "mention": string; + "mentions": string; + "directNotes": string; + "importAndExport": string; + "import": string; + "export": string; + "files": string; + "download": string; + "driveFileDeleteConfirm": string; + "unfollowConfirm": string; + "exportRequested": string; + "importRequested": string; + "lists": string; + "noLists": string; + "note": string; + "notes": string; + "following": string; + "followers": string; + "followsYou": string; + "createList": string; + "manageLists": string; + "error": string; + "somethingHappened": string; + "retry": string; + "pageLoadError": string; + "pageLoadErrorDescription": string; + "serverIsDead": string; + "youShouldUpgradeClient": string; + "enterListName": string; + "privacy": string; + "makeFollowManuallyApprove": string; + "defaultNoteVisibility": string; + "follow": string; + "followRequest": string; + "followRequests": string; + "unfollow": string; + "followRequestPending": string; + "enterEmoji": string; + "renote": string; + "unrenote": string; + "renoted": string; + "cantRenote": string; + "cantReRenote": string; + "quote": string; + "inChannelRenote": string; + "inChannelQuote": string; + "pinnedNote": string; + "pinned": string; + "you": string; + "clickToShow": string; + "sensitive": string; + "add": string; + "reaction": string; + "reactions": string; + "reactionSetting": string; + "reactionSettingDescription2": string; + "rememberNoteVisibility": string; + "attachCancel": string; + "markAsSensitive": string; + "unmarkAsSensitive": string; + "enterFileName": string; + "mute": string; + "unmute": string; + "renoteMute": string; + "renoteUnmute": string; + "block": string; + "unblock": string; + "suspend": string; + "unsuspend": string; + "blockConfirm": string; + "unblockConfirm": string; + "suspendConfirm": string; + "unsuspendConfirm": string; + "selectList": string; + "selectChannel": string; + "selectAntenna": string; + "selectWidget": string; + "editWidgets": string; + "editWidgetsExit": string; + "customEmojis": string; + "emoji": string; + "emojis": string; + "emojiName": string; + "emojiUrl": string; + "addEmoji": string; + "settingGuide": string; + "cacheRemoteFiles": string; + "cacheRemoteFilesDescription": string; + "flagAsBot": string; + "flagAsBotDescription": string; + "flagAsCat": string; + "flagAsCatDescription": string; + "flagShowTimelineReplies": string; + "flagShowTimelineRepliesDescription": string; + "autoAcceptFollowed": string; + "addAccount": string; + "reloadAccountsList": string; + "loginFailed": string; + "showOnRemote": string; + "general": string; + "wallpaper": string; + "setWallpaper": string; + "removeWallpaper": string; + "searchWith": string; + "youHaveNoLists": string; + "followConfirm": string; + "proxyAccount": string; + "proxyAccountDescription": string; + "host": string; + "selectUser": string; + "recipient": string; + "annotation": string; + "federation": string; + "instances": string; + "registeredAt": string; + "latestRequestReceivedAt": string; + "latestStatus": string; + "storageUsage": string; + "charts": string; + "perHour": string; + "perDay": string; + "stopActivityDelivery": string; + "blockThisInstance": string; + "operations": string; + "software": string; + "version": string; + "metadata": string; + "withNFiles": string; + "monitor": string; + "jobQueue": string; + "cpuAndMemory": string; + "network": string; + "disk": string; + "instanceInfo": string; + "statistics": string; + "clearQueue": string; + "clearQueueConfirmTitle": string; + "clearQueueConfirmText": string; + "clearCachedFiles": string; + "clearCachedFilesConfirm": string; + "blockedInstances": string; + "blockedInstancesDescription": string; + "muteAndBlock": string; + "mutedUsers": string; + "blockedUsers": string; + "noUsers": string; + "editProfile": string; + "noteDeleteConfirm": string; + "pinLimitExceeded": string; + "intro": string; + "done": string; + "processing": string; + "preview": string; + "default": string; + "defaultValueIs": string; + "noCustomEmojis": string; + "noJobs": string; + "federating": string; + "blocked": string; + "suspended": string; + "all": string; + "subscribing": string; + "publishing": string; + "notResponding": string; + "instanceFollowing": string; + "instanceFollowers": string; + "instanceUsers": string; + "changePassword": string; + "security": string; + "retypedNotMatch": string; + "currentPassword": string; + "newPassword": string; + "newPasswordRetype": string; + "attachFile": string; + "more": string; + "featured": string; + "usernameOrUserId": string; + "noSuchUser": string; + "lookup": string; + "announcements": string; + "imageUrl": string; + "remove": string; + "removed": string; + "removeAreYouSure": string; + "deleteAreYouSure": string; + "resetAreYouSure": string; + "saved": string; + "messaging": string; + "upload": string; + "keepOriginalUploading": string; + "keepOriginalUploadingDescription": string; + "fromDrive": string; + "fromUrl": string; + "uploadFromUrl": string; + "uploadFromUrlDescription": string; + "uploadFromUrlRequested": string; + "uploadFromUrlMayTakeTime": string; + "explore": string; + "messageRead": string; + "noMoreHistory": string; + "startMessaging": string; + "nUsersRead": string; + "agreeTo": string; + "agree": string; + "agreeBelow": string; + "basicNotesBeforeCreateAccount": string; + "termsOfService": string; + "start": string; + "home": string; + "remoteUserCaution": string; + "activity": string; + "images": string; + "image": string; + "birthday": string; + "yearsOld": string; + "registeredDate": string; + "location": string; + "theme": string; + "themeForLightMode": string; + "themeForDarkMode": string; + "light": string; + "dark": string; + "lightThemes": string; + "darkThemes": string; + "syncDeviceDarkMode": string; + "drive": string; + "fileName": string; + "selectFile": string; + "selectFiles": string; + "selectFolder": string; + "selectFolders": string; + "renameFile": string; + "folderName": string; + "createFolder": string; + "renameFolder": string; + "deleteFolder": string; + "addFile": string; + "emptyDrive": string; + "emptyFolder": string; + "unableToDelete": string; + "inputNewFileName": string; + "inputNewDescription": string; + "inputNewFolderName": string; + "circularReferenceFolder": string; + "hasChildFilesOrFolders": string; + "copyUrl": string; + "rename": string; + "avatar": string; + "banner": string; + "nsfw": string; + "whenServerDisconnected": string; + "disconnectedFromServer": string; + "reload": string; + "doNothing": string; + "reloadConfirm": string; + "watch": string; + "unwatch": string; + "accept": string; + "reject": string; + "normal": string; + "instanceName": string; + "instanceDescription": string; + "maintainerName": string; + "maintainerEmail": string; + "tosUrl": string; + "thisYear": string; + "thisMonth": string; + "today": string; + "dayX": string; + "monthX": string; + "yearX": string; + "pages": string; + "integration": string; + "connectService": string; + "disconnectService": string; + "enableLocalTimeline": string; + "enableGlobalTimeline": string; + "disablingTimelinesInfo": string; + "registration": string; + "enableRegistration": string; + "invite": string; + "driveCapacityPerLocalAccount": string; + "driveCapacityPerRemoteAccount": string; + "inMb": string; + "iconUrl": string; + "bannerUrl": string; + "backgroundImageUrl": string; + "basicInfo": string; + "pinnedUsers": string; + "pinnedUsersDescription": string; + "pinnedPages": string; + "pinnedPagesDescription": string; + "pinnedClipId": string; + "pinnedNotes": string; + "hcaptcha": string; + "enableHcaptcha": string; + "hcaptchaSiteKey": string; + "hcaptchaSecretKey": string; + "recaptcha": string; + "enableRecaptcha": string; + "recaptchaSiteKey": string; + "recaptchaSecretKey": string; + "turnstile": string; + "enableTurnstile": string; + "turnstileSiteKey": string; + "turnstileSecretKey": string; + "avoidMultiCaptchaConfirm": string; + "antennas": string; + "manageAntennas": string; + "name": string; + "antennaSource": string; + "antennaKeywords": string; + "antennaExcludeKeywords": string; + "antennaKeywordsDescription": string; + "notifyAntenna": string; + "withFileAntenna": string; + "enableServiceworker": string; + "antennaUsersDescription": string; + "caseSensitive": string; + "withReplies": string; + "connectedTo": string; + "notesAndReplies": string; + "withFiles": string; + "silence": string; + "silenceConfirm": string; + "unsilence": string; + "unsilenceConfirm": string; + "popularUsers": string; + "recentlyUpdatedUsers": string; + "recentlyRegisteredUsers": string; + "recentlyDiscoveredUsers": string; + "exploreUsersCount": string; + "exploreFediverse": string; + "popularTags": string; + "userList": string; + "about": string; + "aboutMisskey": string; + "administrator": string; + "token": string; + "2fa": string; + "totp": string; + "totpDescription": string; + "moderator": string; + "moderation": string; + "nUsersMentioned": string; + "securityKeyAndPasskey": string; + "securityKey": string; + "lastUsed": string; + "lastUsedAt": string; + "unregister": string; + "passwordLessLogin": string; + "passwordLessLoginDescription": string; + "resetPassword": string; + "newPasswordIs": string; + "reduceUiAnimation": string; + "share": string; + "notFound": string; + "notFoundDescription": string; + "uploadFolder": string; + "cacheClear": string; + "markAsReadAllNotifications": string; + "markAsReadAllUnreadNotes": string; + "markAsReadAllTalkMessages": string; + "help": string; + "inputMessageHere": string; + "close": string; + "invites": string; + "members": string; + "transfer": string; + "title": string; + "text": string; + "enable": string; + "next": string; + "retype": string; + "noteOf": string; + "quoteAttached": string; + "quoteQuestion": string; + "noMessagesYet": string; + "newMessageExists": string; + "onlyOneFileCanBeAttached": string; + "signinRequired": string; + "invitations": string; + "invitationCode": string; + "checking": string; + "available": string; + "unavailable": string; + "usernameInvalidFormat": string; + "tooShort": string; + "tooLong": string; + "weakPassword": string; + "normalPassword": string; + "strongPassword": string; + "passwordMatched": string; + "passwordNotMatched": string; + "signinWith": string; + "signinFailed": string; + "or": string; + "language": string; + "uiLanguage": string; + "aboutX": string; + "emojiStyle": string; + "native": string; + "disableDrawer": string; + "showNoteActionsOnlyHover": string; + "noHistory": string; + "signinHistory": string; + "enableAdvancedMfm": string; + "enableAnimatedMfm": string; + "doing": string; + "category": string; + "tags": string; + "docSource": string; + "createAccount": string; + "existingAccount": string; + "regenerate": string; + "fontSize": string; + "mediaListWithOneImageAppearance": string; + "limitTo": string; + "noFollowRequests": string; + "openImageInNewTab": string; + "dashboard": string; + "local": string; + "remote": string; + "total": string; + "weekOverWeekChanges": string; + "dayOverDayChanges": string; + "appearance": string; + "clientSettings": string; + "accountSettings": string; + "promotion": string; + "promote": string; + "numberOfDays": string; + "hideThisNote": string; + "showFeaturedNotesInTimeline": string; + "objectStorage": string; + "useObjectStorage": string; + "objectStorageBaseUrl": string; + "objectStorageBaseUrlDesc": string; + "objectStorageBucket": string; + "objectStorageBucketDesc": string; + "objectStoragePrefix": string; + "objectStoragePrefixDesc": string; + "objectStorageEndpoint": string; + "objectStorageEndpointDesc": string; + "objectStorageRegion": string; + "objectStorageRegionDesc": string; + "objectStorageUseSSL": string; + "objectStorageUseSSLDesc": string; + "objectStorageUseProxy": string; + "objectStorageUseProxyDesc": string; + "objectStorageSetPublicRead": string; + "s3ForcePathStyleDesc": string; + "serverLogs": string; + "deleteAll": string; + "showFixedPostForm": string; + "showFixedPostFormInChannel": string; + "newNoteRecived": string; + "sounds": string; + "sound": string; + "listen": string; + "none": string; + "showInPage": string; + "popout": string; + "volume": string; + "masterVolume": string; + "details": string; + "chooseEmoji": string; + "unableToProcess": string; + "recentUsed": string; + "install": string; + "uninstall": string; + "installedApps": string; + "nothing": string; + "installedDate": string; + "lastUsedDate": string; + "state": string; + "sort": string; + "ascendingOrder": string; + "descendingOrder": string; + "scratchpad": string; + "scratchpadDescription": string; + "output": string; + "script": string; + "disablePagesScript": string; + "updateRemoteUser": string; + "deleteAllFiles": string; + "deleteAllFilesConfirm": string; + "removeAllFollowing": string; + "removeAllFollowingDescription": string; + "userSuspended": string; + "userSilenced": string; + "yourAccountSuspendedTitle": string; + "yourAccountSuspendedDescription": string; + "tokenRevoked": string; + "tokenRevokedDescription": string; + "accountDeleted": string; + "accountDeletedDescription": string; + "menu": string; + "divider": string; + "addItem": string; + "rearrange": string; + "relays": string; + "addRelay": string; + "inboxUrl": string; + "addedRelays": string; + "serviceworkerInfo": string; + "deletedNote": string; + "invisibleNote": string; + "enableInfiniteScroll": string; + "visibility": string; + "poll": string; + "useCw": string; + "enablePlayer": string; + "disablePlayer": string; + "expandTweet": string; + "themeEditor": string; + "description": string; + "describeFile": string; + "enterFileDescription": string; + "author": string; + "leaveConfirm": string; + "manage": string; + "plugins": string; + "preferencesBackups": string; + "deck": string; + "undeck": string; + "useBlurEffectForModal": string; + "useFullReactionPicker": string; + "width": string; + "height": string; + "large": string; + "medium": string; + "small": string; + "generateAccessToken": string; + "permission": string; + "enableAll": string; + "disableAll": string; + "tokenRequested": string; + "pluginTokenRequestedDescription": string; + "notificationType": string; + "edit": string; + "emailServer": string; + "enableEmail": string; + "emailConfigInfo": string; + "email": string; + "emailAddress": string; + "smtpConfig": string; + "smtpHost": string; + "smtpPort": string; + "smtpUser": string; + "smtpPass": string; + "emptyToDisableSmtpAuth": string; + "smtpSecure": string; + "smtpSecureInfo": string; + "testEmail": string; + "wordMute": string; + "regexpError": string; + "regexpErrorDescription": string; + "instanceMute": string; + "userSaysSomething": string; + "makeActive": string; + "display": string; + "copy": string; + "metrics": string; + "overview": string; + "logs": string; + "delayed": string; + "database": string; + "channel": string; + "create": string; + "notificationSetting": string; + "notificationSettingDesc": string; + "useGlobalSetting": string; + "useGlobalSettingDesc": string; + "other": string; + "regenerateLoginToken": string; + "regenerateLoginTokenDescription": string; + "setMultipleBySeparatingWithSpace": string; + "fileIdOrUrl": string; + "behavior": string; + "sample": string; + "abuseReports": string; + "reportAbuse": string; + "reportAbuseOf": string; + "fillAbuseReportDescription": string; + "abuseReported": string; + "reporter": string; + "reporteeOrigin": string; + "reporterOrigin": string; + "forwardReport": string; + "forwardReportIsAnonymous": string; + "send": string; + "abuseMarkAsResolved": string; + "openInNewTab": string; + "openInSideView": string; + "defaultNavigationBehaviour": string; + "editTheseSettingsMayBreakAccount": string; + "instanceTicker": string; + "waitingFor": string; + "random": string; + "system": string; + "switchUi": string; + "desktop": string; + "clip": string; + "createNew": string; + "optional": string; + "createNewClip": string; + "unclip": string; + "confirmToUnclipAlreadyClippedNote": string; + "public": string; + "i18nInfo": string; + "manageAccessTokens": string; + "accountInfo": string; + "notesCount": string; + "repliesCount": string; + "renotesCount": string; + "repliedCount": string; + "renotedCount": string; + "followingCount": string; + "followersCount": string; + "sentReactionsCount": string; + "receivedReactionsCount": string; + "pollVotesCount": string; + "pollVotedCount": string; + "yes": string; + "no": string; + "driveFilesCount": string; + "driveUsage": string; + "noCrawle": string; + "noCrawleDescription": string; + "lockedAccountInfo": string; + "alwaysMarkSensitive": string; + "loadRawImages": string; + "disableShowingAnimatedImages": string; + "verificationEmailSent": string; + "notSet": string; + "emailVerified": string; + "noteFavoritesCount": string; + "pageLikesCount": string; + "pageLikedCount": string; + "contact": string; + "useSystemFont": string; + "clips": string; + "experimentalFeatures": string; + "experimental": string; + "thisIsExperimentalFeature": string; + "developer": string; + "makeExplorable": string; + "makeExplorableDescription": string; + "showGapBetweenNotesInTimeline": string; + "duplicate": string; + "left": string; + "center": string; + "wide": string; + "narrow": string; + "reloadToApplySetting": string; + "needReloadToApply": string; + "showTitlebar": string; + "clearCache": string; + "onlineUsersCount": string; + "nUsers": string; + "nNotes": string; + "sendErrorReports": string; + "sendErrorReportsDescription": string; + "myTheme": string; + "backgroundColor": string; + "accentColor": string; + "textColor": string; + "saveAs": string; + "advanced": string; + "advancedSettings": string; + "value": string; + "createdAt": string; + "updatedAt": string; + "saveConfirm": string; + "deleteConfirm": string; + "invalidValue": string; + "registry": string; + "closeAccount": string; + "currentVersion": string; + "latestVersion": string; + "youAreRunningUpToDateClient": string; + "newVersionOfClientAvailable": string; + "usageAmount": string; + "capacity": string; + "inUse": string; + "editCode": string; + "apply": string; + "receiveAnnouncementFromInstance": string; + "emailNotification": string; + "publish": string; + "inChannelSearch": string; + "useReactionPickerForContextMenu": string; + "typingUsers": string; + "jumpToSpecifiedDate": string; + "showingPastTimeline": string; + "clear": string; + "markAllAsRead": string; + "goBack": string; + "unlikeConfirm": string; + "fullView": string; + "quitFullView": string; + "addDescription": string; + "userPagePinTip": string; + "notSpecifiedMentionWarning": string; + "info": string; + "userInfo": string; + "unknown": string; + "onlineStatus": string; + "hideOnlineStatus": string; + "hideOnlineStatusDescription": string; + "online": string; + "active": string; + "offline": string; + "notRecommended": string; + "botProtection": string; + "instanceBlocking": string; + "selectAccount": string; + "switchAccount": string; + "enabled": string; + "disabled": string; + "quickAction": string; + "user": string; + "administration": string; + "accounts": string; + "switch": string; + "noMaintainerInformationWarning": string; + "noBotProtectionWarning": string; + "configure": string; + "postToGallery": string; + "gallery": string; + "recentPosts": string; + "popularPosts": string; + "shareWithNote": string; + "ads": string; + "expiration": string; + "startingperiod": string; + "memo": string; + "priority": string; + "high": string; + "middle": string; + "low": string; + "emailNotConfiguredWarning": string; + "ratio": string; + "previewNoteText": string; + "customCss": string; + "customCssWarn": string; + "global": string; + "squareAvatars": string; + "sent": string; + "received": string; + "searchResult": string; + "hashtags": string; + "troubleshooting": string; + "useBlurEffect": string; + "learnMore": string; + "misskeyUpdated": string; + "whatIsNew": string; + "translate": string; + "translatedFrom": string; + "accountDeletionInProgress": string; + "usernameInfo": string; + "aiChanMode": string; + "devMode": string; + "keepCw": string; + "pubSub": string; + "lastCommunication": string; + "resolved": string; + "unresolved": string; + "breakFollow": string; + "breakFollowConfirm": string; + "itsOn": string; + "itsOff": string; + "on": string; + "off": string; + "emailRequiredForSignup": string; + "unread": string; + "filter": string; + "controlPanel": string; + "manageAccounts": string; + "makeReactionsPublic": string; + "makeReactionsPublicDescription": string; + "classic": string; + "muteThread": string; + "unmuteThread": string; + "ffVisibility": string; + "ffVisibilityDescription": string; + "continueThread": string; + "deleteAccountConfirm": string; + "incorrectPassword": string; + "voteConfirm": string; + "hide": string; + "useDrawerReactionPickerForMobile": string; + "welcomeBackWithName": string; + "clickToFinishEmailVerification": string; + "overridedDeviceKind": string; + "smartphone": string; + "tablet": string; + "auto": string; + "themeColor": string; + "size": string; + "numberOfColumn": string; + "searchByGoogle": string; + "instanceDefaultLightTheme": string; + "instanceDefaultDarkTheme": string; + "instanceDefaultThemeDescription": string; + "mutePeriod": string; + "period": string; + "indefinitely": string; + "tenMinutes": string; + "oneHour": string; + "oneDay": string; + "oneWeek": string; + "oneMonth": string; + "reflectMayTakeTime": string; + "failedToFetchAccountInformation": string; + "rateLimitExceeded": string; + "cropImage": string; + "cropImageAsk": string; + "cropYes": string; + "cropNo": string; + "file": string; + "recentNHours": string; + "recentNDays": string; + "noEmailServerWarning": string; + "thereIsUnresolvedAbuseReportWarning": string; + "recommended": string; + "check": string; + "driveCapOverrideLabel": string; + "driveCapOverrideCaption": string; + "requireAdminForView": string; + "isSystemAccount": string; + "typeToConfirm": string; + "deleteAccount": string; + "document": string; + "numberOfPageCache": string; + "numberOfPageCacheDescription": string; + "logoutConfirm": string; + "lastActiveDate": string; + "statusbar": string; + "pleaseSelect": string; + "reverse": string; + "colored": string; + "refreshInterval": string; + "label": string; + "type": string; + "speed": string; + "slow": string; + "fast": string; + "sensitiveMediaDetection": string; + "localOnly": string; + "remoteOnly": string; + "failedToUpload": string; + "cannotUploadBecauseInappropriate": string; + "cannotUploadBecauseNoFreeSpace": string; + "cannotUploadBecauseExceedsFileSizeLimit": string; + "beta": string; + "enableAutoSensitive": string; + "enableAutoSensitiveDescription": string; + "activeEmailValidationDescription": string; + "navbar": string; + "shuffle": string; + "account": string; + "move": string; + "pushNotification": string; + "subscribePushNotification": string; + "unsubscribePushNotification": string; + "pushNotificationAlreadySubscribed": string; + "pushNotificationNotSupported": string; + "sendPushNotificationReadMessage": string; + "sendPushNotificationReadMessageCaption": string; + "windowMaximize": string; + "windowMinimize": string; + "windowRestore": string; + "caption": string; + "loggedInAsBot": string; + "tools": string; + "cannotLoad": string; + "numberOfProfileView": string; + "like": string; + "unlike": string; + "numberOfLikes": string; + "show": string; + "neverShow": string; + "remindMeLater": string; + "didYouLikeMisskey": string; + "pleaseDonate": string; + "roles": string; + "role": string; + "noRole": string; + "normalUser": string; + "undefined": string; + "assign": string; + "unassign": string; + "color": string; + "manageCustomEmojis": string; + "youCannotCreateAnymore": string; + "cannotPerformTemporary": string; + "cannotPerformTemporaryDescription": string; + "invalidParamError": string; + "invalidParamErrorDescription": string; + "permissionDeniedError": string; + "permissionDeniedErrorDescription": string; + "preset": string; + "selectFromPresets": string; + "achievements": string; + "gotInvalidResponseError": string; + "gotInvalidResponseErrorDescription": string; + "thisPostMayBeAnnoying": string; + "thisPostMayBeAnnoyingHome": string; + "thisPostMayBeAnnoyingCancel": string; + "thisPostMayBeAnnoyingIgnore": string; + "collapseRenotes": string; + "internalServerError": string; + "internalServerErrorDescription": string; + "copyErrorInfo": string; + "joinThisServer": string; + "exploreOtherServers": string; + "letsLookAtTimeline": string; + "disableFederationConfirm": string; + "disableFederationConfirmWarn": string; + "disableFederationOk": string; + "invitationRequiredToRegister": string; + "emailNotSupported": string; + "postToTheChannel": string; + "cannotBeChangedLater": string; + "reactionAcceptance": string; + "likeOnly": string; + "likeOnlyForRemote": string; + "nonSensitiveOnly": string; + "nonSensitiveOnlyForLocalLikeOnlyForRemote": string; + "rolesAssignedToMe": string; + "resetPasswordConfirm": string; + "sensitiveWords": string; + "sensitiveWordsDescription": string; + "sensitiveWordsDescription2": string; + "notesSearchNotAvailable": string; + "license": string; + "unfavoriteConfirm": string; + "myClips": string; + "drivecleaner": string; + "retryAllQueuesNow": string; + "retryAllQueuesConfirmTitle": string; + "retryAllQueuesConfirmText": string; + "enableChartsForRemoteUser": string; + "enableChartsForFederatedInstances": string; + "showClipButtonInNoteFooter": string; + "largeNoteReactions": string; + "noteIdOrUrl": string; + "video": string; + "videos": string; + "dataSaver": string; + "accountMigration": string; + "accountMoved": string; + "accountMovedShort": string; + "operationForbidden": string; + "forceShowAds": string; + "addMemo": string; + "editMemo": string; + "reactionsList": string; + "renotesList": string; + "notificationDisplay": string; + "leftTop": string; + "rightTop": string; + "leftBottom": string; + "rightBottom": string; + "stackAxis": string; + "vertical": string; + "horizontal": string; + "position": string; + "serverRules": string; + "pleaseConfirmBelowBeforeSignup": string; + "pleaseAgreeAllToContinue": string; + "continue": string; + "preservedUsernames": string; + "preservedUsernamesDescription": string; + "createNoteFromTheFile": string; + "archive": string; + "channelArchiveConfirmTitle": string; + "channelArchiveConfirmDescription": string; + "thisChannelArchived": string; + "displayOfNote": string; + "initialAccountSetting": string; + "youFollowing": string; + "preventAiLearning": string; + "preventAiLearningDescription": string; + "options": string; + "specifyUser": string; + "failedToPreviewUrl": string; + "update": string; + "rolesThatCanBeUsedThisEmojiAsReaction": string; + "rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription": string; + "rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn": string; + "cancelReactionConfirm": string; + "changeReactionConfirm": string; + "_initialAccountSetting": { + "accountCreated": string; + "letsStartAccountSetup": string; + "letsFillYourProfile": string; + "profileSetting": string; + "privacySetting": string; + "theseSettingsCanEditLater": string; + "youCanEditMoreSettingsInSettingsPageLater": string; + "followUsers": string; + "pushNotificationDescription": string; + "initialAccountSettingCompleted": string; + "haveFun": string; + "ifYouNeedLearnMore": string; + "skipAreYouSure": string; + }; + "_serverRules": { + "description": string; + }; + "_accountMigration": { + "moveFrom": string; + "moveFromSub": string; + "moveFromLabel": string; + "moveFromDescription": string; + "moveTo": string; + "moveToLabel": string; + "moveCannotBeUndone": string; + "moveAccountDescription": string; + "moveAccountHowTo": string; + "startMigration": string; + "migrationConfirm": string; + "movedAndCannotBeUndone": string; + "postMigrationNote": string; + "movedTo": string; + }; + "_achievements": { + "earnedAt": string; + "_types": { + "_notes1": { + "title": string; + "description": string; + "flavor": string; + }; + "_notes10": { + "title": string; + "description": string; + }; + "_notes100": { + "title": string; + "description": string; + }; + "_notes500": { + "title": string; + "description": string; + }; + "_notes1000": { + "title": string; + "description": string; + }; + "_notes5000": { + "title": string; + "description": string; + }; + "_notes10000": { + "title": string; + "description": string; + }; + "_notes20000": { + "title": string; + "description": string; + }; + "_notes30000": { + "title": string; + "description": string; + }; + "_notes40000": { + "title": string; + "description": string; + }; + "_notes50000": { + "title": string; + "description": string; + }; + "_notes60000": { + "title": string; + "description": string; + }; + "_notes70000": { + "title": string; + "description": string; + }; + "_notes80000": { + "title": string; + "description": string; + }; + "_notes90000": { + "title": string; + "description": string; + }; + "_notes100000": { + "title": string; + "description": string; + "flavor": string; + }; + "_login3": { + "title": string; + "description": string; + "flavor": string; + }; + "_login7": { + "title": string; + "description": string; + "flavor": string; + }; + "_login15": { + "title": string; + "description": string; + }; + "_login30": { + "title": string; + "description": string; + }; + "_login60": { + "title": string; + "description": string; + }; + "_login100": { + "title": string; + "description": string; + "flavor": string; + }; + "_login200": { + "title": string; + "description": string; + }; + "_login300": { + "title": string; + "description": string; + }; + "_login400": { + "title": string; + "description": string; + }; + "_login500": { + "title": string; + "description": string; + "flavor": string; + }; + "_login600": { + "title": string; + "description": string; + }; + "_login700": { + "title": string; + "description": string; + }; + "_login800": { + "title": string; + "description": string; + }; + "_login900": { + "title": string; + "description": string; + }; + "_login1000": { + "title": string; + "description": string; + "flavor": string; + }; + "_noteClipped1": { + "title": string; + "description": string; + }; + "_noteFavorited1": { + "title": string; + "description": string; + }; + "_myNoteFavorited1": { + "title": string; + "description": string; + }; + "_profileFilled": { + "title": string; + "description": string; + }; + "_markedAsCat": { + "title": string; + "description": string; + "flavor": string; + }; + "_following1": { + "title": string; + "description": string; + }; + "_following10": { + "title": string; + "description": string; + }; + "_following50": { + "title": string; + "description": string; + }; + "_following100": { + "title": string; + "description": string; + }; + "_following300": { + "title": string; + "description": string; + }; + "_followers1": { + "title": string; + "description": string; + }; + "_followers10": { + "title": string; + "description": string; + }; + "_followers50": { + "title": string; + "description": string; + }; + "_followers100": { + "title": string; + "description": string; + }; + "_followers300": { + "title": string; + "description": string; + }; + "_followers500": { + "title": string; + "description": string; + }; + "_followers1000": { + "title": string; + "description": string; + }; + "_collectAchievements30": { + "title": string; + "description": string; + }; + "_viewAchievements3min": { + "title": string; + "description": string; + }; + "_iLoveMisskey": { + "title": string; + "description": string; + "flavor": string; + }; + "_foundTreasure": { + "title": string; + "description": string; + }; + "_client30min": { + "title": string; + "description": string; + }; + "_client60min": { + "title": string; + "description": string; + }; + "_noteDeletedWithin1min": { + "title": string; + "description": string; + }; + "_postedAtLateNight": { + "title": string; + "description": string; + "flavor": string; + }; + "_postedAt0min0sec": { + "title": string; + "description": string; + "flavor": string; + }; + "_selfQuote": { + "title": string; + "description": string; + }; + "_htl20npm": { + "title": string; + "description": string; + }; + "_viewInstanceChart": { + "title": string; + "description": string; + }; + "_outputHelloWorldOnScratchpad": { + "title": string; + "description": string; + }; + "_open3windows": { + "title": string; + "description": string; + }; + "_driveFolderCircularReference": { + "title": string; + "description": string; + }; + "_reactWithoutRead": { + "title": string; + "description": string; + }; + "_clickedClickHere": { + "title": string; + "description": string; + }; + "_justPlainLucky": { + "title": string; + "description": string; + }; + "_setNameToSyuilo": { + "title": string; + "description": string; + }; + "_passedSinceAccountCreated1": { + "title": string; + "description": string; + }; + "_passedSinceAccountCreated2": { + "title": string; + "description": string; + }; + "_passedSinceAccountCreated3": { + "title": string; + "description": string; + }; + "_loggedInOnBirthday": { + "title": string; + "description": string; + }; + "_loggedInOnNewYearsDay": { + "title": string; + "description": string; + "flavor": string; + }; + "_cookieClicked": { + "title": string; + "description": string; + "flavor": string; + }; + "_brainDiver": { + "title": string; + "description": string; + "flavor": string; + }; + }; + }; + "_role": { + "new": string; + "edit": string; + "name": string; + "description": string; + "permission": string; + "descriptionOfPermission": string; + "assignTarget": string; + "descriptionOfAssignTarget": string; + "manual": string; + "conditional": string; + "condition": string; + "isConditionalRole": string; + "isPublic": string; + "descriptionOfIsPublic": string; + "options": string; + "policies": string; + "baseRole": string; + "useBaseValue": string; + "chooseRoleToAssign": string; + "iconUrl": string; + "asBadge": string; + "descriptionOfAsBadge": string; + "isExplorable": string; + "descriptionOfIsExplorable": string; + "displayOrder": string; + "descriptionOfDisplayOrder": string; + "canEditMembersByModerator": string; + "descriptionOfCanEditMembersByModerator": string; + "priority": string; + "_priority": { + "low": string; + "middle": string; + "high": string; + }; + "_options": { + "gtlAvailable": string; + "ltlAvailable": string; + "canPublicNote": string; + "canInvite": string; + "canManageCustomEmojis": string; + "driveCapacity": string; + "alwaysMarkNsfw": string; + "pinMax": string; + "antennaMax": string; + "wordMuteMax": string; + "webhookMax": string; + "clipMax": string; + "noteEachClipsMax": string; + "userListMax": string; + "userEachUserListsMax": string; + "rateLimitFactor": string; + "descriptionOfRateLimitFactor": string; + "canHideAds": string; + "canSearchNotes": string; + }; + "_condition": { + "isLocal": string; + "isRemote": string; + "createdLessThan": string; + "createdMoreThan": string; + "followersLessThanOrEq": string; + "followersMoreThanOrEq": string; + "followingLessThanOrEq": string; + "followingMoreThanOrEq": string; + "notesLessThanOrEq": string; + "notesMoreThanOrEq": string; + "and": string; + "or": string; + "not": string; + }; + }; + "_sensitiveMediaDetection": { + "description": string; + "sensitivity": string; + "sensitivityDescription": string; + "setSensitiveFlagAutomatically": string; + "setSensitiveFlagAutomaticallyDescription": string; + "analyzeVideos": string; + "analyzeVideosDescription": string; + }; + "_emailUnavailable": { + "used": string; + "format": string; + "disposable": string; + "mx": string; + "smtp": string; + }; + "_ffVisibility": { + "public": string; + "followers": string; + "private": string; + }; + "_signup": { + "almostThere": string; + "emailAddressInfo": string; + "emailSent": string; + }; + "_accountDelete": { + "accountDelete": string; + "mayTakeTime": string; + "sendEmail": string; + "requestAccountDelete": string; + "started": string; + "inProgress": string; + }; + "_ad": { + "back": string; + "reduceFrequencyOfThisAd": string; + "hide": string; + }; + "_forgotPassword": { + "enterEmail": string; + "ifNoEmail": string; + "contactAdmin": string; + }; + "_gallery": { + "my": string; + "liked": string; + "like": string; + "unlike": string; + }; + "_email": { + "_follow": { + "title": string; + }; + "_receiveFollowRequest": { + "title": string; + }; + }; + "_plugin": { + "install": string; + "installWarn": string; + "manage": string; + }; + "_preferencesBackups": { + "list": string; + "saveNew": string; + "loadFile": string; + "apply": string; + "save": string; + "inputName": string; + "cannotSave": string; + "nameAlreadyExists": string; + "applyConfirm": string; + "saveConfirm": string; + "deleteConfirm": string; + "renameConfirm": string; + "noBackups": string; + "createdAt": string; + "updatedAt": string; + "cannotLoad": string; + "invalidFile": string; + }; + "_registry": { + "scope": string; + "key": string; + "keys": string; + "domain": string; + "createKey": string; + }; + "_aboutMisskey": { + "about": string; + "contributors": string; + "allContributors": string; + "source": string; + "translation": string; + "donate": string; + "morePatrons": string; + "patrons": string; + }; + "_nsfw": { + "respect": string; + "ignore": string; + "force": string; + }; + "_instanceTicker": { + "none": string; + "remote": string; + "always": string; + }; + "_serverDisconnectedBehavior": { + "reload": string; + "dialog": string; + "quiet": string; + }; + "_channel": { + "create": string; + "edit": string; + "setBanner": string; + "removeBanner": string; + "featured": string; + "owned": string; + "following": string; + "usersCount": string; + "notesCount": string; + "nameAndDescription": string; + "nameOnly": string; + }; + "_menuDisplay": { + "sideFull": string; + "sideIcon": string; + "top": string; + "hide": string; + }; + "_wordMute": { + "muteWords": string; + "muteWordsDescription": string; + "muteWordsDescription2": string; + "softDescription": string; + "hardDescription": string; + "soft": string; + "hard": string; + "mutedNotes": string; + }; + "_instanceMute": { + "instanceMuteDescription": string; + "instanceMuteDescription2": string; + "title": string; + "heading": string; + }; + "_theme": { + "explore": string; + "install": string; + "manage": string; + "code": string; + "description": string; + "installed": string; + "installedThemes": string; + "builtinThemes": string; + "alreadyInstalled": string; + "invalid": string; + "make": string; + "base": string; + "addConstant": string; + "constant": string; + "defaultValue": string; + "color": string; + "refProp": string; + "refConst": string; + "key": string; + "func": string; + "funcKind": string; + "argument": string; + "basedProp": string; + "alpha": string; + "darken": string; + "lighten": string; + "inputConstantName": string; + "importInfo": string; + "deleteConstantConfirm": string; + "keys": { + "accent": string; + "bg": string; + "fg": string; + "focus": string; + "indicator": string; + "panel": string; + "shadow": string; + "header": string; + "navBg": string; + "navFg": string; + "navHoverFg": string; + "navActive": string; + "navIndicator": string; + "link": string; + "hashtag": string; + "mention": string; + "mentionMe": string; + "renote": string; + "modalBg": string; + "divider": string; + "scrollbarHandle": string; + "scrollbarHandleHover": string; + "dateLabelFg": string; + "infoBg": string; + "infoFg": string; + "infoWarnBg": string; + "infoWarnFg": string; + "cwBg": string; + "cwFg": string; + "cwHoverBg": string; + "toastBg": string; + "toastFg": string; + "buttonBg": string; + "buttonHoverBg": string; + "inputBorder": string; + "listItemHoverBg": string; + "driveFolderBg": string; + "wallpaperOverlay": string; + "badge": string; + "messageBg": string; + "accentDarken": string; + "accentLighten": string; + "fgHighlighted": string; + }; + }; + "_sfx": { + "note": string; + "noteMy": string; + "notification": string; + "chat": string; + "chatBg": string; + "antenna": string; + "channel": string; + }; + "_ago": { + "future": string; + "justNow": string; + "secondsAgo": string; + "minutesAgo": string; + "hoursAgo": string; + "daysAgo": string; + "weeksAgo": string; + "monthsAgo": string; + "yearsAgo": string; + "invalid": string; + }; + "_time": { + "second": string; + "minute": string; + "hour": string; + "day": string; + }; + "_timelineTutorial": { + "title": string; + "step1_1": string; + "step1_2": string; + "step2_1": string; + "step2_2": string; + "step3_1": string; + "step3_2": string; + "step4_1": string; + "step4_2": string; + }; + "_2fa": { + "alreadyRegistered": string; + "registerTOTP": string; + "passwordToTOTP": string; + "step1": string; + "step2": string; + "step2Click": string; + "step2Url": string; + "step3Title": string; + "step3": string; + "step4": string; + "securityKeyNotSupported": string; + "registerTOTPBeforeKey": string; + "securityKeyInfo": string; + "chromePasskeyNotSupported": string; + "registerSecurityKey": string; + "securityKeyName": string; + "tapSecurityKey": string; + "removeKey": string; + "removeKeyConfirm": string; + "whyTOTPOnlyRenew": string; + "renewTOTP": string; + "renewTOTPConfirm": string; + "renewTOTPOk": string; + "renewTOTPCancel": string; + }; + "_permissions": { + "read:account": string; + "write:account": string; + "read:blocks": string; + "write:blocks": string; + "read:drive": string; + "write:drive": string; + "read:favorites": string; + "write:favorites": string; + "read:following": string; + "write:following": string; + "read:messaging": string; + "write:messaging": string; + "read:mutes": string; + "write:mutes": string; + "write:notes": string; + "read:notifications": string; + "write:notifications": string; + "read:reactions": string; + "write:reactions": string; + "write:votes": string; + "read:pages": string; + "write:pages": string; + "read:page-likes": string; + "write:page-likes": string; + "read:user-groups": string; + "write:user-groups": string; + "read:channels": string; + "write:channels": string; + "read:gallery": string; + "write:gallery": string; + "read:gallery-likes": string; + "write:gallery-likes": string; + }; + "_auth": { + "shareAccessTitle": string; + "shareAccess": string; + "shareAccessAsk": string; + "permission": string; + "permissionAsk": string; + "pleaseGoBack": string; + "callback": string; + "denied": string; + "pleaseLogin": string; + }; + "_antennaSources": { + "all": string; + "homeTimeline": string; + "users": string; + "userList": string; + }; + "_weekday": { + "sunday": string; + "monday": string; + "tuesday": string; + "wednesday": string; + "thursday": string; + "friday": string; + "saturday": string; + }; + "_widgets": { + "profile": string; + "instanceInfo": string; + "memo": string; + "notifications": string; + "timeline": string; + "calendar": string; + "trends": string; + "clock": string; + "rss": string; + "rssTicker": string; + "activity": string; + "photos": string; + "digitalClock": string; + "unixClock": string; + "federation": string; + "instanceCloud": string; + "postForm": string; + "slideshow": string; + "button": string; + "onlineUsers": string; + "jobQueue": string; + "serverMetric": string; + "aiscript": string; + "aiscriptApp": string; + "aichan": string; + "userList": string; + "_userList": { + "chooseList": string; + }; + "clicker": string; + }; + "_cw": { + "hide": string; + "show": string; + "chars": string; + "files": string; + }; + "_poll": { + "noOnlyOneChoice": string; + "choiceN": string; + "noMore": string; + "canMultipleVote": string; + "expiration": string; + "infinite": string; + "at": string; + "after": string; + "deadlineDate": string; + "deadlineTime": string; + "duration": string; + "votesCount": string; + "totalVotes": string; + "vote": string; + "showResult": string; + "voted": string; + "closed": string; + "remainingDays": string; + "remainingHours": string; + "remainingMinutes": string; + "remainingSeconds": string; + }; + "_visibility": { + "public": string; + "publicDescription": string; + "home": string; + "homeDescription": string; + "followers": string; + "followersDescription": string; + "specified": string; + "specifiedDescription": string; + "disableFederation": string; + "disableFederationDescription": string; + }; + "_postForm": { + "replyPlaceholder": string; + "quotePlaceholder": string; + "channelPlaceholder": string; + "_placeholders": { + "a": string; + "b": string; + "c": string; + "d": string; + "e": string; + "f": string; + }; + }; + "_profile": { + "name": string; + "username": string; + "description": string; + "youCanIncludeHashtags": string; + "metadata": string; + "metadataEdit": string; + "metadataDescription": string; + "metadataLabel": string; + "metadataContent": string; + "changeAvatar": string; + "changeBanner": string; + }; + "_exportOrImport": { + "allNotes": string; + "favoritedNotes": string; + "followingList": string; + "muteList": string; + "blockingList": string; + "userLists": string; + "excludeMutingUsers": string; + "excludeInactiveUsers": string; + }; + "_charts": { + "federation": string; + "apRequest": string; + "usersIncDec": string; + "usersTotal": string; + "activeUsers": string; + "notesIncDec": string; + "localNotesIncDec": string; + "remoteNotesIncDec": string; + "notesTotal": string; + "filesIncDec": string; + "filesTotal": string; + "storageUsageIncDec": string; + "storageUsageTotal": string; + }; + "_instanceCharts": { + "requests": string; + "users": string; + "usersTotal": string; + "notes": string; + "notesTotal": string; + "ff": string; + "ffTotal": string; + "cacheSize": string; + "cacheSizeTotal": string; + "files": string; + "filesTotal": string; + }; + "_timelines": { + "home": string; + "local": string; + "social": string; + "global": string; + }; + "_play": { + "new": string; + "edit": string; + "created": string; + "updated": string; + "deleted": string; + "pageSetting": string; + "editThisPage": string; + "viewSource": string; + "my": string; + "liked": string; + "featured": string; + "title": string; + "script": string; + "summary": string; + }; + "_pages": { + "newPage": string; + "editPage": string; + "readPage": string; + "created": string; + "updated": string; + "deleted": string; + "pageSetting": string; + "nameAlreadyExists": string; + "invalidNameTitle": string; + "invalidNameText": string; + "editThisPage": string; + "viewSource": string; + "viewPage": string; + "like": string; + "unlike": string; + "my": string; + "liked": string; + "featured": string; + "inspector": string; + "contents": string; + "content": string; + "variables": string; + "title": string; + "url": string; + "summary": string; + "alignCenter": string; + "hideTitleWhenPinned": string; + "font": string; + "fontSerif": string; + "fontSansSerif": string; + "eyeCatchingImageSet": string; + "eyeCatchingImageRemove": string; + "chooseBlock": string; + "selectType": string; + "contentBlocks": string; + "inputBlocks": string; + "specialBlocks": string; + "blocks": { + "text": string; + "textarea": string; + "section": string; + "image": string; + "button": string; + "note": string; + "_note": { + "id": string; + "idDescription": string; + "detailed": string; + }; + }; + }; + "_relayStatus": { + "requesting": string; + "accepted": string; + "rejected": string; + }; + "_notification": { + "fileUploaded": string; + "youGotMention": string; + "youGotReply": string; + "youGotQuote": string; + "youRenoted": string; + "youWereFollowed": string; + "youReceivedFollowRequest": string; + "yourFollowRequestAccepted": string; + "pollEnded": string; + "unreadAntennaNote": string; + "emptyPushNotificationMessage": string; + "achievementEarned": string; + "_types": { + "all": string; + "follow": string; + "mention": string; + "reply": string; + "renote": string; + "quote": string; + "reaction": string; + "pollEnded": string; + "receiveFollowRequest": string; + "followRequestAccepted": string; + "achievementEarned": string; + "app": string; + }; + "_actions": { + "followBack": string; + "reply": string; + "renote": string; + }; + }; + "_deck": { + "alwaysShowMainColumn": string; + "columnAlign": string; + "addColumn": string; + "configureColumn": string; + "swapLeft": string; + "swapRight": string; + "swapUp": string; + "swapDown": string; + "stackLeft": string; + "popRight": string; + "profile": string; + "newProfile": string; + "deleteProfile": string; + "introduction": string; + "introduction2": string; + "widgetsIntroduction": string; + "_columns": { + "main": string; + "widgets": string; + "notifications": string; + "tl": string; + "antenna": string; + "list": string; + "channel": string; + "mentions": string; + "direct": string; + "roleTimeline": string; + }; + }; + "_dialog": { + "charactersExceeded": string; + "charactersBelow": string; + }; + "_disabledTimeline": { + "title": string; + "description": string; + }; + "_drivecleaner": { + "orderBySizeDesc": string; + "orderByCreatedAtAsc": string; + }; + "_webhookSettings": { + "createWebhook": string; + "name": string; + "secret": string; + "events": string; + "active": string; + "_events": { + "follow": string; + "followed": string; + "note": string; + "reply": string; + "renote": string; + "reaction": string; + "mention": string; + }; + }; +} +declare const locales: { + [lang: string]: Locale; +}; export = locales; diff --git a/packages/frontend/src/i18n.ts b/packages/frontend/src/i18n.ts index 220c6210c0..30771ec1b3 100644 --- a/packages/frontend/src/i18n.ts +++ b/packages/frontend/src/i18n.ts @@ -1,8 +1,9 @@ import { markRaw } from 'vue'; +import type { Locale } from '../../../locales'; import { locale } from '@/config'; import { I18n } from '@/scripts/i18n'; -export const i18n = markRaw(new I18n(locale)); +export const i18n = markRaw(new I18n<Locale>(locale)); export function updateI18n(newLocale) { i18n.ts = newLocale; diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 3de9f9bdba..7c9b31c150 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -6,6 +6,7 @@ import { type UserConfig, defineConfig } from 'vite'; import ReactivityTransform from '@vue-macros/reactivity-transform/vite'; import locales from '../../locales'; +import generateDTS from '../../locales/generateDTS'; import meta from '../../package.json'; import pluginJson5 from './vite.json5'; @@ -64,6 +65,10 @@ export function getConfig(): UserConfig { }), ] : [], + { + name: 'locale:generateDTS', + buildStart: generateDTS, + }, ], resolve: { From 0513ff8b4e7177c4846d856b2a4023850c04ddde Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 24 May 2023 17:29:58 +0900 Subject: [PATCH 081/213] refactor --- .../src/components/MkForgotPassword.vue | 55 +++++++------------ 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/packages/frontend/src/components/MkForgotPassword.vue b/packages/frontend/src/components/MkForgotPassword.vue index 0befa7e3ae..1264c42331 100644 --- a/packages/frontend/src/components/MkForgotPassword.vue +++ b/packages/frontend/src/components/MkForgotPassword.vue @@ -8,27 +8,28 @@ > <template #header>{{ i18n.ts.forgotPassword }}</template> - <form v-if="instance.enableEmail" class="bafeceda" @submit.prevent="onSubmit"> - <div class="main _gaps_m"> - <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required> - <template #label>{{ i18n.ts.username }}</template> - <template #prefix>@</template> - </MkInput> + <MkSpacer :marginMin="20" :marginMax="28"> + <form v-if="instance.enableEmail" @submit.prevent="onSubmit"> + <div class="_gaps_m"> + <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required> + <template #label>{{ i18n.ts.username }}</template> + <template #prefix>@</template> + </MkInput> - <MkInput v-model="email" type="email" :spellcheck="false" required> - <template #label>{{ i18n.ts.emailAddress }}</template> - <template #caption>{{ i18n.ts._forgotPassword.enterEmail }}</template> - </MkInput> + <MkInput v-model="email" type="email" :spellcheck="false" required> + <template #label>{{ i18n.ts.emailAddress }}</template> + <template #caption>{{ i18n.ts._forgotPassword.enterEmail }}</template> + </MkInput> - <MkButton type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ i18n.ts.send }}</MkButton> + <MkButton type="submit" rounded :disabled="processing" primary style="margin: 0 auto;">{{ i18n.ts.send }}</MkButton> + + <MkInfo>{{ i18n.ts._forgotPassword.ifNoEmail }}</MkInfo> + </div> + </form> + <div v-else> + {{ i18n.ts._forgotPassword.contactAdmin }} </div> - <div class="sub"> - <MkA to="/about" class="_link">{{ i18n.ts._forgotPassword.ifNoEmail }}</MkA> - </div> - </form> - <div v-else class="bafecedb"> - {{ i18n.ts._forgotPassword.contactAdmin }} - </div> + </MkSpacer> </MkModalWindow> </template> @@ -37,6 +38,7 @@ import { } from 'vue'; import MkModalWindow from '@/components/MkModalWindow.vue'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; +import MkInfo from '@/components/MkInfo.vue'; import * as os from '@/os'; import { instance } from '@/instance'; import { i18n } from '@/i18n'; @@ -62,20 +64,3 @@ async function onSubmit() { dialog.close(); } </script> - -<style lang="scss" scoped> -.bafeceda { - > .main { - padding: 24px; - } - - > .sub { - border-top: solid 0.5px var(--divider); - padding: 24px; - } -} - -.bafecedb { - padding: 24px; -} -</style> From bdf08c8a54d670928576ba47921eadf7f4705ad6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 24 May 2023 17:33:31 +0900 Subject: [PATCH 082/213] refactor --- .../src/widgets/server-metric/pie.vue | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/frontend/src/widgets/server-metric/pie.vue b/packages/frontend/src/widgets/server-metric/pie.vue index 868dbc0484..398815a6ae 100644 --- a/packages/frontend/src/widgets/server-metric/pie.vue +++ b/packages/frontend/src/widgets/server-metric/pie.vue @@ -1,11 +1,12 @@ <template> -<svg class="hsalcinq" viewBox="0 0 1 1" preserveAspectRatio="none"> +<svg :class="$style.root" viewBox="0 0 1 1" preserveAspectRatio="none"> <circle :r="r" cx="50%" cy="50%" fill="none" stroke-width="0.1" stroke="rgba(0, 0, 0, 0.05)" + :class="$style.circle" /> <circle :r="r" @@ -16,7 +17,7 @@ stroke-width="0.1" :stroke="color" /> - <text x="50%" y="50%" dy="0.05" text-anchor="middle">{{ (value * 100).toFixed(0) }}%</text> + <text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text">{{ (value * 100).toFixed(0) }}%</text> </svg> </template> @@ -33,20 +34,20 @@ const color = $computed(() => `hsl(${180 - (props.value * 180)}, 80%, 70%)`); const strokeDashoffset = $computed(() => (1 - props.value) * (Math.PI * (r * 2))); </script> -<style lang="scss" scoped> -.hsalcinq { +<style lang="scss" module> +.root { display: block; height: 100%; +} - > circle { - transform-origin: center; - transform: rotate(-90deg); - transition: stroke-dashoffset 0.5s ease; - } +.circle { + transform-origin: center; + transform: rotate(-90deg); + transition: stroke-dashoffset 0.5s ease; +} - > text { - font-size: 0.15px; - fill: currentColor; - } +.text { + font-size: 0.15px; + fill: currentColor; } </style> From 1c57983bfde68325374a5b86ae1a993bdec937da Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 24 May 2023 17:50:15 +0900 Subject: [PATCH 083/213] refactor --- .../frontend/src/components/MkTagCloud.vue | 24 +++--- .../frontend/src/components/form/slot.vue | 38 +++++----- packages/frontend/src/pages/pages.vue | 36 +++------ packages/frontend/src/pages/settings/apps.vue | 46 ++++++------ packages/frontend/src/pages/user/activity.vue | 4 - .../frontend/src/pages/user/followers.vue | 3 - .../frontend/src/pages/user/following.vue | 3 - packages/frontend/src/pages/user/index.vue | 39 ++++------ packages/frontend/src/widgets/WidgetClock.vue | 74 +++++++++---------- 9 files changed, 113 insertions(+), 154 deletions(-) diff --git a/packages/frontend/src/components/MkTagCloud.vue b/packages/frontend/src/components/MkTagCloud.vue index 4e8d5bab7f..6e4e054aad 100644 --- a/packages/frontend/src/components/MkTagCloud.vue +++ b/packages/frontend/src/components/MkTagCloud.vue @@ -1,7 +1,7 @@ <template> -<div ref="rootEl" class="meijqfqm"> - <canvas :id="idForCanvas" ref="canvasEl" class="canvas" :width="width" height="300" @contextmenu.prevent="() => {}"></canvas> - <div :id="idForTags" ref="tagsEl" class="tags"> +<div ref="rootEl" :class="$style.root"> + <canvas :id="idForCanvas" ref="canvasEl" style="display: block;" :width="width" height="300" @contextmenu.prevent="() => {}"></canvas> + <div :id="idForTags" ref="tagsEl" :class="$style.tags"> <ul> <slot></slot> </ul> @@ -70,21 +70,17 @@ defineExpose({ }); </script> -<style lang="scss" scoped> -.meijqfqm { +<style lang="scss" module> +.root { position: relative; overflow: clip; display: grid; place-items: center; +} - > .canvas { - display: block; - } - - > .tags { - position: absolute; - top: 999px; - left: 999px; - } +.tags { + position: absolute; + top: 999px; + left: 999px; } </style> diff --git a/packages/frontend/src/components/form/slot.vue b/packages/frontend/src/components/form/slot.vue index 79ce8fe51f..792f664ea0 100644 --- a/packages/frontend/src/components/form/slot.vue +++ b/packages/frontend/src/components/form/slot.vue @@ -1,10 +1,10 @@ <template> -<div class="adhpbeou"> - <div class="label" @click="focus"><slot name="label"></slot></div> - <div class="content"> +<div> + <div :class="$style.label" @click="focus"><slot name="label"></slot></div> + <div :class="$style.content"> <slot></slot> </div> - <div class="caption"><slot name="caption"></slot></div> + <div :class="$style.caption"><slot name="caption"></slot></div> </div> </template> @@ -16,26 +16,24 @@ function focus() { } </script> -<style lang="scss" scoped> -.adhpbeou { - > .label { - font-size: 0.85em; - padding: 0 0 8px 0; - user-select: none; +<style lang="scss" module> +.label { + font-size: 0.85em; + padding: 0 0 8px 0; + user-select: none; - &:empty { - display: none; - } + &:empty { + display: none; } +} - > .caption { - font-size: 0.85em; - padding: 8px 0 0 0; - color: var(--fgTransparentWeak); +.caption { + font-size: 0.85em; + padding: 8px 0 0 0; + color: var(--fgTransparentWeak); - &:empty { - display: none; - } + &:empty { + display: none; } } </style> diff --git a/packages/frontend/src/pages/pages.vue b/packages/frontend/src/pages/pages.vue index b72271dbf7..4f67bda11f 100644 --- a/packages/frontend/src/pages/pages.vue +++ b/packages/frontend/src/pages/pages.vue @@ -2,22 +2,28 @@ <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :contentMax="700"> - <div v-if="tab === 'featured'" class="rknalgpo"> + <div v-if="tab === 'featured'"> <MkPagination v-slot="{items}" :pagination="featuredPagesPagination"> - <MkPagePreview v-for="page in items" :key="page.id" class="ckltabjg" :page="page"/> + <div class="_gaps"> + <MkPagePreview v-for="page in items" :key="page.id" :page="page"/> + </div> </MkPagination> </div> - <div v-else-if="tab === 'my'" class="rknalgpo my"> + <div v-else-if="tab === 'my'" class="_gaps"> <MkButton class="new" @click="create()"><i class="ti ti-plus"></i></MkButton> <MkPagination v-slot="{items}" :pagination="myPagesPagination"> - <MkPagePreview v-for="page in items" :key="page.id" class="ckltabjg" :page="page"/> + <div class="_gaps"> + <MkPagePreview v-for="page in items" :key="page.id" :page="page"/> + </div> </MkPagination> </div> - <div v-else-if="tab === 'liked'" class="rknalgpo"> + <div v-else-if="tab === 'liked'"> <MkPagination v-slot="{items}" :pagination="likedPagesPagination"> - <MkPagePreview v-for="like in items" :key="like.page.id" class="ckltabjg" :page="like.page"/> + <div class="_gaps"> + <MkPagePreview v-for="like in items" :key="like.page.id" :page="like.page"/> + </div> </MkPagination> </div> </MkSpacer> @@ -79,21 +85,3 @@ definePageMetadata(computed(() => ({ icon: 'ti ti-note', }))); </script> - -<style lang="scss" scoped> -.rknalgpo { - &.my .ckltabjg:first-child { - margin-top: 16px; - } - - .ckltabjg:not(:last-child) { - margin-bottom: 8px; - } - - @media (min-width: 500px) { - .ckltabjg:not(:last-child) { - margin-bottom: 16px; - } - } -} -</style> diff --git a/packages/frontend/src/pages/settings/apps.vue b/packages/frontend/src/pages/settings/apps.vue index 599d6329e2..fbb78200d4 100644 --- a/packages/frontend/src/pages/settings/apps.vue +++ b/packages/frontend/src/pages/settings/apps.vue @@ -9,11 +9,11 @@ </template> <template #default="{items}"> <div class="_gaps"> - <div v-for="token in items" :key="token.id" class="_panel bfomjevm"> - <img v-if="token.iconUrl" class="icon" :src="token.iconUrl" alt=""/> - <div class="body"> - <div class="name">{{ token.name }}</div> - <div class="description">{{ token.description }}</div> + <div v-for="token in items" :key="token.id" class="_panel" :class="$style.app"> + <img v-if="token.iconUrl" :class="$style.appIcon" :src="token.iconUrl" alt=""/> + <div :class="$style.appBody"> + <div :class="$style.appName">{{ token.name }}</div> + <div>{{ token.description }}</div> <MkKeyValue oneline> <template #key>{{ i18n.ts.installedDate }}</template> <template #value><MkTime :time="token.createdAt"/></template> @@ -28,7 +28,7 @@ <li v-for="p in token.permission" :key="p">{{ i18n.t(`_permissions.${p}`) }}</li> </ul> </details> - <div class="actions"> + <div> <MkButton inline danger @click="revoke(token)"><i class="ti ti-trash"></i></MkButton> </div> </div> @@ -75,27 +75,27 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.bfomjevm { +<style lang="scss" module> +.app { display: flex; padding: 16px; +} - > .icon { - display: block; - flex-shrink: 0; - margin: 0 12px 0 0; - width: 50px; - height: 50px; - border-radius: 8px; - } +.appIcon { + display: block; + flex-shrink: 0; + margin: 0 12px 0 0; + width: 50px; + height: 50px; + border-radius: 8px; +} - > .body { - width: calc(100% - 62px); - position: relative; +.appBody { + width: calc(100% - 62px); + position: relative; +} - > .name { - font-weight: bold; - } - } +.appName { + font-weight: bold; } </style> diff --git a/packages/frontend/src/pages/user/activity.vue b/packages/frontend/src/pages/user/activity.vue index dfdd7edb7d..655371ac1d 100644 --- a/packages/frontend/src/pages/user/activity.vue +++ b/packages/frontend/src/pages/user/activity.vue @@ -34,7 +34,3 @@ const props = defineProps<{ }>(); </script> - -<style lang="scss" scoped> - -</style> diff --git a/packages/frontend/src/pages/user/followers.vue b/packages/frontend/src/pages/user/followers.vue index 7cbc5bee12..b330f78637 100644 --- a/packages/frontend/src/pages/user/followers.vue +++ b/packages/frontend/src/pages/user/followers.vue @@ -56,6 +56,3 @@ definePageMetadata(computed(() => user ? { avatar: user, } : null)); </script> - -<style lang="scss" scoped> -</style> diff --git a/packages/frontend/src/pages/user/following.vue b/packages/frontend/src/pages/user/following.vue index c36bc0b839..9544cf76ca 100644 --- a/packages/frontend/src/pages/user/following.vue +++ b/packages/frontend/src/pages/user/following.vue @@ -56,6 +56,3 @@ definePageMetadata(computed(() => user ? { avatar: user, } : null)); </script> - -<style lang="scss" scoped> -</style> diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index 9fe94d68f6..6aba815e9d 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -2,21 +2,19 @@ <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> <div> - <Transition name="fade" mode="out-in"> - <div v-if="user"> - <XHome v-if="tab === 'home'" :user="user"/> - <XTimeline v-else-if="tab === 'notes'" :user="user"/> - <XActivity v-else-if="tab === 'activity'" :user="user"/> - <XAchievements v-else-if="tab === 'achievements'" :user="user"/> - <XReactions v-else-if="tab === 'reactions'" :user="user"/> - <XClips v-else-if="tab === 'clips'" :user="user"/> - <XLists v-else-if="tab === 'lists'" :user="user"/> - <XPages v-else-if="tab === 'pages'" :user="user"/> - <XGallery v-else-if="tab === 'gallery'" :user="user"/> - </div> - <MkError v-else-if="error" @retry="fetchUser()"/> - <MkLoading v-else/> - </Transition> + <div v-if="user"> + <XHome v-if="tab === 'home'" :user="user"/> + <XTimeline v-else-if="tab === 'notes'" :user="user"/> + <XActivity v-else-if="tab === 'activity'" :user="user"/> + <XAchievements v-else-if="tab === 'achievements'" :user="user"/> + <XReactions v-else-if="tab === 'reactions'" :user="user"/> + <XClips v-else-if="tab === 'clips'" :user="user"/> + <XLists v-else-if="tab === 'lists'" :user="user"/> + <XPages v-else-if="tab === 'pages'" :user="user"/> + <XGallery v-else-if="tab === 'gallery'" :user="user"/> + </div> + <MkError v-else-if="error" @retry="fetchUser()"/> + <MkLoading v-else/> </div> </MkStickyContainer> </template> @@ -118,14 +116,3 @@ definePageMetadata(computed(() => user ? { }, } : null)); </script> - -<style lang="scss" scoped> -.fade-enter-active, -.fade-leave-active { - transition: opacity 0.125s ease; -} -.fade-enter-from, -.fade-leave-to { - opacity: 0; -} -</style> diff --git a/packages/frontend/src/widgets/WidgetClock.vue b/packages/frontend/src/widgets/WidgetClock.vue index 7d814dcd53..707f403603 100644 --- a/packages/frontend/src/widgets/WidgetClock.vue +++ b/packages/frontend/src/widgets/WidgetClock.vue @@ -1,9 +1,9 @@ <template> -<MkContainer :naked="widgetProps.transparent" :showHeader="false" data-cy-mkw-clock class="mkw-clock"> - <div class="vubelbmv" :class="widgetProps.size"> - <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label a abbrev">{{ tzAbbrev }}</div> +<MkContainer :naked="widgetProps.transparent" :showHeader="false" data-cy-mkw-clock> + <div :class="[$style.root, $style[widgetProps.size]]"> + <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace" :class="[$style.label, $style.a]">{{ tzAbbrev }}</div> <MkAnalogClock - class="clock" + :class="$style.clock" :thickness="widgetProps.thickness" :offset="tzOffset" :graduations="widgetProps.graduations" @@ -11,8 +11,8 @@ :twentyfour="widgetProps.twentyFour" :sAnimation="widgetProps.sAnimation" /> - <MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" class="_monospace label c time" :showS="false" :offset="tzOffset"/> - <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label d offset">{{ tzOffsetLabel }}</div> + <MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" :class="[$style.label, $style.c]" class="_monospace" :showS="false" :offset="tzOffset"/> + <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace" :class="[$style.label, $style.d]">{{ tzOffsetLabel }}</div> </div> </MkContainer> </template> @@ -140,39 +140,10 @@ defineExpose<WidgetComponentExpose>({ }); </script> -<style lang="scss" scoped> -.vubelbmv { +<style lang="scss" module> +.root { position: relative; - > .label { - position: absolute; - opacity: 0.7; - - &.a { - top: 14px; - left: 14px; - } - - &.b { - top: 14px; - right: 14px; - } - - &.c { - bottom: 14px; - left: 14px; - } - - &.d { - bottom: 14px; - right: 14px; - } - } - - > .clock { - margin: auto; - } - &.small { padding: 12px; @@ -197,4 +168,33 @@ defineExpose<WidgetComponentExpose>({ } } } + +.label { + position: absolute; + opacity: 0.7; + + &.a { + top: 14px; + left: 14px; + } + + &.b { + top: 14px; + right: 14px; + } + + &.c { + bottom: 14px; + left: 14px; + } + + &.d { + bottom: 14px; + right: 14px; + } +} + +.clock { + margin: auto; +} </style> From 30cb791e93c58c13f4e718aaa822ccc97d54cb83 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 25 May 2023 08:17:09 +0900 Subject: [PATCH 084/213] =?UTF-8?q?enhance(frontend):=20=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=AD=E3=83=BC/=E3=83=95=E3=82=A9=E3=83=AD=E3=83=BC?= =?UTF-8?q?=E8=A7=A3=E9=99=A4=E3=81=97=E3=81=9F=E3=81=A8=E3=81=8D=E3=81=AB?= =?UTF-8?q?=E8=87=AA=E5=8B=95=E3=81=A7TL=E3=82=92=E3=83=AA=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=81=99=E3=82=8B=E3=81=AE=E3=82=92=E3=82=84?= =?UTF-8?q?=E3=82=81=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 不便に感じる場合が多いように思う - 将来的にTLがpush型になったら無意味になる --- packages/frontend/src/components/MkTimeline.vue | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index 2adc4f1d0c..2595ebc45d 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -46,12 +46,6 @@ const onUserRemoved = () => { tlComponent.pagingComponent?.reload(); }; -const onChangeFollowing = () => { - if (!tlComponent.pagingComponent?.backed) { - tlComponent.pagingComponent?.reload(); - } -}; - let endpoint; let query; let connection; @@ -79,8 +73,6 @@ if (props.src === 'antenna') { connection.on('note', prepend); connection2 = stream.useChannel('main'); - connection2.on('follow', onChangeFollowing); - connection2.on('unfollow', onChangeFollowing); } else if (props.src === 'local') { endpoint = 'notes/local-timeline'; query = { From 4129ac157a8e4fb3a16285f4f7a72f93267eb079 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Thu, 25 May 2023 14:50:14 +0000 Subject: [PATCH 085/213] =?UTF-8?q?package.json=E3=81=AE=E4=B8=A6=E3=81=B3?= =?UTF-8?q?=E6=9B=BF=E3=81=88=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 4aa79222f0..71da3bb557 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -103,8 +103,8 @@ "jsdom": "21.1.1", "json5": "2.2.3", "jsonld": "8.1.1", - "meilisearch": "0.32.4", "jsrsasign": "10.8.6", + "meilisearch": "0.32.4", "mfm-js": "0.23.3", "mime-types": "2.1.35", "misskey-js": "workspace:*", From 31a7350a1062739cbda440937dd9ad17d2356f46 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 26 May 2023 10:48:49 +0900 Subject: [PATCH 086/213] :art: --- packages/frontend/src/ui/deck/column.vue | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index e2c651beca..869e2c0afd 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -13,6 +13,11 @@ @dragend="onDragend" @contextmenu.prevent.stop="onContextmenu" > + <svg viewBox="0 0 256 128" :class="$style.tabShape"> + <g transform="matrix(6.2431,0,0,6.2431,-677.417,-29.3839)"> + <path d="M149.512,4.707L108.507,4.707C116.252,4.719 118.758,14.958 118.758,14.958C118.758,14.958 121.381,25.283 129.009,25.209L149.512,25.209L149.512,4.707Z" style="fill:var(--deckDivider);"/> + </g> + </svg> <button v-if="isStacked && !isMainColumn" :class="$style.toggleActive" class="_button" @click="toggleActive"> <template v-if="active"><i class="ti ti-chevron-up"></i></template> <template v-else><i class="ti ti-chevron-down"></i></template> @@ -308,6 +313,14 @@ function onDrop(ev) { user-select: none; } +.tabShape { + position: absolute; + top: 0; + right: -8px; + width: auto; + height: calc(100% - 6px); +} + .title { display: inline-block; align-items: center; From 06b1250d4791dbc0c64c1d667e61a0c57a4d371f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 26 May 2023 11:31:39 +0900 Subject: [PATCH 087/213] :art: --- packages/frontend/src/themes/_dark.json5 | 2 +- packages/frontend/src/themes/_light.json5 | 2 +- packages/frontend/src/themes/d-u0.json5 | 2 +- packages/frontend/src/ui/deck.vue | 11 +++++--- packages/frontend/src/ui/deck/column.vue | 33 +++++++++++++++++++++-- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/packages/frontend/src/themes/_dark.json5 b/packages/frontend/src/themes/_dark.json5 index a23d25e866..b8820bcf86 100644 --- a/packages/frontend/src/themes/_dark.json5 +++ b/packages/frontend/src/themes/_dark.json5 @@ -77,7 +77,7 @@ codeString: '#ffb675', codeNumber: '#cfff9e', codeBoolean: '#c59eff', - deckDivider: '#000', + deckBg: '#000', htmlThemeColor: '@bg', X2: ':darken<2<@panel', X3: 'rgba(255, 255, 255, 0.05)', diff --git a/packages/frontend/src/themes/_light.json5 b/packages/frontend/src/themes/_light.json5 index 713756221a..da3c770555 100644 --- a/packages/frontend/src/themes/_light.json5 +++ b/packages/frontend/src/themes/_light.json5 @@ -77,7 +77,7 @@ codeString: '#b98710', codeNumber: '#0fbbbb', codeBoolean: '#62b70c', - deckDivider: ':darken<3<@bg', + deckBg: ':darken<3<@bg', htmlThemeColor: '@bg', X2: ':darken<2<@panel', X3: 'rgba(0, 0, 0, 0.05)', diff --git a/packages/frontend/src/themes/d-u0.json5 b/packages/frontend/src/themes/d-u0.json5 index b270f809ac..3fce93b2fe 100644 --- a/packages/frontend/src/themes/d-u0.json5 +++ b/packages/frontend/src/themes/d-u0.json5 @@ -83,6 +83,6 @@ fgTransparentWeak: ':alpha<0.75<@fg', panelHeaderDivider: 'rgba(0, 0, 0, 0)', scrollbarHandleHover: 'rgba(255, 255, 255, 0.4)', - deckDivider: '#142022', + deckBg: '#142022', }, } diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index b91d6d7675..937bfe314f 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -282,7 +282,7 @@ async function deleteProfile() { --margin: var(--marginHalf); - --deckDividerThickness: 5px; + --columnGap: 6px; display: flex; height: 100dvh; @@ -306,6 +306,7 @@ async function deleteProfile() { display: flex; overflow-x: auto; overflow-y: clip; + background: var(--deckBg); &.center { > .section:first-of-type { @@ -327,14 +328,16 @@ async function deleteProfile() { flex-direction: column; scroll-snap-align: start; flex-shrink: 0; - border-right: solid var(--deckDividerThickness) var(--deckDivider); + margin-top: var(--columnGap); + margin-bottom: var(--columnGap); + margin-right: var(--columnGap); &:first-of-type { - border-left: solid var(--deckDividerThickness) var(--deckDivider); + margin-left: var(--columnGap); } > .column:not(:last-of-type) { - border-bottom: solid var(--deckDividerThickness) var(--deckDivider); + margin-bottom: var(--columnGap); } } diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 869e2c0afd..73b0aa648f 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -15,9 +15,10 @@ > <svg viewBox="0 0 256 128" :class="$style.tabShape"> <g transform="matrix(6.2431,0,0,6.2431,-677.417,-29.3839)"> - <path d="M149.512,4.707L108.507,4.707C116.252,4.719 118.758,14.958 118.758,14.958C118.758,14.958 121.381,25.283 129.009,25.209L149.512,25.209L149.512,4.707Z" style="fill:var(--deckDivider);"/> + <path d="M149.512,4.707L108.507,4.707C116.252,4.719 118.758,14.958 118.758,14.958C118.758,14.958 121.381,25.283 129.009,25.209L149.512,25.209L149.512,4.707Z" style="fill:var(--deckBg);"/> </g> </svg> + <div :class="$style.color"></div> <button v-if="isStacked && !isMainColumn" :class="$style.toggleActive" class="_button" @click="toggleActive"> <template v-if="active"><i class="ti ti-chevron-up"></i></template> <template v-else><i class="ti ti-chevron-down"></i></template> @@ -240,6 +241,7 @@ function onDrop(ev) { height: 100%; overflow: clip; contain: strict; + border-radius: 8px; &.draghover { &:after { @@ -279,6 +281,7 @@ function onDrop(ev) { &:not(.active) { flex-basis: var(--deckColumnHeaderHeight); min-height: var(--deckColumnHeaderHeight); + border-bottom-right-radius: 0; } &.naked { @@ -291,10 +294,22 @@ function onDrop(ev) { box-shadow: none; color: var(--fg); } + + > .body { + &::-webkit-scrollbar-track { + background: inherit; + } + } } &.paged { background: var(--bg) !important; + + > .body { + &::-webkit-scrollbar-track { + background: inherit; + } + } } } @@ -304,7 +319,7 @@ function onDrop(ev) { z-index: 2; line-height: var(--deckColumnHeaderHeight); height: var(--deckColumnHeaderHeight); - padding: 0 16px; + padding: 0 16px 0 28px; font-size: 0.9em; color: var(--panelHeaderFg); background: var(--panelHeaderBg); @@ -313,6 +328,16 @@ function onDrop(ev) { user-select: none; } +.color { + position: absolute; + top: 10px; + left: 10px; + width: 3px; + height: calc(100% - 20px); + background: var(--accent); + border-radius: 999px; +} + .tabShape { position: absolute; top: 0; @@ -364,5 +389,9 @@ function onDrop(ev) { box-sizing: border-box; container-type: size; background-color: var(--bg); + + &::-webkit-scrollbar-track { + background: var(--panel); + } } </style> From 6cc86272f35432a3d85a77fad500a5e520e08b4a Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 26 May 2023 13:24:31 +0900 Subject: [PATCH 088/213] :art: --- packages/frontend/src/ui/deck/column.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 73b0aa648f..073b036cb9 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -241,7 +241,7 @@ function onDrop(ev) { height: 100%; overflow: clip; contain: strict; - border-radius: 8px; + border-radius: 10px; &.draghover { &:after { @@ -319,7 +319,7 @@ function onDrop(ev) { z-index: 2; line-height: var(--deckColumnHeaderHeight); height: var(--deckColumnHeaderHeight); - padding: 0 16px 0 28px; + padding: 0 16px 0 30px; font-size: 0.9em; color: var(--panelHeaderFg); background: var(--panelHeaderBg); @@ -330,10 +330,10 @@ function onDrop(ev) { .color { position: absolute; - top: 10px; - left: 10px; + top: 12px; + left: 12px; width: 3px; - height: calc(100% - 20px); + height: calc(100% - 24px); background: var(--accent); border-radius: 999px; } From fd03e2e1a7fb7290c68bb1fe6693ff1b10b8e6aa Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 26 May 2023 13:30:26 +0900 Subject: [PATCH 089/213] :art: --- packages/frontend/src/ui/deck.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 937bfe314f..69637b6555 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -4,7 +4,7 @@ <div :class="$style.main"> <XStatusBars/> - <div ref="columnsEl" :class="[$style.sections, deckStore.reactiveState.columnAlign.value, { [$style.snapScroll]: snapScroll }]" @contextmenu.self.prevent="onContextmenu"> + <div ref="columnsEl" :class="[$style.sections, { [$style.center]: deckStore.reactiveState.columnAlign.value === 'center', [$style.snapScroll]: snapScroll }]" @contextmenu.self.prevent="onContextmenu"> <!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため --> <section v-for="ids in layout" @@ -310,11 +310,11 @@ async function deleteProfile() { &.center { > .section:first-of-type { - margin-left: auto; + margin-left: auto !important; } > .section:last-of-type { - margin-right: auto; + margin-right: auto !important; } } From 10634b361505c58c4ec5bf2d7309a6afe75d6273 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 26 May 2023 13:32:42 +0900 Subject: [PATCH 090/213] refactor --- .../frontend/src/ui/_common_/statusbars.vue | 126 +++++++++--------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/packages/frontend/src/ui/_common_/statusbars.vue b/packages/frontend/src/ui/_common_/statusbars.vue index b1e2c80f10..bb245c7dd8 100644 --- a/packages/frontend/src/ui/_common_/statusbars.vue +++ b/packages/frontend/src/ui/_common_/statusbars.vue @@ -1,18 +1,18 @@ <template> -<div class="dlrsnxqu"> +<div :class="$style.root"> <div - v-for="x in defaultStore.reactiveState.statusbars.value" :key="x.id" class="item" :class="[{ black: x.black }, { - verySmall: x.size === 'verySmall', - small: x.size === 'small', - medium: x.size === 'medium', - large: x.size === 'large', - veryLarge: x.size === 'veryLarge', + v-for="x in defaultStore.reactiveState.statusbars.value" :key="x.id" :class="[$style.item, { [$style.black]: x.black, + [$style.verySmall]: x.size === 'verySmall', + [$style.small]: x.size === 'small', + [$style.medium]: x.size === 'medium', + [$style.large]: x.size === 'large', + [$style.veryLarge]: x.size === 'veryLarge', }]" > - <span class="name">{{ x.name }}</span> - <XRss v-if="x.type === 'rss'" class="body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :url="x.props.url" :shuffle="x.props.shuffle"/> - <XFederation v-else-if="x.type === 'federation'" class="body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :colored="x.props.colored"/> - <XUserList v-else-if="x.type === 'userList'" class="body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :userListId="x.props.userListId"/> + <span :class="$style.name">{{ x.name }}</span> + <XRss v-if="x.type === 'rss'" :class="$style.body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :url="x.props.url" :shuffle="x.props.shuffle"/> + <XFederation v-else-if="x.type === 'federation'" :class="$style.body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :colored="x.props.colored"/> + <XUserList v-else-if="x.type === 'userList'" :class="$style.body" :refreshIntervalSec="x.props.refreshIntervalSec" :marqueeDuration="x.props.marqueeDuration" :marqueeReverse="x.props.marqueeReverse" :display="x.props.display" :userListId="x.props.userListId"/> </div> </div> </template> @@ -25,67 +25,67 @@ const XFederation = defineAsyncComponent(() => import('./statusbar-federation.vu const XUserList = defineAsyncComponent(() => import('./statusbar-user-list.vue')); </script> -<style lang="scss" scoped> -.dlrsnxqu { +<style lang="scss" module> +.root { font-size: 15px; background: var(--panel); +} - > .item { - --height: 24px; - --nameMargin: 10px; - font-size: 0.85em; +.item { + --height: 24px; + --nameMargin: 10px; + font-size: 0.85em; - &.verySmall { - --nameMargin: 7px; - --height: 16px; - font-size: 0.75em; - } + &.verySmall { + --nameMargin: 7px; + --height: 16px; + font-size: 0.75em; + } - &.small { - --nameMargin: 8px; - --height: 20px; - font-size: 0.8em; - } + &.small { + --nameMargin: 8px; + --height: 20px; + font-size: 0.8em; + } - &.large { - --nameMargin: 12px; - --height: 26px; - font-size: 0.875em; - } + &.large { + --nameMargin: 12px; + --height: 26px; + font-size: 0.875em; + } - &.veryLarge { - --nameMargin: 14px; - --height: 30px; - font-size: 0.9em; - } + &.veryLarge { + --nameMargin: 14px; + --height: 30px; + font-size: 0.9em; + } - display: flex; - vertical-align: bottom; - width: 100%; - line-height: var(--height); - height: var(--height); - overflow: clip; - contain: strict; + display: flex; + vertical-align: bottom; + width: 100%; + line-height: var(--height); + height: var(--height); + overflow: clip; + contain: strict; - > .name { - padding: 0 var(--nameMargin); - font-weight: bold; - color: var(--accent); - - &:empty { - display: none; - } - } - - > .body { - min-width: 0; - flex: 1; - } - - &.black { - background: #000; - color: #fff; - } + &.black { + background: #000; + color: #fff; } } + +.name { + padding: 0 var(--nameMargin); + font-weight: bold; + color: var(--accent); + + &:empty { + display: none; + } +} + +.body { + min-width: 0; + flex: 1; +} </style> From 406e5d297ba3c2d45734de538c2cad078182190d Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Fri, 26 May 2023 04:34:34 +0000 Subject: [PATCH 091/213] =?UTF-8?q?fix(client):=20/share=E3=82=92subBootPa?= =?UTF-8?q?ths=E3=81=8B=E3=82=89=E5=A4=96=E3=81=99=20Resolve=20#10898?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/_boot_.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/_boot_.ts b/packages/frontend/src/_boot_.ts index 921c161765..ac9191f885 100644 --- a/packages/frontend/src/_boot_.ts +++ b/packages/frontend/src/_boot_.ts @@ -5,7 +5,7 @@ import '@/style.scss'; import { mainBoot } from './boot/main-boot'; import { subBoot } from './boot/sub-boot'; -const subBootPaths = ['/share', '/auth', '/miauth', '/signup-complete']; +const subBootPaths = ['/auth', '/miauth', '/signup-complete']; if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) { subBoot(); From 8050f89d7efb30bda222dca861b7c7c77080925d Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Fri, 26 May 2023 05:06:52 +0000 Subject: [PATCH 092/213] =?UTF-8?q?Revert=20"fix(client):=20/share?= =?UTF-8?q?=E3=82=92subBootPaths=E3=81=8B=E3=82=89=E5=A4=96=E3=81=99"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 406e5d297ba3c2d45734de538c2cad078182190d. --- packages/frontend/src/_boot_.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/_boot_.ts b/packages/frontend/src/_boot_.ts index ac9191f885..921c161765 100644 --- a/packages/frontend/src/_boot_.ts +++ b/packages/frontend/src/_boot_.ts @@ -5,7 +5,7 @@ import '@/style.scss'; import { mainBoot } from './boot/main-boot'; import { subBoot } from './boot/sub-boot'; -const subBootPaths = ['/auth', '/miauth', '/signup-complete']; +const subBootPaths = ['/share', '/auth', '/miauth', '/signup-complete']; if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) { subBoot(); From eee1e741747d4a9fff59b613d304341ccfb6fd10 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Fri, 26 May 2023 05:18:01 +0000 Subject: [PATCH 093/213] =?UTF-8?q?share=E3=83=9A=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=81=AB"Misskey=E3=81=B8"=E3=83=9C=E3=82=BF=E3=83=B3=E3=82=92?= =?UTF-8?q?=E8=A8=AD=E7=BD=AE=20Resolve=20#10898?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + packages/frontend/src/pages/share.vue | 17 +++++++++-------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 6e3edefabb..e4bf6628cc 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1060,6 +1060,7 @@ export interface Locale { "rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn": string; "cancelReactionConfirm": string; "changeReactionConfirm": string; + "goToMisskey": string; "_initialAccountSetting": { "accountCreated": string; "letsStartAccountSetup": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 374eeba390..4f400ab60a 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1057,6 +1057,7 @@ rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールの指定が一 rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロールである必要があります。" cancelReactionConfirm: "リアクションを取り消しますか?" changeReactionConfirm: "リアクションを変更しますか?" +goToMisskey: "Misskeyへ" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/frontend/src/pages/share.vue b/packages/frontend/src/pages/share.vue index 5c10198f7a..e0ac899230 100644 --- a/packages/frontend/src/pages/share.vue +++ b/packages/frontend/src/pages/share.vue @@ -16,7 +16,10 @@ class="_panel" @posted="state = 'posted'" /> - <MkButton v-else-if="state === 'posted'" primary :class="$style.close" @click="close()">{{ i18n.ts.close }}</MkButton> + <div v-else-if="state === 'posted'" class="_buttonsCenter"> + <MkButton primary @click="close">{{ i18n.ts.close }}</MkButton> + <MkButton @click="goToMisskey">{{ i18n.ts.goToMisskey }}</MkButton> + </div> </MkSpacer> </MkStickyContainer> </template> @@ -148,10 +151,14 @@ function close(): void { // 閉じなければ100ms後タイムラインに window.setTimeout(() => { - mainRouter.push('/'); + location.href = '/'; }, 100); } +function goToMisskey(): void { + location.href = '/'; +} + const headerActions = $computed(() => []); const headerTabs = $computed(() => []); @@ -161,9 +168,3 @@ definePageMetadata({ icon: 'ti ti-share', }); </script> - -<style lang="scss" module> -.close { - margin: 16px auto; -} -</style> From cf468166870b38b05f11464e771a952f8805a3b8 Mon Sep 17 00:00:00 2001 From: NoriDev <11006910+noridev@users.noreply.github.com> Date: Fri, 26 May 2023 14:40:44 +0900 Subject: [PATCH 094/213] =?UTF-8?q?feat:=20=E3=82=A2=E3=82=AB=E3=82=A6?= =?UTF-8?q?=E3=83=B3=E3=83=88=E5=88=9D=E6=9C=9F=E8=A8=AD=E5=AE=9A=E3=82=A6?= =?UTF-8?q?=E3=82=A3=E3=82=B6=E3=83=BC=E3=83=89=E3=81=AB=E6=88=BB=E3=82=8B?= =?UTF-8?q?=E3=83=9C=E3=82=BF=E3=83=B3=E3=81=A8=E3=80=81=E5=BE=8C=E3=81=A7?= =?UTF-8?q?=E9=80=B2=E3=82=80=E3=83=9C=E3=82=BF=E3=83=B3=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=20(#10893)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): アカウント初期設定ウィザードに戻るボタンを追加 * enhance(frontend): アカウント初期設定ウィザードにあとでボタンを追加 * tweak --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> --- CHANGELOG.md | 2 ++ cypress/e2e/basic.cy.js | 5 +++ locales/index.d.ts | 2 ++ locales/ja-JP.yml | 2 ++ packages/frontend/src/components/MkButton.vue | 9 +++-- .../src/components/MkUserSetupDialog.vue | 35 ++++++++++++++++--- 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53f903c64b..829d3e2079 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ - AiScriptを0.13.3に更新 - Deck UIを使用している場合、`/`以外にアクセスした際にZen UIで表示するように - メインカラムを設置していない場合の問題を解決 +- アカウント初期設定ウィザードに戻るボタンを追加 +- アカウントの初期設定ウィザードにあとでボタンを追加 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 - Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正 - fix:ロールタイムラインが無効でも投稿が流れてしまう問題の修正 diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.js index 2515c14ad6..652e0c2d70 100644 --- a/cypress/e2e/basic.cy.js +++ b/cypress/e2e/basic.cy.js @@ -169,20 +169,25 @@ describe('After user signed in', () => { cy.get('[data-cy-user-setup-user-description] textarea').type('ほげ'); // TODO: アイコン設定テスト + cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); // プライバシー設定 + cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); // フォローはスキップ + cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); // プッシュ通知設定はスキップ + cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); + cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); }); }); diff --git a/locales/index.d.ts b/locales/index.d.ts index e4bf6628cc..79f0b46d4d 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1060,6 +1060,7 @@ export interface Locale { "rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn": string; "cancelReactionConfirm": string; "changeReactionConfirm": string; + "later": string; "goToMisskey": string; "_initialAccountSetting": { "accountCreated": string; @@ -1075,6 +1076,7 @@ export interface Locale { "haveFun": string; "ifYouNeedLearnMore": string; "skipAreYouSure": string; + "laterAreYouSure": string; }; "_serverRules": { "description": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4f400ab60a..56e2295f10 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1057,6 +1057,7 @@ rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールの指定が一 rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロールである必要があります。" cancelReactionConfirm: "リアクションを取り消しますか?" changeReactionConfirm: "リアクションを変更しますか?" +later: "あとで" goToMisskey: "Misskeyへ" _initialAccountSetting: @@ -1073,6 +1074,7 @@ _initialAccountSetting: haveFun: "{name}をお楽しみください!" ifYouNeedLearnMore: "{name}(Misskey)の使い方などを詳しく知るには{link}をご覧ください。" skipAreYouSure: "初期設定をスキップしますか?" + laterAreYouSure: "初期設定をあとでやり直しますか?" _serverRules: description: "新規登録前に表示する、サーバーの簡潔なルールを設定します。内容は利用規約の要約とすることを推奨します。" diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 0ddee34f0a..6de6a4cc70 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -2,7 +2,7 @@ <button v-if="!link" ref="el" class="_button" - :class="[$style.root, { [$style.inline]: inline, [$style.primary]: primary, [$style.gradate]: gradate, [$style.danger]: danger, [$style.rounded]: rounded, [$style.full]: full, [$style.small]: small, [$style.large]: large, [$style.asLike]: asLike }]" + :class="[$style.root, { [$style.inline]: inline, [$style.primary]: primary, [$style.gradate]: gradate, [$style.danger]: danger, [$style.rounded]: rounded, [$style.full]: full, [$style.small]: small, [$style.large]: large, [$style.transparent]: transparent, [$style.asLike]: asLike }]" :type="type" @click="emit('click', $event)" @mousedown="onMousedown" @@ -14,7 +14,7 @@ </button> <MkA v-else class="_button" - :class="[$style.root, { [$style.inline]: inline, [$style.primary]: primary, [$style.gradate]: gradate, [$style.danger]: danger, [$style.rounded]: rounded, [$style.full]: full, [$style.small]: small, [$style.large]: large, [$style.asLike]: asLike }]" + :class="[$style.root, { [$style.inline]: inline, [$style.primary]: primary, [$style.gradate]: gradate, [$style.danger]: danger, [$style.rounded]: rounded, [$style.full]: full, [$style.small]: small, [$style.large]: large, [$style.transparent]: transparent, [$style.asLike]: asLike }]" :to="to" @mousedown="onMousedown" > @@ -44,6 +44,7 @@ const props = defineProps<{ full?: boolean; small?: boolean; large?: boolean; + transparent?: boolean; asLike?: boolean; }>(); @@ -194,6 +195,10 @@ function onMousedown(evt: MouseEvent): void { } } + &.transparent { + background: transparent; + } + &.gradate { font-weight: bold; color: var(--fgOnAccent) !important; diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 252c2eecce..566441213e 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -34,6 +34,7 @@ <div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.accountCreated }}</div> <div>{{ i18n.ts._initialAccountSetting.letsStartAccountSetup }}</div> <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" data-cy-user-setup-continue @click="page++">{{ i18n.ts._initialAccountSetting.profileSetting }} <i class="ti ti-arrow-right"></i></MkButton> + <MkButton style="margin: 0 auto;" transparent rounded @click="later(true)">{{ i18n.ts.later }}</MkButton> </div> </MkSpacer> </div> @@ -43,6 +44,7 @@ <MkSpacer :marginMin="20" :marginMax="28"> <XProfile/> <div class="_buttonsCenter" style="margin-top: 16px;"> + <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> </div> </MkSpacer> @@ -53,6 +55,7 @@ <MkSpacer :marginMin="20" :marginMax="28"> <XPrivacy/> <div class="_buttonsCenter" style="margin-top: 16px;"> + <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> </div> </MkSpacer> @@ -64,7 +67,10 @@ <XFollow/> </MkSpacer> <div :class="$style.pageFooter"> - <MkButton primary rounded gradate style="margin: 0 auto;" data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + <div class="_buttonsCenter"> + <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> + <MkButton primary rounded gradate style="" data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + </div> </div> </div> </template> @@ -76,7 +82,10 @@ <div style="font-size: 120%;">{{ i18n.ts.pushNotification }}</div> <div style="padding: 0 16px;">{{ i18n.t('_initialAccountSetting.pushNotificationDescription', { name: instance.name ?? host }) }}</div> <MkPushNotificationAllowButton primary showOnlyToRegister style="margin: 0 auto;"/> - <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + <div class="_buttonsCenter" style="margin-top: 16px;"> + <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> + <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> + </div> </div> </MkSpacer> </div> @@ -95,7 +104,10 @@ </template> </I18n> <div>{{ i18n.t('_initialAccountSetting.haveFun', { name: instance.name ?? host }) }}</div> - <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" data-cy-user-setup-continue @click="close(false)">{{ i18n.ts.close }}</MkButton> + <div class="_buttonsCenter" style="margin-top: 16px;"> + <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> + <MkButton primary rounded gradate data-cy-user-setup-continue @click="close(false)">{{ i18n.ts.close }}</MkButton> + </div> </div> </MkSpacer> </div> @@ -144,6 +156,19 @@ async function close(skip: boolean) { dialog.value.close(); defaultStore.set('accountSetupWizard', -1); } + +async function later(later: boolean) { + if (later) { + const { canceled } = await os.confirm({ + type: 'warning', + text: i18n.ts._initialAccountSetting.laterAreYouSure, + }); + if (canceled) return; + } + + dialog.value.close(); + defaultStore.set('accountSetupWizard', 0); +} </script> <style lang="scss" module> @@ -190,7 +215,7 @@ async function close(skip: boolean) { left: 0; padding: 12px; border-top: solid 0.5px var(--divider); - -webkit-backdrop-filter: var(--blur, blur(15px)); - backdrop-filter: var(--blur, blur(15px)); + -webkit-backdrop-filter: blur(15px); + backdrop-filter: blur(15px); } </style> From 98aef974df0bc563ac2aaf47bee996194d5ec200 Mon Sep 17 00:00:00 2001 From: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com> Date: Fri, 26 May 2023 14:47:31 +0900 Subject: [PATCH 095/213] =?UTF-8?q?enhance:=20=E3=83=8F=E3=83=83=E3=82=B7?= =?UTF-8?q?=E3=83=A5=E3=82=BF=E3=82=B0=E3=81=AE=E3=83=8E=E3=83=BC=E3=83=88?= =?UTF-8?q?=E4=B8=80=E8=A6=A7=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=8B=E3=82=89?= =?UTF-8?q?=E3=80=81=E3=81=9D=E3=81=AE=E3=83=8F=E3=83=83=E3=82=B7=E3=83=A5?= =?UTF-8?q?=E3=82=BF=E3=82=B0=E3=81=A7=E6=8A=95=E7=A8=BF=E3=81=99=E3=82=8B?= =?UTF-8?q?=E3=83=9C=E3=82=BF=E3=83=B3=E3=82=92=E8=BF=BD=E5=8A=A0=E3=80=81?= =?UTF-8?q?=E3=81=8A=E7=9F=A5=E3=82=89=E3=81=9B=E3=81=AE=E7=94=BB=E5=83=8F?= =?UTF-8?q?URL=E3=82=92=E7=A9=BA=E3=81=AB=E3=81=A7=E3=81=8D=E3=81=AA?= =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1087?= =?UTF-8?q?8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: お知らせの画像URLを空にできない問題を修正 (misskey-dev/misskey#10657) * ハッシュタグのノート一覧ページからノートできるように(misskey-dev/misskey#10854) * fix: 色々直した * location.reloadを使わないように * CHANGELOGを編集 * tweak * Update tag.vue --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> --- CHANGELOG.md | 4 ++ locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + .../endpoints/admin/announcements/update.ts | 5 ++- packages/frontend/src/pages/tag.vue | 39 ++++++++++++++++++- 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 829d3e2079..ecbad51e90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - AiScriptを0.13.3に更新 - Deck UIを使用している場合、`/`以外にアクセスした際にZen UIで表示するように - メインカラムを設置していない場合の問題を解決 +- ハッシュタグのノート一覧ページから、そのハッシュタグで投稿するボタンを追加 - アカウント初期設定ウィザードに戻るボタンを追加 - アカウントの初期設定ウィザードにあとでボタンを追加 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 @@ -36,6 +37,9 @@ - fix:ロールタイムラインが無効でも投稿が流れてしまう問題の修正 - fix:ロールタイムラインにて全ての投稿が流れてしまう問題の修正 +### Server +- Fix: お知らせの画像URLを空にできない問題を修正 + ## 13.12.2 ## NOTE diff --git a/locales/index.d.ts b/locales/index.d.ts index 79f0b46d4d..a54268676e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -795,6 +795,7 @@ export interface Locale { "noBotProtectionWarning": string; "configure": string; "postToGallery": string; + "postToHashtag": string; "gallery": string; "recentPosts": string; "popularPosts": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 56e2295f10..0ca37caa58 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -792,6 +792,7 @@ noMaintainerInformationWarning: "管理者情報が設定されていません noBotProtectionWarning: "Botプロテクションが設定されていません。" configure: "設定する" postToGallery: "ギャラリーへ投稿" +postToHashtag: "このハッシュタグで投稿" gallery: "ギャラリー" recentPosts: "最近の投稿" popularPosts: "人気の投稿" diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index 2393c2441c..12db1f78fb 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -25,7 +25,7 @@ export const paramDef = { id: { type: 'string', format: 'misskey:id' }, title: { type: 'string', minLength: 1 }, text: { type: 'string', minLength: 1 }, - imageUrl: { type: 'string', nullable: true, minLength: 1 }, + imageUrl: { type: 'string', nullable: true, minLength: 0 }, }, required: ['id', 'title', 'text', 'imageUrl'], } as const; @@ -46,7 +46,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { updatedAt: new Date(), title: ps.title, text: ps.text, - imageUrl: ps.imageUrl, + /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */ + imageUrl: ps.imageUrl || null, }); }); } diff --git a/packages/frontend/src/pages/tag.vue b/packages/frontend/src/pages/tag.vue index b53db3f67b..104e738866 100644 --- a/packages/frontend/src/pages/tag.vue +++ b/packages/frontend/src/pages/tag.vue @@ -2,15 +2,27 @@ <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :contentMax="800"> - <MkNotes class="" :pagination="pagination"/> + <MkNotes ref="notes" class="" :pagination="pagination"/> </MkSpacer> + <template v-if="$i" #footer> + <div :class="$style.footer"> + <MkSpacer :contentMax="800" :marginMin="16" :marginMax="16"> + <MkButton rounded primary :class="$style.button" @click="post()"><i class="ti ti-pencil"></i>{{ i18n.ts.postToHashtag }}</MkButton> + </MkSpacer> + </div> + </template> </MkStickyContainer> </template> <script lang="ts" setup> -import { computed } from 'vue'; +import { computed, ref } from 'vue'; import MkNotes from '@/components/MkNotes.vue'; +import MkButton from '@/components/MkButton.vue'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { i18n } from '@/i18n'; +import { $i } from '@/account'; +import { defaultStore } from '@/store'; +import * as os from '@/os'; const props = defineProps<{ tag: string; @@ -23,6 +35,16 @@ const pagination = { tag: props.tag, })), }; +const notes = ref<InstanceType<typeof MkNotes>>(); + +async function post() { + defaultStore.set('postFormHashtags', props.tag); + defaultStore.set('postFormWithHashtags', true); + await os.post(); + defaultStore.set('postFormHashtags', ''); + defaultStore.set('postFormWithHashtags', false); + notes.value?.pagingComponent?.reload(); +} const headerActions = $computed(() => []); @@ -33,3 +55,16 @@ definePageMetadata(computed(() => ({ icon: 'ti ti-hash', }))); </script> + +<style lang="scss" module> +.footer { + -webkit-backdrop-filter: var(--blur, blur(15px)); + backdrop-filter: var(--blur, blur(15px)); + border-top: solid 0.5px var(--divider); + display: flex; +} + +.button { + margin: 0 auto var(--margin) auto; +} +</style> From a879607479c701733476659de1742d5f7d87eede Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 27 May 2023 11:35:26 +0900 Subject: [PATCH 096/213] refactor --- .../src/components/MkEmojiPickerDialog.vue | 16 +- .../frontend/src/components/MkTextarea.vue | 167 +++++++++--------- .../frontend/src/components/form/link.vue | 120 ++++++------- .../src/components/page/page.section.vue | 38 ++-- .../src/components/page/page.text.vue | 20 +-- .../frontend/src/components/page/page.vue | 18 +- packages/frontend/src/pages/admin/relays.vue | 30 +--- .../frontend/src/pages/flash/flash-index.vue | 32 +--- .../frontend/src/pages/my-lists/index.vue | 48 ++--- 9 files changed, 206 insertions(+), 283 deletions(-) diff --git a/packages/frontend/src/components/MkEmojiPickerDialog.vue b/packages/frontend/src/components/MkEmojiPickerDialog.vue index d60921803b..cfb65e3b63 100644 --- a/packages/frontend/src/components/MkEmojiPickerDialog.vue +++ b/packages/frontend/src/components/MkEmojiPickerDialog.vue @@ -14,8 +14,8 @@ > <MkEmojiPicker ref="picker" - class="ryghynhb _popup _shadow" - :class="{ drawer: type === 'drawer' }" + class="_popup _shadow" + :class="{ [$style.drawer]: type === 'drawer' }" :showPinned="showPinned" :asReactionPicker="asReactionPicker" :asDrawer="type === 'drawer'" @@ -67,12 +67,10 @@ function opening() { } </script> -<style lang="scss" scoped> -.ryghynhb { - &.drawer { - border-radius: 24px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - } +<style lang="scss" module> +.drawer { + border-radius: 24px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; } </style> diff --git a/packages/frontend/src/components/MkTextarea.vue b/packages/frontend/src/components/MkTextarea.vue index e8f10ab048..f5e6c71b75 100644 --- a/packages/frontend/src/components/MkTextarea.vue +++ b/packages/frontend/src/components/MkTextarea.vue @@ -1,12 +1,12 @@ <template> -<div class="adhpbeos"> - <div class="label" @click="focus"><slot name="label"></slot></div> - <div class="input" :class="{ disabled, focused, tall, pre }"> +<div> + <div :class="$style.label" @click="focus"><slot name="label"></slot></div> + <div :class="{ [$style.disabled]: disabled, [$style.focused]: focused, [$style.tall]: tall, [$style.pre]: pre }" style="position: relative;"> <textarea ref="inputEl" v-model="v" v-adaptive-border - :class="{ code, _monospace: code }" + :class="[$style.textarea, { [$style.code]: code, _monospace: code }]" :disabled="disabled" :required="required" :readonly="readonly" @@ -20,9 +20,9 @@ @input="onInput" ></textarea> </div> - <div class="caption"><slot name="caption"></slot></div> + <div :class="$style.caption"><slot name="caption"></slot></div> - <MkButton v-if="manualSave && changed" primary class="save" @click="updated"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> + <MkButton v-if="manualSave && changed" primary :class="$style.save" @click="updated"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> </div> </template> @@ -111,87 +111,82 @@ onMounted(() => { }); </script> -<style lang="scss" scoped> -.adhpbeos { - > .label { - font-size: 0.85em; - padding: 0 0 8px 0; - user-select: none; +<style lang="scss" module> +.label { + font-size: 0.85em; + padding: 0 0 8px 0; + user-select: none; - &:empty { - display: none; - } - } - - > .caption { - font-size: 0.85em; - padding: 8px 0 0 0; - color: var(--fgTransparentWeak); - - &:empty { - display: none; - } - } - - > .input { - position: relative; - - > textarea { - appearance: none; - -webkit-appearance: none; - display: block; - width: 100%; - min-width: 100%; - max-width: 100%; - min-height: 130px; - margin: 0; - padding: 12px; - font: inherit; - font-weight: normal; - font-size: 1em; - color: var(--fg); - background: var(--panel); - border: solid 1px var(--panel); - border-radius: 6px; - outline: none; - box-shadow: none; - box-sizing: border-box; - transition: border-color 0.1s ease-out; - - &:hover { - border-color: var(--inputBorderHover) !important; - } - } - - &.focused { - > textarea { - border-color: var(--accent) !important; - } - } - - &.disabled { - opacity: 0.7; - - &, * { - cursor: not-allowed !important; - } - } - - &.tall { - > textarea { - min-height: 200px; - } - } - - &.pre { - > textarea { - white-space: pre; - } - } - } - - > .save { - margin: 8px 0 0 0; + &:empty { + display: none; } } + +.caption { + font-size: 0.85em; + padding: 8px 0 0 0; + color: var(--fgTransparentWeak); + + &:empty { + display: none; + } +} + +.textarea { + appearance: none; + -webkit-appearance: none; + display: block; + width: 100%; + min-width: 100%; + max-width: 100%; + min-height: 130px; + margin: 0; + padding: 12px; + font: inherit; + font-weight: normal; + font-size: 1em; + color: var(--fg); + background: var(--panel); + border: solid 1px var(--panel); + border-radius: 6px; + outline: none; + box-shadow: none; + box-sizing: border-box; + transition: border-color 0.1s ease-out; + + &:hover { + border-color: var(--inputBorderHover) !important; + } +} + +.focused { + > .textarea { + border-color: var(--accent) !important; + } +} + +.disabled { + opacity: 0.7; + cursor: not-allowed !important; + + > .textarea { + cursor: not-allowed !important; + } +} + +.tall { + > .textarea { + min-height: 200px; + } +} + +.pre { + > .textarea { + white-space: pre; + } +} + +.save { + margin: 8px 0 0 0; +} </style> diff --git a/packages/frontend/src/components/form/link.vue b/packages/frontend/src/components/form/link.vue index a1775c0bdb..1424332dae 100644 --- a/packages/frontend/src/components/form/link.vue +++ b/packages/frontend/src/components/form/link.vue @@ -1,19 +1,19 @@ <template> -<div class="ffcbddfc" :class="{ inline }"> - <a v-if="external" class="main _button" :href="to" target="_blank"> - <span class="icon"><slot name="icon"></slot></span> - <span class="text"><slot></slot></span> - <span class="right"> - <span class="text"><slot name="suffix"></slot></span> - <i class="ti ti-external-link icon"></i> +<div :class="[$style.root, { [$style.inline]: inline }]"> + <a v-if="external" :class="$style.main" class="_button" :href="to" target="_blank"> + <span :class="$style.icon"><slot name="icon"></slot></span> + <span :class="$style.text"><slot></slot></span> + <span :class="$style.suffix"> + <span :class="$style.suffixText"><slot name="suffix"></slot></span> + <i class="ti ti-external-link" :class="$style.suffixIcon"></i> </span> </a> - <MkA v-else class="main _button" :class="{ active }" :to="to" :behavior="behavior"> - <span class="icon"><slot name="icon"></slot></span> - <span class="text"><slot></slot></span> - <span class="right"> - <span class="text"><slot name="suffix"></slot></span> - <i class="ti ti-chevron-right icon"></i> + <MkA v-else :class="[$style.main, { [$style.active]: active }]" class="_button" :to="to" :behavior="behavior"> + <span :class="$style.icon"><slot name="icon"></slot></span> + <span :class="$style.text"><slot></slot></span> + <span :class="$style.suffix"> + <span :class="$style.suffixText"><slot name="suffix"></slot></span> + <i class="ti ti-chevron-right" :class="$style.suffixIcon"></i> </span> </MkA> </div> @@ -31,65 +31,65 @@ const props = defineProps<{ }>(); </script> -<style lang="scss" scoped> -.ffcbddfc { +<style lang="scss" module> +.root { display: block; &.inline { display: inline-block; } +} - > .main { - display: flex; - align-items: center; - width: 100%; - box-sizing: border-box; - padding: 10px 14px; - background: var(--buttonBg); - border-radius: 6px; - font-size: 0.9em; +.main { + display: flex; + align-items: center; + width: 100%; + box-sizing: border-box; + padding: 10px 14px; + background: var(--buttonBg); + border-radius: 6px; + font-size: 0.9em; - &:hover { - text-decoration: none; - background: var(--buttonHoverBg); - } + &:hover { + text-decoration: none; + background: var(--buttonHoverBg); + } - &.active { - color: var(--accent); - background: var(--buttonHoverBg); - } + &.active { + color: var(--accent); + background: var(--buttonHoverBg); + } +} - > .icon { - margin-right: 0.75em; - flex-shrink: 0; - text-align: center; - color: var(--fgTransparentWeak); +.icon { + margin-right: 0.75em; + flex-shrink: 0; + text-align: center; + color: var(--fgTransparentWeak); - &:empty { - display: none; + &:empty { + display: none; - & + .text { - padding-left: 4px; - } - } - } - - > .text { - flex-shrink: 1; - white-space: normal; - padding-right: 12px; - text-align: center; - } - - > .right { - margin-left: auto; - opacity: 0.7; - white-space: nowrap; - - > .text:not(:empty) { - margin-right: 0.75em; - } + & + .text { + padding-left: 4px; } } } + +.text { + flex-shrink: 1; + white-space: normal; + padding-right: 12px; + text-align: center; +} + +.suffix { + margin-left: auto; + opacity: 0.7; + white-space: nowrap; + + > .suffixText:not(:empty) { + margin-right: 0.75em; + } +} </style> diff --git a/packages/frontend/src/components/page/page.section.vue b/packages/frontend/src/components/page/page.section.vue index dc06a231f9..9f79ecc833 100644 --- a/packages/frontend/src/components/page/page.section.vue +++ b/packages/frontend/src/components/page/page.section.vue @@ -1,8 +1,8 @@ <template> -<section class="sdgxphyu"> - <component :is="'h' + h">{{ block.title }}</component> +<section> + <component :is="'h' + h" :class="h < 5 ? $style['h' + h] : null">{{ block.title }}</component> - <div class="children"> + <div class="_gaps"> <XBlock v-for="child in block.children" :key="child.id" :page="page" :block="child" :h="h + 1"/> </div> </section> @@ -22,27 +22,19 @@ defineProps<{ }>(); </script> -<style lang="scss" scoped> -.sdgxphyu { - margin: 1.5em 0; +<style lang="scss" module> +.h2 { + font-size: 1.35em; + margin: 0 0 0.5em 0; +} - > h2 { - font-size: 1.35em; - margin: 0 0 0.5em 0; - } +.h3 { + font-size: 1em; + margin: 0 0 0.5em 0; +} - > h3 { - font-size: 1em; - margin: 0 0 0.5em 0; - } - - > h4 { - font-size: 1em; - margin: 0 0 0.5em 0; - } - - > .children { - //padding 16px - } +.h4 { + font-size: 1em; + margin: 0 0 0.5em 0; } </style> diff --git a/packages/frontend/src/components/page/page.text.vue b/packages/frontend/src/components/page/page.text.vue index 308948b45c..48ce4b0e1e 100644 --- a/packages/frontend/src/components/page/page.text.vue +++ b/packages/frontend/src/components/page/page.text.vue @@ -1,7 +1,7 @@ <template> -<div class="mrdgzndn"> +<div class="_gaps"> <Mfm :text="block.text" :isNote="false" :i="$i"/> - <MkUrlPreview v-for="url in urls" :key="url" :url="url" class="url"/> + <MkUrlPreview v-for="url in urls" :key="url" :url="url"/> </div> </template> @@ -22,19 +22,3 @@ const props = defineProps<{ const urls = props.block.text ? extractUrlFromMfm(mfm.parse(props.block.text)) : []; </script> - -<style lang="scss" scoped> -.mrdgzndn { - &:not(:first-child) { - margin-top: 0.5em; - } - - &:not(:last-child) { - margin-bottom: 0.5em; - } - - > .url { - margin: 0.5em 0; - } -} -</style> diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue index f9291c4d2d..a6d3ff6359 100644 --- a/packages/frontend/src/components/page/page.vue +++ b/packages/frontend/src/components/page/page.vue @@ -1,5 +1,5 @@ <template> -<div class="iroscrza" :class="{ center: page.alignCenter, serif: page.font === 'serif' }"> +<div :class="{ [$style.center]: page.alignCenter, [$style.serif]: page.font === 'serif' }"> <XBlock v-for="child in page.content" :key="child.id" :block="child" :h="2"/> </div> </template> @@ -14,16 +14,12 @@ defineProps<{ }>(); </script> -<style lang="scss" scoped> -.iroscrza { - &.serif { - > div { - font-family: serif; - } - } +<style lang="scss" module> +.serif { + font-family: serif; +} - &.center { - text-align: center; - } +.center { + text-align: center; } </style> diff --git a/packages/frontend/src/pages/admin/relays.vue b/packages/frontend/src/pages/admin/relays.vue index c82e7e1e00..119439c958 100644 --- a/packages/frontend/src/pages/admin/relays.vue +++ b/packages/frontend/src/pages/admin/relays.vue @@ -5,10 +5,10 @@ <div class="_gaps"> <div v-for="relay in relays" :key="relay.inbox" class="relaycxt _panel" style="padding: 16px;"> <div>{{ relay.inbox }}</div> - <div class="status"> - <i v-if="relay.status === 'accepted'" class="ti ti-check icon accepted"></i> - <i v-else-if="relay.status === 'rejected'" class="ti ti-ban icon rejected"></i> - <i v-else class="ti ti-clock icon requesting"></i> + <div style="margin: 8px 0;"> + <i v-if="relay.status === 'accepted'" class="ti ti-check" :class="$style.icon" style="color: var(--success);"></i> + <i v-else-if="relay.status === 'rejected'" class="ti ti-ban" :class="$style.icon" style="color: var(--error);"></i> + <i v-else class="ti ti-clock" :class="$style.icon"></i> <span>{{ i18n.t(`_relayStatus.${relay.status}`) }}</span> </div> <MkButton class="button" inline danger @click="remove(relay.inbox)"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton> @@ -83,23 +83,9 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.relaycxt { - > .status { - margin: 8px 0; - - > .icon { - width: 1em; - margin-right: 0.75em; - - &.accepted { - color: var(--success); - } - - &.rejected { - color: var(--error); - } - } - } +<style lang="scss" module> +.icon { + width: 1em; + margin-right: 0.75em; } </style> diff --git a/packages/frontend/src/pages/flash/flash-index.vue b/packages/frontend/src/pages/flash/flash-index.vue index 0fd5527a85..1f933c2346 100644 --- a/packages/frontend/src/pages/flash/flash-index.vue +++ b/packages/frontend/src/pages/flash/flash-index.vue @@ -2,29 +2,29 @@ <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :contentMax="700"> - <div v-if="tab === 'featured'" class=""> + <div v-if="tab === 'featured'"> <MkPagination v-slot="{items}" :pagination="featuredFlashsPagination"> <div class="_gaps_s"> - <MkFlashPreview v-for="flash in items" :key="flash.id" class="" :flash="flash"/> + <MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash"/> </div> </MkPagination> </div> - <div v-else-if="tab === 'my'" class="my"> + <div v-else-if="tab === 'my'"> <div class="_gaps"> - <MkButton class="new" gradate rounded style="margin: 0 auto;" @click="create()"><i class="ti ti-plus"></i></MkButton> + <MkButton gradate rounded style="margin: 0 auto;" @click="create()"><i class="ti ti-plus"></i></MkButton> <MkPagination v-slot="{items}" :pagination="myFlashsPagination"> <div class="_gaps_s"> - <MkFlashPreview v-for="flash in items" :key="flash.id" class="" :flash="flash"/> + <MkFlashPreview v-for="flash in items" :key="flash.id" :flash="flash"/> </div> </MkPagination> </div> </div> - <div v-else-if="tab === 'liked'" class=""> + <div v-else-if="tab === 'liked'"> <MkPagination v-slot="{items}" :pagination="likedFlashsPagination"> <div class="_gaps_s"> - <MkFlashPreview v-for="like in items" :key="like.flash.id" class="" :flash="like.flash"/> + <MkFlashPreview v-for="like in items" :key="like.flash.id" :flash="like.flash"/> </div> </MkPagination> </div> @@ -87,21 +87,3 @@ definePageMetadata(computed(() => ({ icon: 'ti ti-player-play', }))); </script> - -<style lang="scss" scoped> -.rknalgpo { - &.my .ckltabjg:first-child { - margin-top: 16px; - } - - .ckltabjg:not(:last-child) { - margin-bottom: 8px; - } - - @media (min-width: 500px) { - .ckltabjg:not(:last-child) { - margin-bottom: 16px; - } - } -} -</style> diff --git a/packages/frontend/src/pages/my-lists/index.vue b/packages/frontend/src/pages/my-lists/index.vue index e4b6f0e5bc..cee241c489 100644 --- a/packages/frontend/src/pages/my-lists/index.vue +++ b/packages/frontend/src/pages/my-lists/index.vue @@ -2,14 +2,16 @@ <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <MkSpacer :contentMax="700"> - <div class="qkcjvfiv"> - <MkButton primary class="add" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton> + <div class="_gaps"> + <MkButton primary rounded style="margin: 0 auto;" @click="create"><i class="ti ti-plus"></i> {{ i18n.ts.createList }}</MkButton> - <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination" class="lists"> - <MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`"> - <div class="name">{{ list.name }}</div> - <MkAvatars :userIds="list.userIds"/> - </MkA> + <MkPagination v-slot="{items}" ref="pagingComponent" :pagination="pagination"> + <div class="_gaps"> + <MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/my/lists/${ list.id }`"> + <div style="margin-bottom: 4px;">{{ list.name }}</div> + <MkAvatars :userIds="list.userIds"/> + </MkA> + </div> </MkPagination> </div> </MkSpacer> @@ -58,29 +60,17 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> -.qkcjvfiv { - > .add { - margin: 0 auto var(--margin) auto; - } +<style lang="scss" module> +.list { + display: block; + padding: 16px; + border: solid 1px var(--divider); + border-radius: 6px; + margin-bottom: 8px; - > .lists { - > .list { - display: block; - padding: 16px; - border: solid 1px var(--divider); - border-radius: 6px; - margin-bottom: 8px; - - &:hover { - border: solid 1px var(--accent); - text-decoration: none; - } - - > .name { - margin-bottom: 4px; - } - } + &:hover { + border: solid 1px var(--accent); + text-decoration: none; } } </style> From 11d22c7b7324e34ce329903271b297430516ff8c Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 27 May 2023 11:38:08 +0900 Subject: [PATCH 097/213] refactor --- .../src/components/MkModalPageWindow.vue | 182 ------------------ .../frontend/src/components/form/link.vue | 2 +- .../frontend/src/components/global/MkA.vue | 12 +- packages/frontend/src/os.ts | 6 - packages/frontend/src/ui/classic.header.vue | 4 +- packages/frontend/src/ui/classic.sidebar.vue | 4 +- 6 files changed, 6 insertions(+), 204 deletions(-) delete mode 100644 packages/frontend/src/components/MkModalPageWindow.vue diff --git a/packages/frontend/src/components/MkModalPageWindow.vue b/packages/frontend/src/components/MkModalPageWindow.vue deleted file mode 100644 index b38865f525..0000000000 --- a/packages/frontend/src/components/MkModalPageWindow.vue +++ /dev/null @@ -1,182 +0,0 @@ -<template> -<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')"> - <div ref="rootEl" class="hrmcaedk" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }"> - <div class="header" @contextmenu="onContextmenu"> - <button v-if="history.length > 0" v-tooltip="i18n.ts.goBack" class="_button" @click="back()"><i class="ti ti-arrow-left"></i></button> - <span v-else style="display: inline-block; width: 20px"></span> - <span v-if="pageMetadata?.value" class="title"> - <i v-if="pageMetadata?.value.icon" class="icon" :class="pageMetadata?.value.icon"></i> - <span>{{ pageMetadata?.value.title }}</span> - </span> - <button class="_button" @click="$refs.modal.close()"><i class="ti ti-x"></i></button> - </div> - <div class="body" style="container-type: inline-size;"> - <MkStickyContainer> - <template #header><MkPageHeader v-if="pageMetadata?.value && !pageMetadata?.value.hideHeader" :info="pageMetadata?.value"/></template> - <RouterView :router="router"/> - </MkStickyContainer> - </div> - </div> -</MkModal> -</template> - -<script lang="ts" setup> -import { ComputedRef, provide } from 'vue'; -import MkModal from '@/components/MkModal.vue'; -import { popout as _popout } from '@/scripts/popout'; -import copyToClipboard from '@/scripts/copy-to-clipboard'; -import { url } from '@/config'; -import * as os from '@/os'; -import { mainRouter, routes } from '@/router'; -import { i18n } from '@/i18n'; -import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; -import { Router } from '@/nirax'; - -const props = defineProps<{ - initialPath: string; -}>(); - -defineEmits<{ - (ev: 'closed'): void; - (ev: 'click'): void; -}>(); - -const router = new Router(routes, props.initialPath); - -router.addListener('push', ctx => { - -}); - -let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); -let rootEl = $ref(); -let modal = $shallowRef<InstanceType<typeof MkModal>>(); -let path = $ref(props.initialPath); -let width = $ref(860); -let height = $ref(660); -const history = []; - -provide('router', router); -provideMetadataReceiver((info) => { - pageMetadata = info; -}); -provide('shouldOmitHeaderTitle', true); -provide('shouldHeaderThin', true); - -const pageUrl = $computed(() => url + path); -const contextmenu = $computed(() => { - return [{ - type: 'label', - text: path, - }, { - icon: 'ti ti-player-eject', - text: i18n.ts.showInPage, - action: expand, - }, { - icon: 'ti ti-window-maximize', - text: i18n.ts.popout, - action: popout, - }, null, { - icon: 'ti ti-external-link', - text: i18n.ts.openInNewTab, - action: () => { - window.open(pageUrl, '_blank'); - modal.close(); - }, - }, { - icon: 'ti ti-link', - text: i18n.ts.copyLink, - action: () => { - copyToClipboard(pageUrl); - }, - }]; -}); - -function navigate(path, record = true) { - if (record) history.push(router.getCurrentPath()); - router.push(path); -} - -function back() { - navigate(history.pop(), false); -} - -function expand() { - mainRouter.push(path); - modal.close(); -} - -function popout() { - _popout(path, rootEl); - modal.close(); -} - -function onContextmenu(ev: MouseEvent) { - os.contextMenu(contextmenu, ev); -} -</script> - -<style lang="scss" scoped> -.hrmcaedk { - margin: auto; - overflow: hidden; - display: flex; - flex-direction: column; - contain: content; - border-radius: var(--radius); - - --root-margin: 24px; - - @media (max-width: 500px) { - --root-margin: 16px; - } - - > .header { - $height: 52px; - $height-narrow: 42px; - display: flex; - flex-shrink: 0; - height: $height; - line-height: $height; - font-weight: bold; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - background: var(--windowHeader); - -webkit-backdrop-filter: var(--blur, blur(15px)); - backdrop-filter: var(--blur, blur(15px)); - - > button { - height: $height; - width: $height; - - &:hover { - color: var(--fgHighlighted); - } - } - - @media (max-width: 500px) { - height: $height-narrow; - line-height: $height-narrow; - padding-left: 16px; - - > button { - height: $height-narrow; - width: $height-narrow; - } - } - - > .title { - flex: 1; - - > .icon { - margin-right: 0.5em; - } - } - } - - > .body { - overflow: auto; - background: var(--bg); - } -} -</style> diff --git a/packages/frontend/src/components/form/link.vue b/packages/frontend/src/components/form/link.vue index 1424332dae..e6da039ac5 100644 --- a/packages/frontend/src/components/form/link.vue +++ b/packages/frontend/src/components/form/link.vue @@ -26,7 +26,7 @@ const props = defineProps<{ to: string; active?: boolean; external?: boolean; - behavior?: null | 'window' | 'browser' | 'modalWindow'; + behavior?: null | 'window' | 'browser'; inline?: boolean; }>(); </script> diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue index 40d134dffb..4e608c6efe 100644 --- a/packages/frontend/src/components/global/MkA.vue +++ b/packages/frontend/src/components/global/MkA.vue @@ -15,7 +15,7 @@ import { useRouter } from '@/router'; const props = withDefaults(defineProps<{ to: string; activeClass?: null | string; - behavior?: null | 'window' | 'browser' | 'modalWindow'; + behavior?: null | 'window' | 'browser'; }>(), { activeClass: null, behavior: null, @@ -70,14 +70,6 @@ function openWindow() { os.pageWindow(props.to); } -function modalWindow() { - os.modalPageWindow(props.to); -} - -function popout() { - popout_(props.to); -} - function nav(ev: MouseEvent) { if (props.behavior === 'browser') { location.href = props.to; @@ -87,8 +79,6 @@ function nav(ev: MouseEvent) { if (props.behavior) { if (props.behavior === 'window') { return openWindow(); - } else if (props.behavior === 'modalWindow') { - return modalWindow(); } } diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index c4f9d47d7d..c44d348046 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -172,12 +172,6 @@ export function pageWindow(path: string) { }, {}, 'closed'); } -export function modalPageWindow(path: string) { - popup(defineAsyncComponent(() => import('@/components/MkModalPageWindow.vue')), { - initialPath: path, - }, {}, 'closed'); -} - export function toast(message: string) { popup(MkToast, { message, diff --git a/packages/frontend/src/ui/classic.header.vue b/packages/frontend/src/ui/classic.header.vue index 233d5b2644..747d4edcb4 100644 --- a/packages/frontend/src/ui/classic.header.vue +++ b/packages/frontend/src/ui/classic.header.vue @@ -16,7 +16,7 @@ </component> </template> <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip="i18n.ts.controlPanel" class="item" activeClass="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip="i18n.ts.controlPanel" class="item" activeClass="active" to="/admin" :behavior="settingsWindowed ? 'window' : null"> <i class="ti ti-dashboard ti-fw"></i> </MkA> <button v-click-anime class="item _button" @click="more"> @@ -25,7 +25,7 @@ </button> </div> <div class="right"> - <MkA v-click-anime v-tooltip="i18n.ts.settings" class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-click-anime v-tooltip="i18n.ts.settings" class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'window' : null"> <i class="ti ti-settings ti-fw"></i> </MkA> <button v-click-anime class="item _button account" @click="openAccountMenu"> diff --git a/packages/frontend/src/ui/classic.sidebar.vue b/packages/frontend/src/ui/classic.sidebar.vue index e5755e87c9..cb264fc3ba 100644 --- a/packages/frontend/src/ui/classic.sidebar.vue +++ b/packages/frontend/src/ui/classic.sidebar.vue @@ -20,14 +20,14 @@ </component> </template> <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" activeClass="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" activeClass="active" to="/admin" :behavior="settingsWindowed ? 'window' : null"> <i class="ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> </MkA> <button v-click-anime class="item _button" @click="more"> <i class="ti ti-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> <span v-if="otherNavItemIndicated" class="indicator"><i class="_indicatorCircle"></i></span> </button> - <MkA v-click-anime class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null"> + <MkA v-click-anime class="item" activeClass="active" to="/settings" :behavior="settingsWindowed ? 'window' : null"> <i class="ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> </MkA> <div class="divider"></div> From 3a924f3dc62048e5edea9288de195f0b60760cee Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 27 May 2023 11:44:04 +0900 Subject: [PATCH 098/213] refactor --- .../frontend/src/components/MkImageViewer.vue | 78 ------------------- .../frontend/src/components/form/suspense.vue | 41 ++++------ 2 files changed, 13 insertions(+), 106 deletions(-) delete mode 100644 packages/frontend/src/components/MkImageViewer.vue diff --git a/packages/frontend/src/components/MkImageViewer.vue b/packages/frontend/src/components/MkImageViewer.vue deleted file mode 100644 index e3b2ebe651..0000000000 --- a/packages/frontend/src/components/MkImageViewer.vue +++ /dev/null @@ -1,78 +0,0 @@ -<template> -<MkModal ref="modal" :zPriority="'middle'" @click="modal.close()" @closed="emit('closed')"> - <div class="xubzgfga"> - <header>{{ image.name }}</header> - <img :src="image.url" :alt="image.comment" :title="image.comment" @click="modal.close()"/> - <footer> - <span>{{ image.type }}</span> - <span>{{ bytes(image.size) }}</span> - <span v-if="image.properties && image.properties.width">{{ number(image.properties.width) }}px × {{ number(image.properties.height) }}px</span> - </footer> - </div> -</MkModal> -</template> - -<script lang="ts" setup> -import { } from 'vue'; -import * as misskey from 'misskey-js'; -import bytes from '@/filters/bytes'; -import number from '@/filters/number'; -import MkModal from '@/components/MkModal.vue'; - -const props = withDefaults(defineProps<{ - image: misskey.entities.DriveFile; -}>(), { -}); - -const emit = defineEmits<{ - (ev: 'closed'): void; -}>(); - -const modal = $shallowRef<InstanceType<typeof MkModal>>(); -</script> - -<style lang="scss" scoped> -.xubzgfga { - margin: auto; - display: flex; - flex-direction: column; - height: 100%; - - > header, - > footer { - align-self: center; - display: inline-block; - padding: 6px 9px; - font-size: 90%; - background: rgba(0, 0, 0, 0.5); - border-radius: 6px; - color: #fff; - } - - > header { - margin-bottom: 8px; - opacity: 0.9; - } - - > img { - display: block; - flex: 1; - min-height: 0; - object-fit: contain; - width: 100%; - cursor: zoom-out; - image-orientation: from-image; - } - - > footer { - margin-top: 8px; - opacity: 0.8; - - > span + span { - margin-left: 0.5em; - padding-left: 0.5em; - border-left: solid 1px rgba(255, 255, 255, 0.5); - } - } -} -</style> diff --git a/packages/frontend/src/components/form/suspense.vue b/packages/frontend/src/components/form/suspense.vue index 9b39858ca1..b3d8c22b27 100644 --- a/packages/frontend/src/components/form/suspense.vue +++ b/packages/frontend/src/components/form/suspense.vue @@ -1,18 +1,16 @@ <template> -<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in"> - <div v-if="pending"> - <MkLoading/> +<div v-if="pending"> + <MkLoading/> +</div> +<div v-else-if="resolved"> + <slot :result="result"></slot> +</div> +<div v-else> + <div :class="$style.error"> + <div><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</div> + <MkButton inline style="margin-top: 16px;" @click="retry"><i class="ti ti-reload"></i> {{ i18n.ts.retry }}</MkButton> </div> - <div v-else-if="resolved"> - <slot :result="result"></slot> - </div> - <div v-else> - <div class="wszdbhzo"> - <div><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</div> - <MkButton inline class="retry" @click="retry"><i class="ti ti-reload"></i> {{ i18n.ts.retry }}</MkButton> - </div> - </div> -</Transition> +</div> </template> <script lang="ts" setup> @@ -60,22 +58,9 @@ const retry = () => { }; </script> -<style lang="scss" scoped> -.fade-enter-active, -.fade-leave-active { - transition: opacity 0.125s ease; -} -.fade-enter-from, -.fade-leave-to { - opacity: 0; -} - -.wszdbhzo { +<style lang="scss" module> +.error { padding: 16px; text-align: center; - - > .retry { - margin-top: 16px; - } } </style> From fb54c58a661bee64365b7ec0c52d456062aaa200 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 27 May 2023 12:09:19 +0900 Subject: [PATCH 099/213] :art: --- packages/frontend/src/ui/deck.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 69637b6555..126aa807a8 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -328,12 +328,12 @@ async function deleteProfile() { flex-direction: column; scroll-snap-align: start; flex-shrink: 0; - margin-top: var(--columnGap); - margin-bottom: var(--columnGap); - margin-right: var(--columnGap); + padding-top: var(--columnGap); + padding-bottom: var(--columnGap); + padding-right: var(--columnGap); &:first-of-type { - margin-left: var(--columnGap); + padding-left: var(--columnGap); } > .column:not(:last-of-type) { From a80003cde57da44b39189e32d43c5297f963f0cf Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Sun, 28 May 2023 20:58:39 +0900 Subject: [PATCH 100/213] =?UTF-8?q?fix(frontend):=20Zen=20UI=E3=81=A7?= =?UTF-8?q?=E3=80=81=E3=83=87=E3=83=83=E3=82=AD=E8=A8=AD=E5=AE=9A=E3=81=A7?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5/=E4=BB=A5=E5=A4=96=E3=82=92=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=97=E3=81=9F=E3=81=A8=E3=81=8D=E3=83=87=E3=83=83?= =?UTF-8?q?=E3=82=AD=E3=81=AB=E6=88=BB=E3=82=8B=E3=83=9C=E3=82=BF=E3=83=B3?= =?UTF-8?q?=E3=82=92=E8=A1=A8=E7=A4=BA=20(#10909)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): デッキ設定で直接/以外を表示したときのZen UIでデッキに戻るボタン * fix style * ?zenが指定されていた場合はボタンを表示しない --- packages/frontend/src/ui/zen.vue | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/ui/zen.vue b/packages/frontend/src/ui/zen.vue index e656f00bb2..d516a5df75 100644 --- a/packages/frontend/src/ui/zen.vue +++ b/packages/frontend/src/ui/zen.vue @@ -1,9 +1,17 @@ <template> -<div :class="$style.root" style="container-type: inline-size;"> +<div :class="showBottom ? $style.rootWithBottom : $style.root" style="container-type: inline-size;"> <RouterView/> <XCommon/> </div> + +<!-- + デッキUIが設定されている場合はデッキUIに戻れるようにする (ただし?zenが明示された場合は表示しない) + See https://github.com/misskey-dev/misskey/issues/10905 +--> +<div v-if="showBottom" :class="$style.bottom"> + <button v-tooltip="i18n.ts.goToMisskey" :class="['_button', '_shadow', $style.button]" @click="goToMisskey"><i class="ti ti-home"></i></button> +</div> </template> <script lang="ts" setup> @@ -11,10 +19,13 @@ import { provide, ComputedRef } from 'vue'; import XCommon from './_common_/common.vue'; import { mainRouter } from '@/router'; import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; -import { instanceName } from '@/config'; +import { instanceName, ui } from '@/config'; +import { i18n } from '@/i18n'; let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); +const showBottom = !(new URLSearchParams(location.search)).has('zen') && ui === 'deck'; + provide('router', mainRouter); provideMetadataReceiver((info) => { pageMetadata = info; @@ -23,6 +34,10 @@ provideMetadataReceiver((info) => { } }); +function goToMisskey() { + window.location.href = '/'; +} + document.documentElement.style.overflowY = 'scroll'; </script> @@ -31,4 +46,29 @@ document.documentElement.style.overflowY = 'scroll'; min-height: 100dvh; box-sizing: border-box; } + +.rootWithBottom { + min-height: calc(100dvh - (60px + (var(--margin) * 2) + env(safe-area-inset-bottom, 0px))); + box-sizing: border-box; +} + +.bottom { + height: calc(60px + (var(--margin) * 2) + env(safe-area-inset-bottom, 0px)); + width: 100%; + margin-top: auto; +} + +.button { + position: fixed !important; + padding: 0; + aspect-ratio: 1; + width: 100%; + max-width: 60px; + margin: auto; + border-radius: 100%; + background: var(--panel); + color: var(--fg); + right: var(--margin); + bottom: calc(var(--margin) + env(safe-area-inset-bottom, 0px)); +} </style> From 7cbd852fe5a2d1ef84049c48c30f51f1170cc5de Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Mon, 29 May 2023 06:37:13 +0900 Subject: [PATCH 101/213] =?UTF-8?q?pnpm=20dev=E3=81=A7Ctrl+C=E3=81=A7?= =?UTF-8?q?=E7=B5=82=E4=BA=86=E3=81=95=E3=81=9B=E3=81=A6=E3=82=82=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=82=BB=E3=82=B9=E3=81=8C=E5=AE=8C=E5=85=A8=E3=81=AB?= =?UTF-8?q?=E6=AE=BA=E3=81=9B=E3=81=AA=E3=81=84=E3=81=AE=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=20(#10914)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/dev.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/dev.js b/scripts/dev.js index db7bc11feb..2f20d8f07c 100644 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -44,11 +44,17 @@ const fs = require('fs'); if (!stat) throw new Error('not exist yet'); if (stat.size === 0) throw new Error('not built yet'); - await execa('pnpm', ['start'], { + const subprocess = await execa('pnpm', ['start'], { cwd: __dirname + '/../', stdout: process.stdout, stderr: process.stderr, }); + + // なぜかworkerだけが終了してmasterが残るのでその対策 + process.on('SIGINT', () => { + subprocess.kill('SIGINT'); + process.exit(0); + }); } catch (e) { await new Promise(resolve => setTimeout(resolve, 3000)); start(); From fd7b77c542b51313d8b8ea60124725fe65a295d5 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 11:54:49 +0900 Subject: [PATCH 102/213] enhance(backend): migrate bull to bullmq (#10910) * wip * wip * Update QueueService.ts * wip * refactor * :v: * fix * Update QueueStatsService.ts * refactor * Update ApNoteService.ts * Update mock-resolver.ts * refactor * Update mock-resolver.ts --- CHANGELOG.md | 1 + packages/backend/package.json | 3 +- packages/backend/src/config.ts | 2 +- packages/backend/src/core/CaptchaService.ts | 20 +- .../src/core/FetchInstanceMetadataService.ts | 6 +- .../backend/src/core/NoteCreateService.ts | 2 +- packages/backend/src/core/QueueModule.ts | 53 +-- packages/backend/src/core/QueueService.ts | 65 +++- .../core/activitypub/LdSignatureService.ts | 4 +- .../core/activitypub/models/ApNoteService.ts | 6 +- .../backend/src/daemons/QueueStatsService.ts | 16 +- packages/backend/src/misc/id/aid.ts | 2 +- packages/backend/src/misc/prelude/time.ts | 17 +- .../src/queue/QueueProcessorService.ts | 320 +++++++++++------- packages/backend/src/queue/const.ts | 26 ++ packages/backend/src/queue/get-job-info.ts | 15 - .../AggregateRetentionProcessorService.ts | 6 +- .../CheckExpiredMutingsProcessorService.ts | 5 +- .../processors/CleanChartsProcessorService.ts | 5 +- .../queue/processors/CleanProcessorService.ts | 5 +- .../CleanRemoteFilesProcessorService.ts | 11 +- .../DeleteAccountProcessorService.ts | 6 +- .../DeleteDriveFilesProcessorService.ts | 14 +- .../processors/DeleteFileProcessorService.ts | 6 +- .../processors/DeliverProcessorService.ts | 10 +- .../EndedPollNotificationProcessorService.ts | 7 +- .../ExportAntennasProcessorService.ts | 6 +- .../ExportBlockingProcessorService.ts | 15 +- .../ExportCustomEmojisProcessorService.ts | 39 +-- .../ExportFavoritesProcessorService.ts | 11 +- .../ExportFollowingProcessorService.ts | 11 +- .../ExportMutingProcessorService.ts | 15 +- .../processors/ExportNotesProcessorService.ts | 11 +- .../ExportUserListsProcessorService.ts | 11 +- .../ImportAntennasProcessorService.ts | 6 +- .../ImportBlockingProcessorService.ts | 13 +- .../ImportCustomEmojisProcessorService.ts | 6 +- .../ImportFollowingProcessorService.ts | 13 +- .../ImportMutingProcessorService.ts | 13 +- .../ImportUserListsProcessorService.ts | 7 +- .../queue/processors/InboxProcessorService.ts | 38 +-- .../RelationshipProcessorService.ts | 2 +- .../ResyncChartsProcessorService.ts | 5 +- .../processors/TickChartsProcessorService.ts | 5 +- .../WebhookDeliverProcessorService.ts | 6 +- .../server/api/endpoints/admin/relays/add.ts | 2 +- .../api/endpoints/notes/search-by-tag.ts | 4 +- .../src/server/api/endpoints/reset-db.ts | 2 +- packages/backend/test/misc/mock-resolver.ts | 6 +- packages/backend/test/utils.ts | 2 +- packages/frontend/src/scripts/time.ts | 17 +- packages/shared/.eslintrc.js | 2 +- pnpm-lock.yaml | 121 ++++--- 53 files changed, 532 insertions(+), 490 deletions(-) create mode 100644 packages/backend/src/queue/const.ts delete mode 100644 packages/backend/src/queue/get-job-info.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index ecbad51e90..6b107c72f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ - fix:ロールタイムラインにて全ての投稿が流れてしまう問題の修正 ### Server +- bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 - Fix: お知らせの画像URLを空にできない問題を修正 ## 13.12.2 diff --git a/packages/backend/package.json b/packages/backend/package.json index 71da3bb557..99c04d6bf6 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -76,7 +76,7 @@ "autwh": "0.1.0", "bcryptjs": "2.4.3", "blurhash": "2.0.5", - "bull": "4.10.4", + "bullmq": "3.14.1", "cacheable-lookup": "6.1.0", "cbor": "8.1.0", "chalk": "5.2.0", @@ -167,7 +167,6 @@ "@types/accepts": "1.3.5", "@types/archiver": "5.3.2", "@types/bcryptjs": "2.4.2", - "@types/bull": "4.10.0", "@types/cbor": "6.0.0", "@types/color-convert": "2.0.0", "@types/content-disposition": "0.5.5", diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index 744f999596..9d1945e4d4 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -190,6 +190,6 @@ function tryCreateUrl(url: string) { try { return new URL(url); } catch (e) { - throw `url="${url}" is not a valid URL.`; + throw new Error(`url="${url}" is not a valid URL.`); } } diff --git a/packages/backend/src/core/CaptchaService.ts b/packages/backend/src/core/CaptchaService.ts index 7aaa1b833f..1a52a229c5 100644 --- a/packages/backend/src/core/CaptchaService.ts +++ b/packages/backend/src/core/CaptchaService.ts @@ -30,7 +30,7 @@ export class CaptchaService { }, { throwErrorWhenResponseNotOk: false }); if (!res.ok) { - throw `${res.status}`; + throw new Error(`${res.status}`); } return await res.json() as CaptchaResponse; @@ -39,48 +39,48 @@ export class CaptchaService { @bindThis public async verifyRecaptcha(secret: string, response: string | null | undefined): Promise<void> { if (response == null) { - throw 'recaptcha-failed: no response provided'; + throw new Error('recaptcha-failed: no response provided'); } const result = await this.getCaptchaResponse('https://www.recaptcha.net/recaptcha/api/siteverify', secret, response).catch(err => { - throw `recaptcha-request-failed: ${err}`; + throw new Error(`recaptcha-request-failed: ${err}`); }); if (result.success !== true) { const errorCodes = result['error-codes'] ? result['error-codes'].join(', ') : ''; - throw `recaptcha-failed: ${errorCodes}`; + throw new Error(`recaptcha-failed: ${errorCodes}`); } } @bindThis public async verifyHcaptcha(secret: string, response: string | null | undefined): Promise<void> { if (response == null) { - throw 'hcaptcha-failed: no response provided'; + throw new Error('hcaptcha-failed: no response provided'); } const result = await this.getCaptchaResponse('https://hcaptcha.com/siteverify', secret, response).catch(err => { - throw `hcaptcha-request-failed: ${err}`; + throw new Error(`hcaptcha-request-failed: ${err}`); }); if (result.success !== true) { const errorCodes = result['error-codes'] ? result['error-codes'].join(', ') : ''; - throw `hcaptcha-failed: ${errorCodes}`; + throw new Error(`hcaptcha-failed: ${errorCodes}`); } } @bindThis public async verifyTurnstile(secret: string, response: string | null | undefined): Promise<void> { if (response == null) { - throw 'turnstile-failed: no response provided'; + throw new Error('turnstile-failed: no response provided'); } const result = await this.getCaptchaResponse('https://challenges.cloudflare.com/turnstile/v0/siteverify', secret, response).catch(err => { - throw `turnstile-request-failed: ${err}`; + throw new Error(`turnstile-request-failed: ${err}`); }); if (result.success !== true) { const errorCodes = result['error-codes'] ? result['error-codes'].join(', ') : ''; - throw `turnstile-failed: ${errorCodes}`; + throw new Error(`turnstile-failed: ${errorCodes}`); } } } diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts index 8103d5afe9..9de633350b 100644 --- a/packages/backend/src/core/FetchInstanceMetadataService.ts +++ b/packages/backend/src/core/FetchInstanceMetadataService.ts @@ -116,14 +116,14 @@ export class FetchInstanceMetadataService { const wellknown = await this.httpRequestService.getJson('https://' + instance.host + '/.well-known/nodeinfo') .catch(err => { if (err.statusCode === 404) { - throw 'No nodeinfo provided'; + throw new Error('No nodeinfo provided'); } else { throw err.statusCode ?? err.message; } }) as Record<string, unknown>; if (wellknown.links == null || !Array.isArray(wellknown.links)) { - throw 'No wellknown links'; + throw new Error('No wellknown links'); } const links = wellknown.links as any[]; @@ -134,7 +134,7 @@ export class FetchInstanceMetadataService { const link = lnik2_1 ?? lnik2_0 ?? lnik1_0; if (link == null) { - throw 'No nodeinfo link provided'; + throw new Error('No nodeinfo link provided'); } const info = await this.httpRequestService.getJson(link.href) diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 977c9052c0..2fd7a8ac86 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -510,7 +510,7 @@ export class NoteCreateService implements OnApplicationShutdown { if (data.poll && data.poll.expiresAt) { const delay = data.poll.expiresAt.getTime() - Date.now(); - this.queueService.endedPollNotificationQueue.add({ + this.queueService.endedPollNotificationQueue.add(note.id, { noteId: note.id, }, { delay, diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts index 1d73947776..6db9bb14cf 100644 --- a/packages/backend/src/core/QueueModule.ts +++ b/packages/backend/src/core/QueueModule.ts @@ -1,42 +1,11 @@ import { setTimeout } from 'node:timers/promises'; import { Inject, Module, OnApplicationShutdown } from '@nestjs/common'; -import Bull from 'bull'; +import * as Bull from 'bullmq'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; +import { QUEUE, baseQueueOptions } from '@/queue/const.js'; import type { Provider } from '@nestjs/common'; -import type { DeliverJobData, InboxJobData, DbJobData, ObjectStorageJobData, EndedPollNotificationJobData, WebhookDeliverJobData, RelationshipJobData, DbJobMap } from '../queue/types.js'; - -function q<T>(config: Config, name: string, limitPerSec = -1) { - return new Bull<T>(name, { - redis: { - port: config.redisForJobQueue.port, - host: config.redisForJobQueue.host, - family: config.redisForJobQueue.family == null ? 0 : config.redisForJobQueue.family, - password: config.redisForJobQueue.pass, - db: config.redisForJobQueue.db ?? 0, - }, - prefix: config.redisForJobQueue.prefix ? `${config.redisForJobQueue.prefix}:queue` : 'queue', - limiter: limitPerSec > 0 ? { - max: limitPerSec, - duration: 1000, - } : undefined, - settings: { - backoffStrategies: { - apBackoff, - }, - }, - }); -} - -// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019 -function apBackoff(attemptsMade: number, err: Error) { - const baseDelay = 60 * 1000; // 1min - const maxBackoff = 8 * 60 * 60 * 1000; // 8hours - let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay; - backoff = Math.min(backoff, maxBackoff); - backoff += Math.round(backoff * Math.random() * 0.2); - return backoff; -} +import type { DeliverJobData, InboxJobData, EndedPollNotificationJobData, WebhookDeliverJobData, RelationshipJobData } from '../queue/types.js'; export type SystemQueue = Bull.Queue<Record<string, unknown>>; export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>; @@ -49,49 +18,49 @@ export type WebhookDeliverQueue = Bull.Queue<WebhookDeliverJobData>; const $system: Provider = { provide: 'queue:system', - useFactory: (config: Config) => q(config, 'system'), + useFactory: (config: Config) => new Bull.Queue(QUEUE.SYSTEM, baseQueueOptions(config, QUEUE.SYSTEM)), inject: [DI.config], }; const $endedPollNotification: Provider = { provide: 'queue:endedPollNotification', - useFactory: (config: Config) => q(config, 'endedPollNotification'), + useFactory: (config: Config) => new Bull.Queue(QUEUE.ENDED_POLL_NOTIFICATION, baseQueueOptions(config, QUEUE.ENDED_POLL_NOTIFICATION)), inject: [DI.config], }; const $deliver: Provider = { provide: 'queue:deliver', - useFactory: (config: Config) => q(config, 'deliver', config.deliverJobPerSec ?? 128), + useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)), inject: [DI.config], }; const $inbox: Provider = { provide: 'queue:inbox', - useFactory: (config: Config) => q(config, 'inbox', config.inboxJobPerSec ?? 16), + useFactory: (config: Config) => new Bull.Queue(QUEUE.INBOX, baseQueueOptions(config, QUEUE.INBOX)), inject: [DI.config], }; const $db: Provider = { provide: 'queue:db', - useFactory: (config: Config) => q(config, 'db'), + useFactory: (config: Config) => new Bull.Queue(QUEUE.DB, baseQueueOptions(config, QUEUE.DB)), inject: [DI.config], }; const $relationship: Provider = { provide: 'queue:relationship', - useFactory: (config: Config) => q(config, 'relationship', config.relashionshipJobPerSec ?? 64), + useFactory: (config: Config) => new Bull.Queue(QUEUE.RELATIONSHIP, baseQueueOptions(config, QUEUE.RELATIONSHIP)), inject: [DI.config], }; const $objectStorage: Provider = { provide: 'queue:objectStorage', - useFactory: (config: Config) => q(config, 'objectStorage'), + useFactory: (config: Config) => new Bull.Queue(QUEUE.OBJECT_STORAGE, baseQueueOptions(config, QUEUE.OBJECT_STORAGE)), inject: [DI.config], }; const $webhookDeliver: Provider = { provide: 'queue:webhookDeliver', - useFactory: (config: Config) => q(config, 'webhookDeliver', 64), + useFactory: (config: Config) => new Bull.Queue(QUEUE.WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.WEBHOOK_DELIVER)), inject: [DI.config], }; diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index b4ffffecc0..2ae8a2b754 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -1,6 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; import { v4 as uuid } from 'uuid'; -import Bull from 'bull'; import type { IActivity } from '@/core/activitypub/type.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { Webhook, webhookEventTypes } from '@/models/entities/Webhook.js'; @@ -11,6 +10,7 @@ import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js'; import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js'; import type { DbJobData, RelationshipJobData, ThinUser } from '../queue/types.js'; import type httpSignature from '@peertube/http-signature'; +import type * as Bull from 'bullmq'; @Injectable() export class QueueService { @@ -26,7 +26,43 @@ export class QueueService { @Inject('queue:relationship') public relationshipQueue: RelationshipQueue, @Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue, @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue, - ) {} + ) { + this.systemQueue.add('tickCharts', { + }, { + repeat: { pattern: '55 * * * *' }, + removeOnComplete: true, + }); + + this.systemQueue.add('resyncCharts', { + }, { + repeat: { pattern: '0 0 * * *' }, + removeOnComplete: true, + }); + + this.systemQueue.add('cleanCharts', { + }, { + repeat: { pattern: '0 0 * * *' }, + removeOnComplete: true, + }); + + this.systemQueue.add('aggregateRetention', { + }, { + repeat: { pattern: '0 0 * * *' }, + removeOnComplete: true, + }); + + this.systemQueue.add('clean', { + }, { + repeat: { pattern: '0 0 * * *' }, + removeOnComplete: true, + }); + + this.systemQueue.add('checkExpiredMutings', { + }, { + repeat: { pattern: '*/5 * * * *' }, + removeOnComplete: true, + }); + } @bindThis public deliver(user: ThinUser, content: IActivity | null, to: string | null, isSharedInbox: boolean) { @@ -42,11 +78,10 @@ export class QueueService { isSharedInbox, }; - return this.deliverQueue.add(data, { + return this.deliverQueue.add(to, data, { attempts: this.config.deliverJobMaxAttempts ?? 12, - timeout: 1 * 60 * 1000, // 1min backoff: { - type: 'apBackoff', + type: 'custom', }, removeOnComplete: true, removeOnFail: true, @@ -60,11 +95,10 @@ export class QueueService { signature, }; - return this.inboxQueue.add(data, { + return this.inboxQueue.add('', data, { attempts: this.config.inboxJobMaxAttempts ?? 8, - timeout: 5 * 60 * 1000, // 5min backoff: { - type: 'apBackoff', + type: 'custom', }, removeOnComplete: true, removeOnFail: true, @@ -212,7 +246,7 @@ export class QueueService { private generateToDbJobData<T extends 'importFollowingToDb' | 'importBlockingToDb', D extends DbJobData<T>>(name: T, data: D): { name: string, data: D, - opts: Bull.JobOptions, + opts: Bull.JobsOptions, } { return { name, @@ -299,10 +333,10 @@ export class QueueService { } @bindThis - private generateRelationshipJobData(name: 'follow' | 'unfollow' | 'block' | 'unblock', data: RelationshipJobData, opts: Bull.JobOptions = {}): { + private generateRelationshipJobData(name: 'follow' | 'unfollow' | 'block' | 'unblock', data: RelationshipJobData, opts: Bull.JobsOptions = {}): { name: string, data: RelationshipJobData, - opts: Bull.JobOptions, + opts: Bull.JobsOptions, } { return { name, @@ -351,11 +385,10 @@ export class QueueService { eventId: uuid(), }; - return this.webhookDeliverQueue.add(data, { + return this.webhookDeliverQueue.add(webhook.id, data, { attempts: 4, - timeout: 1 * 60 * 1000, // 1min backoff: { - type: 'apBackoff', + type: 'custom', }, removeOnComplete: true, removeOnFail: true, @@ -367,11 +400,11 @@ export class QueueService { this.deliverQueue.once('cleaned', (jobs, status) => { //deliverLogger.succ(`Cleaned ${jobs.length} ${status} jobs`); }); - this.deliverQueue.clean(0, 'delayed'); + this.deliverQueue.clean(0, Infinity, 'delayed'); this.inboxQueue.once('cleaned', (jobs, status) => { //inboxLogger.succ(`Cleaned ${jobs.length} ${status} jobs`); }); - this.inboxQueue.clean(0, 'delayed'); + this.inboxQueue.clean(0, Infinity, 'delayed'); } } diff --git a/packages/backend/src/core/activitypub/LdSignatureService.ts b/packages/backend/src/core/activitypub/LdSignatureService.ts index 2dc1a410ac..20fe2a0a77 100644 --- a/packages/backend/src/core/activitypub/LdSignatureService.ts +++ b/packages/backend/src/core/activitypub/LdSignatureService.ts @@ -94,7 +94,7 @@ class LdSignature { @bindThis private getLoader() { return async (url: string): Promise<any> => { - if (!url.match('^https?\:\/\/')) throw `Invalid URL ${url}`; + if (!url.match('^https?\:\/\/')) throw new Error(`Invalid URL ${url}`); if (this.preLoad) { if (url in CONTEXTS) { @@ -126,7 +126,7 @@ class LdSignature { timeout: this.loderTimeout, }, { throwErrorWhenResponseNotOk: false }).then(res => { if (!res.ok) { - throw `${res.status} ${res.statusText}`; + throw new Error(`${res.status} ${res.statusText}`); } else { return res.json(); } diff --git a/packages/backend/src/core/activitypub/models/ApNoteService.ts b/packages/backend/src/core/activitypub/models/ApNoteService.ts index 87a9db405f..76757f530a 100644 --- a/packages/backend/src/core/activitypub/models/ApNoteService.ts +++ b/packages/backend/src/core/activitypub/models/ApNoteService.ts @@ -18,6 +18,7 @@ import { PollService } from '@/core/PollService.js'; import { StatusError } from '@/misc/status-error.js'; import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; +import { checkHttps } from '@/misc/check-https.js'; import { getOneApId, getApId, getOneApHrefNullable, validPost, isEmoji, getApType } from '../type.js'; // eslint-disable-next-line @typescript-eslint/consistent-type-imports import { ApLoggerService } from '../ApLoggerService.js'; @@ -32,7 +33,6 @@ import { ApQuestionService } from './ApQuestionService.js'; import { ApImageService } from './ApImageService.js'; import type { Resolver } from '../ApResolverService.js'; import type { IObject, IPost } from '../type.js'; -import { checkHttps } from '@/misc/check-https.js'; @Injectable() export class ApNoteService { @@ -230,7 +230,7 @@ export class ApNoteService { quote = results.filter((x): x is { status: 'ok', res: Note | null } => x.status === 'ok').map(x => x.res).find(x => x); if (!quote) { if (results.some(x => x.status === 'temperror')) { - throw 'quote resolve failed'; + throw new Error('quote resolve failed'); } } } @@ -311,7 +311,7 @@ export class ApNoteService { // ブロックしてたら中断 const meta = await this.metaService.fetch(); - if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) throw { statusCode: 451 }; + if (this.utilityService.isBlockedHost(meta.blockedHosts, this.utilityService.extractDbHost(uri))) throw new StatusError('blocked host', 451); const unlock = await this.appLockService.getApLock(uri); diff --git a/packages/backend/src/daemons/QueueStatsService.ts b/packages/backend/src/daemons/QueueStatsService.ts index b717434e09..0a5b3184d2 100644 --- a/packages/backend/src/daemons/QueueStatsService.ts +++ b/packages/backend/src/daemons/QueueStatsService.ts @@ -1,7 +1,11 @@ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import Xev from 'xev'; +import * as Bull from 'bullmq'; import { QueueService } from '@/core/QueueService.js'; import { bindThis } from '@/decorators.js'; +import { DI } from '@/di-symbols.js'; +import type { Config } from '@/config.js'; +import { QUEUE, baseQueueOptions } from '@/queue/const.js'; import type { OnApplicationShutdown } from '@nestjs/common'; const ev = new Xev(); @@ -13,6 +17,9 @@ export class QueueStatsService implements OnApplicationShutdown { private intervalId: NodeJS.Timer; constructor( + @Inject(DI.config) + private config: Config, + private queueService: QueueService, ) { } @@ -31,11 +38,14 @@ export class QueueStatsService implements OnApplicationShutdown { let activeDeliverJobs = 0; let activeInboxJobs = 0; - this.queueService.deliverQueue.on('global:active', () => { + const deliverQueueEvents = new Bull.QueueEvents(QUEUE.DELIVER, baseQueueOptions(this.config, QUEUE.DELIVER)); + const inboxQueueEvents = new Bull.QueueEvents(QUEUE.INBOX, baseQueueOptions(this.config, QUEUE.INBOX)); + + deliverQueueEvents.on('active', () => { activeDeliverJobs++; }); - this.queueService.inboxQueue.on('global:active', () => { + inboxQueueEvents.on('active', () => { activeInboxJobs++; }); diff --git a/packages/backend/src/misc/id/aid.ts b/packages/backend/src/misc/id/aid.ts index 9e206ee98f..f0cbc9900d 100644 --- a/packages/backend/src/misc/id/aid.ts +++ b/packages/backend/src/misc/id/aid.ts @@ -21,7 +21,7 @@ function getNoise(): string { export function genAid(date: Date): string { const t = date.getTime(); - if (isNaN(t)) throw 'Failed to create AID: Invalid Date'; + if (isNaN(t)) throw new Error('Failed to create AID: Invalid Date'); counter++; return getTime(t) + getNoise(); } diff --git a/packages/backend/src/misc/prelude/time.ts b/packages/backend/src/misc/prelude/time.ts index 34e8b6b17c..b21978b186 100644 --- a/packages/backend/src/misc/prelude/time.ts +++ b/packages/backend/src/misc/prelude/time.ts @@ -5,15 +5,16 @@ const dateTimeIntervals = { }; export function dateUTC(time: number[]): Date { - const d = time.length === 2 ? Date.UTC(time[0], time[1]) - : time.length === 3 ? Date.UTC(time[0], time[1], time[2]) - : time.length === 4 ? Date.UTC(time[0], time[1], time[2], time[3]) - : time.length === 5 ? Date.UTC(time[0], time[1], time[2], time[3], time[4]) - : time.length === 6 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5]) - : time.length === 7 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5], time[6]) - : null; + const d = + time.length === 2 ? Date.UTC(time[0], time[1]) + : time.length === 3 ? Date.UTC(time[0], time[1], time[2]) + : time.length === 4 ? Date.UTC(time[0], time[1], time[2], time[3]) + : time.length === 5 ? Date.UTC(time[0], time[1], time[2], time[3], time[4]) + : time.length === 6 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5]) + : time.length === 7 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5], time[6]) + : null; - if (!d) throw 'wrong number of arguments'; + if (!d) throw new Error('wrong number of arguments'); return new Date(d); } diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index dc025f9889..011082cd36 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -1,10 +1,9 @@ import { Inject, Injectable } from '@nestjs/common'; +import * as Bull from 'bullmq'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import type Logger from '@/logger.js'; -import { QueueService } from '@/core/QueueService.js'; import { bindThis } from '@/decorators.js'; -import { getJobInfo } from './get-job-info.js'; import { WebhookDeliverProcessorService } from './processors/WebhookDeliverProcessorService.js'; import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js'; import { DeliverProcessorService } from './processors/DeliverProcessorService.js'; @@ -35,6 +34,33 @@ import { CheckExpiredMutingsProcessorService } from './processors/CheckExpiredMu import { CleanProcessorService } from './processors/CleanProcessorService.js'; import { AggregateRetentionProcessorService } from './processors/AggregateRetentionProcessorService.js'; import { QueueLoggerService } from './QueueLoggerService.js'; +import { QUEUE, baseQueueOptions } from './const.js'; + +// ref. https://github.com/misskey-dev/misskey/pull/7635#issue-971097019 +function httpRelatedBackoff(attemptsMade: number) { + const baseDelay = 60 * 1000; // 1min + const maxBackoff = 8 * 60 * 60 * 1000; // 8hours + let backoff = (Math.pow(2, attemptsMade) - 1) * baseDelay; + backoff = Math.min(backoff, maxBackoff); + backoff += Math.round(backoff * Math.random() * 0.2); + return backoff; +} + +function getJobInfo(job: Bull.Job | undefined, increment = false): string { + if (job == null) return '-'; + + const age = Date.now() - job.timestamp; + + const formated = age > 60000 ? `${Math.floor(age / 1000 / 60)}m` + : age > 10000 ? `${Math.floor(age / 1000)}s` + : `${age}ms`; + + // onActiveとかonCompletedのattemptsMadeがなぜか0始まりなのでインクリメントする + const currentAttempts = job.attemptsMade + (increment ? 1 : 0); + const maxAttempts = job.opts ? job.opts.attempts : 0; + + return `id=${job.id} attempts=${currentAttempts}/${maxAttempts} age=${formated}`; +} @Injectable() export class QueueProcessorService { @@ -45,7 +71,6 @@ export class QueueProcessorService { private config: Config, private queueLoggerService: QueueLoggerService, - private queueService: QueueService, private webhookDeliverProcessorService: WebhookDeliverProcessorService, private endedPollNotificationProcessorService: EndedPollNotificationProcessorService, private deliverProcessorService: DeliverProcessorService, @@ -97,146 +122,191 @@ export class QueueProcessorService { } } - const systemLogger = this.logger.createSubLogger('system'); - const deliverLogger = this.logger.createSubLogger('deliver'); - const webhookLogger = this.logger.createSubLogger('webhook'); - const inboxLogger = this.logger.createSubLogger('inbox'); - const dbLogger = this.logger.createSubLogger('db'); - const relationshipLogger = this.logger.createSubLogger('relationship'); - const objectStorageLogger = this.logger.createSubLogger('objectStorage'); + //#region system + const systemQueueWorker = new Bull.Worker(QUEUE.SYSTEM, (job) => { + switch (job.name) { + case 'tickCharts': return this.tickChartsProcessorService.process(); + case 'resyncCharts': return this.resyncChartsProcessorService.process(); + case 'cleanCharts': return this.cleanChartsProcessorService.process(); + case 'aggregateRetention': return this.aggregateRetentionProcessorService.process(); + case 'checkExpiredMutings': return this.checkExpiredMutingsProcessorService.process(); + case 'clean': return this.cleanProcessorService.process(); + default: throw new Error(`unrecognized job type ${job.name} for system`); + } + }, { + ...baseQueueOptions(this.config, QUEUE.SYSTEM), + }); - this.queueService.systemQueue - .on('waiting', (jobId) => systemLogger.debug(`waiting id=${jobId}`)) + const systemLogger = this.logger.createSubLogger('system'); + + systemQueueWorker .on('active', (job) => systemLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => systemLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => systemLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => systemLogger.warn(`stalled id=${job.id}`)); + .on('failed', (job, err) => systemLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => systemLogger.error(`error ${err}`, { e: renderError(err) })) + .on('stalled', (jobId) => systemLogger.warn(`stalled id=${jobId}`)); + //#endregion - this.queueService.deliverQueue - .on('waiting', (jobId) => deliverLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => deliverLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job.data.to}`)) - .on('error', (job: any, err: Error) => deliverLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => deliverLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`)); + //#region db + const dbQueueWorker = new Bull.Worker(QUEUE.DB, (job) => { + switch (job.name) { + case 'deleteDriveFiles': return this.deleteDriveFilesProcessorService.process(job); + case 'exportCustomEmojis': return this.exportCustomEmojisProcessorService.process(job); + case 'exportNotes': return this.exportNotesProcessorService.process(job); + case 'exportFavorites': return this.exportFavoritesProcessorService.process(job); + case 'exportFollowing': return this.exportFollowingProcessorService.process(job); + case 'exportMuting': return this.exportMutingProcessorService.process(job); + case 'exportBlocking': return this.exportBlockingProcessorService.process(job); + case 'exportUserLists': return this.exportUserListsProcessorService.process(job); + case 'exportAntennas': return this.exportAntennasProcessorService.process(job); + case 'importFollowing': return this.importFollowingProcessorService.process(job); + case 'importFollowingToDb': return this.importFollowingProcessorService.processDb(job); + case 'importMuting': return this.importMutingProcessorService.process(job); + case 'importBlocking': return this.importBlockingProcessorService.process(job); + case 'importBlockingToDb': return this.importBlockingProcessorService.processDb(job); + case 'importUserLists': return this.importUserListsProcessorService.process(job); + case 'importCustomEmojis': return this.importCustomEmojisProcessorService.process(job); + case 'importAntennas': return this.importAntennasProcessorService.process(job); + case 'deleteAccount': return this.deleteAccountProcessorService.process(job); + default: throw new Error(`unrecognized job type ${job.name} for db`); + } + }, { + ...baseQueueOptions(this.config, QUEUE.DB), + }); - this.queueService.inboxQueue - .on('waiting', (jobId) => inboxLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) - .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) - .on('failed', (job, err) => inboxLogger.warn(`failed(${err}) ${getJobInfo(job)} activity=${job.data.activity ? job.data.activity.id : 'none'}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => inboxLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => inboxLogger.warn(`stalled ${getJobInfo(job)} activity=${job.data.activity ? job.data.activity.id : 'none'}`)); + const dbLogger = this.logger.createSubLogger('db'); - this.queueService.dbQueue - .on('waiting', (jobId) => dbLogger.debug(`waiting id=${jobId}`)) + dbQueueWorker .on('active', (job) => dbLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => dbLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => dbLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => dbLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => dbLogger.warn(`stalled id=${job.id}`)); + .on('failed', (job, err) => dbLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => dbLogger.error(`error ${err}`, { e: renderError(err) })) + .on('stalled', (jobId) => dbLogger.warn(`stalled id=${jobId}`)); + //#endregion - this.queueService.relationshipQueue - .on('waiting', (jobId) => relationshipLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => relationshipLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => relationshipLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => relationshipLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => relationshipLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => relationshipLogger.warn(`stalled id=${job.id}`)); + //#region deliver + const deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => this.deliverProcessorService.process(job), { + ...baseQueueOptions(this.config, QUEUE.DELIVER), + concurrency: this.config.deliverJobConcurrency ?? 128, + limiter: { + max: this.config.deliverJobPerSec ?? 128, + duration: 1000, + }, + settings: { + backoffStrategy: httpRelatedBackoff, + }, + }); - this.queueService.objectStorageQueue - .on('waiting', (jobId) => objectStorageLogger.debug(`waiting id=${jobId}`)) - .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`)) - .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`)) - .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err}) id=${job.id}`, { job, e: renderError(err) })) - .on('error', (job: any, err: Error) => objectStorageLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => objectStorageLogger.warn(`stalled id=${job.id}`)); + const deliverLogger = this.logger.createSubLogger('deliver'); - this.queueService.webhookDeliverQueue - .on('waiting', (jobId) => webhookLogger.debug(`waiting id=${jobId}`)) + deliverQueueWorker + .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) + .on('failed', (job, err) => deliverLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) + .on('error', (err: Error) => deliverLogger.error(`error ${err}`, { e: renderError(err) })) + .on('stalled', (jobId) => deliverLogger.warn(`stalled id=${jobId}`)); + //#endregion + + //#region inbox + const inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => this.inboxProcessorService.process(job), { + ...baseQueueOptions(this.config, QUEUE.INBOX), + concurrency: this.config.inboxJobConcurrency ?? 16, + limiter: { + max: this.config.inboxJobPerSec ?? 16, + duration: 1000, + }, + settings: { + backoffStrategy: httpRelatedBackoff, + }, + }); + + const inboxLogger = this.logger.createSubLogger('inbox'); + + inboxQueueWorker + .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) + .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) + .on('failed', (job, err) => inboxLogger.warn(`failed(${err}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => inboxLogger.error(`error ${err}`, { e: renderError(err) })) + .on('stalled', (jobId) => inboxLogger.warn(`stalled id=${jobId}`)); + //#endregion + + //#region webhook deliver + const webhookDeliverQueueWorker = new Bull.Worker(QUEUE.WEBHOOK_DELIVER, (job) => this.webhookDeliverProcessorService.process(job), { + ...baseQueueOptions(this.config, QUEUE.WEBHOOK_DELIVER), + concurrency: 64, + limiter: { + max: 64, + duration: 1000, + }, + settings: { + backoffStrategy: httpRelatedBackoff, + }, + }); + + const webhookLogger = this.logger.createSubLogger('webhook'); + + webhookDeliverQueueWorker .on('active', (job) => webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) .on('completed', (job, result) => webhookLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) - .on('failed', (job, err) => webhookLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job.data.to}`)) - .on('error', (job: any, err: Error) => webhookLogger.error(`error ${err}`, { job, e: renderError(err) })) - .on('stalled', (job) => webhookLogger.warn(`stalled ${getJobInfo(job)} to=${job.data.to}`)); + .on('failed', (job, err) => webhookLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) + .on('error', (err: Error) => webhookLogger.error(`error ${err}`, { e: renderError(err) })) + .on('stalled', (jobId) => webhookLogger.warn(`stalled id=${jobId}`)); + //#endregion - this.queueService.systemQueue.add('tickCharts', { + //#region relationship + const relationshipQueueWorker = new Bull.Worker(QUEUE.RELATIONSHIP, (job) => { + switch (job.name) { + case 'follow': return this.relationshipProcessorService.processFollow(job); + case 'unfollow': return this.relationshipProcessorService.processUnfollow(job); + case 'block': return this.relationshipProcessorService.processBlock(job); + case 'unblock': return this.relationshipProcessorService.processUnblock(job); + default: throw new Error(`unrecognized job type ${job.name} for relationship`); + } }, { - repeat: { cron: '55 * * * *' }, - removeOnComplete: true, + ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP), + concurrency: this.config.relashionshipJobConcurrency ?? 16, + limiter: { + max: this.config.relashionshipJobPerSec ?? 64, + duration: 1000, + }, }); - this.queueService.systemQueue.add('resyncCharts', { - }, { - repeat: { cron: '0 0 * * *' }, - removeOnComplete: true, - }); - - this.queueService.systemQueue.add('cleanCharts', { - }, { - repeat: { cron: '0 0 * * *' }, - removeOnComplete: true, - }); - - this.queueService.systemQueue.add('aggregateRetention', { - }, { - repeat: { cron: '0 0 * * *' }, - removeOnComplete: true, - }); - - this.queueService.systemQueue.add('clean', { - }, { - repeat: { cron: '0 0 * * *' }, - removeOnComplete: true, - }); - - this.queueService.systemQueue.add('checkExpiredMutings', { - }, { - repeat: { cron: '*/5 * * * *' }, - removeOnComplete: true, - }); - - this.queueService.deliverQueue.process(this.config.deliverJobConcurrency ?? 128, (job) => this.deliverProcessorService.process(job)); - this.queueService.inboxQueue.process(this.config.inboxJobConcurrency ?? 16, (job) => this.inboxProcessorService.process(job)); - this.queueService.endedPollNotificationQueue.process((job, done) => this.endedPollNotificationProcessorService.process(job, done)); - this.queueService.webhookDeliverQueue.process(64, (job) => this.webhookDeliverProcessorService.process(job)); - - this.queueService.dbQueue.process('deleteDriveFiles', (job, done) => this.deleteDriveFilesProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportCustomEmojis', (job, done) => this.exportCustomEmojisProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportNotes', (job, done) => this.exportNotesProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportFavorites', (job, done) => this.exportFavoritesProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportFollowing', (job, done) => this.exportFollowingProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportMuting', (job, done) => this.exportMutingProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportBlocking', (job, done) => this.exportBlockingProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportUserLists', (job, done) => this.exportUserListsProcessorService.process(job, done)); - this.queueService.dbQueue.process('exportAntennas', (job, done) => this.exportAntennasProcessorService.process(job, done)); - this.queueService.dbQueue.process('importFollowing', (job, done) => this.importFollowingProcessorService.process(job, done)); - this.queueService.dbQueue.process('importFollowingToDb', (job) => this.importFollowingProcessorService.processDb(job)); - this.queueService.dbQueue.process('importMuting', (job, done) => this.importMutingProcessorService.process(job, done)); - this.queueService.dbQueue.process('importBlocking', (job, done) => this.importBlockingProcessorService.process(job, done)); - this.queueService.dbQueue.process('importBlockingToDb', (job) => this.importBlockingProcessorService.processDb(job)); - this.queueService.dbQueue.process('importUserLists', (job, done) => this.importUserListsProcessorService.process(job, done)); - this.queueService.dbQueue.process('importCustomEmojis', (job, done) => this.importCustomEmojisProcessorService.process(job, done)); - this.queueService.dbQueue.process('importAntennas', (job, done) => this.importAntennasProcessorService.process(job, done)); - this.queueService.dbQueue.process('deleteAccount', (job) => this.deleteAccountProcessorService.process(job)); - - this.queueService.objectStorageQueue.process('deleteFile', 16, (job) => this.deleteFileProcessorService.process(job)); - this.queueService.objectStorageQueue.process('cleanRemoteFiles', 16, (job, done) => this.cleanRemoteFilesProcessorService.process(job, done)); + const relationshipLogger = this.logger.createSubLogger('relationship'); - { - const maxJobs = this.config.relashionshipJobConcurrency ?? 16; - this.queueService.relationshipQueue.process('follow', maxJobs, (job) => this.relationshipProcessorService.processFollow(job)); - this.queueService.relationshipQueue.process('unfollow', maxJobs, (job) => this.relationshipProcessorService.processUnfollow(job)); - this.queueService.relationshipQueue.process('block', maxJobs, (job) => this.relationshipProcessorService.processBlock(job)); - this.queueService.relationshipQueue.process('unblock', maxJobs, (job) => this.relationshipProcessorService.processUnblock(job)); - } + relationshipQueueWorker + .on('active', (job) => relationshipLogger.debug(`active id=${job.id}`)) + .on('completed', (job, result) => relationshipLogger.debug(`completed(${result}) id=${job.id}`)) + .on('failed', (job, err) => relationshipLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => relationshipLogger.error(`error ${err}`, { e: renderError(err) })) + .on('stalled', (jobId) => relationshipLogger.warn(`stalled id=${jobId}`)); + //#endregion - this.queueService.systemQueue.process('tickCharts', (job, done) => this.tickChartsProcessorService.process(job, done)); - this.queueService.systemQueue.process('resyncCharts', (job, done) => this.resyncChartsProcessorService.process(job, done)); - this.queueService.systemQueue.process('cleanCharts', (job, done) => this.cleanChartsProcessorService.process(job, done)); - this.queueService.systemQueue.process('aggregateRetention', (job, done) => this.aggregateRetentionProcessorService.process(job, done)); - this.queueService.systemQueue.process('checkExpiredMutings', (job, done) => this.checkExpiredMutingsProcessorService.process(job, done)); - this.queueService.systemQueue.process('clean', (job, done) => this.cleanProcessorService.process(job, done)); + //#region object storage + const objectStorageQueueWorker = new Bull.Worker(QUEUE.OBJECT_STORAGE, (job) => { + switch (job.name) { + case 'deleteFile': return this.deleteFileProcessorService.process(job); + case 'cleanRemoteFiles': return this.cleanRemoteFilesProcessorService.process(job); + default: throw new Error(`unrecognized job type ${job.name} for objectStorage`); + } + }, { + ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE), + concurrency: 16, + }); + + const objectStorageLogger = this.logger.createSubLogger('objectStorage'); + + objectStorageQueueWorker + .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`)) + .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`)) + .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) + .on('error', (err: Error) => objectStorageLogger.error(`error ${err}`, { e: renderError(err) })) + .on('stalled', (jobId) => objectStorageLogger.warn(`stalled id=${jobId}`)); + //#endregion + + //#region ended poll notification + const endedPollNotificationWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => this.endedPollNotificationProcessorService.process(job), { + ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION), + }); + //#endregion } } diff --git a/packages/backend/src/queue/const.ts b/packages/backend/src/queue/const.ts new file mode 100644 index 0000000000..d240fe70e0 --- /dev/null +++ b/packages/backend/src/queue/const.ts @@ -0,0 +1,26 @@ +import { Config } from '@/config.js'; +import type * as Bull from 'bullmq'; + +export const QUEUE = { + DELIVER: 'deliver', + INBOX: 'inbox', + SYSTEM: 'system', + ENDED_POLL_NOTIFICATION: 'endedPollNotification', + DB: 'db', + RELATIONSHIP: 'relationship', + OBJECT_STORAGE: 'objectStorage', + WEBHOOK_DELIVER: 'webhookDeliver', +}; + +export function baseQueueOptions(config: Config, queueName: typeof QUEUE[keyof typeof QUEUE]): Bull.QueueOptions { + return { + connection: { + port: config.redisForJobQueue.port, + host: config.redisForJobQueue.host, + family: config.redisForJobQueue.family == null ? 0 : config.redisForJobQueue.family, + password: config.redisForJobQueue.pass, + db: config.redisForJobQueue.db ?? 0, + }, + prefix: config.redisForJobQueue.prefix ? `${config.redisForJobQueue.prefix}:queue:${queueName}` : `queue:${queueName}`, + }; +} diff --git a/packages/backend/src/queue/get-job-info.ts b/packages/backend/src/queue/get-job-info.ts deleted file mode 100644 index d33e349c36..0000000000 --- a/packages/backend/src/queue/get-job-info.ts +++ /dev/null @@ -1,15 +0,0 @@ -import Bull from 'bull'; - -export function getJobInfo(job: Bull.Job, increment = false) { - const age = Date.now() - job.timestamp; - - const formated = age > 60000 ? `${Math.floor(age / 1000 / 60)}m` - : age > 10000 ? `${Math.floor(age / 1000)}s` - : `${age}ms`; - - // onActiveとかonCompletedのattemptsMadeがなぜか0始まりなのでインクリメントする - const currentAttempts = job.attemptsMade + (increment ? 1 : 0); - const maxAttempts = job.opts ? job.opts.attempts : 0; - - return `id=${job.id} attempts=${currentAttempts}/${maxAttempts} age=${formated}`; -} diff --git a/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts b/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts index e2720b4fe0..600ce0828f 100644 --- a/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts +++ b/packages/backend/src/queue/processors/AggregateRetentionProcessorService.ts @@ -9,7 +9,7 @@ import { deepClone } from '@/misc/clone.js'; import { IdService } from '@/core/IdService.js'; import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class AggregateRetentionProcessorService { @@ -32,7 +32,7 @@ export class AggregateRetentionProcessorService { } @bindThis - public async process(job: Bull.Job<Record<string, unknown>>, done: () => void): Promise<void> { + public async process(): Promise<void> { this.logger.info('Aggregating retention...'); const now = new Date(); @@ -62,7 +62,6 @@ export class AggregateRetentionProcessorService { } catch (err) { if (isDuplicateKeyValueError(err)) { this.logger.succ('Skip because it has already been processed by another worker.'); - done(); return; } throw err; @@ -88,6 +87,5 @@ export class AggregateRetentionProcessorService { } this.logger.succ('Retention aggregated.'); - done(); } } diff --git a/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts b/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts index 2476d71a5e..c4ee212bab 100644 --- a/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts +++ b/packages/backend/src/queue/processors/CheckExpiredMutingsProcessorService.ts @@ -7,7 +7,7 @@ import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; import { UserMutingService } from '@/core/UserMutingService.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class CheckExpiredMutingsProcessorService { @@ -27,7 +27,7 @@ export class CheckExpiredMutingsProcessorService { } @bindThis - public async process(job: Bull.Job<Record<string, unknown>>, done: () => void): Promise<void> { + public async process(): Promise<void> { this.logger.info('Checking expired mutings...'); const expired = await this.mutingsRepository.createQueryBuilder('muting') @@ -41,6 +41,5 @@ export class CheckExpiredMutingsProcessorService { } this.logger.succ('All expired mutings checked.'); - done(); } } diff --git a/packages/backend/src/queue/processors/CleanChartsProcessorService.ts b/packages/backend/src/queue/processors/CleanChartsProcessorService.ts index b458167042..22d7c1b4fb 100644 --- a/packages/backend/src/queue/processors/CleanChartsProcessorService.ts +++ b/packages/backend/src/queue/processors/CleanChartsProcessorService.ts @@ -16,7 +16,7 @@ import PerUserDriveChart from '@/core/chart/charts/per-user-drive.js'; import ApRequestChart from '@/core/chart/charts/ap-request.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class CleanChartsProcessorService { @@ -45,7 +45,7 @@ export class CleanChartsProcessorService { } @bindThis - public async process(job: Bull.Job<Record<string, unknown>>, done: () => void): Promise<void> { + public async process(): Promise<void> { this.logger.info('Clean charts...'); await Promise.all([ @@ -64,6 +64,5 @@ export class CleanChartsProcessorService { ]); this.logger.succ('All charts successfully cleaned.'); - done(); } } diff --git a/packages/backend/src/queue/processors/CleanProcessorService.ts b/packages/backend/src/queue/processors/CleanProcessorService.ts index 1936e8df23..cefa6da5e9 100644 --- a/packages/backend/src/queue/processors/CleanProcessorService.ts +++ b/packages/backend/src/queue/processors/CleanProcessorService.ts @@ -7,7 +7,7 @@ import type Logger from '@/logger.js'; import { bindThis } from '@/decorators.js'; import { IdService } from '@/core/IdService.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class CleanProcessorService { @@ -36,7 +36,7 @@ export class CleanProcessorService { } @bindThis - public async process(job: Bull.Job<Record<string, unknown>>, done: () => void): Promise<void> { + public async process(): Promise<void> { this.logger.info('Cleaning...'); this.userIpsRepository.delete({ @@ -72,6 +72,5 @@ export class CleanProcessorService { } this.logger.succ('Cleaned.'); - done(); } } diff --git a/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts b/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts index 5a33c27188..c54bf59ae4 100644 --- a/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts +++ b/packages/backend/src/queue/processors/CleanRemoteFilesProcessorService.ts @@ -5,9 +5,9 @@ import type { DriveFilesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; import { DriveService } from '@/core/DriveService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; @Injectable() export class CleanRemoteFilesProcessorService { @@ -27,7 +27,7 @@ export class CleanRemoteFilesProcessorService { } @bindThis - public async process(job: Bull.Job<Record<string, unknown>>, done: () => void): Promise<void> { + public async process(job: Bull.Job<Record<string, unknown>>): Promise<void> { this.logger.info('Deleting cached remote files...'); let deletedCount = 0; @@ -47,7 +47,7 @@ export class CleanRemoteFilesProcessorService { }); if (files.length === 0) { - job.progress(100); + job.updateProgress(100); break; } @@ -62,10 +62,9 @@ export class CleanRemoteFilesProcessorService { isLink: false, }); - job.progress(deletedCount / total); + job.updateProgress(deletedCount / total); } this.logger.succ('All cached remote files has been deleted.'); - done(); } } diff --git a/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts b/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts index e36a78de6a..39dd801af0 100644 --- a/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts +++ b/packages/backend/src/queue/processors/DeleteAccountProcessorService.ts @@ -8,10 +8,10 @@ import { DriveService } from '@/core/DriveService.js'; import type { DriveFile } from '@/models/entities/DriveFile.js'; import type { Note } from '@/models/entities/Note.js'; import { EmailService } from '@/core/EmailService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbUserDeleteJobData } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbUserDeleteJobData } from '../types.js'; @Injectable() export class DeleteAccountProcessorService { diff --git a/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts b/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts index 604497cf54..6772c5dc76 100644 --- a/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts +++ b/packages/backend/src/queue/processors/DeleteDriveFilesProcessorService.ts @@ -5,10 +5,10 @@ import type { UsersRepository, DriveFilesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; import { DriveService } from '@/core/DriveService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbJobDataWithUser } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbJobDataWithUser } from '../types.js'; @Injectable() export class DeleteDriveFilesProcessorService { @@ -31,12 +31,11 @@ export class DeleteDriveFilesProcessorService { } @bindThis - public async process(job: Bull.Job<DbJobDataWithUser>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbJobDataWithUser>): Promise<void> { this.logger.info(`Deleting drive files of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -56,7 +55,7 @@ export class DeleteDriveFilesProcessorService { }); if (files.length === 0) { - job.progress(100); + job.updateProgress(100); break; } @@ -71,10 +70,9 @@ export class DeleteDriveFilesProcessorService { userId: user.id, }); - job.progress(deletedCount / total); + job.updateProgress(deletedCount / total); } this.logger.succ(`All drive files (${deletedCount}) of ${user.id} has been deleted.`); - done(); } } diff --git a/packages/backend/src/queue/processors/DeleteFileProcessorService.ts b/packages/backend/src/queue/processors/DeleteFileProcessorService.ts index 2fb2f56f8d..edf87bd921 100644 --- a/packages/backend/src/queue/processors/DeleteFileProcessorService.ts +++ b/packages/backend/src/queue/processors/DeleteFileProcessorService.ts @@ -3,10 +3,10 @@ import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; import { DriveService } from '@/core/DriveService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { ObjectStorageFileJobData } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { ObjectStorageFileJobData } from '../types.js'; @Injectable() export class DeleteFileProcessorService { diff --git a/packages/backend/src/queue/processors/DeliverProcessorService.ts b/packages/backend/src/queue/processors/DeliverProcessorService.ts index f293bd4d7e..406e9df850 100644 --- a/packages/backend/src/queue/processors/DeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/DeliverProcessorService.ts @@ -1,4 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; +import * as Bull from 'bullmq'; import { DI } from '@/di-symbols.js'; import type { DriveFilesRepository, InstancesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; @@ -16,7 +17,6 @@ import { StatusError } from '@/misc/status-error.js'; import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; import type { DeliverJobData } from '../types.js'; @Injectable() @@ -121,15 +121,13 @@ export class DeliverProcessorService { isSuspended: true, }); }); - return `${host} is gone`; + throw new Bull.UnrecoverableError(`${host} is gone`); } - // HTTPステータスコード4xxはクライアントエラーであり、それはつまり - // 何回再送しても成功することはないということなのでエラーにはしないでおく - return `${res.statusCode} ${res.statusMessage}`; + throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`); } // 5xx etc. - throw `${res.statusCode} ${res.statusMessage}`; + throw new Error(`${res.statusCode} ${res.statusMessage}`); } else { // DNS error, socket error, timeout ... throw res; diff --git a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts index 501ed4090a..21501592f2 100644 --- a/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts +++ b/packages/backend/src/queue/processors/EndedPollNotificationProcessorService.ts @@ -6,7 +6,7 @@ import type Logger from '@/logger.js'; import { NotificationService } from '@/core/NotificationService.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; import type { EndedPollNotificationJobData } from '../types.js'; @Injectable() @@ -30,10 +30,9 @@ export class EndedPollNotificationProcessorService { } @bindThis - public async process(job: Bull.Job<EndedPollNotificationJobData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<EndedPollNotificationJobData>): Promise<void> { const note = await this.notesRepository.findOneBy({ id: job.data.noteId }); if (note == null || !note.hasPoll) { - done(); return; } @@ -51,7 +50,5 @@ export class EndedPollNotificationProcessorService { noteId: note.id, }); } - - done(); } } diff --git a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts index 894903e79b..ac52325c8d 100644 --- a/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportAntennasProcessorService.ts @@ -12,7 +12,7 @@ import { createTemp } from '@/misc/create-temp.js'; import { UtilityService } from '@/core/UtilityService.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import type { DBExportAntennasData } from '../types.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class ExportAntennasProcessorService { @@ -39,10 +39,9 @@ export class ExportAntennasProcessorService { } @bindThis - public async process(job: Bull.Job<DBExportAntennasData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DBExportAntennasData>): Promise<void> { const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } const [path, cleanup] = await createTemp(); @@ -96,7 +95,6 @@ export class ExportAntennasProcessorService { this.logger.succ('Exported to: ' + driveFile.id); } finally { cleanup(); - done(); } } } diff --git a/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts b/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts index c7b54070d6..eb758e162d 100644 --- a/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportBlockingProcessorService.ts @@ -9,10 +9,10 @@ import type Logger from '@/logger.js'; import { DriveService } from '@/core/DriveService.js'; import { createTemp } from '@/misc/create-temp.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbJobDataWithUser } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbJobDataWithUser } from '../types.js'; @Injectable() export class ExportBlockingProcessorService { @@ -36,12 +36,11 @@ export class ExportBlockingProcessorService { } @bindThis - public async process(job: Bull.Job<DbJobDataWithUser>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbJobDataWithUser>): Promise<void> { this.logger.info(`Exporting blocking of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -69,7 +68,7 @@ export class ExportBlockingProcessorService { }); if (blockings.length === 0) { - job.progress(100); + job.updateProgress(100); break; } @@ -99,7 +98,7 @@ export class ExportBlockingProcessorService { blockerId: user.id, }); - job.progress(exportedCount / total); + job.updateProgress(exportedCount / total); } stream.end(); @@ -112,7 +111,5 @@ export class ExportBlockingProcessorService { } finally { cleanup(); } - - done(); } } diff --git a/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts index b50f373ef8..3203d9f3e5 100644 --- a/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportCustomEmojisProcessorService.ts @@ -13,7 +13,7 @@ import { createTemp, createTempDir } from '@/misc/create-temp.js'; import { DownloadService } from '@/core/DownloadService.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class ExportCustomEmojisProcessorService { @@ -37,12 +37,11 @@ export class ExportCustomEmojisProcessorService { } @bindThis - public async process(job: Bull.Job, done: () => void): Promise<void> { + public async process(job: Bull.Job): Promise<void> { this.logger.info('Exporting custom emojis ...'); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -117,24 +116,26 @@ export class ExportCustomEmojisProcessorService { metaStream.end(); // Create archive - const [archivePath, archiveCleanup] = await createTemp(); - const archiveStream = fs.createWriteStream(archivePath); - const archive = archiver('zip', { - zlib: { level: 0 }, - }); - archiveStream.on('close', async () => { - this.logger.succ(`Exported to: ${archivePath}`); + await new Promise<void>(async (resolve) => { + const [archivePath, archiveCleanup] = await createTemp(); + const archiveStream = fs.createWriteStream(archivePath); + const archive = archiver('zip', { + zlib: { level: 0 }, + }); + archiveStream.on('close', async () => { + this.logger.succ(`Exported to: ${archivePath}`); - const fileName = 'custom-emojis-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.zip'; - const driveFile = await this.driveService.addFile({ user, path: archivePath, name: fileName, force: true }); + const fileName = 'custom-emojis-' + dateFormat(new Date(), 'yyyy-MM-dd-HH-mm-ss') + '.zip'; + const driveFile = await this.driveService.addFile({ user, path: archivePath, name: fileName, force: true }); - this.logger.succ(`Exported to: ${driveFile.id}`); - cleanup(); - archiveCleanup(); - done(); + this.logger.succ(`Exported to: ${driveFile.id}`); + cleanup(); + archiveCleanup(); + resolve(); + }); + archive.pipe(archiveStream); + archive.directory(path, false); + archive.finalize(); }); - archive.pipe(archiveStream); - archive.directory(path, false); - archive.finalize(); } } diff --git a/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts b/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts index f2f2383a88..76c38a6b86 100644 --- a/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportFavoritesProcessorService.ts @@ -12,7 +12,7 @@ import type { Poll } from '@/models/entities/Poll.js'; import type { Note } from '@/models/entities/Note.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; import type { DbJobDataWithUser } from '../types.js'; @Injectable() @@ -42,12 +42,11 @@ export class ExportFavoritesProcessorService { } @bindThis - public async process(job: Bull.Job<DbJobDataWithUser>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbJobDataWithUser>): Promise<void> { this.logger.info(`Exporting favorites of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -91,7 +90,7 @@ export class ExportFavoritesProcessorService { }) as (NoteFavorite & { note: Note & { user: User } })[]; if (favorites.length === 0) { - job.progress(100); + job.updateProgress(100); break; } @@ -112,7 +111,7 @@ export class ExportFavoritesProcessorService { userId: user.id, }); - job.progress(exportedFavoritesCount / total); + job.updateProgress(exportedFavoritesCount / total); } await write(']'); @@ -127,8 +126,6 @@ export class ExportFavoritesProcessorService { } finally { cleanup(); } - - done(); } } diff --git a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts index fa9c1ac1ea..8726cb1402 100644 --- a/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportFollowingProcessorService.ts @@ -10,10 +10,10 @@ import { DriveService } from '@/core/DriveService.js'; import { createTemp } from '@/misc/create-temp.js'; import type { Following } from '@/models/entities/Following.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbExportFollowingData } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbExportFollowingData } from '../types.js'; @Injectable() export class ExportFollowingProcessorService { @@ -40,12 +40,11 @@ export class ExportFollowingProcessorService { } @bindThis - public async process(job: Bull.Job<DbExportFollowingData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbExportFollowingData>): Promise<void> { this.logger.info(`Exporting following of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -116,7 +115,5 @@ export class ExportFollowingProcessorService { } finally { cleanup(); } - - done(); } } diff --git a/packages/backend/src/queue/processors/ExportMutingProcessorService.ts b/packages/backend/src/queue/processors/ExportMutingProcessorService.ts index b14bf5f5b1..0f11a9e843 100644 --- a/packages/backend/src/queue/processors/ExportMutingProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportMutingProcessorService.ts @@ -9,10 +9,10 @@ import type Logger from '@/logger.js'; import { DriveService } from '@/core/DriveService.js'; import { createTemp } from '@/misc/create-temp.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbJobDataWithUser } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbJobDataWithUser } from '../types.js'; @Injectable() export class ExportMutingProcessorService { @@ -39,12 +39,11 @@ export class ExportMutingProcessorService { } @bindThis - public async process(job: Bull.Job<DbJobDataWithUser>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbJobDataWithUser>): Promise<void> { this.logger.info(`Exporting muting of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -73,7 +72,7 @@ export class ExportMutingProcessorService { }); if (mutes.length === 0) { - job.progress(100); + job.updateProgress(100); break; } @@ -103,7 +102,7 @@ export class ExportMutingProcessorService { muterId: user.id, }); - job.progress(exportedCount / total); + job.updateProgress(exportedCount / total); } stream.end(); @@ -116,7 +115,5 @@ export class ExportMutingProcessorService { } finally { cleanup(); } - - done(); } } diff --git a/packages/backend/src/queue/processors/ExportNotesProcessorService.ts b/packages/backend/src/queue/processors/ExportNotesProcessorService.ts index e4f12ad101..24fb331883 100644 --- a/packages/backend/src/queue/processors/ExportNotesProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportNotesProcessorService.ts @@ -12,7 +12,7 @@ import type { Poll } from '@/models/entities/Poll.js'; import type { Note } from '@/models/entities/Note.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; import type { DbJobDataWithUser } from '../types.js'; @Injectable() @@ -39,12 +39,11 @@ export class ExportNotesProcessorService { } @bindThis - public async process(job: Bull.Job<DbJobDataWithUser>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbJobDataWithUser>): Promise<void> { this.logger.info(`Exporting notes of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -87,7 +86,7 @@ export class ExportNotesProcessorService { }) as Note[]; if (notes.length === 0) { - job.progress(100); + job.updateProgress(100); break; } @@ -108,7 +107,7 @@ export class ExportNotesProcessorService { userId: user.id, }); - job.progress(exportedNotesCount / total); + job.updateProgress(exportedNotesCount / total); } await write(']'); @@ -123,8 +122,6 @@ export class ExportNotesProcessorService { } finally { cleanup(); } - - done(); } } diff --git a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts index 54bde44044..ec63358053 100644 --- a/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts +++ b/packages/backend/src/queue/processors/ExportUserListsProcessorService.ts @@ -9,10 +9,10 @@ import type Logger from '@/logger.js'; import { DriveService } from '@/core/DriveService.js'; import { createTemp } from '@/misc/create-temp.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbJobDataWithUser } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbJobDataWithUser } from '../types.js'; @Injectable() export class ExportUserListsProcessorService { @@ -39,12 +39,11 @@ export class ExportUserListsProcessorService { } @bindThis - public async process(job: Bull.Job<DbJobDataWithUser>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbJobDataWithUser>): Promise<void> { this.logger.info(`Exporting user lists of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -92,7 +91,5 @@ export class ExportUserListsProcessorService { } finally { cleanup(); } - - done(); } } diff --git a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts index d06131b8c8..575cad69d5 100644 --- a/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportAntennasProcessorService.ts @@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; import { DBAntennaImportJobData } from '../types.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; const validate = new Ajv().compile({ type: 'object', @@ -59,7 +59,7 @@ export class ImportAntennasProcessorService { } @bindThis - public async process(job: Bull.Job<DBAntennaImportJobData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DBAntennaImportJobData>): Promise<void> { const now = new Date(); try { for (const antenna of job.data.antenna) { @@ -89,8 +89,6 @@ export class ImportAntennasProcessorService { } } catch (err: any) { this.logger.error(err); - } finally { - done(); } } } diff --git a/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts b/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts index 3f075b02d2..2f1a9e5b03 100644 --- a/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportBlockingProcessorService.ts @@ -7,11 +7,11 @@ import * as Acct from '@/misc/acct.js'; import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js'; import { DownloadService } from '@/core/DownloadService.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbUserImportJobData, DbUserImportToDbJobData } from '../types.js'; import { bindThis } from '@/decorators.js'; import { QueueService } from '@/core/QueueService.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbUserImportJobData, DbUserImportToDbJobData } from '../types.js'; @Injectable() export class ImportBlockingProcessorService { @@ -34,12 +34,11 @@ export class ImportBlockingProcessorService { } @bindThis - public async process(job: Bull.Job<DbUserImportJobData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbUserImportJobData>): Promise<void> { this.logger.info(`Importing blocking of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -47,7 +46,6 @@ export class ImportBlockingProcessorService { id: job.data.fileId, }); if (file == null) { - done(); return; } @@ -56,7 +54,6 @@ export class ImportBlockingProcessorService { this.queueService.createImportBlockingToDbJob({ id: user.id }, targets); this.logger.succ('Import jobs created'); - done(); } @bindThis @@ -85,7 +82,7 @@ export class ImportBlockingProcessorService { } if (target == null) { - throw `Unable to resolve user: @${username}@${host}`; + throw new Error(`Unable to resolve user: @${username}@${host}`); } // skip myself diff --git a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts index 600468a286..d862567871 100644 --- a/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportCustomEmojisProcessorService.ts @@ -12,7 +12,7 @@ import { DriveService } from '@/core/DriveService.js'; import { DownloadService } from '@/core/DownloadService.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; import type { DbUserImportJobData } from '../types.js'; // TODO: 名前衝突時の動作を選べるようにする @@ -45,14 +45,13 @@ export class ImportCustomEmojisProcessorService { } @bindThis - public async process(job: Bull.Job<DbUserImportJobData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbUserImportJobData>): Promise<void> { this.logger.info('Importing custom emojis ...'); const file = await this.driveFilesRepository.findOneBy({ id: job.data.fileId, }); if (file == null) { - done(); return; } @@ -116,7 +115,6 @@ export class ImportCustomEmojisProcessorService { cleanup(); this.logger.succ('Imported'); - done(); }); unzipStream.pipe(extractor); this.logger.succ(`Unzipping to ${outputPath}`); diff --git a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts index aa5cf12c50..15bee9672e 100644 --- a/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportFollowingProcessorService.ts @@ -7,11 +7,11 @@ import * as Acct from '@/misc/acct.js'; import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js'; import { DownloadService } from '@/core/DownloadService.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbUserImportJobData, DbUserImportToDbJobData } from '../types.js'; import { bindThis } from '@/decorators.js'; import { QueueService } from '@/core/QueueService.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbUserImportJobData, DbUserImportToDbJobData } from '../types.js'; @Injectable() export class ImportFollowingProcessorService { @@ -34,12 +34,11 @@ export class ImportFollowingProcessorService { } @bindThis - public async process(job: Bull.Job<DbUserImportJobData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbUserImportJobData>): Promise<void> { this.logger.info(`Importing following of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -47,7 +46,6 @@ export class ImportFollowingProcessorService { id: job.data.fileId, }); if (file == null) { - done(); return; } @@ -56,7 +54,6 @@ export class ImportFollowingProcessorService { this.queueService.createImportFollowingToDbJob({ id: user.id }, targets); this.logger.succ('Import jobs created'); - done(); } @bindThis @@ -85,7 +82,7 @@ export class ImportFollowingProcessorService { } if (target == null) { - throw `Unable to resolve user: @${username}@${host}`; + throw new Error(`Unable to resolve user: @${username}@${host}`); } // skip myself diff --git a/packages/backend/src/queue/processors/ImportMutingProcessorService.ts b/packages/backend/src/queue/processors/ImportMutingProcessorService.ts index 379994ee79..723935cd31 100644 --- a/packages/backend/src/queue/processors/ImportMutingProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportMutingProcessorService.ts @@ -9,10 +9,10 @@ import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js'; import { DownloadService } from '@/core/DownloadService.js'; import { UserMutingService } from '@/core/UserMutingService.js'; import { UtilityService } from '@/core/UtilityService.js'; -import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; -import type { DbUserImportJobData } from '../types.js'; import { bindThis } from '@/decorators.js'; +import { QueueLoggerService } from '../QueueLoggerService.js'; +import type * as Bull from 'bullmq'; +import type { DbUserImportJobData } from '../types.js'; @Injectable() export class ImportMutingProcessorService { @@ -38,12 +38,11 @@ export class ImportMutingProcessorService { } @bindThis - public async process(job: Bull.Job<DbUserImportJobData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbUserImportJobData>): Promise<void> { this.logger.info(`Importing muting of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -51,7 +50,6 @@ export class ImportMutingProcessorService { id: job.data.fileId, }); if (file == null) { - done(); return; } @@ -83,7 +81,7 @@ export class ImportMutingProcessorService { } if (target == null) { - throw `cannot resolve user: @${username}@${host}`; + throw new Error(`cannot resolve user: @${username}@${host}`); } // skip myself @@ -98,6 +96,5 @@ export class ImportMutingProcessorService { } this.logger.succ('Imported'); - done(); } } diff --git a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts index c423863410..824ee8157a 100644 --- a/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts +++ b/packages/backend/src/queue/processors/ImportUserListsProcessorService.ts @@ -12,7 +12,7 @@ import { IdService } from '@/core/IdService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; import type { DbUserImportJobData } from '../types.js'; @Injectable() @@ -46,12 +46,11 @@ export class ImportUserListsProcessorService { } @bindThis - public async process(job: Bull.Job<DbUserImportJobData>, done: () => void): Promise<void> { + public async process(job: Bull.Job<DbUserImportJobData>): Promise<void> { this.logger.info(`Importing user lists of ${job.data.user.id} ...`); const user = await this.usersRepository.findOneBy({ id: job.data.user.id }); if (user == null) { - done(); return; } @@ -59,7 +58,6 @@ export class ImportUserListsProcessorService { id: job.data.fileId, }); if (file == null) { - done(); return; } @@ -109,6 +107,5 @@ export class ImportUserListsProcessorService { } this.logger.succ('Imported'); - done(); } } diff --git a/packages/backend/src/queue/processors/InboxProcessorService.ts b/packages/backend/src/queue/processors/InboxProcessorService.ts index ab8b1e9e22..ce1d7aaa1b 100644 --- a/packages/backend/src/queue/processors/InboxProcessorService.ts +++ b/packages/backend/src/queue/processors/InboxProcessorService.ts @@ -1,8 +1,8 @@ import { URL } from 'node:url'; import { Inject, Injectable } from '@nestjs/common'; import httpSignature from '@peertube/http-signature'; +import * as Bull from 'bullmq'; import { DI } from '@/di-symbols.js'; -import type { InstancesRepository, DriveFilesRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; import type Logger from '@/logger.js'; import { MetaService } from '@/core/MetaService.js'; @@ -23,10 +23,8 @@ import { LdSignatureService } from '@/core/activitypub/LdSignatureService.js'; import { ApInboxService } from '@/core/activitypub/ApInboxService.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; import type { InboxJobData } from '../types.js'; -// ユーザーのinboxにアクティビティが届いた時の処理 @Injectable() export class InboxProcessorService { private logger: Logger; @@ -35,12 +33,6 @@ export class InboxProcessorService { @Inject(DI.config) private config: Config, - @Inject(DI.instancesRepository) - private instancesRepository: InstancesRepository, - - @Inject(DI.driveFilesRepository) - private driveFilesRepository: DriveFilesRepository, - private utilityService: UtilityService, private metaService: MetaService, private apInboxService: ApInboxService, @@ -93,24 +85,24 @@ export class InboxProcessorService { try { authUser = await this.apDbResolverService.getAuthUserFromApId(getApId(activity.actor)); } catch (err) { - // 対象が4xxならスキップ + // 対象が4xxならスキップ if (err instanceof StatusError) { if (err.isClientError) { - return `skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`; + throw new Bull.UnrecoverableError(`skip: Ignored deleted actors on both ends ${activity.actor} - ${err.statusCode}`); } - throw `Error in actor ${activity.actor} - ${err.statusCode ?? err}`; + throw new Error(`Error in actor ${activity.actor} - ${err.statusCode ?? err}`); } } } // それでもわからなければ終了 if (authUser == null) { - return 'skip: failed to resolve user'; + throw new Bull.UnrecoverableError('skip: failed to resolve user'); } // publicKey がなくても終了 if (authUser.key == null) { - return 'skip: failed to resolve user publicKey'; + throw new Bull.UnrecoverableError('skip: failed to resolve user publicKey'); } // HTTP-Signatureの検証 @@ -118,10 +110,10 @@ export class InboxProcessorService { // また、signatureのsignerは、activity.actorと一致する必要がある if (!httpSignatureValidated || authUser.user.uri !== activity.actor) { - // 一致しなくても、でもLD-Signatureがありそうならそっちも見る + // 一致しなくても、でもLD-Signatureがありそうならそっちも見る if (activity.signature) { if (activity.signature.type !== 'RsaSignature2017') { - return `skip: unsupported LD-signature type ${activity.signature.type}`; + throw new Bull.UnrecoverableError(`skip: unsupported LD-signature type ${activity.signature.type}`); } // activity.signature.creator: https://example.oom/users/user#main-key @@ -134,32 +126,32 @@ export class InboxProcessorService { // keyIdからLD-Signatureのユーザーを取得 authUser = await this.apDbResolverService.getAuthUserFromKeyId(activity.signature.creator); if (authUser == null) { - return 'skip: LD-Signatureのユーザーが取得できませんでした'; + throw new Bull.UnrecoverableError('skip: LD-Signatureのユーザーが取得できませんでした'); } if (authUser.key == null) { - return 'skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした'; + throw new Bull.UnrecoverableError('skip: LD-SignatureのユーザーはpublicKeyを持っていませんでした'); } // LD-Signature検証 const ldSignature = this.ldSignatureService.use(); const verified = await ldSignature.verifyRsaSignature2017(activity, authUser.key.keyPem).catch(() => false); if (!verified) { - return 'skip: LD-Signatureの検証に失敗しました'; + throw new Bull.UnrecoverableError('skip: LD-Signatureの検証に失敗しました'); } // もう一度actorチェック if (authUser.user.uri !== activity.actor) { - return `skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${activity.actor})`; + throw new Bull.UnrecoverableError(`skip: LD-Signature user(${authUser.user.uri}) !== activity.actor(${activity.actor})`); } // ブロックしてたら中断 const ldHost = this.utilityService.extractDbHost(authUser.user.uri); if (this.utilityService.isBlockedHost(meta.blockedHosts, ldHost)) { - return `Blocked request: ${ldHost}`; + throw new Bull.UnrecoverableError(`Blocked request: ${ldHost}`); } } else { - return `skip: http-signature verification failed and no LD-Signature. keyId=${signature.keyId}`; + throw new Bull.UnrecoverableError(`skip: http-signature verification failed and no LD-Signature. keyId=${signature.keyId}`); } } @@ -168,7 +160,7 @@ export class InboxProcessorService { const signerHost = this.utilityService.extractDbHost(authUser.user.uri!); const activityIdHost = this.utilityService.extractDbHost(activity.id); if (signerHost !== activityIdHost) { - return `skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`; + throw new Bull.UnrecoverableError(`skip: signerHost(${signerHost}) !== activity.id host(${activityIdHost}`); } } diff --git a/packages/backend/src/queue/processors/RelationshipProcessorService.ts b/packages/backend/src/queue/processors/RelationshipProcessorService.ts index ff454df455..722260d948 100644 --- a/packages/backend/src/queue/processors/RelationshipProcessorService.ts +++ b/packages/backend/src/queue/processors/RelationshipProcessorService.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; import { UserFollowingService } from '@/core/UserFollowingService.js'; import { UserBlockingService } from '@/core/UserBlockingService.js'; diff --git a/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts b/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts index e5840f3da8..eab8e1e68d 100644 --- a/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts +++ b/packages/backend/src/queue/processors/ResyncChartsProcessorService.ts @@ -15,7 +15,7 @@ import PerUserDriveChart from '@/core/chart/charts/per-user-drive.js'; import ApRequestChart from '@/core/chart/charts/ap-request.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class ResyncChartsProcessorService { @@ -43,7 +43,7 @@ export class ResyncChartsProcessorService { } @bindThis - public async process(job: Bull.Job<Record<string, unknown>>, done: () => void): Promise<void> { + public async process(): Promise<void> { this.logger.info('Resync charts...'); // TODO: ユーザーごとのチャートも更新する @@ -55,6 +55,5 @@ export class ResyncChartsProcessorService { ]); this.logger.succ('All charts successfully resynced.'); - done(); } } diff --git a/packages/backend/src/queue/processors/TickChartsProcessorService.ts b/packages/backend/src/queue/processors/TickChartsProcessorService.ts index 7ff84c15a5..f1696bf567 100644 --- a/packages/backend/src/queue/processors/TickChartsProcessorService.ts +++ b/packages/backend/src/queue/processors/TickChartsProcessorService.ts @@ -16,7 +16,7 @@ import PerUserDriveChart from '@/core/chart/charts/per-user-drive.js'; import ApRequestChart from '@/core/chart/charts/ap-request.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; +import type * as Bull from 'bullmq'; @Injectable() export class TickChartsProcessorService { @@ -45,7 +45,7 @@ export class TickChartsProcessorService { } @bindThis - public async process(job: Bull.Job<Record<string, unknown>>, done: () => void): Promise<void> { + public async process(): Promise<void> { this.logger.info('Tick charts...'); await Promise.all([ @@ -64,6 +64,5 @@ export class TickChartsProcessorService { ]); this.logger.succ('All charts successfully ticked.'); - done(); } } diff --git a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts index 84a5c21c49..8b40c16749 100644 --- a/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts +++ b/packages/backend/src/queue/processors/WebhookDeliverProcessorService.ts @@ -1,4 +1,5 @@ import { Inject, Injectable } from '@nestjs/common'; +import * as Bull from 'bullmq'; import { DI } from '@/di-symbols.js'; import type { WebhooksRepository } from '@/models/index.js'; import type { Config } from '@/config.js'; @@ -7,7 +8,6 @@ import { HttpRequestService } from '@/core/HttpRequestService.js'; import { StatusError } from '@/misc/status-error.js'; import { bindThis } from '@/decorators.js'; import { QueueLoggerService } from '../QueueLoggerService.js'; -import type Bull from 'bull'; import type { WebhookDeliverJobData } from '../types.js'; @Injectable() @@ -66,11 +66,11 @@ export class WebhookDeliverProcessorService { if (res instanceof StatusError) { // 4xx if (res.isClientError) { - return `${res.statusCode} ${res.statusMessage}`; + throw new Bull.UnrecoverableError(`${res.statusCode} ${res.statusMessage}`); } // 5xx etc. - throw `${res.statusCode} ${res.statusMessage}`; + throw new Error(`${res.statusCode} ${res.statusMessage}`); } else { // DNS error, socket error, timeout ... throw res; diff --git a/packages/backend/src/server/api/endpoints/admin/relays/add.ts b/packages/backend/src/server/api/endpoints/admin/relays/add.ts index f12738bd3a..f2d4aa8996 100644 --- a/packages/backend/src/server/api/endpoints/admin/relays/add.ts +++ b/packages/backend/src/server/api/endpoints/admin/relays/add.ts @@ -62,7 +62,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { ) { super(meta, paramDef, async (ps, me) => { try { - if (new URL(ps.inbox).protocol !== 'https:') throw 'https only'; + if (new URL(ps.inbox).protocol !== 'https:') throw new Error('https only'); } catch { throw new ApiError(meta.errors.invalidUrl); } diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index 2956bf1cbd..742df0ca95 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -82,14 +82,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { try { if (ps.tag) { - if (!safeForSql(normalizeForSearch(ps.tag))) throw 'Injection'; + if (!safeForSql(normalizeForSearch(ps.tag))) throw new Error('Injection'); query.andWhere(`'{"${normalizeForSearch(ps.tag)}"}' <@ note.tags`); } else { query.andWhere(new Brackets(qb => { for (const tags of ps.query!) { qb.orWhere(new Brackets(qb => { for (const tag of tags) { - if (!safeForSql(normalizeForSearch(tag))) throw 'Injection'; + if (!safeForSql(normalizeForSearch(tag))) throw new Error('Injection'); qb.andWhere(`'{"${normalizeForSearch(tag)}"}' <@ note.tags`); } })); diff --git a/packages/backend/src/server/api/endpoints/reset-db.ts b/packages/backend/src/server/api/endpoints/reset-db.ts index 4ced6d3ff1..1d4825f812 100644 --- a/packages/backend/src/server/api/endpoints/reset-db.ts +++ b/packages/backend/src/server/api/endpoints/reset-db.ts @@ -34,7 +34,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { private redisClient: Redis.Redis, ) { super(meta, paramDef, async (ps, me) => { - if (process.env.NODE_ENV !== 'test') throw 'NODE_ENV is not a test'; + if (process.env.NODE_ENV !== 'test') throw new Error('NODE_ENV is not a test'); await redisClient.flushdb(); await resetDb(this.db); diff --git a/packages/backend/test/misc/mock-resolver.ts b/packages/backend/test/misc/mock-resolver.ts index 6b31e68616..a7bcd859ae 100644 --- a/packages/backend/test/misc/mock-resolver.ts +++ b/packages/backend/test/misc/mock-resolver.ts @@ -52,11 +52,7 @@ export class MockResolver extends Resolver { const r = this._rs.get(value); if (!r) { - throw { - name: 'StatusError', - statusCode: 404, - message: 'Not registed for mock', - }; + throw new Error('Not registed for mock'); } const object = JSON.parse(r.content); diff --git a/packages/backend/test/utils.ts b/packages/backend/test/utils.ts index 1a4a0b3545..22f7d81e4e 100644 --- a/packages/backend/test/utils.ts +++ b/packages/backend/test/utils.ts @@ -478,7 +478,7 @@ export async function testPaginationConsistency<Entity extends { id: string, cre } export async function initTestDb(justBorrow = false, initEntities?: any[]) { - if (process.env.NODE_ENV !== 'test') throw 'NODE_ENV is not a test'; + if (process.env.NODE_ENV !== 'test') throw new Error('NODE_ENV is not a test'); const db = new DataSource({ type: 'postgres', diff --git a/packages/frontend/src/scripts/time.ts b/packages/frontend/src/scripts/time.ts index 34e8b6b17c..b21978b186 100644 --- a/packages/frontend/src/scripts/time.ts +++ b/packages/frontend/src/scripts/time.ts @@ -5,15 +5,16 @@ const dateTimeIntervals = { }; export function dateUTC(time: number[]): Date { - const d = time.length === 2 ? Date.UTC(time[0], time[1]) - : time.length === 3 ? Date.UTC(time[0], time[1], time[2]) - : time.length === 4 ? Date.UTC(time[0], time[1], time[2], time[3]) - : time.length === 5 ? Date.UTC(time[0], time[1], time[2], time[3], time[4]) - : time.length === 6 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5]) - : time.length === 7 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5], time[6]) - : null; + const d = + time.length === 2 ? Date.UTC(time[0], time[1]) + : time.length === 3 ? Date.UTC(time[0], time[1], time[2]) + : time.length === 4 ? Date.UTC(time[0], time[1], time[2], time[3]) + : time.length === 5 ? Date.UTC(time[0], time[1], time[2], time[3], time[4]) + : time.length === 6 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5]) + : time.length === 7 ? Date.UTC(time[0], time[1], time[2], time[3], time[4], time[5], time[6]) + : null; - if (!d) throw 'wrong number of arguments'; + if (!d) throw new Error('wrong number of arguments'); return new Date(d); } diff --git a/packages/shared/.eslintrc.js b/packages/shared/.eslintrc.js index 7c979a93dc..a53ad17894 100644 --- a/packages/shared/.eslintrc.js +++ b/packages/shared/.eslintrc.js @@ -49,7 +49,7 @@ module.exports = { 'no-multi-spaces': ['error'], 'no-var': ['error'], 'prefer-arrow-callback': ['error'], - 'no-throw-literal': ['warn'], + 'no-throw-literal': ['error'], 'no-param-reassign': ['warn'], 'no-constant-condition': ['warn'], 'no-empty-pattern': ['warn'], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ab17897f1..7930458cb0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -145,9 +145,9 @@ importers: blurhash: specifier: 2.0.5 version: 2.0.5 - bull: - specifier: 4.10.4 - version: 4.10.4 + bullmq: + specifier: 3.14.1 + version: 3.14.1 cacheable-lookup: specifier: 6.1.0 version: 6.1.0 @@ -489,9 +489,6 @@ importers: '@types/bcryptjs': specifier: 2.4.2 version: 2.4.2 - '@types/bull': - specifier: 4.10.0 - version: 4.10.0 '@types/cbor': specifier: 6.0.0 version: 6.0.0 @@ -3956,6 +3953,7 @@ packages: /@ioredis/commands@1.2.0: resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} + dev: false /@istanbuljs/load-nyc-config@1.1.0: resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} @@ -4364,46 +4362,52 @@ packages: os-filter-obj: 2.0.0 dev: false - /@msgpackr-extract/msgpackr-extract-darwin-arm64@2.2.0: - resolution: {integrity: sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==} + /@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2: + resolution: {integrity: sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==} cpu: [arm64] os: [darwin] requiresBuild: true + dev: false optional: true - /@msgpackr-extract/msgpackr-extract-darwin-x64@2.2.0: - resolution: {integrity: sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==} + /@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2: + resolution: {integrity: sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==} cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true - /@msgpackr-extract/msgpackr-extract-linux-arm64@2.2.0: - resolution: {integrity: sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==} + /@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2: + resolution: {integrity: sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==} cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true - /@msgpackr-extract/msgpackr-extract-linux-arm@2.2.0: - resolution: {integrity: sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==} + /@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2: + resolution: {integrity: sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==} cpu: [arm] os: [linux] requiresBuild: true + dev: false optional: true - /@msgpackr-extract/msgpackr-extract-linux-x64@2.2.0: - resolution: {integrity: sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==} + /@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2: + resolution: {integrity: sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==} cpu: [x64] os: [linux] requiresBuild: true + dev: false optional: true - /@msgpackr-extract/msgpackr-extract-win32-x64@2.2.0: - resolution: {integrity: sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==} + /@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2: + resolution: {integrity: sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==} cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@mswjs/cookies@0.2.2: @@ -6511,14 +6515,6 @@ packages: resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==} dev: true - /@types/bull@4.10.0: - resolution: {integrity: sha512-RkYW8K2H3J76HT6twmHYbzJ0GtLDDotpLP9ah9gtiA7zfF6peBH1l5fEiK0oeIZ3/642M7Jcb9sPmor8Vf4w6g==} - dependencies: - bull: 4.10.4 - transitivePeerDependencies: - - supports-color - dev: true - /@types/cacheable-request@6.0.3: resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} dependencies: @@ -8708,20 +8704,20 @@ packages: node-gyp-build: 4.6.0 dev: false - /bull@4.10.4: - resolution: {integrity: sha512-o9m/7HjS/Or3vqRd59evBlWCXd9Lp+ALppKseoSKHaykK46SmRjAilX98PgmOz1yeVaurt8D5UtvEt4bUjM3eA==} - engines: {node: '>=12'} + /bullmq@3.14.1: + resolution: {integrity: sha512-Fom78UKljYsnJmwbROVPx3eFLuVfQjQbw9KCnVupLzT31RQHhFHV2xd/4J4oWl4u34bZ1JmEUfNnqNBz+IOJuA==} dependencies: - cron-parser: 4.7.1 - debuglog: 1.0.1 - get-port: 5.1.1 + cron-parser: 4.8.1 + glob: 8.1.0 ioredis: 5.3.2 lodash: 4.17.21 - msgpackr: 1.8.1 + msgpackr: 1.9.2 semver: 7.5.1 - uuid: 8.3.2 + tslib: 2.5.2 + uuid: 9.0.0 transitivePeerDependencies: - supports-color + dev: false /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} @@ -9306,6 +9302,7 @@ packages: /cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + dev: false /co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} @@ -9607,11 +9604,12 @@ packages: readable-stream: 3.6.0 dev: false - /cron-parser@4.7.1: - resolution: {integrity: sha512-WguFaoQ0hQ61SgsCZLHUcNbAvlK0lypKXu62ARguefYmjzaOXIVRNrAmyXzabTwUn4sQvQLkk6bjH+ipGfw8bA==} + /cron-parser@4.8.1: + resolution: {integrity: sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==} engines: {node: '>=12.0.0'} dependencies: - luxon: 3.2.1 + luxon: 3.3.0 + dev: false /cropperjs@2.0.0-beta.2: resolution: {integrity: sha512-jDRSODDGKmi9vp3p/+WXkxMqV/AE+GpSld1U3cHZDRdLy9UykRzurSe8k1dR0TExn45ygCMrv31qkg+K3EeXXw==} @@ -9890,9 +9888,6 @@ packages: ms: 2.1.2 supports-color: 8.1.1 - /debuglog@1.0.1: - resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} - /decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -10084,6 +10079,7 @@ packages: /denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} + dev: false /depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} @@ -11753,6 +11749,7 @@ packages: /get-port@5.1.1: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} engines: {node: '>=8'} + dev: true /get-stream@3.0.0: resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} @@ -12606,6 +12603,7 @@ packages: standard-as-callback: 2.1.0 transitivePeerDependencies: - supports-color + dev: false /iota-array@1.0.0: resolution: {integrity: sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==} @@ -14288,6 +14286,7 @@ packages: /lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false /lodash.difference@4.5.0: resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} @@ -14319,6 +14318,7 @@ packages: /lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + dev: false /lodash.isempty@4.4.0: resolution: {integrity: sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==} @@ -14472,9 +14472,10 @@ packages: engines: {node: '>=16.14'} dev: true - /luxon@3.2.1: - resolution: {integrity: sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==} + /luxon@3.3.0: + resolution: {integrity: sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==} engines: {node: '>=12'} + dev: false /lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} @@ -14950,24 +14951,27 @@ packages: engines: {node: '>=12.13'} dev: false - /msgpackr-extract@2.2.0: - resolution: {integrity: sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==} + /msgpackr-extract@3.0.2: + resolution: {integrity: sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==} + hasBin: true requiresBuild: true dependencies: - node-gyp-build-optional-packages: 5.0.3 + node-gyp-build-optional-packages: 5.0.7 optionalDependencies: - '@msgpackr-extract/msgpackr-extract-darwin-arm64': 2.2.0 - '@msgpackr-extract/msgpackr-extract-darwin-x64': 2.2.0 - '@msgpackr-extract/msgpackr-extract-linux-arm': 2.2.0 - '@msgpackr-extract/msgpackr-extract-linux-arm64': 2.2.0 - '@msgpackr-extract/msgpackr-extract-linux-x64': 2.2.0 - '@msgpackr-extract/msgpackr-extract-win32-x64': 2.2.0 + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.2 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.2 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.2 + dev: false optional: true - /msgpackr@1.8.1: - resolution: {integrity: sha512-05fT4J8ZqjYlR4QcRDIhLCYKUOHXk7C/xa62GzMKj74l3up9k2QZ3LgFc6qWdsPHl91QA2WLWqWc8b8t7GLNNw==} + /msgpackr@1.9.2: + resolution: {integrity: sha512-xtDgI3Xv0AAiZWLRGDchyzBwU6aq0rwJ+W+5Y4CZhEWtkl/hJtFFLc+3JtGTw7nz1yquxs7nL8q/yA2aqpflIQ==} optionalDependencies: - msgpackr-extract: 2.2.0 + msgpackr-extract: 3.0.2 + dev: false /msw-storybook-addon@1.8.0(msw@1.2.1): resolution: {integrity: sha512-dw3vZwqjixmiur0vouRSOax7wPSu9Og2Hspy9JZFHf49bZRjwDiLF0Pfn2NXEkGviYJOJiGxS1ejoTiUwoSg4A==} @@ -15219,8 +15223,10 @@ packages: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 - /node-gyp-build-optional-packages@5.0.3: - resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} + /node-gyp-build-optional-packages@5.0.7: + resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==} + hasBin: true + dev: false optional: true /node-gyp-build@4.6.0: @@ -17252,6 +17258,7 @@ packages: /redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} engines: {node: '>=4'} + dev: false /redis-info@3.1.0: resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==} @@ -17269,6 +17276,7 @@ packages: engines: {node: '>=4'} dependencies: redis-errors: 1.2.0 + dev: false /redis@4.5.1: resolution: {integrity: sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==} @@ -18395,6 +18403,7 @@ packages: /standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} + dev: false /start-server-and-test@2.0.0: resolution: {integrity: sha512-UqKLw0mJbfrsG1jcRLTUlvuRi9sjNuUiDOLI42r7R5fA9dsFoywAy9DoLXNYys9B886E4RCKb+qM1Gzu96h7DQ==} From b6f21b6edb95882d1616c36ed7eeb1f78809e2f6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 13:21:26 +0900 Subject: [PATCH 103/213] refactor --- packages/backend/src/GlobalModule.ts | 6 +++++- packages/backend/src/core/AntennaService.ts | 15 ++++++++++----- packages/backend/src/core/CacheService.ts | 7 ++++++- packages/backend/src/core/MetaService.ts | 7 ++++++- packages/backend/src/core/NoteCreateService.ts | 8 +++++++- packages/backend/src/core/NoteReadService.ts | 8 +++++++- packages/backend/src/core/NotificationService.ts | 8 +++++++- packages/backend/src/core/QueueModule.ts | 6 +++++- packages/backend/src/core/RoleService.ts | 7 ++++++- packages/backend/src/core/WebhookService.ts | 7 ++++++- .../src/core/chart/ChartManagementService.ts | 8 +++++++- packages/backend/src/daemons/JanitorService.ts | 7 ++++++- packages/backend/src/daemons/QueueStatsService.ts | 9 +++++++-- .../backend/src/daemons/ServerStatsService.ts | 7 ++++++- packages/backend/src/server/ServerService.ts | 8 +++++++- packages/backend/src/server/api/ApiCallService.ts | 7 ++++++- 16 files changed, 104 insertions(+), 21 deletions(-) diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts index 564787392f..406e3192bb 100644 --- a/packages/backend/src/GlobalModule.ts +++ b/packages/backend/src/GlobalModule.ts @@ -100,7 +100,7 @@ export class GlobalModule implements OnApplicationShutdown { @Inject(DI.redisForSub) private redisForSub: Redis.Redis, ) {} - async onApplicationShutdown(signal: string): Promise<void> { + public async dispose(): Promise<void> { if (process.env.NODE_ENV === 'test') { // XXX: // Shutting down the existing connections causes errors on Jest as @@ -116,4 +116,8 @@ export class GlobalModule implements OnApplicationShutdown { this.redisForSub.disconnect(), ]); } + + async onApplicationShutdown(signal: string): Promise<void> { + await this.dispose(); + } } diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 2d4226a32d..d8df371916 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -55,11 +55,6 @@ export class AntennaService implements OnApplicationShutdown { this.redisForSub.on('message', this.onRedisMessage); } - @bindThis - public onApplicationShutdown(signal?: string | undefined) { - this.redisForSub.off('message', this.onRedisMessage); - } - @bindThis private async onRedisMessage(_: string, data: string): Promise<void> { const obj = JSON.parse(data); @@ -196,4 +191,14 @@ export class AntennaService implements OnApplicationShutdown { return this.antennas; } + + @bindThis + public dispose(): void { + this.redisForSub.off('message', this.onRedisMessage); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index cf1e81ffc8..de33e4c243 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -166,7 +166,12 @@ export class CacheService implements OnApplicationShutdown { } @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { this.redisForSub.off('message', this.onMessage); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/MetaService.ts b/packages/backend/src/core/MetaService.ts index 0b861be8d0..5acc9ad9ad 100644 --- a/packages/backend/src/core/MetaService.ts +++ b/packages/backend/src/core/MetaService.ts @@ -120,8 +120,13 @@ export class MetaService implements OnApplicationShutdown { } @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { clearInterval(this.intervalId); this.redisForSub.off('message', this.onMessage); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 2fd7a8ac86..1c8491bf57 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -790,7 +790,13 @@ export class NoteCreateService implements OnApplicationShutdown { return mentionedUsers; } - onApplicationShutdown(signal?: string | undefined) { + @bindThis + public dispose(): void { this.#shutdownController.abort(); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/NoteReadService.ts b/packages/backend/src/core/NoteReadService.ts index 1129bd159c..e57e57d310 100644 --- a/packages/backend/src/core/NoteReadService.ts +++ b/packages/backend/src/core/NoteReadService.ts @@ -122,7 +122,13 @@ export class NoteReadService implements OnApplicationShutdown { } } - onApplicationShutdown(signal?: string | undefined): void { + @bindThis + public dispose(): void { this.#shutdownController.abort(); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts index a245908c98..ed47165f7b 100644 --- a/packages/backend/src/core/NotificationService.ts +++ b/packages/backend/src/core/NotificationService.ts @@ -152,7 +152,13 @@ export class NotificationService implements OnApplicationShutdown { */ } - onApplicationShutdown(signal?: string | undefined): void { + @bindThis + public dispose(): void { this.#shutdownController.abort(); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts index 6db9bb14cf..3384ca4577 100644 --- a/packages/backend/src/core/QueueModule.ts +++ b/packages/backend/src/core/QueueModule.ts @@ -100,7 +100,7 @@ export class QueueModule implements OnApplicationShutdown { @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue, ) {} - async onApplicationShutdown(signal: string): Promise<void> { + public async dispose(): Promise<void> { if (process.env.NODE_ENV === 'test') { // XXX: // Shutting down the existing connections causes errors on Jest as @@ -120,4 +120,8 @@ export class QueueModule implements OnApplicationShutdown { this.webhookDeliverQueue.close(), ]); } + + async onApplicationShutdown(signal: string): Promise<void> { + await this.dispose(); + } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 130ec5ec8c..40ae106662 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -433,7 +433,12 @@ export class RoleService implements OnApplicationShutdown { } @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { this.redisForSub.off('message', this.onMessage); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/WebhookService.ts b/packages/backend/src/core/WebhookService.ts index 57baade777..467755a072 100644 --- a/packages/backend/src/core/WebhookService.ts +++ b/packages/backend/src/core/WebhookService.ts @@ -81,7 +81,12 @@ export class WebhookService implements OnApplicationShutdown { } @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { this.redisForSub.off('message', this.onMessage); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/chart/ChartManagementService.ts b/packages/backend/src/core/chart/ChartManagementService.ts index 03e3612658..b0e9e534df 100644 --- a/packages/backend/src/core/chart/ChartManagementService.ts +++ b/packages/backend/src/core/chart/ChartManagementService.ts @@ -60,7 +60,8 @@ export class ChartManagementService implements OnApplicationShutdown { }, 1000 * 60 * 20); } - async onApplicationShutdown(signal: string): Promise<void> { + @bindThis + public async dispose(): Promise<void> { clearInterval(this.saveIntervalId); if (process.env.NODE_ENV !== 'test') { await Promise.all( @@ -68,4 +69,9 @@ export class ChartManagementService implements OnApplicationShutdown { ); } } + + @bindThis + async onApplicationShutdown(signal: string): Promise<void> { + await this.dispose(); + } } diff --git a/packages/backend/src/daemons/JanitorService.ts b/packages/backend/src/daemons/JanitorService.ts index 8cdfb703f1..f826d50625 100644 --- a/packages/backend/src/daemons/JanitorService.ts +++ b/packages/backend/src/daemons/JanitorService.ts @@ -34,7 +34,12 @@ export class JanitorService implements OnApplicationShutdown { } @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { clearInterval(this.intervalId); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/daemons/QueueStatsService.ts b/packages/backend/src/daemons/QueueStatsService.ts index 0a5b3184d2..53a0d14cd7 100644 --- a/packages/backend/src/daemons/QueueStatsService.ts +++ b/packages/backend/src/daemons/QueueStatsService.ts @@ -81,9 +81,14 @@ export class QueueStatsService implements OnApplicationShutdown { this.intervalId = setInterval(tick, interval); } - + @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { clearInterval(this.intervalId); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/daemons/ServerStatsService.ts b/packages/backend/src/daemons/ServerStatsService.ts index bb190cf60f..6cd71c0e2a 100644 --- a/packages/backend/src/daemons/ServerStatsService.ts +++ b/packages/backend/src/daemons/ServerStatsService.ts @@ -63,9 +63,14 @@ export class ServerStatsService implements OnApplicationShutdown { } @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { clearInterval(this.intervalId); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } // CPU STAT diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index 9257fee13e..ce6a1f7043 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -222,7 +222,13 @@ export class ServerService implements OnApplicationShutdown { await fastify.ready(); } - async onApplicationShutdown(signal: string): Promise<void> { + @bindThis + public async dispose(): Promise<void> { await this.#fastify.close(); } + + @bindThis + async onApplicationShutdown(signal: string): Promise<void> { + await this.dispose(); + } } diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index e3483c82c6..dad1a4132a 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -359,7 +359,12 @@ export class ApiCallService implements OnApplicationShutdown { } @bindThis - public onApplicationShutdown(signal?: string | undefined) { + public dispose(): void { clearInterval(this.userIpHistoriesClearIntervalId); } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } From 4790ddfad68ab4889db11c3f9c7f0159a69d4829 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 13:30:26 +0900 Subject: [PATCH 104/213] refactor of QueueProcessorService --- .../src/queue/QueueProcessorService.ts | 84 ++++++++++++++----- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index 011082cd36..da5069c29e 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Bull from 'bullmq'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; @@ -63,8 +63,16 @@ function getJobInfo(job: Bull.Job | undefined, increment = false): string { } @Injectable() -export class QueueProcessorService { +export class QueueProcessorService implements OnApplicationShutdown { private logger: Logger; + private systemQueueWorker: Bull.Worker; + private dbQueueWorker: Bull.Worker; + private deliverQueueWorker: Bull.Worker; + private inboxQueueWorker: Bull.Worker; + private webhookDeliverQueueWorker: Bull.Worker; + private relationshipQueueWorker: Bull.Worker; + private objectStorageQueueWorker: Bull.Worker; + private endedPollNotificationQueueWorker: Bull.Worker; constructor( @Inject(DI.config) @@ -102,10 +110,7 @@ export class QueueProcessorService { private cleanProcessorService: CleanProcessorService, ) { this.logger = this.queueLoggerService.logger; - } - @bindThis - public start() { function renderError(e: Error): any { if (e) { // 何故かeがundefinedで来ることがある return { @@ -123,7 +128,7 @@ export class QueueProcessorService { } //#region system - const systemQueueWorker = new Bull.Worker(QUEUE.SYSTEM, (job) => { + this.systemQueueWorker = new Bull.Worker(QUEUE.SYSTEM, (job) => { switch (job.name) { case 'tickCharts': return this.tickChartsProcessorService.process(); case 'resyncCharts': return this.resyncChartsProcessorService.process(); @@ -135,11 +140,12 @@ export class QueueProcessorService { } }, { ...baseQueueOptions(this.config, QUEUE.SYSTEM), + autorun: false, }); const systemLogger = this.logger.createSubLogger('system'); - systemQueueWorker + this.systemQueueWorker .on('active', (job) => systemLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => systemLogger.debug(`completed(${result}) id=${job.id}`)) .on('failed', (job, err) => systemLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) @@ -148,7 +154,7 @@ export class QueueProcessorService { //#endregion //#region db - const dbQueueWorker = new Bull.Worker(QUEUE.DB, (job) => { + this.dbQueueWorker = new Bull.Worker(QUEUE.DB, (job) => { switch (job.name) { case 'deleteDriveFiles': return this.deleteDriveFilesProcessorService.process(job); case 'exportCustomEmojis': return this.exportCustomEmojisProcessorService.process(job); @@ -172,11 +178,12 @@ export class QueueProcessorService { } }, { ...baseQueueOptions(this.config, QUEUE.DB), + autorun: false, }); const dbLogger = this.logger.createSubLogger('db'); - dbQueueWorker + this.dbQueueWorker .on('active', (job) => dbLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => dbLogger.debug(`completed(${result}) id=${job.id}`)) .on('failed', (job, err) => dbLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) @@ -185,8 +192,9 @@ export class QueueProcessorService { //#endregion //#region deliver - const deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => this.deliverProcessorService.process(job), { + this.deliverQueueWorker = new Bull.Worker(QUEUE.DELIVER, (job) => this.deliverProcessorService.process(job), { ...baseQueueOptions(this.config, QUEUE.DELIVER), + autorun: false, concurrency: this.config.deliverJobConcurrency ?? 128, limiter: { max: this.config.deliverJobPerSec ?? 128, @@ -199,7 +207,7 @@ export class QueueProcessorService { const deliverLogger = this.logger.createSubLogger('deliver'); - deliverQueueWorker + this.deliverQueueWorker .on('active', (job) => deliverLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) .on('completed', (job, result) => deliverLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) .on('failed', (job, err) => deliverLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) @@ -208,8 +216,9 @@ export class QueueProcessorService { //#endregion //#region inbox - const inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => this.inboxProcessorService.process(job), { + this.inboxQueueWorker = new Bull.Worker(QUEUE.INBOX, (job) => this.inboxProcessorService.process(job), { ...baseQueueOptions(this.config, QUEUE.INBOX), + autorun: false, concurrency: this.config.inboxJobConcurrency ?? 16, limiter: { max: this.config.inboxJobPerSec ?? 16, @@ -222,7 +231,7 @@ export class QueueProcessorService { const inboxLogger = this.logger.createSubLogger('inbox'); - inboxQueueWorker + this.inboxQueueWorker .on('active', (job) => inboxLogger.debug(`active ${getJobInfo(job, true)}`)) .on('completed', (job, result) => inboxLogger.debug(`completed(${result}) ${getJobInfo(job, true)}`)) .on('failed', (job, err) => inboxLogger.warn(`failed(${err}) ${getJobInfo(job)} activity=${job ? (job.data.activity ? job.data.activity.id : 'none') : '-'}`, { job, e: renderError(err) })) @@ -231,8 +240,9 @@ export class QueueProcessorService { //#endregion //#region webhook deliver - const webhookDeliverQueueWorker = new Bull.Worker(QUEUE.WEBHOOK_DELIVER, (job) => this.webhookDeliverProcessorService.process(job), { + this.webhookDeliverQueueWorker = new Bull.Worker(QUEUE.WEBHOOK_DELIVER, (job) => this.webhookDeliverProcessorService.process(job), { ...baseQueueOptions(this.config, QUEUE.WEBHOOK_DELIVER), + autorun: false, concurrency: 64, limiter: { max: 64, @@ -245,7 +255,7 @@ export class QueueProcessorService { const webhookLogger = this.logger.createSubLogger('webhook'); - webhookDeliverQueueWorker + this.webhookDeliverQueueWorker .on('active', (job) => webhookLogger.debug(`active ${getJobInfo(job, true)} to=${job.data.to}`)) .on('completed', (job, result) => webhookLogger.debug(`completed(${result}) ${getJobInfo(job, true)} to=${job.data.to}`)) .on('failed', (job, err) => webhookLogger.warn(`failed(${err}) ${getJobInfo(job)} to=${job ? job.data.to : '-'}`)) @@ -254,7 +264,7 @@ export class QueueProcessorService { //#endregion //#region relationship - const relationshipQueueWorker = new Bull.Worker(QUEUE.RELATIONSHIP, (job) => { + this.relationshipQueueWorker = new Bull.Worker(QUEUE.RELATIONSHIP, (job) => { switch (job.name) { case 'follow': return this.relationshipProcessorService.processFollow(job); case 'unfollow': return this.relationshipProcessorService.processUnfollow(job); @@ -264,6 +274,7 @@ export class QueueProcessorService { } }, { ...baseQueueOptions(this.config, QUEUE.RELATIONSHIP), + autorun: false, concurrency: this.config.relashionshipJobConcurrency ?? 16, limiter: { max: this.config.relashionshipJobPerSec ?? 64, @@ -273,7 +284,7 @@ export class QueueProcessorService { const relationshipLogger = this.logger.createSubLogger('relationship'); - relationshipQueueWorker + this.relationshipQueueWorker .on('active', (job) => relationshipLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => relationshipLogger.debug(`completed(${result}) id=${job.id}`)) .on('failed', (job, err) => relationshipLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) @@ -282,7 +293,7 @@ export class QueueProcessorService { //#endregion //#region object storage - const objectStorageQueueWorker = new Bull.Worker(QUEUE.OBJECT_STORAGE, (job) => { + this.objectStorageQueueWorker = new Bull.Worker(QUEUE.OBJECT_STORAGE, (job) => { switch (job.name) { case 'deleteFile': return this.deleteFileProcessorService.process(job); case 'cleanRemoteFiles': return this.cleanRemoteFilesProcessorService.process(job); @@ -290,12 +301,13 @@ export class QueueProcessorService { } }, { ...baseQueueOptions(this.config, QUEUE.OBJECT_STORAGE), + autorun: false, concurrency: 16, }); const objectStorageLogger = this.logger.createSubLogger('objectStorage'); - objectStorageQueueWorker + this.objectStorageQueueWorker .on('active', (job) => objectStorageLogger.debug(`active id=${job.id}`)) .on('completed', (job, result) => objectStorageLogger.debug(`completed(${result}) id=${job.id}`)) .on('failed', (job, err) => objectStorageLogger.warn(`failed(${err}) id=${job ? job.id : '-'}`, { job, e: renderError(err) })) @@ -304,9 +316,41 @@ export class QueueProcessorService { //#endregion //#region ended poll notification - const endedPollNotificationWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => this.endedPollNotificationProcessorService.process(job), { + this.endedPollNotificationQueueWorker = new Bull.Worker(QUEUE.ENDED_POLL_NOTIFICATION, (job) => this.endedPollNotificationProcessorService.process(job), { ...baseQueueOptions(this.config, QUEUE.ENDED_POLL_NOTIFICATION), + autorun: false, }); //#endregion } + + @bindThis + public start() { + this.systemQueueWorker.run(); + this.dbQueueWorker.run(); + this.deliverQueueWorker.run(); + this.inboxQueueWorker.run(); + this.webhookDeliverQueueWorker.run(); + this.relationshipQueueWorker.run(); + this.objectStorageQueueWorker.run(); + this.endedPollNotificationQueueWorker.run(); + } + + @bindThis + public async stop(): Promise<void> { + await Promise.all([ + this.systemQueueWorker.close(), + this.dbQueueWorker.close(), + this.deliverQueueWorker.close(), + this.inboxQueueWorker.close(), + this.webhookDeliverQueueWorker.close(), + this.relationshipQueueWorker.close(), + this.objectStorageQueueWorker.close(), + this.endedPollNotificationQueueWorker.close(), + ]); + } + + @bindThis + public async onApplicationShutdown(signal?: string | undefined): Promise<void> { + await this.stop(); + } } From b35b9bc27ff762938495d2ce73521fbe68643793 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 13:30:57 +0900 Subject: [PATCH 105/213] Update QueueProcessorService.ts --- .../src/queue/QueueProcessorService.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts index da5069c29e..42f9c1af7d 100644 --- a/packages/backend/src/queue/QueueProcessorService.ts +++ b/packages/backend/src/queue/QueueProcessorService.ts @@ -324,15 +324,17 @@ export class QueueProcessorService implements OnApplicationShutdown { } @bindThis - public start() { - this.systemQueueWorker.run(); - this.dbQueueWorker.run(); - this.deliverQueueWorker.run(); - this.inboxQueueWorker.run(); - this.webhookDeliverQueueWorker.run(); - this.relationshipQueueWorker.run(); - this.objectStorageQueueWorker.run(); - this.endedPollNotificationQueueWorker.run(); + public async start(): Promise<void> { + await Promise.all([ + this.systemQueueWorker.run(), + this.dbQueueWorker.run(), + this.deliverQueueWorker.run(), + this.inboxQueueWorker.run(), + this.webhookDeliverQueueWorker.run(), + this.relationshipQueueWorker.run(), + this.objectStorageQueueWorker.run(), + this.endedPollNotificationQueueWorker.run(), + ]); } @bindThis From f930eaee020520c1f9496803dcf445b2f2955526 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 13:32:19 +0900 Subject: [PATCH 106/213] perf(backend): use websockets/ws instead of theturtle32/WebSocket-Node (#10884) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf(backend): use websockets/ws instead of theturtle32/WebSocket-Node Resolve #10883 * refactor * Update StreamingApiServerService.ts * Update StreamingApiServerService.ts * :v: * Update StreamingApiServerService.ts * fix main stream init * fix timing 2 * setIntervalの重複を避ける(気休め) * add comment * :v: --------- Co-authored-by: tamaina <tamaina@hotmail.co.jp> --- packages/backend/package.json | 5 +- packages/backend/src/server/ServerService.ts | 3 +- .../src/server/api/AuthenticateService.ts | 2 +- .../server/api/StreamingApiServerService.ts | 121 ++++++++++-------- .../backend/src/server/api/stream/index.ts | 21 ++- pnpm-lock.yaml | 63 +++------ 6 files changed, 107 insertions(+), 108 deletions(-) diff --git a/packages/backend/package.json b/packages/backend/package.json index 99c04d6bf6..66bc7ee478 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -35,6 +35,7 @@ "@swc/core-win32-x64-msvc": "1.3.56", "@tensorflow/tfjs": "4.4.0", "@tensorflow/tfjs-node": "4.4.0", + "bufferutil": "^4.0.7", "slacc-android-arm-eabi": "0.0.9", "slacc-android-arm64": "0.0.9", "slacc-darwin-arm64": "0.0.9", @@ -46,7 +47,8 @@ "slacc-linux-arm64-musl": "0.0.9", "slacc-linux-x64-gnu": "0.0.9", "slacc-win32-arm64-msvc": "0.0.9", - "slacc-win32-x64-msvc": "0.0.9" + "slacc-win32-x64-msvc": "0.0.9", + "utf-8-validate": "^6.0.3" }, "dependencies": { "@aws-sdk/client-s3": "3.321.1", @@ -157,7 +159,6 @@ "uuid": "9.0.0", "vary": "1.1.2", "web-push": "3.6.1", - "websocket": "1.0.34", "ws": "8.13.0", "xev": "3.0.2" }, diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index ce6a1f7043..c3d45e4ad6 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -194,7 +194,7 @@ export class ServerService implements OnApplicationShutdown { fastify.register(this.clientServerService.createServer); - this.streamingApiServerService.attachStreamingApi(fastify.server); + this.streamingApiServerService.attach(fastify.server); fastify.server.on('error', err => { switch ((err as any).code) { @@ -224,6 +224,7 @@ export class ServerService implements OnApplicationShutdown { @bindThis public async dispose(): Promise<void> { + await this.streamingApiServerService.detach(); await this.#fastify.close(); } diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index 6548c475b2..e23591d876 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -36,7 +36,7 @@ export class AuthenticateService { } @bindThis - public async authenticate(token: string | null | undefined): Promise<[LocalUser | null | undefined, AccessToken | null | undefined]> { + public async authenticate(token: string | null | undefined): Promise<[LocalUser | null, AccessToken | null]> { if (token == null) { return [null, null]; } diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index 258e8de034..fdda581ada 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -1,23 +1,25 @@ import { EventEmitter } from 'events'; import { Inject, Injectable } from '@nestjs/common'; import * as Redis from 'ioredis'; -import * as websocket from 'websocket'; +import * as WebSocket from 'ws'; import { DI } from '@/di-symbols.js'; -import type { UsersRepository, BlockingsRepository, ChannelFollowingsRepository, FollowingsRepository, MutingsRepository, UserProfilesRepository, RenoteMutingsRepository } from '@/models/index.js'; +import type { UsersRepository, AccessToken } from '@/models/index.js'; import type { Config } from '@/config.js'; import { NoteReadService } from '@/core/NoteReadService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { NotificationService } from '@/core/NotificationService.js'; import { bindThis } from '@/decorators.js'; import { CacheService } from '@/core/CacheService.js'; -import { AuthenticateService } from './AuthenticateService.js'; +import { LocalUser } from '@/models/entities/User'; +import { AuthenticateService, AuthenticationError } from './AuthenticateService.js'; import MainStreamConnection from './stream/index.js'; import { ChannelsService } from './stream/ChannelsService.js'; -import type { ParsedUrlQuery } from 'querystring'; import type * as http from 'node:http'; @Injectable() export class StreamingApiServerService { + #wss: WebSocket.WebSocketServer; + constructor( @Inject(DI.config) private config: Config, @@ -28,24 +30,6 @@ export class StreamingApiServerService { @Inject(DI.usersRepository) private usersRepository: UsersRepository, - @Inject(DI.followingsRepository) - private followingsRepository: FollowingsRepository, - - @Inject(DI.mutingsRepository) - private mutingsRepository: MutingsRepository, - - @Inject(DI.renoteMutingsRepository) - private renoteMutingsRepository: RenoteMutingsRepository, - - @Inject(DI.blockingsRepository) - private blockingsRepository: BlockingsRepository, - - @Inject(DI.channelFollowingsRepository) - private channelFollowingsRepository: ChannelFollowingsRepository, - - @Inject(DI.userProfilesRepository) - private userProfilesRepository: UserProfilesRepository, - private cacheService: CacheService, private noteReadService: NoteReadService, private authenticateService: AuthenticateService, @@ -55,25 +39,65 @@ export class StreamingApiServerService { } @bindThis - public attachStreamingApi(server: http.Server) { - // Init websocket server - const ws = new websocket.server({ - httpServer: server, + public attach(server: http.Server): void { + this.#wss = new WebSocket.WebSocketServer({ + noServer: true, }); - ws.on('request', async (request) => { - const q = request.resourceURL.query as ParsedUrlQuery; - - // TODO: トークンが間違ってるなどしてauthenticateに失敗したら - // コネクション切断するなりエラーメッセージ返すなりする - // (現状はエラーがキャッチされておらずサーバーのログに流れて邪魔なので) - const [user, miapp] = await this.authenticateService.authenticate(q.i as string); - - if (user?.isSuspended) { - request.reject(400); + server.on('upgrade', async (request, socket, head) => { + if (request.url == null) { + socket.write('HTTP/1.1 400 Bad Request\r\n\r\n'); + socket.destroy(); return; } + const q = new URL(request.url, `http://${request.headers.host}`).searchParams; + + let user: LocalUser | null = null; + let app: AccessToken | null = null; + + try { + [user, app] = await this.authenticateService.authenticate(q.get('i')); + } catch (e) { + if (e instanceof AuthenticationError) { + socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); + } else { + socket.write('HTTP/1.1 500 Internal Server Error\r\n\r\n'); + } + socket.destroy(); + return; + } + + if (user?.isSuspended) { + socket.write('HTTP/1.1 403 Forbidden\r\n\r\n'); + socket.destroy(); + return; + } + + const stream = new MainStreamConnection( + this.channelsService, + this.noteReadService, + this.notificationService, + this.cacheService, + user, app, + ); + + await stream.init(); + + this.#wss.handleUpgrade(request, socket, head, (ws) => { + this.#wss.emit('connection', ws, request, { + stream, user, app, + }); + }); + }); + + this.#wss.on('connection', async (connection: WebSocket.WebSocket, request: http.IncomingMessage, ctx: { + stream: MainStreamConnection, + user: LocalUser | null; + app: AccessToken | null + }) => { + const { stream, user, app } = ctx; + const ev = new EventEmitter(); async function onRedisMessage(_: string, data: string): Promise<void> { @@ -83,19 +107,7 @@ export class StreamingApiServerService { this.redisForSub.on('message', onRedisMessage); - const main = new MainStreamConnection( - this.channelsService, - this.noteReadService, - this.notificationService, - this.cacheService, - ev, user, miapp, - ); - - await main.init(); - - const connection = request.accept(); - - main.init2(connection); + await stream.listen(ev, connection); const intervalId = user ? setInterval(() => { this.usersRepository.update(user.id, { @@ -110,16 +122,23 @@ export class StreamingApiServerService { connection.once('close', () => { ev.removeAllListeners(); - main.dispose(); + stream.dispose(); this.redisForSub.off('message', onRedisMessage); if (intervalId) clearInterval(intervalId); }); connection.on('message', async (data) => { - if (data.type === 'utf8' && data.utf8Data === 'ping') { + if (data.toString() === 'ping') { connection.send('pong'); } }); }); } + + @bindThis + public detach(): Promise<void> { + return new Promise((resolve) => { + this.#wss.close(() => resolve()); + }); + } } diff --git a/packages/backend/src/server/api/stream/index.ts b/packages/backend/src/server/api/stream/index.ts index fee56e3668..8b1c2c09c9 100644 --- a/packages/backend/src/server/api/stream/index.ts +++ b/packages/backend/src/server/api/stream/index.ts @@ -1,3 +1,4 @@ +import * as WebSocket from 'ws'; import type { User } from '@/models/entities/User.js'; import type { AccessToken } from '@/models/entities/AccessToken.js'; import type { Packed } from '@/misc/json-schema.js'; @@ -7,7 +8,6 @@ import { bindThis } from '@/decorators.js'; import { CacheService } from '@/core/CacheService.js'; import { UserProfile } from '@/models/index.js'; import type { ChannelsService } from './ChannelsService.js'; -import type * as websocket from 'websocket'; import type { EventEmitter } from 'events'; import type Channel from './channel.js'; import type { StreamEventEmitter, StreamMessages } from './types.js'; @@ -18,7 +18,7 @@ import type { StreamEventEmitter, StreamMessages } from './types.js'; export default class Connection { public user?: User; public token?: AccessToken; - private wsConnection: websocket.connection; + private wsConnection: WebSocket.WebSocket; public subscriber: StreamEventEmitter; private channels: Channel[] = []; private subscribingNotes: any = {}; @@ -37,11 +37,9 @@ export default class Connection { private notificationService: NotificationService, private cacheService: CacheService, - subscriber: EventEmitter, user: User | null | undefined, token: AccessToken | null | undefined, ) { - this.subscriber = subscriber; if (user) this.user = user; if (token) this.token = token; } @@ -70,12 +68,16 @@ export default class Connection { if (this.user != null) { await this.fetch(); - this.fetchIntervalId = setInterval(this.fetch, 1000 * 10); + if (!this.fetchIntervalId) { + this.fetchIntervalId = setInterval(this.fetch, 1000 * 10); + } } } @bindThis - public async init2(wsConnection: websocket.connection) { + public async listen(subscriber: EventEmitter, wsConnection: WebSocket.WebSocket) { + this.subscriber = subscriber; + this.wsConnection = wsConnection; this.wsConnection.on('message', this.onWsConnectionMessage); @@ -88,14 +90,11 @@ export default class Connection { * クライアントからメッセージ受信時 */ @bindThis - private async onWsConnectionMessage(data: websocket.Message) { - if (data.type !== 'utf8') return; - if (data.utf8Data == null) return; - + private async onWsConnectionMessage(data: WebSocket.RawData) { let obj: Record<string, any>; try { - obj = JSON.parse(data.utf8Data); + obj = JSON.parse(data.toString()); } catch (e) { return; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7930458cb0..57e8cf850d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,7 +96,7 @@ importers: version: 8.2.1 '@fastify/http-proxy': specifier: 9.1.0 - version: 9.1.0 + version: 9.1.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) '@fastify/multipart': specifier: 7.6.0 version: 7.6.0 @@ -219,7 +219,7 @@ importers: version: 4.1.0 jsdom: specifier: 21.1.1 - version: 21.1.1 + version: 21.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3) json5: specifier: 2.2.3 version: 2.2.3 @@ -388,12 +388,9 @@ importers: web-push: specifier: 3.6.1 version: 3.6.1 - websocket: - specifier: 1.0.34 - version: 1.0.34 ws: specifier: 8.13.0 - version: 8.13.0 + version: 8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) xev: specifier: 3.0.2 version: 3.0.2 @@ -437,6 +434,9 @@ importers: '@tensorflow/tfjs-node': specifier: 4.4.0 version: 4.4.0(seedrandom@3.0.5) + bufferutil: + specifier: ^4.0.7 + version: 4.0.7 slacc-android-arm-eabi: specifier: 0.0.9 version: 0.0.9 @@ -473,6 +473,9 @@ importers: slacc-win32-x64-msvc: specifier: 0.0.9 version: 0.0.9 + utf-8-validate: + specifier: ^6.0.3 + version: 6.0.3 devDependencies: '@jest/globals': specifier: 29.5.0 @@ -3852,12 +3855,12 @@ packages: fast-json-stringify: 5.7.0 dev: false - /@fastify/http-proxy@9.1.0: + /@fastify/http-proxy@9.1.0(bufferutil@4.0.7)(utf-8-validate@6.0.3): resolution: {integrity: sha512-vgHCTDKOqLB437zQJiLWFFnsrYfFZ6Lfwu/xXQoKqRUKIPDt+xG6LBRtf8s5MNqfFVoTE7kw1U/0qdRGDsMp4Q==} dependencies: '@fastify/reply-from': 9.0.1 fastify-plugin: 4.5.0 - ws: 8.13.0 + ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -5532,7 +5535,7 @@ packages: ts-dedent: 2.2.0 util-deprecate: 1.0.2 watchpack: 2.4.0 - ws: 8.13.0 + ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -8702,7 +8705,6 @@ packages: requiresBuild: true dependencies: node-gyp-build: 4.6.0 - dev: false /bullmq@3.14.1: resolution: {integrity: sha512-Fom78UKljYsnJmwbROVPx3eFLuVfQjQbw9KCnVupLzT31RQHhFHV2xd/4J4oWl4u34bZ1JmEUfNnqNBz+IOJuA==} @@ -13872,7 +13874,7 @@ packages: - supports-color dev: true - /jsdom@21.1.1: + /jsdom@21.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3): resolution: {integrity: sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==} engines: {node: '>=14'} peerDependencies: @@ -13905,7 +13907,7 @@ packages: whatwg-encoding: 2.0.0 whatwg-mimetype: 3.0.0 whatwg-url: 12.0.1 - ws: 8.13.0 + ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) xml-name-validator: 4.0.0 transitivePeerDependencies: - bufferutil @@ -15231,7 +15233,7 @@ packages: /node-gyp-build@4.6.0: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} - dev: false + hasBin: true /node-gyp@9.3.1: resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} @@ -19276,12 +19278,6 @@ packages: resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} dev: false - /typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - dependencies: - is-typedarray: 1.0.0 - dev: false - /typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} @@ -19656,13 +19652,12 @@ packages: resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} engines: {node: '>=0.10.0'} - /utf-8-validate@5.0.10: - resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + /utf-8-validate@6.0.3: + resolution: {integrity: sha512-uIuGf9TWQ/y+0Lp+KGZCMuJWc3N9BHA+l/UmHd/oUHwJJDeysyTRxNQVkbzsIWfGFbRe3OcgML/i0mvVRPOyDA==} engines: {node: '>=6.14.2'} requiresBuild: true dependencies: node-gyp-build: 4.6.0 - dev: false /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -20132,20 +20127,6 @@ packages: resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} dev: false - /websocket@1.0.34: - resolution: {integrity: sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==} - engines: {node: '>=4.0.0'} - dependencies: - bufferutil: 4.0.7 - debug: 2.6.9 - es5-ext: 0.10.62 - typedarray-to-buffer: 3.1.5 - utf-8-validate: 5.0.10 - yaeti: 0.0.6 - transitivePeerDependencies: - - supports-color - dev: false - /well-known-symbols@2.0.0: resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} engines: {node: '>=6'} @@ -20336,7 +20317,7 @@ packages: async-limiter: 1.0.1 dev: true - /ws@8.13.0: + /ws@8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3): resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} engines: {node: '>=10.0.0'} peerDependencies: @@ -20347,6 +20328,9 @@ packages: optional: true utf-8-validate: optional: true + dependencies: + bufferutil: 4.0.7 + utf-8-validate: 6.0.3 /xev@3.0.2: resolution: {integrity: sha512-8kxuH95iMXzHZj+fwqfA4UrPcYOy6bGIgfWzo9Ji23JoEc30ge/Z++Ubkiuy8c0+M64nXmmxrmJ7C8wnuBhluw==} @@ -20394,11 +20378,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - /yaeti@0.0.6: - resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} - engines: {node: '>=0.10.32'} - dev: false - /yallist@2.1.2: resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} From afa4cd9112b429afa53396c2435baf5ef3b3dea9 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 13:34:55 +0900 Subject: [PATCH 107/213] 13.13.0-beta.4 --- CHANGELOG.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b107c72f0..36bc63b0af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ ### Server - bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 +- ストリーミングのパフォーマンスを改善 - Fix: お知らせの画像URLを空にできない問題を修正 ## 13.12.2 diff --git a/package.json b/package.json index 7723623198..58257a8b0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0-beta.3", + "version": "13.13.0-beta.4", "codename": "nasubi", "repository": { "type": "git", From 8c66fad96b28ae498b78610d88089d9c9a798eb1 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 17:13:12 +0900 Subject: [PATCH 108/213] lint --- packages/frontend/.eslintrc.js | 1 + packages/frontend/src/pages/admin/RolesEditorFormula.vue | 4 ++-- packages/frontend/src/pages/admin/roles.role.vue | 6 +++--- packages/frontend/src/pages/admin/roles.vue | 8 ++++---- packages/frontend/src/pages/admin/security.vue | 8 ++++---- packages/frontend/src/pages/gallery/edit.vue | 2 +- packages/frontend/src/pages/gallery/index.vue | 6 +++--- packages/frontend/src/pages/gallery/post.vue | 2 +- packages/frontend/src/widgets/server-metric/index.vue | 2 +- 9 files changed, 20 insertions(+), 19 deletions(-) diff --git a/packages/frontend/.eslintrc.js b/packages/frontend/.eslintrc.js index 303b74ca16..24c3ad4b83 100644 --- a/packages/frontend/.eslintrc.js +++ b/packages/frontend/.eslintrc.js @@ -56,6 +56,7 @@ module.exports = { 'vue/require-v-for-key': 'warn', 'vue/no-unused-components': 'warn', 'vue/no-unused-vars': 'warn', + 'vue/no-dupe-keys': 'warn', 'vue/valid-v-for': 'warn', 'vue/return-in-computed-property': 'warn', 'vue/no-setup-props-destructure': 'warn', diff --git a/packages/frontend/src/pages/admin/RolesEditorFormula.vue b/packages/frontend/src/pages/admin/RolesEditorFormula.vue index 343d2c4c5c..36e3c32391 100644 --- a/packages/frontend/src/pages/admin/RolesEditorFormula.vue +++ b/packages/frontend/src/pages/admin/RolesEditorFormula.vue @@ -25,11 +25,11 @@ </div> <div v-if="type === 'and' || type === 'or'" :class="$style.values" class="_gaps"> - <Sortable v-model="v.values" tag="div" class="_gaps" item-key="id" handle=".drag-handle" :group="{ name: 'roleFormula' }" :animation="150" :swap-threshold="0.5"> + <Sortable v-model="v.values" tag="div" class="_gaps" itemKey="id" handle=".drag-handle" :group="{ name: 'roleFormula' }" :animation="150" :swapThreshold="0.5"> <template #item="{element}"> <div :class="$style.item"> <!-- divが無いとエラーになる https://github.com/SortableJS/vue.draggable.next/issues/189 --> - <RolesEditorFormula :model-value="element" draggable @update:model-value="updated => valuesItemUpdated(updated)" @remove="removeItem(element)"/> + <RolesEditorFormula :modelValue="element" draggable @update:modelValue="updated => valuesItemUpdated(updated)" @remove="removeItem(element)"/> </div> </template> </Sortable> diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue index 6eac902577..4ed6abf200 100644 --- a/packages/frontend/src/pages/admin/roles.role.vue +++ b/packages/frontend/src/pages/admin/roles.role.vue @@ -2,7 +2,7 @@ <div> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div class="_gaps"> <div class="_buttons"> <MkButton primary rounded @click="edit"><i class="ti ti-pencil"></i> {{ i18n.ts.edit }}</MkButton> @@ -11,9 +11,9 @@ <MkFolder> <template #icon><i class="ti ti-info-circle"></i></template> <template #label>{{ i18n.ts.info }}</template> - <XEditor :model-value="role" readonly/> + <XEditor :modelValue="role" readonly/> </MkFolder> - <MkFolder v-if="role.target === 'manual'" default-open> + <MkFolder v-if="role.target === 'manual'" defaultOpen> <template #icon><i class="ti ti-users"></i></template> <template #label>{{ i18n.ts.users }}</template> <template #suffix>{{ role.usersCount }}</template> diff --git a/packages/frontend/src/pages/admin/roles.vue b/packages/frontend/src/pages/admin/roles.vue index e8dbe1c5f0..6634d9cba9 100644 --- a/packages/frontend/src/pages/admin/roles.vue +++ b/packages/frontend/src/pages/admin/roles.vue @@ -2,7 +2,7 @@ <div> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700"> + <MkSpacer :contentMax="700"> <div class="_gaps"> <MkFolder> <template #label>{{ i18n.ts._role.baseRole }}</template> @@ -14,7 +14,7 @@ <MkFolder v-if="matchQuery([i18n.ts._role._options.rateLimitFactor, 'rateLimitFactor'])"> <template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template> <template #suffix>{{ Math.floor(policies.rateLimitFactor * 100) }}%</template> - <MkRange :model-value="policies.rateLimitFactor * 100" :min="30" :max="300" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => policies.rateLimitFactor = (v / 100)"> + <MkRange :modelValue="policies.rateLimitFactor * 100" :min="30" :max="300" :step="10" :textConverter="(v) => `${v}%`" @update:modelValue="v => policies.rateLimitFactor = (v / 100)"> <template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template> </MkRange> </MkFolder> @@ -156,13 +156,13 @@ <MkFoldableSection> <template #header>Manual roles</template> <div class="_gaps_s"> - <MkRolePreview v-for="role in roles.filter(x => x.target === 'manual')" :key="role.id" :role="role" :for-moderation="true"/> + <MkRolePreview v-for="role in roles.filter(x => x.target === 'manual')" :key="role.id" :role="role" :forModeration="true"/> </div> </MkFoldableSection> <MkFoldableSection> <template #header>Conditional roles</template> <div class="_gaps_s"> - <MkRolePreview v-for="role in roles.filter(x => x.target === 'conditional')" :key="role.id" :role="role" :for-moderation="true"/> + <MkRolePreview v-for="role in roles.filter(x => x.target === 'conditional')" :key="role.id" :role="role" :forModeration="true"/> </div> </MkFoldableSection> </div> diff --git a/packages/frontend/src/pages/admin/security.vue b/packages/frontend/src/pages/admin/security.vue index cd8ef9e68b..efb9f81f25 100644 --- a/packages/frontend/src/pages/admin/security.vue +++ b/packages/frontend/src/pages/admin/security.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> <FormSuspense :p="init"> <div class="_gaps_m"> <MkFolder> @@ -33,7 +33,7 @@ <option value="remote">{{ i18n.ts.remoteOnly }}</option> </MkRadios> - <MkRange v-model="sensitiveMediaDetectionSensitivity" :min="0" :max="4" :step="1" :text-converter="(v) => `${v + 1}`"> + <MkRange v-model="sensitiveMediaDetectionSensitivity" :min="0" :max="4" :step="1" :textConverter="(v) => `${v + 1}`"> <template #label>{{ i18n.ts._sensitiveMediaDetection.sensitivity }}</template> <template #caption>{{ i18n.ts._sensitiveMediaDetection.sensitivityDescription }}</template> </MkRange> @@ -65,7 +65,7 @@ <div class="_gaps_m"> <span>{{ i18n.ts.activeEmailValidationDescription }}</span> - <MkSwitch v-model="enableActiveEmailValidation" @update:model-value="save"> + <MkSwitch v-model="enableActiveEmailValidation" @update:modelValue="save"> <template #label>Enable</template> </MkSwitch> </div> @@ -77,7 +77,7 @@ <template v-else #suffix>Disabled</template> <div class="_gaps_m"> - <MkSwitch v-model="enableIpLogging" @update:model-value="save"> + <MkSwitch v-model="enableIpLogging" @update:modelValue="save"> <template #label>Enable</template> </MkSwitch> </div> diff --git a/packages/frontend/src/pages/gallery/edit.vue b/packages/frontend/src/pages/gallery/edit.vue index cafcee0c33..f381636a78 100644 --- a/packages/frontend/src/pages/gallery/edit.vue +++ b/packages/frontend/src/pages/gallery/edit.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="800" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="800" :marginMin="16" :marginMax="32"> <FormSuspense :p="init" class="_gaps"> <MkInput v-model="title"> <template #label>{{ i18n.ts.title }}</template> diff --git a/packages/frontend/src/pages/gallery/index.vue b/packages/frontend/src/pages/gallery/index.vue index 3855a6d9d8..3c9c21a2ff 100644 --- a/packages/frontend/src/pages/gallery/index.vue +++ b/packages/frontend/src/pages/gallery/index.vue @@ -1,12 +1,12 @@ <template> <MkStickyContainer> <template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="1400"> + <MkSpacer :contentMax="1400"> <div class="_root"> <div v-if="tab === 'explore'"> <MkFoldableSection class="_margin"> <template #header><i class="ti ti-clock"></i>{{ i18n.ts.recentPosts }}</template> - <MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disable-auto-load="true"> + <MkPagination v-slot="{items}" :pagination="recentPostsPagination" :disableAutoLoad="true"> <div :class="$style.items"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> </div> @@ -14,7 +14,7 @@ </MkFoldableSection> <MkFoldableSection class="_margin"> <template #header><i class="ti ti-comet"></i>{{ i18n.ts.popularPosts }}</template> - <MkPagination v-slot="{items}" :pagination="popularPostsPagination" :disable-auto-load="true"> + <MkPagination v-slot="{items}" :pagination="popularPostsPagination" :disableAutoLoad="true"> <div :class="$style.items"> <MkGalleryPostPreview v-for="post in items" :key="post.id" :post="post" class="post"/> </div> diff --git a/packages/frontend/src/pages/gallery/post.vue b/packages/frontend/src/pages/gallery/post.vue index e0f3c105e1..dfa6c0bac0 100644 --- a/packages/frontend/src/pages/gallery/post.vue +++ b/packages/frontend/src/pages/gallery/post.vue @@ -1,7 +1,7 @@ <template> <MkStickyContainer> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> - <MkSpacer :content-max="1000" :margin-min="16" :margin-max="32"> + <MkSpacer :contentMax="1000" :marginMin="16" :marginMax="32"> <div class="_root"> <Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in"> <div v-if="post" class="rkxwuolj"> diff --git a/packages/frontend/src/widgets/server-metric/index.vue b/packages/frontend/src/widgets/server-metric/index.vue index df8de10f63..e019ff540b 100644 --- a/packages/frontend/src/widgets/server-metric/index.vue +++ b/packages/frontend/src/widgets/server-metric/index.vue @@ -1,5 +1,5 @@ <template> -<MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent"> +<MkContainer :showHeader="widgetProps.showHeader" :naked="widgetProps.transparent"> <template #icon><i class="ti ti-server"></i></template> <template #header>{{ i18n.ts._widgets.serverMetric }}</template> <template #func="{ buttonStyleClass }"><button class="_button" :class="buttonStyleClass" @click="toggleView()"><i class="ti ti-selector"></i></button></template> From c5f9b1c2240c459c1d98cd6c53027f8655b748d6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 17:13:45 +0900 Subject: [PATCH 109/213] lint --- packages/frontend/src/components/MkModalWindow.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkModalWindow.vue b/packages/frontend/src/components/MkModalWindow.vue index 63c55b904a..08569b4d6e 100644 --- a/packages/frontend/src/components/MkModalWindow.vue +++ b/packages/frontend/src/components/MkModalWindow.vue @@ -1,5 +1,5 @@ <template> -<MkModal ref="modal" :prefer-type="'dialog'" @click="onBgClick" @closed="$emit('closed')"> +<MkModal ref="modal" :preferType="'dialog'" @click="onBgClick" @closed="$emit('closed')"> <div ref="rootEl" :class="$style.root" :style="{ width: `${width}px`, height: `min(${height}px, 100%)` }" @keydown="onKeydown"> <div ref="headerEl" :class="$style.header"> <button v-if="withOkButton" :class="$style.headerButton" class="_button" @click="$emit('close')"><i class="ti ti-x"></i></button> From 25d1b66ca48a6c513aebe59397ea705a562f2e55 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 17:22:09 +0900 Subject: [PATCH 110/213] refactor --- .../src/ui/_common_/statusbar-federation.vue | 73 +++++++++------- .../src/ui/_common_/statusbar-rss.vue | 57 ++++++------ .../src/ui/_common_/statusbar-user-list.vue | 87 ++++++++++--------- 3 files changed, 118 insertions(+), 99 deletions(-) diff --git a/packages/frontend/src/ui/_common_/statusbar-federation.vue b/packages/frontend/src/ui/_common_/statusbar-federation.vue index fe95460ba4..4ea84c82c2 100644 --- a/packages/frontend/src/ui/_common_/statusbar-federation.vue +++ b/packages/frontend/src/ui/_common_/statusbar-federation.vue @@ -1,14 +1,20 @@ <template> -<span v-if="!fetching" class="nmidsaqw"> +<span v-if="!fetching" :class="$style.root"> <template v-if="display === 'marquee'"> - <Transition name="change" mode="default"> + <Transition + :enterActiveClass="$style.transition_change_enterActive" + :leaveActiveClass="$style.transition_change_leaveActive" + :enterFromClass="$style.transition_change_enterFrom" + :leaveToClass="$style.transition_change_leaveTo" + mode="default" + > <MarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> - <span v-for="instance in instances" :key="instance.id" class="item" :class="{ colored }" :style="{ background: colored ? instance.themeColor : null }"> - <img class="icon" :src="getInstanceIcon(instance)" alt=""/> - <MkA :to="`/instance-info/${instance.host}`" class="host _monospace"> + <span v-for="instance in instances" :key="instance.id" :class="[$style.item, { [$style.colored]: colored }]" :style="{ background: colored ? instance.themeColor : null }"> + <img :class="$style.icon" :src="getInstanceIcon(instance)" alt=""/> + <MkA :to="`/instance-info/${instance.host}`" :class="$style.host" class="_monospace"> {{ instance.host }} </MkA> - <span class="divider"></span> + <span :class="$style.divider"></span> </span> </MarqueeText> </Transition> @@ -61,46 +67,47 @@ function getInstanceIcon(instance): string { } </script> -<style lang="scss" scoped> -.change-enter-active, .change-leave-active { +<style lang="scss" module> +.transition_change_enterActive, +.transition_change_leaveActive { position: absolute; top: 0; transition: all 1s ease; } -.change-enter-from { - opacity: 0; +.transition_change_enterFrom { + opacity: 0; transform: translateY(-100%); } -.change-leave-to { - opacity: 0; +.transition_change_leaveTo { + opacity: 0; transform: translateY(100%); } -.nmidsaqw { +.root { display: inline-block; position: relative; +} - ::v-deep(.item) { - display: inline-block; - vertical-align: bottom; - margin-right: 5em; +.item { + display: inline-block; + vertical-align: bottom; + margin-right: 5em; - > .icon { - display: inline-block; - height: var(--height); - aspect-ratio: 1; - vertical-align: bottom; - margin-right: 1em; - } - - > .host { - vertical-align: bottom; - } - - &.colored { - padding-right: 1em; - color: #fff; - } + &.colored { + padding-right: 1em; + color: #fff; } } + +.icon { + display: inline-block; + height: var(--height); + aspect-ratio: 1; + vertical-align: bottom; + margin-right: 1em; +} + +.host { + vertical-align: bottom; +} </style> diff --git a/packages/frontend/src/ui/_common_/statusbar-rss.vue b/packages/frontend/src/ui/_common_/statusbar-rss.vue index 44b6b278ea..82473b609f 100644 --- a/packages/frontend/src/ui/_common_/statusbar-rss.vue +++ b/packages/frontend/src/ui/_common_/statusbar-rss.vue @@ -1,10 +1,16 @@ <template> -<span v-if="!fetching" class="xbhtxfms"> +<span v-if="!fetching" :class="$style.root"> <template v-if="display === 'marquee'"> - <Transition name="change" mode="default"> + <Transition + :enterActiveClass="$style.transition_change_enterActive" + :leaveActiveClass="$style.transition_change_leaveActive" + :enterFromClass="$style.transition_change_enterFrom" + :leaveToClass="$style.transition_change_leaveTo" + mode="default" + > <MarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> - <span v-for="item in items" class="item"> - <a class="link" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span class="divider"></span> + <span v-for="item in items" :class="$style.item"> + <a :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span :class="$style.divider"></span> </span> </MarqueeText> </Transition> @@ -54,39 +60,40 @@ useInterval(tick, Math.max(5000, props.refreshIntervalSec * 1000), { }); </script> -<style lang="scss" scoped> -.change-enter-active, .change-leave-active { +<style lang="scss" module> +.transition_change_enterActive, +.transition_change_leaveActive { position: absolute; top: 0; transition: all 1s ease; } -.change-enter-from { - opacity: 0; +.transition_change_enterFrom { + opacity: 0; transform: translateY(-100%); } -.change-leave-to { - opacity: 0; +.transition_change_leaveTo { + opacity: 0; transform: translateY(100%); } -.xbhtxfms { +.root { display: inline-block; position: relative; +} - ::v-deep(.item) { - display: inline-flex; - align-items: center; - vertical-align: bottom; - margin: 0; +.item { + display: inline-flex; + align-items: center; + vertical-align: bottom; + margin: 0; +} - > .divider { - display: inline-block; - width: 0.5px; - height: var(--height); - margin: 0 3em; - background: currentColor; - opacity: 0.3; - } - } +.divider { + display: inline-block; + width: 0.5px; + height: var(--height); + margin: 0 3em; + background: currentColor; + opacity: 0.3; } </style> diff --git a/packages/frontend/src/ui/_common_/statusbar-user-list.vue b/packages/frontend/src/ui/_common_/statusbar-user-list.vue index 16df69d968..9ac744943d 100644 --- a/packages/frontend/src/ui/_common_/statusbar-user-list.vue +++ b/packages/frontend/src/ui/_common_/statusbar-user-list.vue @@ -1,14 +1,20 @@ <template> -<span v-if="!fetching" class="osdsvwzy"> +<span v-if="!fetching" :class="$style.root"> <template v-if="display === 'marquee'"> - <Transition name="change" mode="default"> + <Transition + :enterActiveClass="$style.transition_change_enterActive" + :leaveActiveClass="$style.transition_change_leaveActive" + :enterFromClass="$style.transition_change_enterFrom" + :leaveToClass="$style.transition_change_leaveTo" + mode="default" + > <MarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> - <span v-for="note in notes" :key="note.id" class="item"> - <img class="avatar" :src="note.user.avatarUrl" decoding="async"/> - <MkA class="text" :to="notePage(note)"> - <Mfm class="text" :text="getNoteSummary(note)" :plain="true" :nowrap="true"/> + <span v-for="note in notes" :key="note.id" :class="$style.item"> + <img :class="$style.avatar" :src="note.user.avatarUrl" decoding="async"/> + <MkA :class="$style.text" :to="notePage(note)"> + <Mfm :text="getNoteSummary(note)" :plain="true" :nowrap="true"/> </MkA> - <span class="divider"></span> + <span :class="$style.divider"></span> </span> </MarqueeText> </Transition> @@ -60,54 +66,53 @@ useInterval(tick, Math.max(5000, props.refreshIntervalSec * 1000), { }); </script> -<style lang="scss" scoped> -.change-enter-active, .change-leave-active { +<style lang="scss" module> +.transition_change_enterActive, +.transition_change_leaveActive { position: absolute; top: 0; transition: all 1s ease; } -.change-enter-from { - opacity: 0; +.transition_change_enterFrom { + opacity: 0; transform: translateY(-100%); } -.change-leave-to { - opacity: 0; +.transition_change_leaveTo { + opacity: 0; transform: translateY(100%); } -.osdsvwzy { +.root { display: inline-block; position: relative; +} - ::v-deep(.item) { - display: inline-flex; - align-items: center; - vertical-align: bottom; - margin: 0; +.item { + display: inline-flex; + align-items: center; + vertical-align: bottom; + margin: 0; +} - > .avatar { - display: inline-block; - height: var(--height); - aspect-ratio: 1; - vertical-align: bottom; - margin-right: 8px; - } +.avatar { + display: inline-block; + height: var(--height); + aspect-ratio: 1; + vertical-align: bottom; + margin-right: 8px; +} - > .text { - > .text { - display: inline-block; - vertical-align: bottom; - } - } +.text { + display: inline-block; + vertical-align: bottom; +} - > .divider { - display: inline-block; - width: 0.5px; - height: 16px; - margin: 0 3em; - background: currentColor; - opacity: 0; - } - } +.divider { + display: inline-block; + width: 0.5px; + height: 16px; + margin: 0 3em; + background: currentColor; + opacity: 0; } </style> From a1200ad886a6643914dde091a568ca9413584f3d Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 17:24:46 +0900 Subject: [PATCH 111/213] lint --- packages/frontend/src/pages/user/index.activity.vue | 2 +- packages/frontend/src/ui/deck/antenna-column.vue | 6 +----- packages/frontend/src/ui/deck/channel-column.vue | 6 +----- packages/frontend/src/ui/deck/direct-column.vue | 3 --- packages/frontend/src/ui/deck/list-column.vue | 6 +----- packages/frontend/src/ui/deck/main-column.vue | 3 --- packages/frontend/src/ui/deck/mentions-column.vue | 3 --- packages/frontend/src/ui/deck/notifications-column.vue | 3 --- packages/frontend/src/ui/deck/role-timeline-column.vue | 6 +----- packages/frontend/src/ui/deck/tl-column.vue | 6 +----- packages/frontend/src/ui/deck/widgets-column.vue | 3 --- 11 files changed, 6 insertions(+), 41 deletions(-) diff --git a/packages/frontend/src/pages/user/index.activity.vue b/packages/frontend/src/pages/user/index.activity.vue index 2d9ee85bc4..64d36307e9 100644 --- a/packages/frontend/src/pages/user/index.activity.vue +++ b/packages/frontend/src/pages/user/index.activity.vue @@ -9,7 +9,7 @@ </template> <div style="padding: 8px;"> - <MkChart :src="chartSrc" :args="{ user, withoutAll: true }" span="day" :limit="limit" :bar="true" :stacked="true" :detailed="false" :aspect-ratio="5"/> + <MkChart :src="chartSrc" :args="{ user, withoutAll: true }" span="day" :limit="limit" :bar="true" :stacked="true" :detailed="false" :aspectRatio="5"/> </div> </MkContainer> </template> diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue index d35fa58638..d21a9cc580 100644 --- a/packages/frontend/src/ui/deck/antenna-column.vue +++ b/packages/frontend/src/ui/deck/antenna-column.vue @@ -4,7 +4,7 @@ <i class="ti ti-antenna"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> - <MkTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId" @after="() => emit('loaded')"/> + <MkTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId"/> </XColumn> </template> @@ -21,10 +21,6 @@ const props = defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ - (ev: 'loaded'): void; -}>(); - let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); onMounted(() => { diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue index a967d9f08e..8b05ecc0bb 100644 --- a/packages/frontend/src/ui/deck/channel-column.vue +++ b/packages/frontend/src/ui/deck/channel-column.vue @@ -8,7 +8,7 @@ <div style="padding: 8px; text-align: center;"> <MkButton primary gradate rounded inline @click="post"><i class="ti ti-pencil"></i></MkButton> </div> - <MkTimeline ref="timeline" src="channel" :channel="column.channelId" @after="() => emit('loaded')"/> + <MkTimeline ref="timeline" src="channel" :channel="column.channelId"/> </template> </XColumn> </template> @@ -27,10 +27,6 @@ const props = defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ - (ev: 'loaded'): void; -}>(); - let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); let channel = $shallowRef<misskey.entities.Channel>(); diff --git a/packages/frontend/src/ui/deck/direct-column.vue b/packages/frontend/src/ui/deck/direct-column.vue index f3397ceae6..dc3f58e6a4 100644 --- a/packages/frontend/src/ui/deck/direct-column.vue +++ b/packages/frontend/src/ui/deck/direct-column.vue @@ -17,9 +17,6 @@ defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ -}>(); - const pagination = { endpoint: 'notes/mentions' as const, limit: 10, diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue index 439db8815a..f36dc6151c 100644 --- a/packages/frontend/src/ui/deck/list-column.vue +++ b/packages/frontend/src/ui/deck/list-column.vue @@ -4,7 +4,7 @@ <i class="ti ti-list"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> - <MkTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" @after="() => emit('loaded')"/> + <MkTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId"/> </XColumn> </template> @@ -21,10 +21,6 @@ const props = defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ - (ev: 'loaded'): void; -}>(); - let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); if (props.column.listId == null) { diff --git a/packages/frontend/src/ui/deck/main-column.vue b/packages/frontend/src/ui/deck/main-column.vue index b2b558b308..169fac70a2 100644 --- a/packages/frontend/src/ui/deck/main-column.vue +++ b/packages/frontend/src/ui/deck/main-column.vue @@ -25,9 +25,6 @@ defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ -}>(); - let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); provide('router', mainRouter); diff --git a/packages/frontend/src/ui/deck/mentions-column.vue b/packages/frontend/src/ui/deck/mentions-column.vue index 63fc57db74..98cf898749 100644 --- a/packages/frontend/src/ui/deck/mentions-column.vue +++ b/packages/frontend/src/ui/deck/mentions-column.vue @@ -17,9 +17,6 @@ defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ -}>(); - const pagination = { endpoint: 'notes/mentions' as const, limit: 10, diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue index e10b496447..8cf6ec1f65 100644 --- a/packages/frontend/src/ui/deck/notifications-column.vue +++ b/packages/frontend/src/ui/deck/notifications-column.vue @@ -19,9 +19,6 @@ const props = defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ -}>(); - function func() { os.popup(defineAsyncComponent(() => import('@/components/MkNotificationSettingWindow.vue')), { includingTypes: props.column.includingTypes, diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue index df21fff431..a0b7f1c675 100644 --- a/packages/frontend/src/ui/deck/role-timeline-column.vue +++ b/packages/frontend/src/ui/deck/role-timeline-column.vue @@ -4,7 +4,7 @@ <i class="ti ti-badge"></i><span style="margin-left: 8px;">{{ column.name }}</span> </template> - <MkTimeline v-if="column.roleId" ref="timeline" src="role" :role="column.roleId" @after="() => emit('loaded')"/> + <MkTimeline v-if="column.roleId" ref="timeline" src="role" :role="column.roleId"/> </XColumn> </template> @@ -21,10 +21,6 @@ const props = defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ - (ev: 'loaded'): void; -}>(); - let timeline = $shallowRef<InstanceType<typeof MkTimeline>>(); onMounted(() => { diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue index c0840f9d98..4844ad11ff 100644 --- a/packages/frontend/src/ui/deck/tl-column.vue +++ b/packages/frontend/src/ui/deck/tl-column.vue @@ -15,7 +15,7 @@ </p> <p :class="$style.disabledDescription">{{ i18n.ts._disabledTimeline.description }}</p> </div> - <MkTimeline v-else-if="column.tl" ref="timeline" :key="column.tl" :src="column.tl" @after="() => emit('loaded')"/> + <MkTimeline v-else-if="column.tl" ref="timeline" :key="column.tl" :src="column.tl"/> </XColumn> </template> @@ -34,10 +34,6 @@ const props = defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ - (ev: 'loaded'): void; -}>(); - let disabled = $ref(false); const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable)); diff --git a/packages/frontend/src/ui/deck/widgets-column.vue b/packages/frontend/src/ui/deck/widgets-column.vue index 2c4095ac4e..da14e54f74 100644 --- a/packages/frontend/src/ui/deck/widgets-column.vue +++ b/packages/frontend/src/ui/deck/widgets-column.vue @@ -21,9 +21,6 @@ const props = defineProps<{ isStacked: boolean; }>(); -const emit = defineEmits<{ -}>(); - let edit = $ref(false); function addWidget(widget) { From 115167e6dac3deb16266cfcf2b03242055f87b08 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 17:52:55 +0900 Subject: [PATCH 112/213] update deps --- packages/frontend/package.json | 42 +- pnpm-lock.yaml | 855 +++++++++++++++++---------------- 2 files changed, 472 insertions(+), 425 deletions(-) diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 9a471c9c07..1175ce2e1e 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -70,40 +70,40 @@ "typescript": "5.0.4", "uuid": "9.0.0", "vanilla-tilt": "1.8.0", - "vite": "4.3.8", + "vite": "4.3.9", "vue": "3.3.4", "vue-plyr": "7.0.0", "vue-prism-editor": "2.0.0-alpha.2", "vuedraggable": "next" }, "devDependencies": { - "@storybook/addon-actions": "7.0.15", - "@storybook/addon-essentials": "7.0.15", - "@storybook/addon-interactions": "7.0.15", - "@storybook/addon-links": "7.0.15", - "@storybook/addon-storysource": "7.0.15", - "@storybook/addons": "7.0.15", - "@storybook/blocks": "7.0.15", - "@storybook/core-events": "7.0.15", + "@storybook/addon-actions": "7.0.18", + "@storybook/addon-essentials": "7.0.18", + "@storybook/addon-interactions": "7.0.18", + "@storybook/addon-links": "7.0.18", + "@storybook/addon-storysource": "7.0.18", + "@storybook/addons": "7.0.18", + "@storybook/blocks": "7.0.18", + "@storybook/core-events": "7.0.18", "@storybook/jest": "0.1.0", - "@storybook/manager-api": "7.0.15", - "@storybook/preview-api": "7.0.15", - "@storybook/react": "7.0.15", - "@storybook/react-vite": "7.0.15", + "@storybook/manager-api": "7.0.18", + "@storybook/preview-api": "7.0.18", + "@storybook/react": "7.0.18", + "@storybook/react-vite": "7.0.18", "@storybook/testing-library": "0.1.0", - "@storybook/theming": "7.0.15", - "@storybook/types": "7.0.15", - "@storybook/vue3": "7.0.15", - "@storybook/vue3-vite": "7.0.15", + "@storybook/theming": "7.0.18", + "@storybook/types": "7.0.18", + "@storybook/vue3": "7.0.18", + "@storybook/vue3-vite": "7.0.18", "@testing-library/jest-dom": "5.16.5", "@testing-library/vue": "7.0.0", "@types/escape-regexp": "0.0.1", "@types/estree": "1.0.1", "@types/gulp": "4.0.10", "@types/gulp-rename": "2.0.2", - "@types/matter-js": "0.18.4", + "@types/matter-js": "0.18.5", "@types/micromatch": "4.0.2", - "@types/node": "20.2.3", + "@types/node": "20.2.5", "@types/punycode": "2.1.0", "@types/sanitize-html": "2.9.0", "@types/seedrandom": "3.0.5", @@ -123,7 +123,7 @@ "cypress": "12.13.0", "eslint": "8.40.0", "eslint-plugin-import": "2.27.5", - "eslint-plugin-vue": "9.14.0", + "eslint-plugin-vue": "9.14.1", "fast-glob": "3.2.12", "happy-dom": "9.19.2", "micromatch": "3.1.10", @@ -133,7 +133,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "start-server-and-test": "2.0.0", - "storybook": "7.0.15", + "storybook": "7.0.18", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "summaly": "github:misskey-dev/summaly", "vite-plugin-turbosnap": "1.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57e8cf850d..6d836499ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -650,7 +650,7 @@ importers: version: 2.17.0 '@vitejs/plugin-vue': specifier: 4.2.3 - version: 4.2.3(vite@4.3.8)(vue@3.3.4) + version: 4.2.3(vite@4.3.9)(vue@3.3.4) '@vue-macros/reactivity-transform': specifier: 0.3.8 version: 0.3.8(rollup@3.23.0)(vue@3.3.4) @@ -796,8 +796,8 @@ importers: specifier: 1.8.0 version: 1.8.0 vite: - specifier: 4.3.8 - version: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + specifier: 4.3.9 + version: 4.3.9(@types/node@20.2.5)(sass@1.62.1) vue: specifier: 3.3.4 version: 3.3.4 @@ -812,59 +812,59 @@ importers: version: 4.1.0(vue@3.3.4) devDependencies: '@storybook/addon-actions': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-essentials': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-interactions': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-links': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/addon-storysource': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/addons': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/blocks': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/core-events': - specifier: 7.0.15 - version: 7.0.15 + specifier: 7.0.18 + version: 7.0.18 '@storybook/jest': specifier: 0.1.0 version: 0.1.0 '@storybook/manager-api': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/preview-api': - specifier: 7.0.15 - version: 7.0.15 + specifier: 7.0.18 + version: 7.0.18 '@storybook/react': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) '@storybook/react-vite': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9) '@storybook/testing-library': specifier: 0.1.0 version: 0.1.0 '@storybook/theming': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0) '@storybook/types': - specifier: 7.0.15 - version: 7.0.15 + specifier: 7.0.18 + version: 7.0.18 '@storybook/vue3': - specifier: 7.0.15 - version: 7.0.15(vue@3.3.4) + specifier: 7.0.18 + version: 7.0.18(vue@3.3.4) '@storybook/vue3-vite': - specifier: 7.0.15 - version: 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4) + specifier: 7.0.18 + version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9)(vue@3.3.4) '@testing-library/jest-dom': specifier: 5.16.5 version: 5.16.5 @@ -884,14 +884,14 @@ importers: specifier: 2.0.2 version: 2.0.2 '@types/matter-js': - specifier: 0.18.4 - version: 0.18.4 + specifier: 0.18.5 + version: 0.18.5 '@types/micromatch': specifier: 4.0.2 version: 4.0.2 '@types/node': - specifier: 20.2.3 - version: 20.2.3 + specifier: 20.2.5 + version: 20.2.5 '@types/punycode': specifier: 2.1.0 version: 2.1.0 @@ -950,8 +950,8 @@ importers: specifier: 2.27.5 version: 2.27.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0) eslint-plugin-vue: - specifier: 9.14.0 - version: 9.14.0(eslint@8.40.0) + specifier: 9.14.1 + version: 9.14.1(eslint@8.40.0) fast-glob: specifier: 3.2.12 version: 3.2.12 @@ -980,11 +980,11 @@ importers: specifier: 2.0.0 version: 2.0.0 storybook: - specifier: 7.0.15 - version: 7.0.15 + specifier: 7.0.18 + version: 7.0.18 storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.15)(@storybook/components@7.0.15)(@storybook/core-events@7.0.15)(@storybook/manager-api@7.0.15)(@storybook/preview-api@7.0.15)(@storybook/theming@7.0.15)(@storybook/types@7.0.15)(react-dom@18.2.0)(react@18.2.0) + version: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.18)(@storybook/components@7.0.18)(@storybook/core-events@7.0.18)(@storybook/manager-api@7.0.18)(@storybook/preview-api@7.0.18)(@storybook/theming@7.0.18)(@storybook/types@7.0.18)(react-dom@18.2.0)(react@18.2.0) summaly: specifier: github:misskey-dev/summaly version: github.com/misskey-dev/summaly/77dd5654bb82280b38c1f50e51a771c33f3df503 @@ -3979,7 +3979,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 chalk: 4.1.2 jest-message-util: 29.5.0 jest-util: 29.5.0 @@ -4000,14 +4000,14 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.5.0 - jest-config: 29.5.0(@types/node@20.2.3) + jest-config: 29.5.0(@types/node@20.2.5) jest-haste-map: 29.5.0 jest-message-util: 29.5.0 jest-regex-util: 29.4.3 @@ -4041,7 +4041,7 @@ packages: dependencies: '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 jest-mock: 29.5.0 dev: true @@ -4068,7 +4068,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@sinonjs/fake-timers': 10.0.2 - '@types/node': 20.2.3 + '@types/node': 20.2.5 jest-message-util: 29.5.0 jest-mock: 29.5.0 jest-util: 29.5.0 @@ -4101,7 +4101,7 @@ packages: '@jest/transform': 29.5.0 '@jest/types': 29.5.0 '@jridgewell/trace-mapping': 0.3.17 - '@types/node': 20.2.3 + '@types/node': 20.2.5 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -4195,7 +4195,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: true @@ -4207,12 +4207,12 @@ packages: '@jest/schemas': 29.4.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/yargs': 17.0.19 chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.0.4)(vite@4.3.8): + /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.0.4)(vite@4.3.9): resolution: {integrity: sha512-ou4ZJSXMMWHqGS4g8uNRbC5TiTWxAgQZiVucoUrOCWuPrTbkpJbmVyIi9jU72SBry7gQtuMEDp4YR8EEXAg7VQ==} peerDependencies: typescript: '>= 4.3.x' @@ -4226,7 +4226,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.0.4) typescript: 5.0.4 - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) dev: true /@jridgewell/gen-mapping@0.3.2: @@ -4854,8 +4854,8 @@ packages: resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} dev: false - /@storybook/addon-actions@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-1urDxJpG5BTmZCbda+93iuCNwzj7AiPt/VlmpDpd9Mc/WTOKBg0cXo8oBLibOZgCTLEx+4sq5eVgdMVybBa87g==} + /@storybook/addon-actions@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3M5AU/ZD79YP88vKlFezIJbIoG/II7wCixUBTmwiC3BeQZDuVsqPNl8eiP6MGT70xwyx7a993lSM5f5N5W93vg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4865,14 +4865,14 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 dequal: 2.0.3 lodash: 4.17.21 polished: 4.2.2 @@ -4885,8 +4885,8 @@ packages: uuid: 9.0.0 dev: true - /@storybook/addon-backgrounds@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-cUb5i3dn4MhXFtCuA8p/ax6dtFaJ52+q6Dex8L40DtWC/fPrC2igAXN4o7WhRHztY6utZSLy4invEjqAFCEYRw==} + /@storybook/addon-backgrounds@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-cPQy1Ot7Urf4hQz+xnF1YKrqSyR0DRwozBmF+sGzceACWmueFl0CifYZC8RSmaiIyVh0RyWPxZ9F/eT67NX2lA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4896,22 +4896,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-controls@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-sLLYVgprrsC6k0/2ErKJSa6Jtlxo+lHSO41K6nB0WQmQ8Moroe2kBaNTP6C9+zhGuI427Eueuzs3cKHwn/eIKw==} + /@storybook/addon-controls@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-mD6DE52CCMKugXk2Uab0QxwgfE76kFJroxASmnePnXUNWfP9EZJpJXYE3cyyBbmZuxa46VHDGGEGXQWRl4+Eog==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4921,15 +4921,15 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.15 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.0.15 - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/blocks': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.18 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.0.18 + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 lodash: 4.17.21 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4938,8 +4938,8 @@ packages: - supports-color dev: true - /@storybook/addon-docs@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-FBXHFwm6wH3SYsv73SmVQMs+FxP8eSoWlDFBEZ1lulCK7f0NKflhzTTimyh9m+aRCsbvC2Vm+7/9CJ5OZU+GEQ==} + /@storybook/addon-docs@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-oq+ZN5809gIRdTZQIpeK1F8BJtL1/VWo9rWvl6ymVOL/Xzdgd7AOfKf9Y99X35RcxAGysRIHLGJjF4bgLoY1Aw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4948,19 +4948,19 @@ packages: '@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.21.3) '@jest/transform': 29.5.0 '@mdx-js/react': 2.3.0(react@18.2.0) - '@storybook/blocks': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/csf-plugin': 7.0.15 - '@storybook/csf-tools': 7.0.15 + '@storybook/blocks': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/csf-plugin': 7.0.18 + '@storybook/csf-tools': 7.0.18 '@storybook/global': 5.0.0 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.0.15 - '@storybook/postinstall': 7.0.15 - '@storybook/preview-api': 7.0.15 - '@storybook/react-dom-shim': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/node-logger': 7.0.18 + '@storybook/postinstall': 7.0.18 + '@storybook/preview-api': 7.0.18 + '@storybook/react-dom-shim': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 fs-extra: 11.1.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -4971,25 +4971,25 @@ packages: - supports-color dev: true - /@storybook/addon-essentials@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-YfacNHFOkXu3Ela/Bo7VIJ4cA7/KUFrSzQ463R9GxKsUpBOoXEowbZnur/Aa6ipX7arckdzpc7vXkPFGiRlsdw==} + /@storybook/addon-essentials@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-0XXu7xhtRefA1WxxorKk6BWeeB+7gQ+r2+bG1zQEfBgDYPR06YbPw4H79IZ8JiR97aJRsZBK5UUhOZMDrc5zcQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/addon-actions': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-backgrounds': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-controls': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-docs': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-highlight': 7.0.15 - '@storybook/addon-measure': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-outline': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-toolbars': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/addon-viewport': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.15 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/node-logger': 7.0.15 - '@storybook/preview-api': 7.0.15 + '@storybook/addon-actions': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-backgrounds': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-controls': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-docs': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-highlight': 7.0.18 + '@storybook/addon-measure': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-outline': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-toolbars': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/addon-viewport': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.18 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/node-logger': 7.0.18 + '@storybook/preview-api': 7.0.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 @@ -4997,16 +4997,16 @@ packages: - supports-color dev: true - /@storybook/addon-highlight@7.0.15: - resolution: {integrity: sha512-lqf2rZkCpbxse0DXWjlRbCUTjCbUDNTh0aqt1L2NJkZKN2UrHjKbCXOHdtbMJewTLCuatKmjpHNbYp3sAzVq7w==} + /@storybook/addon-highlight@7.0.18: + resolution: {integrity: sha512-a3nfUhbu6whoDclIZSV/fzLj132tNNjV05ENTpuN3JpLoMd3+obDUWzeQUs9TetK4RBRN3ewM7sIMEI4oBpgmg==} dependencies: - '@storybook/core-events': 7.0.15 + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.15 + '@storybook/preview-api': 7.0.18 dev: true - /@storybook/addon-interactions@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-yhPhGMGdYwjYOaSLIp8iol9owpo5Dwk4UcH7WS7z4GwYgQwZ1GYBty1NcVpmxvFA429WQp0grqhJ+Q2xaJYstw==} + /@storybook/addon-interactions@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-V3OD5lSj6Te6Kzc//2k2S79dLPk6Zu1pAbqWAN4RrdXyKj6YCiZ666GmVdiaG+24Qp5UuMeAkd1D05osJlOteA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5016,16 +5016,16 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-common': 7.0.15 - '@storybook/core-events': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-common': 7.0.18 + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 7.0.15 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/instrumenter': 7.0.18 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 jest-mock: 27.5.1 polished: 4.2.2 react: 18.2.0 @@ -5035,8 +5035,8 @@ packages: - supports-color dev: true - /@storybook/addon-links@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-rr2L46GeqX/4tvINzFTwe2TCq1gTFsOqMXPIgpsoiIA7A6Kj8AMGya3tWr7GPCK23MZxkuquyj+jTbO4kZjCwQ==} + /@storybook/addon-links@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-xEwflt7bp9FRoZVeqPGb6d3s2Gh+/jaSmnyIxMxrBy2oovKIqu9ptolqz1AhjFOXfaLs9c2RAmJUuFZJtETLxA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5046,22 +5046,22 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/core-events': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/core-events': 7.0.18 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/router': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/router': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-measure@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-jnLh/Kyb6DWL5wdtqcR8Quuf25GzU6bmAJfMbQ/WUbf60M2fXK4d6h6YiFY9HSiAzc/UaH66tiAvqwe+ztgf4A==} + /@storybook/addon-measure@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-iu8vQpGOA+CFYbWR6QNshj20o33OQ/xcTbp5P4U6xGYDUliUBbwJ2KLxcKlmIeBanBrBdz0jPFtHwY4dM1ZdKw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5071,19 +5071,19 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/types': 7.0.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addon-outline@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-fc4P5f9bk0m8g5MDyj5V4MFsyNlMWEk1wPD6oBoi7VluTBZxfeLRaNrj9Ek6uDcuilTz2KBAf9aOMgluhEKEYw==} + /@storybook/addon-outline@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3vNWO7ezo6GIvidbz8JxFrKtfVEoTQN7tnZx+wpqmCF8ihBORewkpeMUnvgb9ZKjD0X7gE8eQvvG8KKWcyHDBQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5093,20 +5093,20 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/types': 7.0.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) ts-dedent: 2.2.0 dev: true - /@storybook/addon-storysource@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-62UHB6m/CA5+YfrdmHVzoI7yULaKXfrTK5ymNm8qV/zOx5QNYkldmtEfKZSDbeMlW740Awgd4QBD3neS2TNFXQ==} + /@storybook/addon-storysource@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ejOO9d9Aa63DCXCoXtCsOJLefdbrsvSAEV9wU2HfT+EOIS1dq/SV+ZtIMAvdAf4whB42K+pEzB5hLE2+zCK9PQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5116,13 +5116,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/router': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/source-loader': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/router': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/source-loader': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) estraverse: 5.3.0 prop-types: 15.8.1 react: 18.2.0 @@ -5130,8 +5130,8 @@ packages: react-syntax-highlighter: 15.5.0(react@18.2.0) dev: true - /@storybook/addon-toolbars@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-DOyOHlChprAn/QLENBeu13MiGjNXHPJt+uOt+GlBY6b4oZbDUHC9l4uC+C/iDzuGBZ1hZ9VQlS2xM8GUcyy78w==} + /@storybook/addon-toolbars@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-mwhq962o0WloHAeFjJ6BXO2nzdTo5KE2fqawPpqcB2lwXP6tvaA2tDWwgntjPCHejqWTS+ZTdO4/1xrMhWYt/g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5141,17 +5141,17 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addon-viewport@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-VIOEVKlgHlbzVz00aehSgFa8rSZZDBleadyGKm+XPtuZmY5ovyCYtp1CBtslTxmzJ/U1e2I++SCqeuT4bxNarw==} + /@storybook/addon-viewport@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aVVLBsWXfGDX3z1pc93LWWdG5RUoJbGL/JJPMZGwXdwWpP8V3OBl8D8bgPymyg+MgwhSRZZDDGgnJaVGGwZ6bQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5161,49 +5161,49 @@ packages: react-dom: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) memoizerific: 1.11.3 prop-types: 15.8.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/addons@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-7C9NlhFy9iJopulYhzUaxsNepOFG3tIMrzxfxkLVizlparffDybWfHtUa27wfMAnOu7G71jE7+PreJDz0Lyblg==} + /@storybook/addons@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-+j9ItxWoVzarbllaV4WRaJpDM3P2aC5O6F3cPn4YkG/unb6HOs11WLAqFbzZnLYZNAFvWS8PYEAtqs1BxG66YQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/types': 7.0.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/blocks@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-ygWH4UukbfEOdTnYs0uWVNQflR2ZEmX4izyLdDrbk3XCi8O5SdgAa4vb7/KW7sErIgkLWr/vo1INo/XXrX/Ceg==} + /@storybook/blocks@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-HLsuzmUdVIeFXEP5v5vyjnEePRNYjzltwTjCKQhHAlt8/aQZmREiIMOfoMoAa1Rd+On8Ib2DUd2cN10VS18H8A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.0.15 - '@storybook/client-logger': 7.0.15 - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.15 + '@storybook/channels': 7.0.18 + '@storybook/client-logger': 7.0.18 + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.18 '@storybook/csf': 0.1.0 - '@storybook/docs-tools': 7.0.15 + '@storybook/docs-tools': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 '@types/lodash': 4.14.191 color-convert: 2.0.1 dequal: 2.0.3 @@ -5221,13 +5221,13 @@ packages: - supports-color dev: true - /@storybook/builder-manager@7.0.15: - resolution: {integrity: sha512-NeEhrE6NTL8aOcxyH4TWazAI+6JyrhN+GUk+0ZPwzaraGfgAefMxATACHhDteU8DeSMQW3pymUOvU1uwjLrjWA==} + /@storybook/builder-manager@7.0.18: + resolution: {integrity: sha512-yFMm3xuYkyg2hS1uz3CkvyvLzK7qJsDPVEh7lew8GiJK1Xx8cc+FnAOlRTjWNxvhfiT296wAMCTPWv7LeoSgqQ==} dependencies: '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@storybook/core-common': 7.0.15 - '@storybook/manager': 7.0.15 - '@storybook/node-logger': 7.0.15 + '@storybook/core-common': 7.0.18 + '@storybook/manager': 7.0.18 + '@storybook/node-logger': 7.0.18 '@types/ejs': 3.1.2 '@types/find-cache-dir': 3.2.1 '@yarnpkg/esbuild-plugin-pnp': 3.0.0-rc.15(esbuild@0.17.18) @@ -5244,8 +5244,8 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.0.15(typescript@5.0.4)(vite@4.3.8): - resolution: {integrity: sha512-JLdStf1ykV54+FBfcO5GoPYJkhY413EhUNAFlZ04FqcVQjpRcRvWXZ/swiIFubAZo/2eHV8eGbRrlB/aNduq0w==} + /@storybook/builder-vite@7.0.18(typescript@5.0.4)(vite@4.3.9): + resolution: {integrity: sha512-Qze6/PwUJq+z776dBoG5uinAEVZyPalZIaU/VOWpTrN8L9FQbL0+HDrZU2E/BMNW+ZfnSjF3V2USLyiutsC1Tw==} peerDependencies: '@preact/preset-vite': '*' typescript: '>= 4.3.x' @@ -5259,17 +5259,16 @@ packages: vite-plugin-glimmerx: optional: true dependencies: - '@storybook/channel-postmessage': 7.0.15 - '@storybook/channel-websocket': 7.0.15 - '@storybook/client-logger': 7.0.15 - '@storybook/core-common': 7.0.15 - '@storybook/csf-plugin': 7.0.15 - '@storybook/global': 5.0.0 + '@storybook/channel-postmessage': 7.0.18 + '@storybook/channel-websocket': 7.0.18 + '@storybook/client-logger': 7.0.18 + '@storybook/core-common': 7.0.18 + '@storybook/csf-plugin': 7.0.18 '@storybook/mdx2-csf': 1.0.0 - '@storybook/node-logger': 7.0.15 - '@storybook/preview': 7.0.15 - '@storybook/preview-api': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/node-logger': 7.0.18 + '@storybook/preview': 7.0.18 + '@storybook/preview-api': 7.0.18 + '@storybook/types': 7.0.18 browser-assert: 1.2.1 es-module-lexer: 0.9.3 express: 4.18.2 @@ -5281,17 +5280,17 @@ packages: remark-slug: 6.1.0 rollup: 3.23.0 typescript: 5.0.4 - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true - /@storybook/channel-postmessage@7.0.15: - resolution: {integrity: sha512-5ZHIQI+Upb12C1lxeXHKVDBEtjjwtWN7XbTz+B1OQ09SRW4LEr8OMD/E9UHsQ2cuKrtBLPs8gkfYO+Ibvx5CkQ==} + /@storybook/channel-postmessage@7.0.18: + resolution: {integrity: sha512-rpwBH5ANdPnugS6+7xG9qHSoS+aPSEnBxDKsONWFubfMTTXQuFkf/793rBbxGkoINdqh8kSdKOM2rIty6e9cmQ==} dependencies: - '@storybook/channels': 7.0.15 - '@storybook/client-logger': 7.0.15 - '@storybook/core-events': 7.0.15 + '@storybook/channels': 7.0.18 + '@storybook/client-logger': 7.0.18 + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 qs: 6.11.1 telejson: 7.0.4 @@ -5319,17 +5318,17 @@ packages: telejson: 7.0.4 dev: true - /@storybook/channel-websocket@7.0.15: - resolution: {integrity: sha512-v+PWiSW0yLdDT+X8UXeacmWV9nmXu/AcWvodFEOj4/WUQnN2V5JJszbFm3lmFDrl1sGHEKZt8r3Q31yq3Jm5Lg==} + /@storybook/channel-websocket@7.0.18: + resolution: {integrity: sha512-QYsZIfe23NN4i+oIdPKHaYBehk3a/HYk57a+M2oR3Frmv8IOqc/e31uH+xx5NxnjHrTJj7Y80ZJw6EKB682S6w==} dependencies: - '@storybook/channels': 7.0.15 - '@storybook/client-logger': 7.0.15 + '@storybook/channels': 7.0.18 + '@storybook/client-logger': 7.0.18 '@storybook/global': 5.0.0 telejson: 7.0.4 dev: true - /@storybook/channels@7.0.15: - resolution: {integrity: sha512-oCXop4qiikZPOWTeuBYyURszXUW81V4SkOJ1c76rU69DQzzMyTZArlGZCSk2OlwePjsLcKGj9bw+6410MaDtCA==} + /@storybook/channels@7.0.18: + resolution: {integrity: sha512-rkA7ea0M3+dWS+71iHJdiZ5R2QuIdiVg0CgyLJHDagc1qej7pEVNhMWtppeq+X5Pwp9nkz8ZTQ7aCjTf6th0/A==} dev: true /@storybook/channels@7.0.2: @@ -5340,20 +5339,20 @@ packages: resolution: {integrity: sha512-+34cVmrXZ3lb1s5tDK+OWd5HLtEPSUMas0VKFJ0k9LBpFlVl9aiCZBJRvSYmWL7beauUfa+HSmJgjlD6228ChQ==} dev: true - /@storybook/cli@7.0.15: - resolution: {integrity: sha512-BxnSAdxsgCFVsey7ASONVJQ7coOZARQou13w7Xleq6y+a7Wi6JQRXNEeNA6JHjMiceuq69BMkvBYr+sJ9Bzwhg==} + /@storybook/cli@7.0.18: + resolution: {integrity: sha512-9n4J4thiCUsGSXiRc6ZysqYUaCMCrpu0/qgC+5ngfFRuMmZgUV0y5+0fmaOhT2XjsonTTgucizO82i7+ottCVg==} hasBin: true dependencies: '@babel/core': 7.21.3 '@babel/preset-env': 7.21.4(@babel/core@7.21.3) '@ndelangen/get-tarball': 3.0.7 - '@storybook/codemod': 7.0.15 - '@storybook/core-common': 7.0.15 - '@storybook/core-server': 7.0.15 - '@storybook/csf-tools': 7.0.15 - '@storybook/node-logger': 7.0.15 - '@storybook/telemetry': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/codemod': 7.0.18 + '@storybook/core-common': 7.0.18 + '@storybook/core-server': 7.0.18 + '@storybook/csf-tools': 7.0.18 + '@storybook/node-logger': 7.0.18 + '@storybook/telemetry': 7.0.18 + '@storybook/types': 7.0.18 '@types/semver': 7.5.0 boxen: 5.1.2 chalk: 4.1.2 @@ -5390,8 +5389,8 @@ packages: - utf-8-validate dev: true - /@storybook/client-logger@7.0.15: - resolution: {integrity: sha512-ezy6i7e0PvNB+s+gAmE2vEHgdlFQZIzpFkNMZjM/lsJYX5+Q7Jgz/+i/fWEtFILUBPiRQGqcDsH7PAn2AfGRcw==} + /@storybook/client-logger@7.0.18: + resolution: {integrity: sha512-uKgFdVedYoRDZBVrE1IBdWNHDFln1IxWEeI+7ZiNSQwREG9swHpU5Fa8DceclM/oLjJRuzG1jFzv+XZY8894+Q==} dependencies: '@storybook/global': 5.0.0 dev: true @@ -5408,16 +5407,16 @@ packages: '@storybook/global': 5.0.0 dev: true - /@storybook/codemod@7.0.15: - resolution: {integrity: sha512-mUoOuqjiPVeMU+Z1J+3QycTwc8IPZlvY24mqdHy6Q2y7vKgozu1G/D/OkJBV+zlleguBpBxQkDLRB3CHA+LVkQ==} + /@storybook/codemod@7.0.18: + resolution: {integrity: sha512-+9XFns29e8FpPLsqA8ZCQ3mNnIIKD3QnqGYkbkCVKi/G1fomvVQsIfsnkrYv5SobTbz29B4aNWxAaeSnO7/OGg==} dependencies: '@babel/core': 7.21.3 '@babel/preset-env': 7.21.4(@babel/core@7.21.3) '@babel/types': 7.21.5 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.0.15 - '@storybook/node-logger': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/csf-tools': 7.0.18 + '@storybook/node-logger': 7.0.18 + '@storybook/types': 7.0.18 cross-spawn: 7.0.3 globby: 11.1.0 jscodeshift: 0.14.0(@babel/preset-env@7.21.4) @@ -5428,17 +5427,17 @@ packages: - supports-color dev: true - /@storybook/components@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-aek4/F5h3DShxS17tUYzI2FBwDT8+IRkg3OnkvybJC2U0MizPjwNa8qUk0kt4lEzt1y1TwnXH7TFCjWYY5zS6A==} + /@storybook/components@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Jn1CbF9UAKt8BVaZtuhmthpcZ02VMaCFXR0ISfDXCpiMKnylmpP0+WfXcoKLzz6yS+EW8EW5S9+Qq8xgQY8H7A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.0.15 + '@storybook/client-logger': 7.0.18 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -5446,18 +5445,18 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/core-client@7.0.15: - resolution: {integrity: sha512-h4/X597DnWp3Ocpli1B27fpKLXEU1qD4PYCnJW4Pl9DyJXBbzCo2VFZ7LyG3Wrod7ZjrmGOYjOiSisS3f8pcPA==} + /@storybook/core-client@7.0.18: + resolution: {integrity: sha512-ueExRZx6fd9LRssgdhDJ0bL4Ir2RrbXzJz/kjIT2KgYY3l7jkhe0dpT3bOgGKjQt0f7XMFU24t/r7aDLGMB+2Q==} dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/preview-api': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/preview-api': 7.0.18 dev: true - /@storybook/core-common@7.0.15: - resolution: {integrity: sha512-uAgpAqGedA7oRXstkZJfJYzuQuK4IrbdfJmA+fVlQ8wdpOtV/BL9YVy80W+YJQCkgUYW7KDagpQ8OMqIpiWt2w==} + /@storybook/core-common@7.0.18: + resolution: {integrity: sha512-HZAB1NIK/Yv0x9poyzqYcue2tx39+MAF1mbHgGy+JJZRerO2fRShgo8f8VPH9ChbFCoJ7isL5wNhgGdg9kp2kA==} dependencies: - '@storybook/node-logger': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/node-logger': 7.0.18 + '@storybook/types': 7.0.18 '@types/node': 16.18.16 '@types/pretty-hrtime': 1.0.1 chalk: 4.1.2 @@ -5479,8 +5478,8 @@ packages: - supports-color dev: true - /@storybook/core-events@7.0.15: - resolution: {integrity: sha512-ffpOLFpDs1T/HVUpGNDyo7c81lfH3Vvga0Hl6uhxm6zi9PkayV3DCgtmZ/W7daC7DiJC+upG/ziMG+5Oj33PDQ==} + /@storybook/core-events@7.0.18: + resolution: {integrity: sha512-7gxHBQDezdKOeq/u1LL80Bwjfcwsv7XOS3yWQElcgqp+gLaYB6OwwgtkCB2yV6a6l4nep9IdPWE8G3TxIzn9xw==} dev: true /@storybook/core-events@7.0.2: @@ -5491,23 +5490,23 @@ packages: resolution: {integrity: sha512-kGrtjlYtjd4iTVk+Phb4CymZaVkB+MGscKAgcO8gfgJ/Q/gq8HQLVZSIzeoCDcDSHOGlBzbg2WVtdHIHhCKlOQ==} dev: true - /@storybook/core-server@7.0.15: - resolution: {integrity: sha512-342wGx7uk4j2R8Zk03GLkiwONXUMV2Frpw2HG2HmGviWArN4B3UmU0YHj00GjFM51kyYtjhaJVyTMA20x+6/Yw==} + /@storybook/core-server@7.0.18: + resolution: {integrity: sha512-zGSGYSoCaSXM28OYKW7zsmpo8VU1icubXLRgdF21fbMhFN1WVS+bPA5+gSkAMf8acq5RNM8uSKskh7E2YDVEqA==} dependencies: '@aw-web-design/x-default-browser': 1.4.88 '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-manager': 7.0.15 - '@storybook/core-common': 7.0.15 - '@storybook/core-events': 7.0.15 + '@storybook/builder-manager': 7.0.18 + '@storybook/core-common': 7.0.18 + '@storybook/core-events': 7.0.18 '@storybook/csf': 0.1.0 - '@storybook/csf-tools': 7.0.15 + '@storybook/csf-tools': 7.0.18 '@storybook/docs-mdx': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/manager': 7.0.15 - '@storybook/node-logger': 7.0.15 - '@storybook/preview-api': 7.0.15 - '@storybook/telemetry': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/manager': 7.0.18 + '@storybook/node-logger': 7.0.18 + '@storybook/preview-api': 7.0.18 + '@storybook/telemetry': 7.0.18 + '@storybook/types': 7.0.18 '@types/detect-port': 1.3.2 '@types/node': 16.18.16 '@types/node-fetch': 2.6.2 @@ -5543,24 +5542,24 @@ packages: - utf-8-validate dev: true - /@storybook/csf-plugin@7.0.15: - resolution: {integrity: sha512-qJwZ6FhTt5HhsXY1rgwqwB1aMbuUSJYEVDM2Y5w0vOB+RHRT6JZpZgVlFz2C8qagX/F27seq6GF0VtfgOAJpaA==} + /@storybook/csf-plugin@7.0.18: + resolution: {integrity: sha512-Cr/Qr4/H4JIYgbbmDjQIYuqjp6nOaZga73R3KZcuClk27B90sI2ADegMYvORgbFgSkwweNQjgak6hLoOyogAhw==} dependencies: - '@storybook/csf-tools': 7.0.15 + '@storybook/csf-tools': 7.0.18 unplugin: 0.10.2 transitivePeerDependencies: - supports-color dev: true - /@storybook/csf-tools@7.0.15: - resolution: {integrity: sha512-PTA8NJTWsAtHsmJcU18PJZA66vyiZtKJJwNL7bTkKuG5HJLer8En6OarJERomhnnr8k0I6dycfWmWgcfeTNoxg==} + /@storybook/csf-tools@7.0.18: + resolution: {integrity: sha512-0IJ2qdrxleTl67FUzsEvGcy96CY0OKyERE33tAsLNbvWcabdJKpLHP+rJwbsCw4z6IlS+kkmEffeFf5qRPTwkQ==} dependencies: '@babel/generator': 7.21.3 '@babel/parser': 7.21.9 '@babel/traverse': 7.21.3 '@babel/types': 7.21.5 '@storybook/csf': 0.1.0 - '@storybook/types': 7.0.15 + '@storybook/types': 7.0.18 fs-extra: 11.1.0 recast: 0.23.1 ts-dedent: 2.2.0 @@ -5578,13 +5577,13 @@ packages: resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} dev: true - /@storybook/docs-tools@7.0.15: - resolution: {integrity: sha512-d2GP3UGSz3TS6c/wcB+ngXRNwXlZzyy3vQRAFdirLeTjTN07koyr3aagd5mdJwlMbO2vEIVjNetY4TFX1zfuSQ==} + /@storybook/docs-tools@7.0.18: + resolution: {integrity: sha512-H95dW2DquGQ75ZVrFjvznPdCxT0eW6esDnemzLJB61KitcYZrWRavfrZzFtUcpzIa84OgY5pllFYt636v11LHQ==} dependencies: '@babel/core': 7.21.3 - '@storybook/core-common': 7.0.15 - '@storybook/preview-api': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/core-common': 7.0.18 + '@storybook/preview-api': 7.0.18 + '@storybook/types': 7.0.18 '@types/doctrine': 0.0.3 doctrine: 3.0.0 lodash: 4.17.21 @@ -5602,14 +5601,14 @@ packages: resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} dev: true - /@storybook/instrumenter@7.0.15: - resolution: {integrity: sha512-vg+glFfRwk9LRBdFYoRQa6JQrTpdIZV35C24dm+tytnIoGqe5jexI+Lmkb+417JQsfdYKZ11IaL0Zj43CbC6vw==} + /@storybook/instrumenter@7.0.18: + resolution: {integrity: sha512-fyQxeuVC0H+w3oyTuByE95xnAQ+l/WhUBVkHV2X+PWjg9vg9Y9JmrbNWynlvz5HLFlsY3qAWJh+ciVRVSvY5Jw==} dependencies: - '@storybook/channels': 7.0.15 - '@storybook/client-logger': 7.0.15 - '@storybook/core-events': 7.0.15 + '@storybook/channels': 7.0.18 + '@storybook/client-logger': 7.0.18 + '@storybook/core-events': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.15 + '@storybook/preview-api': 7.0.18 dev: true /@storybook/instrumenter@7.0.2: @@ -5641,20 +5640,20 @@ packages: jest-mock: 27.5.1 dev: true - /@storybook/manager-api@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-S5OZz8QB8pABLFV4hDJrZE5DLk/EJhn/i48xiycuAtBCVcU4jw4xOyrF4f2ZbtsaWQ5GLAAanOb8yTJcqKnItA==} + /@storybook/manager-api@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-anQkm09twL96YkKGXHa+LI0+yMaY6Jxs1lRaetHdMlIqN4VHBHhizHaMgtGfH6xCTuO3WdrKTN7cZii5RH7PBQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/channels': 7.0.15 - '@storybook/client-logger': 7.0.15 - '@storybook/core-events': 7.0.15 + '@storybook/channels': 7.0.18 + '@storybook/client-logger': 7.0.18 + '@storybook/core-events': 7.0.18 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/router': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/router': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 dequal: 2.0.3 lodash: 4.17.21 memoizerific: 1.11.3 @@ -5666,16 +5665,16 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/manager@7.0.15: - resolution: {integrity: sha512-ixx+E2Vb34VIY9JqKoWA+Qv3soJhSWW0ETdMaPn+QmcSoicqM4I861hmxm37ROhwRpAMi2U0sS0m4L+6VeB0lQ==} + /@storybook/manager@7.0.18: + resolution: {integrity: sha512-hasb8XDmkT9lyX2cwb3Xg0ngcNQ1QCNHKurl2YJtXowb1CvawGKokhnVUTso15NCnurolDyw/Wqka1sagfm+Mg==} dev: true /@storybook/mdx2-csf@1.0.0: resolution: {integrity: sha512-dBAnEL4HfxxJmv7LdEYUoZlQbWj9APZNIbOaq0tgF8XkxiIbzqvgB0jhL/9UOrysSDbQWBiCRTu2wOVxedGfmw==} dev: true - /@storybook/node-logger@7.0.15: - resolution: {integrity: sha512-h7kAbugjW4OqVIs5fd3Lme8+WBaEZYAULaNJ1zdvVpvWepG6iBaF/j8RlZdJzrPDdwQvZ2g9gVk5HySXpeXOjA==} + /@storybook/node-logger@7.0.18: + resolution: {integrity: sha512-cIeKEBvELtoVP/5UeQ01GJWZ7wM69/9Q+R5uOtNQBlwWFcCD6AVFWMRqq7ObMvdJG/okhXSF+sDetb+BF3zvdw==} dependencies: '@types/npmlog': 4.1.4 chalk: 4.1.2 @@ -5683,20 +5682,20 @@ packages: pretty-hrtime: 1.0.3 dev: true - /@storybook/postinstall@7.0.15: - resolution: {integrity: sha512-oVw7E7iBDEN3toMJPH2bxkS/rLShSHNmK8cU8bO6kdxBVCmUdhqMME7TOzqy7bAZ+ODlFCqwdstp85pO6xarig==} + /@storybook/postinstall@7.0.18: + resolution: {integrity: sha512-ObIwAK2UiYhXN/7UifISQgBoH5jnyxh6T8kvCw83YhC78SDOPNgIGjToJECizJ7iubtqAWtCfCT5TrGEpyLGbg==} dev: true - /@storybook/preview-api@7.0.15: - resolution: {integrity: sha512-ZjqMFsOYVklO1h4BfyNGpn4FM6lHgQ9RZ+LmUnd1qh/GdxpRHIGLKtsvd4nxaSJLHNE53WO+1yUeJPiglEeE4g==} + /@storybook/preview-api@7.0.18: + resolution: {integrity: sha512-xxtC0gPGMn/DbwvS4ZuJaBwfFNsjUCf0yLYHFrNe6fxncbvcLZ550RuyUwYuIRfsiKrlgfa3QmmCa4JM/JesHQ==} dependencies: - '@storybook/channel-postmessage': 7.0.15 - '@storybook/channels': 7.0.15 - '@storybook/client-logger': 7.0.15 - '@storybook/core-events': 7.0.15 + '@storybook/channel-postmessage': 7.0.18 + '@storybook/channels': 7.0.18 + '@storybook/client-logger': 7.0.18 + '@storybook/core-events': 7.0.18 '@storybook/csf': 0.1.0 '@storybook/global': 5.0.0 - '@storybook/types': 7.0.15 + '@storybook/types': 7.0.18 '@types/qs': 6.9.7 dequal: 2.0.3 lodash: 4.17.21 @@ -5747,12 +5746,12 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/preview@7.0.15: - resolution: {integrity: sha512-rTHgSCpKOnypMVQZdJ78Hlcnkm54UK6KTbQrM3LW41W5sbmTV3OpN6x0Ke7FY6tvrpWATJs26YrTTatDV8tbUA==} + /@storybook/preview@7.0.18: + resolution: {integrity: sha512-L53p2eo8G12U6tp7hD3mk5tdWFXLvdEyV9e7a1x9bw1LfH15K/bp8lO6U/W1kkpse7+rqWBqoTjJC1Ktm5Sxog==} dev: true - /@storybook/react-dom-shim@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Yi/1ZtzttAay3TMFyiF5oV317fUwdAT+Z595sBCMHEzhZWUA9zKxvR0KAQ2cBlCc6u7+tJvIMaGkcS/IZWVqPw==} + /@storybook/react-dom-shim@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-O1FRypR8q1katjbznnxI+NtALd2gaWa7KnTwbIDf+ddZltXHMZ8xMiEGEtAMrfXlIuqIr9UvmLRfKZC/ysuA+g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5761,25 +5760,25 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8): - resolution: {integrity: sha512-bPNvjHccYgXCskrW6CIpqcuZWsASdlOuFgJs1q/sxEHy5gGw+kMEm0XKmha4cTLlUAFd4EwhmKkC6BEgtSYVWw==} + /@storybook/react-vite@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9): + resolution: {integrity: sha512-rxJwp/b0dPazn15xLIeRgwrdZGWmoqoLhU7Mm+AXKToXvbe77i2bjHhkFbz34dpKFtD0i/ajcZSpmsxpxfB0HA==} engines: {node: '>=16'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.8) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.9) '@rollup/pluginutils': 4.2.1 - '@storybook/builder-vite': 7.0.15(typescript@5.0.4)(vite@4.3.8) - '@storybook/react': 7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) - '@vitejs/plugin-react': 3.1.0(vite@4.3.8) + '@storybook/builder-vite': 7.0.18(typescript@5.0.4)(vite@4.3.9) + '@storybook/react': 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + '@vitejs/plugin-react': 3.1.0(vite@4.3.9) ast-types: 0.14.2 magic-string: 0.27.0 react: 18.2.0 react-docgen: 6.0.0-alpha.3 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) transitivePeerDependencies: - '@preact/preset-vite' - supports-color @@ -5787,8 +5786,8 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4): - resolution: {integrity: sha512-YuqUyfbPr4mFsRAIUTmVgx5mCNK00fg/Mztwyg3PRN4SuRWhx5MJy6kMX2GV3DcKqyeC5U2aWKHlzjzrGwXymw==} + /@storybook/react@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4): + resolution: {integrity: sha512-lumUbHYeuL3qa4SZR9K2YC4UIt1hwW19GuI/6f2HEV5gR9QHHSJHg9HD9pjcxv4fQaiG81ACZ0Sg6lyUkcJvuQ==} engines: {node: '>=16.0.0'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5798,13 +5797,13 @@ packages: typescript: optional: true dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/core-client': 7.0.15 - '@storybook/docs-tools': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/core-client': 7.0.18 + '@storybook/docs-tools': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.15 - '@storybook/react-dom-shim': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/preview-api': 7.0.18 + '@storybook/react-dom-shim': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 '@types/escodegen': 0.0.6 '@types/estree': 0.0.51 '@types/node': 16.18.16 @@ -5826,27 +5825,27 @@ packages: - supports-color dev: true - /@storybook/router@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-iwW2bzoULMIHjzK7ok0l+4O5AafyZ1APMUcYv8S+lC1bOl7odAcV2dbUQ21M1D/L+no7LrcnfJBGOD8NKE4nTQ==} + /@storybook/router@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Mue4s/BnKgdYcsiW9yuvW3qL9k3AgYn5HIhnkBExAteyiUGdAca4IJFhArmGgFktgeLc4ecBQ7sgaCljApnbgg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/client-logger': 7.0.15 + '@storybook/client-logger': 7.0.18 memoizerific: 1.11.3 qs: 6.11.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/source-loader@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-bk+TbRx9WoUE6to39TjL5BYxZmaq4expM1OlgBabES+mJmdYIvNoDWNYufSv5Gdj25Rg6nG9vYGaf1iviTna9A==} + /@storybook/source-loader@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-n910+/rNJ3tCRUx3JJm/5ehjp5CK2WZg+KPRtG5a4AeVhQBdxsxw2D2pDYBWY1aFhJ+S4AZJOLIk9cdOMneA9g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@storybook/csf': 0.1.0 - '@storybook/types': 7.0.15 + '@storybook/types': 7.0.18 estraverse: 5.3.0 lodash: 4.17.21 prettier: 2.8.8 @@ -5854,11 +5853,11 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/telemetry@7.0.15: - resolution: {integrity: sha512-Tuf6Oy1Lxr+bGT9rILT1oKlQtHrO9oCzk/6/wSSZnV08yzwqe5Tmc8OUd9ytc2BbQb67yObsT9Lb9YC+9+X3+g==} + /@storybook/telemetry@7.0.18: + resolution: {integrity: sha512-JP5Z7lGU+oKjNmz2cZW5J7EerwyWBBPOU+NvvooZsymIx02ZvJ4ClmFtolJnBM7m4KoAy50JxV5NQWi+q8PicQ==} dependencies: - '@storybook/client-logger': 7.0.15 - '@storybook/core-common': 7.0.15 + '@storybook/client-logger': 7.0.18 + '@storybook/core-common': 7.0.18 chalk: 4.1.2 detect-package-manager: 2.0.1 fetch-retry: 5.0.4 @@ -5881,24 +5880,24 @@ packages: ts-dedent: 2.2.0 dev: true - /@storybook/theming@7.0.15(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-oxy1jTt1lYLWCRXhSnjvxIzJHW+tQS4kqD/F8mr3/C0WbMXbSv/rKlS2fkIYbOecjqs0C/8ypa1KzEMcBTfIRQ==} + /@storybook/theming@7.0.18(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-P1gMKa/mKQHIMq0sxBIwTzAcF6v/6hrc62YmkuV62vXu+8zNV2YWbRwywqm3Q6faZEadmb/bL9+z8whaKhCL/g==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: '@emotion/use-insertion-effect-with-fallbacks': 1.0.0(react@18.2.0) - '@storybook/client-logger': 7.0.15 + '@storybook/client-logger': 7.0.18 '@storybook/global': 5.0.0 memoizerific: 1.11.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/types@7.0.15: - resolution: {integrity: sha512-WjrTpRxCZDL7noDv7ziRdOsuYMppbKRsWlH53HY5GFXJZPYaFWs6lKZOo7+T8OxYXegD4Y5AcD8tGQrX8GtycQ==} + /@storybook/types@7.0.18: + resolution: {integrity: sha512-qPop2CbvmX42/BX29YT9jIzW2TlMcMjAE+KCpcKLBiD1oT5DJ1fhMzpe6RW9HkMegkBxjWx54iamN4oHM/pwcQ==} dependencies: - '@storybook/channels': 7.0.15 + '@storybook/channels': 7.0.18 '@types/babel__core': 7.20.0 '@types/express': 4.17.17 file-system-cache: 2.0.2 @@ -5922,22 +5921,22 @@ packages: file-system-cache: 2.0.2 dev: true - /@storybook/vue3-vite@7.0.15(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.8)(vue@3.3.4): - resolution: {integrity: sha512-a5kjtOxVUTZ++QPYT294110OZA1xec8HB9XbF4Mq9xmMK4HAJ2Tv4yx1UtMA6bCanOOCpa1VyA0CQVje6RdgMQ==} + /@storybook/vue3-vite@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9)(vue@3.3.4): + resolution: {integrity: sha512-dwkwBQRDUSvf44Z4ZDftusP6obuczPkApxALxsTczkbpOxK/13SXArlrKgyUaFrcqto9i2e8HbAYb7y1ymO3ig==} engines: {node: ^14.18 || >=16} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@storybook/builder-vite': 7.0.15(typescript@5.0.4)(vite@4.3.8) - '@storybook/core-server': 7.0.15 - '@storybook/vue3': 7.0.15(vue@3.3.4) - '@vitejs/plugin-vue': 4.2.3(vite@4.3.8)(vue@3.3.4) + '@storybook/builder-vite': 7.0.18(typescript@5.0.4)(vite@4.3.9) + '@storybook/core-server': 7.0.18 + '@storybook/vue3': 7.0.18(vue@3.3.4) + '@vitejs/plugin-vue': 4.2.3(vite@4.3.9)(vue@3.3.4) magic-string: 0.27.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) vue-docgen-api: 4.64.1(vue@3.3.4) transitivePeerDependencies: - '@preact/preset-vite' @@ -5950,20 +5949,21 @@ packages: - vue dev: true - /@storybook/vue3@7.0.15(vue@3.3.4): - resolution: {integrity: sha512-h38XFH2fpfZcflg2xifaiwiSfgZd7Ry+/HbwRRKPpvPsBsfXt79KC8H2vHLdMU2KNWpERMKw2eG1PTzYUGUr5w==} + /@storybook/vue3@7.0.18(vue@3.3.4): + resolution: {integrity: sha512-++oC4Ee74ln9jPJSUnA6RWLxk5PNBGSP7lu71bA0b98MYsQ4GKliNEQf8lZmelSQy6nWoVHO0iyOhsKey7K3Ow==} engines: {node: '>=16.0.0'} peerDependencies: vue: ^3.0.0 dependencies: - '@storybook/core-client': 7.0.15 - '@storybook/docs-tools': 7.0.15 + '@storybook/core-client': 7.0.18 + '@storybook/docs-tools': 7.0.18 '@storybook/global': 5.0.0 - '@storybook/preview-api': 7.0.15 - '@storybook/types': 7.0.15 + '@storybook/preview-api': 7.0.18 + '@storybook/types': 7.0.18 ts-dedent: 2.2.0 type-fest: 2.19.0 vue: 3.3.4 + vue-component-type-helpers: 1.6.5 transitivePeerDependencies: - supports-color dev: true @@ -6477,7 +6477,7 @@ packages: /@types/babel__core@7.20.0: resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@babel/types': 7.21.5 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 @@ -6511,7 +6511,7 @@ packages: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/braces@3.0.1: @@ -6523,7 +6523,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/responselike': 1.0.0 dev: false @@ -6556,7 +6556,7 @@ packages: /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/content-disposition@0.5.5: @@ -6621,7 +6621,7 @@ packages: /@types/express-serve-static-core@4.17.33: resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: true @@ -6649,27 +6649,27 @@ packages: resolution: {integrity: sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==} dependencies: '@types/glob': 8.1.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/gulp-rename@2.0.1: @@ -6682,7 +6682,7 @@ packages: /@types/gulp-rename@2.0.2: resolution: {integrity: sha512-CQsXqTVtAXqrPd4IbrrlJEEzRkUR3RXsyZbrVoOVqjlchDDmnyRDatAUisjpQjjCg/wjJrSiNg8T1uAbJ/7Qqg==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/vinyl': 2.0.7 dev: true @@ -6761,7 +6761,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: false /@types/lodash@4.14.191: @@ -6772,8 +6772,8 @@ packages: resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} dev: false - /@types/matter-js@0.18.4: - resolution: {integrity: sha512-7YgBqVLbLTCTMKmWfvPkohb5sTErBrLui3jRypFLCAxfTYc/HH+gaz10FT8Qw5XipWf7/Ns7Aksmo8nsIIL3lw==} + /@types/matter-js@0.18.5: + resolution: {integrity: sha512-CV8m/FUmjmFNFcI7fUnsKcCLeqbf0kzWdKOTLGrpfKwWwrF6ggLaQlHNsg8267TkkiUAPoXY/7q6H9qwmR5TZg==} dev: true /@types/mdx@2.0.3: @@ -6809,7 +6809,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 form-data: 3.0.1 /@types/node-fetch@3.0.3: @@ -6839,6 +6839,10 @@ packages: /@types/node@20.2.3: resolution: {integrity: sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==} + dev: true + + /@types/node@20.2.5: + resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==} /@types/nodemailer@6.4.8: resolution: {integrity: sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==} @@ -6929,7 +6933,7 @@ packages: /@types/readdir-glob@1.1.1: resolution: {integrity: sha512-ImM6TmoF8bgOwvehGviEj3tRdRBbQujr1N+0ypaln/GWjaerOB26jb93vsRHmdMtvVQZQebOlqt2HROark87mQ==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/redis@4.0.11: @@ -6945,7 +6949,7 @@ packages: /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: false /@types/sanitize-html@2.9.0: @@ -6973,7 +6977,7 @@ packages: resolution: {integrity: sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==} dependencies: '@types/mime': 3.0.1 - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/serviceworker@0.0.67: @@ -6983,7 +6987,7 @@ packages: /@types/set-cookie-parser@2.4.2: resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/sharp@0.32.0: @@ -7048,7 +7052,7 @@ packages: /@types/undertaker@1.2.8: resolution: {integrity: sha512-gW3PRqCHYpo45XFQHJBhch7L6hytPsIe0QeLujlnFsjHPnXLhJcPdN6a9368d7aIQgH2I/dUTPFBlGeSNA3qOg==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/undertaker-registry': 1.0.1 async-done: 1.3.2 dev: true @@ -7077,7 +7081,7 @@ packages: resolution: {integrity: sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==} dependencies: '@types/glob-stream': 6.1.1 - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/vinyl': 2.0.7 dev: true @@ -7085,7 +7089,7 @@ packages: resolution: {integrity: sha512-4UqPv+2567NhMQuMLdKAyK4yzrfCqwaTt6bLhHEs8PFcxbHILsrxaY63n4wgE/BRLDWDQeI+WcTmkXKExh9hQg==} dependencies: '@types/expect': 1.20.4 - '@types/node': 20.2.3 + '@types/node': 20.2.5 /@types/web-push@3.3.2: resolution: {integrity: sha512-JxWGVL/m7mWTIg4mRYO+A6s0jPmBkr4iJr39DqJpRJAc+jrPiEe1/asmkwerzRon8ZZDxaZJpsxpv0Z18Wo9gw==} @@ -7133,7 +7137,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true optional: true @@ -7267,7 +7271,7 @@ packages: eslint-visitor-keys: 3.4.1 dev: true - /@vitejs/plugin-react@3.1.0(vite@4.3.8): + /@vitejs/plugin-react@3.1.0(vite@4.3.9): resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -7278,19 +7282,19 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.3) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) transitivePeerDependencies: - supports-color dev: true - /@vitejs/plugin-vue@4.2.3(vite@4.3.8)(vue@3.3.4): + /@vitejs/plugin-vue@4.2.3(vite@4.3.9)(vue@3.3.4): resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.0.0 vue: ^3.2.25 dependencies: - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) vue: 3.3.4 /@vitest/coverage-c8@0.31.1(vitest@0.31.1): @@ -7471,7 +7475,7 @@ packages: /@vue/reactivity-transform@3.3.4: resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} dependencies: - '@babel/parser': 7.21.8 + '@babel/parser': 7.21.9 '@vue/compiler-core': 3.3.4 '@vue/shared': 3.3.4 estree-walker: 2.0.2 @@ -10655,8 +10659,8 @@ packages: - supports-color dev: true - /eslint-plugin-vue@9.14.0(eslint@8.40.0): - resolution: {integrity: sha512-4O7EuiqPGVQA1wYCzLvCzsBTv9JIPHLHhrf0k55DLzbwtmJbSw2TKS0G/l7pOwi9RWMSkjIT7ftChU5gZpgnJw==} + /eslint-plugin-vue@9.14.1(eslint@8.40.0): + resolution: {integrity: sha512-LQazDB1qkNEKejLe/b5a9VfEbtbczcOaui5lQ4Qw0tbRBbQYREyxxOV5BQgNDTqGPs9pxqiEpbMi9ywuIaF7vw==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 @@ -13236,7 +13240,7 @@ packages: '@jest/expect': 29.5.0 '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -13390,6 +13394,45 @@ packages: - supports-color dev: true + /jest-config@29.5.0(@types/node@20.2.5): + resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.21.3 + '@jest/test-sequencer': 29.5.0 + '@jest/types': 29.5.0 + '@types/node': 20.2.5 + babel-jest: 29.5.0(@babel/core@7.21.3) + chalk: 4.1.2 + ci-info: 3.7.1 + deepmerge: 4.2.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.5.0 + jest-environment-node: 29.5.0 + jest-get-type: 29.4.3 + jest-regex-util: 29.4.3 + jest-resolve: 29.5.0 + jest-runner: 29.5.0 + jest-util: 29.5.0 + jest-validate: 29.5.0 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.5.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + /jest-diff@28.1.3: resolution: {integrity: sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -13435,7 +13478,7 @@ packages: '@jest/environment': 29.5.0 '@jest/fake-timers': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 jest-mock: 29.5.0 jest-util: 29.5.0 dev: true @@ -13465,7 +13508,7 @@ packages: dependencies: '@jest/types': 29.5.0 '@types/graceful-fs': 4.1.6 - '@types/node': 20.2.3 + '@types/node': 20.2.5 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -13516,7 +13559,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /jest-mock@29.5.0: @@ -13579,7 +13622,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -13610,7 +13653,7 @@ packages: '@jest/test-result': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -13665,7 +13708,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 chalk: 4.1.2 ci-info: 3.7.1 graceful-fs: 4.2.11 @@ -13690,7 +13733,7 @@ packages: dependencies: '@jest/test-result': 29.5.0 '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -13709,7 +13752,7 @@ packages: resolution: {integrity: sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 jest-util: 29.5.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -18450,11 +18493,11 @@ packages: resolution: {integrity: sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==} dev: true - /storybook@7.0.15: - resolution: {integrity: sha512-GYGRH20H2G0oUhoh40p0o0AGPXN/cKntpt/BX7NKB1Dr4OqbawBw/65yGhuFuYA+HFjBUonWixicOgPkrsyuKg==} + /storybook@7.0.18: + resolution: {integrity: sha512-FXMmTiomSlLPTHty7vGLr0prPf6pCV07EwAmNOYYYTskitEYV0R7hlhawByd7HuobjIhHvSTKesa1Whl86zLNA==} hasBin: true dependencies: - '@storybook/cli': 7.0.15 + '@storybook/cli': 7.0.18 transitivePeerDependencies: - bufferutil - encoding @@ -19796,7 +19839,7 @@ packages: replace-ext: 1.0.1 dev: false - /vite-node@0.31.1(@types/node@20.2.3)(sass@1.62.1): + /vite-node@0.31.1(@types/node@20.2.5)(sass@1.62.1): resolution: {integrity: sha512-BajE/IsNQ6JyizPzu9zRgHrBwczkAs0erQf/JRpgTIESpKvNj9/Gd0vxX905klLkb0I0SJVCKbdrl5c6FnqYKA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -19806,7 +19849,7 @@ packages: mlly: 1.2.0 pathe: 1.1.0 picocolors: 1.0.0 - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) transitivePeerDependencies: - '@types/node' - less @@ -19821,8 +19864,8 @@ packages: resolution: {integrity: sha512-irjKcKXRn7v5bPAg4mAbsS6DgibpP1VUFL9tlgxU6lloK6V9yw9qCZkS+s2PtbkZpWNzr3TN3zVJAc6J7gJZmA==} dev: true - /vite@4.3.8(@types/node@20.2.3)(sass@1.62.1): - resolution: {integrity: sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==} + /vite@4.3.9(@types/node@20.2.5)(sass@1.62.1): + resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -19846,7 +19889,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 esbuild: 0.17.18 postcss: 8.4.23 rollup: 3.23.0 @@ -19899,7 +19942,7 @@ packages: dependencies: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@vitest/expect': 0.31.1 '@vitest/runner': 0.31.1 '@vitest/snapshot': 0.31.1 @@ -19920,8 +19963,8 @@ packages: strip-literal: 1.0.1 tinybench: 2.5.0 tinypool: 0.5.0 - vite: 4.3.8(@types/node@20.2.3)(sass@1.62.1) - vite-node: 0.31.1(@types/node@20.2.3)(sass@1.62.1) + vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) + vite-node: 0.31.1(@types/node@20.2.5)(sass@1.62.1) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -19936,6 +19979,10 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} + /vue-component-type-helpers@1.6.5: + resolution: {integrity: sha512-iGdlqtajmiqed8ptURKPJ/Olz0/mwripVZszg6tygfZSIL9kYFPJTNY6+Q6OjWGznl2L06vxG5HvNvAnWrnzbg==} + dev: true + /vue-docgen-api@4.64.1(vue@3.3.4): resolution: {integrity: sha512-jbOf7ByE3Zvtuk+429Jorl+eIeh2aB2Fx1GUo3xJd1aByJWE8KDlSEa6b11PB1ze8f0sRUBraRDinICCk0KY7g==} dependencies: @@ -20550,7 +20597,7 @@ packages: sharp: 0.31.3 dev: false - github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.15)(@storybook/components@7.0.15)(@storybook/core-events@7.0.15)(@storybook/manager-api@7.0.15)(@storybook/preview-api@7.0.15)(@storybook/theming@7.0.15)(@storybook/types@7.0.15)(react-dom@18.2.0)(react@18.2.0): + github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@7.0.18)(@storybook/components@7.0.18)(@storybook/core-events@7.0.18)(@storybook/manager-api@7.0.18)(@storybook/preview-api@7.0.18)(@storybook/theming@7.0.18)(@storybook/types@7.0.18)(react-dom@18.2.0)(react@18.2.0): resolution: {tarball: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640} id: github.com/misskey-dev/storybook-addon-misskey-theme/cf583db098365b2ccc81a82f63ca9c93bc32b640 name: storybook-addon-misskey-theme @@ -20571,13 +20618,13 @@ packages: react-dom: optional: true dependencies: - '@storybook/blocks': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/components': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/core-events': 7.0.15 - '@storybook/manager-api': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/preview-api': 7.0.15 - '@storybook/theming': 7.0.15(react-dom@18.2.0)(react@18.2.0) - '@storybook/types': 7.0.15 + '@storybook/blocks': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/components': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/core-events': 7.0.18 + '@storybook/manager-api': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/preview-api': 7.0.18 + '@storybook/theming': 7.0.18(react-dom@18.2.0)(react@18.2.0) + '@storybook/types': 7.0.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true From f469f555e8b33f37aec76cc9dbaa18f2008a6de6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 17:53:05 +0900 Subject: [PATCH 113/213] New Crowdin updates (#10916) * New translations ja-JP.yml (French) * New translations ja-JP.yml (Spanish) * New translations ja-JP.yml (Arabic) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Norwegian) * New translations ja-JP.yml (Russian) * New translations ja-JP.yml (Chinese Simplified) * New translations ja-JP.yml (Chinese Traditional) * New translations ja-JP.yml (Indonesian) * New translations ja-JP.yml (Thai) * New translations ja-JP.yml (Japanese, Kansai) --- locales/ar-SA.yml | 128 ++++++++++++++++++++++++++++++++++++++++++++++ locales/es-ES.yml | 13 +++++ locales/fr-FR.yml | 7 +++ locales/id-ID.yml | 3 ++ locales/ja-KS.yml | 2 +- locales/ko-KR.yml | 9 +++- locales/no-NO.yml | 117 ++++++++++++++++++++++++++++++++++++++++++ locales/ru-RU.yml | 2 + locales/th-TH.yml | 9 ++++ locales/zh-CN.yml | 31 +++++++++++ locales/zh-TW.yml | 6 ++- 11 files changed, 322 insertions(+), 5 deletions(-) diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index bfca086f5c..3b97f435d2 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -2,6 +2,7 @@ _lang_: "العربية" headlineMisskey: "شبكة مرتبطة بالملاحظات" introMisskey: "اهلا بك! ميسكي هو منصة تدوين مصغر لا مركزية ومفتوحة المصدر.\nيمكنك مشاركة \"ملاحظات\" عن ما يجري حولك، وإخبار الجميع عن نفسك 📡\nتسمح لك \"الانفعالات\" بتعبير عن شعورك حول ملاحظات الآخرين 👍\nاكتشف عالمًا جديدًا 🚀" +poweredByMisskeyDescription: "{name} هو إحدى الخِدمات التي تستخدم المنصة مفتوحة المصدر <b>ميسكي</b> (يشار إليه كمثيل ميسكي)" monthAndDay: "{day}/{month}" search: "البحث" notifications: "الإشعارات" @@ -49,6 +50,7 @@ deleteAndEdit: "إزالة وإعادة الصياغة" deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها." addToList: "أضفه إلى قائمة" sendMessage: "أرسل رسالة" +copyRSS: "انسخ رابط RSS" copyUsername: "انسخ اسم المستخدم" searchUser: "ابحث عن مستخدمين" reply: "رد" @@ -102,6 +104,8 @@ renoted: "أُعيد نشره" cantRenote: "لا يمكن إعادة نشر الملاحظة" cantReRenote: "لا يمكنك إعادة نشر ملاحظة معاد نشرها" quote: "اقتبس" +inChannelRenote: "إعادة نشر في قناة" +inChannelQuote: "اقتباس في قناة" pinnedNote: "ملاحظة مدبسة" pinned: "دبّسها على الصفحة الشخصية" you: "أنت" @@ -119,6 +123,8 @@ unmarkAsSensitive: "ألغ تعيينه كمحتوى حساس" enterFileName: "ادخل اسم الملف" mute: "اكتم" unmute: "إلغاء الكتم" +renoteMute: "اكتم إعادة النشر" +renoteUnmute: "ارفع الكتم عن إعادة النشر" block: "احجب" unblock: "إلغاء الحجب" suspend: "علِق" @@ -141,6 +147,7 @@ emojiUrl: "رابط الإيموجي" addEmoji: "إضافة إيموجي" settingGuide: "الإعدادات المستحسنة" cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة" +cacheRemoteFilesDescription: "إذا عُطل هذا الإعداد، ستُحمل الملفات من المثيل البعيد، هذا سيقلل من المساحة المستغلة على القرص لكن سيزيد حجم تدفق البيانات وهذا لأن الصور المصغرة لن تولّد." flagAsBot: "علّمه كحساب آلي" flagAsBotDescription: "فعّل هذا الخيار إذا كان هذا الحساب يُدار عبر برمجية. إذا فُعل فسيكون بمثابة علامة للمطورين الآخرين لتجنب سلاسل لا متناهية من التفاعل بين حسابات الآلية وضبط أنظمة ميسكي للتعامل مع هذا الحساب كآلي." flagAsCat: "علّم هذا الحساب كحساب قط" @@ -253,6 +260,7 @@ startMessaging: "ابدأ محادثة" nUsersRead: "قرأه {n}" agreeTo: "اوافق على {0}" agree: "أقبل" +agreeBelow: "أقبل ما يلي" basicNotesBeforeCreateAccount: "ملاحظات مهمة" termsOfService: "شروط الخدمة" start: "البداية" @@ -362,6 +370,7 @@ antennaExcludeKeywords: "الكلمات المفتاحية المستثناة" antennaKeywordsDescription: "افصل بينهم بمسافة لاستخدام معامل \"و\" أو بسطر لاستخدام معامل \"أو\"" notifyAntenna: "نبهني بصول ملاحظات جديدة" withFileAntenna: "ملاحظات تحوي ملفات فقط" +enableServiceworker: "فعّل إرسال الإشعارات للمتصفح" antennaUsersDescription: "اكتب اسم مستخدم لكل سطر" caseSensitive: "حساسية حالة الأحرف" withReplies: "بالردود" @@ -391,6 +400,7 @@ moderation: "الإشراف" nUsersMentioned: "{n} مستخدمين أُشير إليهم" securityKey: "مفتاح الأمان" lastUsed: "آخر استخدام" +lastUsedAt: "آخر استخدام: {t}" unregister: "إلغاء التسجيل" passwordLessLogin: "لِج مِن دون كلمة سرية" resetPassword: "أعد تعيين كلمتك السرية" @@ -441,6 +451,7 @@ or: "أو" language: "اللغة" uiLanguage: "لغة واجهة المستخدم" aboutX: "عن {x}" +emojiStyle: "نمط الوجوه التعبيرية" noHistory: "السجل فارغ" signinHistory: "تاريخ تسجيل الدخول" doing: "انتظر لحظة" @@ -451,6 +462,7 @@ createAccount: "أنشئ حسابًا" existingAccount: "الحسابات الموجودة" regenerate: "أعِد التوليد" fontSize: "حجم الخط" +limitTo: "سقفهُ لـ{x}" noFollowRequests: "ليس لديك طلبات متابعة معلقة" openImageInNewTab: "إفتح الصورة بصفحة جديدة" dashboard: "لوحة التحكم" @@ -479,6 +491,7 @@ objectStorageUseProxyDesc: "عطل هذا الخيار إذا لم ترد است serverLogs: "سجلات الخادم" deleteAll: "حذف الكل" showFixedPostForm: "أظهر نموذج الكتابة في أعلى الصفحة" +showFixedPostFormInChannel: "أظهر نموذج الكتابة في أعلى الخط الزمني (قنوات)" newNoteRecived: "هناك ملاحظات جديدة" sounds: "الرنات" sound: "الرنات" @@ -514,6 +527,7 @@ userSilenced: "كُتم هذا المستخدم." yourAccountSuspendedTitle: "هذا الحساب معلق" yourAccountSuspendedDescription: "عُلق الحساب بسبب انتهاك شروط خدمة المثيل و ما شابه. إذا أردت معرفة التفصيل تواصل مع مدير المثيل. رجاءً لا تنشئ حساب جديد." accountDeleted: "حُذف الحساب" +accountDeletedDescription: "حُذف هذا الحساب." menu: "القائمة" divider: "فاصل" addItem: "إضافة عنصر" @@ -539,6 +553,7 @@ author: "الكاتب" leaveConfirm: "لديك تغييرات غير محفوظة. أتريد المتابعة دون حفظها؟" manage: "إدارة " plugins: "الإضافات" +preferencesBackups: "النُسخ الاحتياطية للإعدادات" useFullReactionPicker: "استخدم الحجم الكامل لمنتقي التفاعلات" width: "العرض" height: "الإرتفاع" @@ -648,6 +663,7 @@ contact: "التواصل" useSystemFont: "استخدم الخط الافتراضية للنظام" clips: "مشابك" experimentalFeatures: "ميّزات اختبارية" +experimental: "اختباري" developer: "المطور" makeExplorable: "أظهر الحساب في صفحة \"استكشاف\"" makeExplorableDescription: "بتعطيل هذا الخيار لن يظهر حسابك في صفحة \"استكشاف\"" @@ -669,6 +685,7 @@ accentColor: "طابع لوني" textColor: "لون النص" saveAs: "احفظ كـ..." advanced: "متقدم" +advancedSettings: "إعدادات متقدمة" value: "القيمة" createdAt: "أُنشئ في" updatedAt: "حُدّث في" @@ -733,6 +750,7 @@ popularPosts: "المشاركات المتداولة" shareWithNote: "شاركه في ملاحظة" ads: "الإعلانات" expiration: "ينتهي استطلاع الرأي في" +startingperiod: "ابدأ" memo: "تذكير" priority: "الأولوية" high: "عالية" @@ -763,6 +781,7 @@ lastCommunication: "آخر تواصل" resolved: "عولج" unresolved: "لم يعالج" breakFollow: "إلغاء الاشتراك" +breakFollowConfirm: "أمتأكد من إزالة المتابِع ؟" itsOn: "مفعّل" itsOff: "معطّل" emailRequiredForSignup: "عنوان البريد الإلكتروني إلزامي للتسجيل" @@ -777,6 +796,7 @@ muteThread: "اكتم النقاش" unmuteThread: "ارفع الكتم عن النقاش" ffVisibility: "مرئية المتابِعين/المتابَعين" ffVisibilityDescription: "يسمح لك بتحديد من يمكنهم رؤية متابِعيك ومتابَعيك." +continueThread: "اعرض بقية النقاش" deleteAccountConfirm: "سيحذف حسابك نهائيًا، أتريد المتابعة؟" incorrectPassword: "كلمة السر خاطئة." voteConfirm: "متيقِّن من تصويتك لـ {choice}؟" @@ -798,25 +818,127 @@ tenMinutes: "10 دقائق" oneHour: "ساعة" oneDay: "يوم" oneWeek: "أسبوع" +oneMonth: "شهر" failedToFetchAccountInformation: "تعذر جلب معلومات الحساب" +cropNo: "استخدمها كما هي" file: "الملفات" +recentNHours: "آخر {n} ساعة" +recentNDays: "آخر {n} أيام" +noEmailServerWarning: "خادم البريد غير مضبوط." +thereIsUnresolvedAbuseReportWarning: "توجد بلاغات غير معالجة." +recommended: "مقترح" +driveCapOverrideLabel: "غيّر حجم قرص التخزين لهذا المستخدم" +driveCapOverrideCaption: "أعد الحجم إلى القيمة الافتراضية بإدخال 0 أو أقل." +requireAdminForView: "لاستعراض هذه الصفحة وجب عليك الولوج كمدير." +typeToConfirm: "أدخل {x} للتأكيد" +deleteAccount: "احذف الحساب" +document: "التوثيق" +numberOfPageCache: "عدد الصفحات المخزنة مؤقتًا" +logoutConfirm: "أتريد الخروج؟" +lastActiveDate: "آخر استخدام" +statusbar: "شريط الحالة" +pleaseSelect: "حدد خيارًا" reverse: "اقلب" colored: "ملوّن" label: "التسمية" +type: "نوع" +speed: "سرعة" +slow: "بطيء" +fast: "سريع" +sensitiveMediaDetection: "التعرف على المحتوى الحساس" localOnly: "المحلي فقط" +failedToUpload: "فشل الرفع" +cannotUploadBecauseInappropriate: "تعذر رفع الملف لوجود محتوى حساس فيه." +cannotUploadBecauseNoFreeSpace: "تعذر رفع الملف لنقص مساحة التخزين." +cannotUploadBecauseExceedsFileSizeLimit: "تعذر رفع الملف بسبب تجاوز حجمه للحد المسموح" +beta: "بيتا" +navbar: "شريط التنقل" +shuffle: "خلط" account: "الحسابات" +move: "أنقل" +pushNotification: "إرسال الإشعارات" +subscribePushNotification: "فعّل إرسال الإشعارات" +unsubscribePushNotification: "عطل إرسال الإشعارات" +pushNotificationAlreadySubscribed: "إرسال الإشعارات مفعل سلفًا" +pushNotificationNotSupported: "متصفحك لا يدعم إرسال الإشعارات أو المثيل لا يدعمها." +sendPushNotificationReadMessage: "احذف الإشعارات فور قراءتها" +sendPushNotificationReadMessageCaption: "هذا قد يزيد من معدل استهلاك الطاقة لجهازك." +caption: "التعليق التوضيحي" +tools: "أدوات" cannotLoad: "تعذر التحميل" like: "أعجبني" +unlike: "ألغِ الإعجاب" show: "المظهر" +neverShow: "لا تظهره مجددًا" +didYouLikeMisskey: "هل أعجبك ميسكي؟" +roles: "الأدوار" +role: "الدور" +noRole: "لم يُعثر على دور" +normalUser: "مستخدم عادي" +undefined: "غير معرّف" color: "اللون" +manageCustomEmojis: "إدارة الإيموجي المخصصة" +cannotPerformTemporary: "غير متاح مؤقتاً" +permissionDeniedError: "رُفضة العملية" +preset: "إعدادات مسبقة" +selectFromPresets: "اختر من الإعدادات المسبقة" +achievements: "الإنجازات" +gotInvalidResponseError: "استجابة غير متوقعة من الخادم" +gotInvalidResponseErrorDescription: "يتعذر الوصول إلى الخادم أوأنه يُصان، رجاءً حاول لاحقًا." +thisPostMayBeAnnoying: "هذا قد يزعج الآخرين." +thisPostMayBeAnnoyingHome: "أنشر في الخط الزمني الرئيس" +thisPostMayBeAnnoyingCancel: "ألغِ" +internalServerError: "خطأ داخلي في الخادم" +internalServerErrorDescription: "واجه الخادم خطأ غي متوقع." +copyErrorInfo: "انسخ تفاصيل الخطأ" +joinThisServer: "سجل في هذا المثيل" +exploreOtherServers: "اعثر على مثيل آخر" +disableFederationOk: "عطّل" +invitationRequiredToRegister: "هذا المثيل للمدعوين فقط. لتسجيل فيه تحتاج رمزًا صالحًا." +postToTheChannel: "انشر في قناة" +cannotBeChangedLater: "لا يمكن تغييره لاحقًا." +reactionAcceptance: "قبول التفاعلات" +rolesAssignedToMe: "الأدوار المسندة إلي" +resetPasswordConfirm: "هل تريد إعادة تعيين كلمة السر؟" +noteIdOrUrl: "معرف الملاحظة أو رابطها" +video: "فيديو" +videos: "فيديوهات" +accountMigration: "ترحيل الحساب" +accountMoved: "نقل هذا المستخدم حسابه:" +accountMovedShort: "رُحل هذا الحساب." +operationForbidden: "عملية ممنوعة" +forceShowAds: "أظهر الإعلانات التجارية دائما" +vertical: "عمودي" horizontal: "جانبي" +position: "الموضع" +serverRules: "قوانين الخادم" +pleaseConfirmBelowBeforeSignup: "رجاءً وافق على ما يلي قبل التسجيل." +pleaseAgreeAllToContinue: "للمتابعة وافق على الحقول أعلاه." +continue: "متابعة" +preservedUsernames: "أسماء المستخدمين المحجوزة" +preservedUsernamesDescription: "قائمة بأسماء المستخدمين المحجوزة كلٌ في سطر. لن يُقبل التسجيل بهذه الأسماء وستبقى محصورة على التسجيل اليدوي بواسطة المديرين. لن يتأثر المستخدمون الذين يملكون هذه الأسماء سلفًا." +archive: "الأرشيف" youFollowing: "متابَع" +options: "خيارات" _role: + new: "دور جديد" + edit: "حرر الأدوار" + name: "اسم الدور" + description: "وصف الدور" + permission: "أذونات الدور" + assignTarget: "نوع الإسناد" + options: "خيارات" + policies: "السياسة العامة" priority: "الأولوية" _priority: low: "منخفضة" middle: "متوسط" high: "عالية" + _options: + canManageCustomEmojis: "إدارة الإيموجي المخصصة" + _condition: + isLocal: "مستخدم محلي" + isRemote: "مستخدم بعيد" _emailUnavailable: used: "هذا البريد الإلكتروني مستخدم" format: "صيغة البريد الإلكتروني غير صالحة" @@ -1064,6 +1186,7 @@ _widgets: onlineUsers: "المتّصلون" jobQueue: "قائمة الانتظار" serverMetric: "إحصائيات الخادم" + userList: "قائمة المستخدمين" _userList: chooseList: "اختر قائمة" _cw: @@ -1127,6 +1250,7 @@ _profile: changeBanner: "غيّر اللافتة" _exportOrImport: allNotes: "كل الملاحظات" + favoritedNotes: " الملاحظات المفضلة" followingList: "المتابَعون" muteList: "المستخدمون المكتومون" blockingList: "المستخدمون المحجوبون" @@ -1145,6 +1269,8 @@ _charts: notesTotal: "إجمالي الملاحظات" filesIncDec: "تباين عدد الملفات" filesTotal: "العدد الإجمالي للملفات" + storageUsageIncDec: "التباين في استغلال مساحة التخزين" + storageUsageTotal: "اجمالي مساحة التخزين المستغلة" _instanceCharts: requests: "الطلبات" users: "تباين عدد المستخدمين" @@ -1264,3 +1390,5 @@ _deck: _webhookSettings: name: "الإسم" active: "مفعّل" + _events: + reaction: "عند تلقي تفاعل" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index b043ecf3cf..a5dd18e3fc 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -20,6 +20,7 @@ noNotes: "No hay notas" noNotifications: "No hay notificaciones" instance: "Instancia" settings: "Configuración" +notificationSettings: "Configurar las notificaciones" basicSettings: "Configuración Básica" otherSettings: "Configuración avanzada" openInWindow: "Abrir en una ventana" @@ -262,8 +263,10 @@ noMoreHistory: "El historial se ha acabado" startMessaging: "Iniciar chat" nUsersRead: "Leído por {n} personas" agreeTo: "De acuerdo con {0}" +agree: "De acuerdo." agreeBelow: "Estoy de acuerdo con lo siguiente" basicNotesBeforeCreateAccount: "Notas básicas" +termsOfService: "Términos y condiciones" start: "Comenzar" home: "Inicio" remoteUserCaution: "Para el usuario remoto, la información está incompleta" @@ -473,6 +476,8 @@ createAccount: "Crear cuenta" existingAccount: "Cuenta existente" regenerate: "Regenerar" fontSize: "Tamaño de la letra" +mediaListWithOneImageAppearance: "Altura de la lista de medios con una sola imagen." +limitTo: "{x} hasta un máximo de" noFollowRequests: "No hay solicitudes de seguimiento" openImageInNewTab: "Abrir imagen en nueva pestaña" dashboard: "Panel de control" @@ -555,6 +560,7 @@ accountDeletedDescription: "Esta cuenta ha sido borrada." menu: "Menú" divider: "Divisor" addItem: "Agregar elemento" +rearrange: "Ordenar" relays: "Relés" addRelay: "Agregar relé" inboxUrl: "Inbox URL" @@ -698,6 +704,8 @@ contact: "Contacto" useSystemFont: "Utilizar la tipografía por defecto del sistema" clips: "Clip" experimentalFeatures: "Características experimentales" +experimental: "Función experimental" +thisIsExperimentalFeature: "Se trata de una función experimental. Las especificaciones pueden cambiar o puede que no funcione correctamente." developer: "Desarrolladores" makeExplorable: "Hacer visible la cuenta en \"Explorar\"" makeExplorableDescription: "Si desactiva esta opción, su cuenta no aparecerá en la sección \"Explorar\"." @@ -991,9 +999,12 @@ largeNoteReactions: "Agrandar las reacciones de las notas" noteIdOrUrl: "ID o URL de la nota" accountMigration: "Migración de cuenta" accountMoved: "Este usuario se ha mudado a una nueva cuenta:" +accountMovedShort: "Esta cuenta ha sido migrada." horizontal: "Horizontal" youFollowing: "Siguiendo" options: "Opción" +_initialAccountSetting: + accountCreated: "¡La cuenta ha sido creada!" _accountMigration: moveFrom: "Trasladar de otra cuenta a ésta" moveFromLabel: "Cuenta desde la que se realiza el traslado:" @@ -1174,6 +1185,8 @@ _achievements: _client30min: title: "Un descansito" description: "30 minutos dedicados a Misskey" + _client60min: + title: "Viendo mucho Misskey." _noteDeletedWithin1min: title: "Ah... Mejor no..." description: "Borrar una nota antes que de pase 1 minuto" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index d8ac41c925..173380805c 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -908,12 +908,14 @@ neverShow: "Ne plus afficher" remindMeLater: "Peut-être plus tard" roles: "Rôles" role: "Rôles" +noRole: "Aucun rôle" normalUser: "Simple utilisateur·rice" assign: "Attribuer" color: "Couleur" manageCustomEmojis: "Gestion des émojis personnalisés" preset: "Préréglage" selectFromPresets: "Sélectionner à partir des préréglages" +thisPostMayBeAnnoying: "Cette note peut gêner d'autres personnes." thisPostMayBeAnnoyingCancel: "Annuler" license: "Licence" video: "Vidéo" @@ -921,6 +923,7 @@ videos: "Vidéos" dataSaver: "Économiseur de données" accountMigration: "Migration de compte" accountMoved: "Cet·te utilisateur·rice a migré son compte vers :" +addMemo: "Ajouter un mémo" notificationDisplay: "Style des notifications" leftTop: "En haut à gauche" rightTop: "En haut à droite" @@ -935,6 +938,8 @@ _achievements: _notes1: description: "Publiez votre première note" flavor: "Passez un bon moment avec Misskey !" + _notes100: + title: "Beaucoup de notes" _notes100000: title: "ALL YOUR NOTE ARE BELONG TO US" _login3: @@ -985,6 +990,8 @@ _achievements: title: "Joyeux Anniversaire !" _loggedInOnNewYearsDay: title: "Bonne année !" + _cookieClicked: + flavor: "Attendez une minute, vous êtes sur le mauvais site web ?" _role: assignTarget: "Attribuer" priority: "Priorité" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index df42697ccb..70217caa27 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -20,6 +20,7 @@ noNotes: "Tidak ada catatan" noNotifications: "Tidak ada pemberitahuan" instance: "Instansi" settings: "Pengaturan" +notificationSettings: "Atur Notifikasi" basicSettings: "Pengaturan umum" otherSettings: "Pengaturan lainnya" openInWindow: "Buka di jendela" @@ -261,8 +262,10 @@ noMoreHistory: "Tidak ada sejarah lagi" startMessaging: "Mulai mengirim pesan" nUsersRead: "Dibaca oleh {n}" agreeTo: "Saya setuju kepada {0}" +agree: "Setuju" agreeBelow: "Saya setuju dengan di bawah ini" basicNotesBeforeCreateAccount: "Catatan penting" +termsOfService: "Syarat dan ketentuan" start: "Mulai" home: "Beranda" remoteUserCaution: "Informasi ini mungkin tidak mutakhir, karena pengguna ini berasal dari instansi luar." diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index d09f75155d..69ea0d172a 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -8,7 +8,7 @@ search: "探す" notifications: "通知" username: "ユーザー名" password: "パスワード" -forgotPassword: "パスワード忘れてもうた" +forgotPassword: "パスワード忘れたん?" fetchingAsApObject: "今ちと連合に照会しとるで" ok: "ええで" gotIt: "ほい" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 39574d3321..11ab762aa4 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -505,7 +505,7 @@ objectStoragePrefixDesc: "이 Prefix 의 디렉토리 아래에 파일이 저장 objectStorageEndpoint: "Endpoint" objectStorageEndpointDesc: "AWS S3의 경우 공란, 다른 서비스의 경우 각 서비스의 가이드에 맞게 endpoint를 설정해주세요. '<host>' 혹은 '<host>:<port>' 와 같이 지정합니다." objectStorageRegion: "Region" -objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해주세요. 사용하는 서비스에 region 개념이 없는 경우, 비워 두거나 'us-east-1'으로 설정해 주세요." +objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해주세요. 사용하는 서비스에 region 개념이 없는 경우 'us-east-1'으로 설정해 주세요. AWS 설정 파일 또는 환경 변수를 참조할 경우에는 비워주세요." objectStorageUseSSL: "SSL 사용" objectStorageUseSSLDesc: "API 호출시 HTTPS 를 사용하지 않는 경우 OFF 로 설정해 주세요" objectStorageUseProxy: "연결에 프록시를 사용" @@ -990,6 +990,7 @@ rolesAssignedToMe: "나에게 할당된 역할" resetPasswordConfirm: "비밀번호를 재설정하시겠습니까?" sensitiveWords: "민감한 단어" sensitiveWordsDescription: "설정한 단어가 포함된 노트의 공개 범위를 '홈'으로 강제합니다. 개행으로 구분하여 여러 개를 지정할 수 있습니다." +sensitiveWordsDescription2: "공백으로 구분하면 AND 지정이 되며, 키워드를 슬래시로 둘러싸면 정규 표현식이 됩니다." notesSearchNotAvailable: "노트 검색을 이용하실 수 없습니다." license: "라이선스" unfavoriteConfirm: "즐겨찾기를 해제하시겠습니까?" @@ -1038,12 +1039,16 @@ thisChannelArchived: "이 채널은 아카이브되었습니다." displayOfNote: "노트 표시" initialAccountSetting: "초기 설정" youFollowing: "팔로잉" +preventAiLearning: "기계학습(생성형 AI)으로의 사용을 거부" +preventAiLearningDescription: "외부의 문장 생성 AI나 이미지 생성 AI에 대해 제출한 노트나 이미지 등의 콘텐츠를 학습의 대상으로 사용하지 않도록 요구합니다. 다만, 이 요구사항을 지킬 의무는 없기 때문에 학습을 완전히 방지하는 것은 아닙니다." options: "옵션" +specifyUser: "사용자 지정" _initialAccountSetting: accountCreated: "계정 생성이 완료되었습니다!" letsStartAccountSetup: "계정의 초기 설정을 진행합니다." letsFillYourProfile: "우선 나의 프로필을 설정해 보아요." profileSetting: "프로필 설정" + privacySetting: "\n프라이버시설정" theseSettingsCanEditLater: "이 설정들은 나중에도 변경할 수 있습니다." youCanEditMoreSettingsInSettingsPageLater: "이 외에도 '설정' 페이지에서 다양한 설정을 나의 입맛에 맛게 조절할 수 있습니다. 꼭 확인해 보세요!" followUsers: "관심사가 맞는 유저를 팔로우하여 타임라인을 가꾸어 봅시다." @@ -1491,7 +1496,7 @@ _menuDisplay: hide: "숨기기" _wordMute: muteWords: "뮤트할 단어" - muteWordsDescription: "공백으로 구분하는 경우 AND, 줄바꿈으로 구분하는 경우 OR로 지정됩니다。" + muteWordsDescription: "공백으로 구분하는 경우 AND, 줄바꿈으로 구분하는 경우 OR로 지정됩니다." muteWordsDescription2: "정규 표현식을 사용하려면 키워드를 빗금표(/)로 감싸 주세요." softDescription: "지정한 조건의 노트를 타임라인에서 숨깁니다." hardDescription: "지정한 조건의 노트를 타임라인에 추가하지 않습니다. 타임라인에 추가되지 않은 노트는 조건을 변경해도 표시되지 않습니다." diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 36c29295f6..585fb95b3d 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -1,21 +1,27 @@ --- _lang_: "Norsk Bokmål" +monthAndDay: "{day}-{month}" search: "Søk" notifications: "Varsler" username: "Brukernavn" password: "Passord" forgotPassword: "Glemt passord" +fetchingAsApObject: "Henter fra Fediverse..." ok: "OK" gotIt: "Skjønner" cancel: "Avbryt" noThankYou: "Avbryt" +enterUsername: "Skriv inn brukernavn" noNotifications: "Ingen varsler" instance: "Server" settings: "Innstillinger" notificationSettings: "Varslingsinnstillinger" +basicSettings: "Grunnleggende innstillinger" otherSettings: "Andre innstillinger" +openInWindow: "Åpne i vindu" profile: "Profil" timeline: "Tidslinje" +noAccountDescription: "Denne brukeren har ikke skrevet sin bio ennå." login: "Logg inn" loggingIn: "Logget inn" logout: "Logg ut" @@ -27,6 +33,9 @@ addUser: "Legg til bruker" favorite: "Favoritt" favorites: "Favoritter" unfavorite: "Fjern favoritt" +favorited: "Lagt til i favoritter." +alreadyFavorited: "Allerede lagt til i favoritter." +cantFavorite: "Kunne ikke legge til i favoritter." pin: "Fest" unpin: "Opphev festing" copyContent: "Kopier innhold" @@ -42,8 +51,16 @@ reply: "Svar" loadMore: "Vis mer" showMore: "Vis mer" showLess: "Lukk" +youGotNewFollower: "fulgte deg" +followRequestAccepted: "Følgeforespørsel akseptert" +importAndExport: "Importer og eksporter" +import: "Importer" +export: "Eksporter" files: "Filer" download: "Nedlastinger" +driveFileDeleteConfirm: "Er du sikker på at du vil slette \"{name}\"? Det vil også forsvinne fra alt innhold som bruker det." +unfollowConfirm: "Er du sikker på at du vil slutte å følge {name}?" +importRequested: "Du har bedt om import. Dette kan ta en stund." lists: "Lister" noLists: "Ingen lister" following: "Følg" @@ -51,14 +68,18 @@ followers: "Følgere" followsYou: "Følger deg" createList: "Opprett liste" error: "Feil" +somethingHappened: "En feil har oppstått" retry: "Prøv igjen" pageLoadError: "Kunne ikke hente side." +serverIsDead: "Denne serveren svarer ikke. Vennligst vent en stund og prøv igjen." +enterListName: "Skriv inn et navn på listen" privacy: "Personvern" follow: "Følg" followRequest: "Følgeforespørsel" followRequests: "Følgeforespørsel" unfollow: "Avfølg" followRequestPending: "Venter på godkjenning" +enterEmoji: "Skriv inn en emoji" quote: "Sitat" pinned: "Fest" you: "Du" @@ -66,49 +87,90 @@ clickToShow: "Klikk for å vise" add: "Legg til" reaction: "Reaksjon" reactions: "Reaksjoner" +reactionSetting: "Reaksjoner som vises i reaksjonsvelgeren" +reactionSettingDescription2: "Dra for å endre rekkefølgen, klikk for å slette, trykk \"+\" for å legge til." +attachCancel: "Fjern vedlegg" +enterFileName: "Skriv inn filnavn" mute: "Skjul" unmute: "Vis" block: "Blokker" unblock: "Opphev blokkering" +suspend: "Suspender" blockConfirm: "Blokker?" +unblockConfirm: "Er du sikker på at du vil oppheve blokkeringen av denne kontoen?" +suspendConfirm: "Er du sikker på at du vil suspendere denne kontoen?" selectList: "Velg liste" selectChannel: "Velg kanal" +selectAntenna: "Velg en antenne" +selectWidget: "Velg en widget" +editWidgets: "Rediger widgeter" +editWidgetsExit: "Ferdig" emoji: "Emoji" emojis: "Emojier" addEmoji: "Legg til emoji" +settingGuide: "Anbefalte innstillinger" +flagAsBot: "Merk denne kontoen som en bot" +flagAsBotDescription: "Aktiver dette alternativet hvis denne kontoen styres av et program. Hvis det er aktivert, vil det fungere som et flagg for andre utviklere for å forhindre endeløse interaksjonskjeder med andre roboter og justere Misskeys interne systemer til å behandle denne kontoen som en bot." +flagAsCat: "Merk denne kontoen som en katt" +flagAsCatDescription: "Aktiver dette alternativet for å merke denne kontoen som en katt." addAccount: "Legg til konto" +reloadAccountsList: "Last inn kontoliste på nytt" +loginFailed: "Kunne ikke logge inn" +general: "Generelt" +searchWith: "Søk: {q}" +youHaveNoLists: "Du har ingen lister" +followConfirm: "Er du sikker på at du vil følge {name}?" selectUser: "Velg bruker" +recipient: "Mottaker" +annotation: "Kommentarer" +federation: "Føderasjon" instances: "Server" registeredAt: "Registrerte seg" perHour: "Per time" perDay: "Per dag" +stopActivityDelivery: "Slutt å sende aktiviteter" blockThisInstance: "Blokker denne serveren" +software: "Programvare" version: "Versjon" +withNFiles: "{n} fil(er)" +network: "Nettverk" statistics: "Statistikk" clearQueue: "Tøm kø" clearQueueConfirmTitle: "Vil du tømme kø?" blockedInstances: "Blokkerte severe" +blockedInstancesDescription: "Skriv opp vertsnavnene til serverne du vil blokkere, atskilt med linjeskift. Serverne i listen vil ikke lenger kunne kommunisere med denne serveren." muteAndBlock: "Skjul og blokker" mutedUsers: "Skjulte brukere" blockedUsers: "Blokkerte brukere" +noUsers: "Det er ingen brukere" editProfile: "Rediger profil" pinLimitExceeded: "Du kan ikke feste flere." +done: "Ferdig" noCustomEmojis: "Ingen emoji" +noJobs: "Det er ingen jobber" blocked: "Blokkert" +suspended: "Suspendert" all: "Alle" +notResponding: "Svarer ikke" changePassword: "Endre passord" security: "Sikkerhet" newPassword: "Nytt passord" newPasswordRetype: "Nytt passord (gjenta)" +attachFile: "Legg ved filer" more: "Mer!" +announcements: "Kunngjøringer" remove: "Slett" removed: "Slettet" +removeAreYouSure: "Er du sikker på at du vil fjerne \"{x}\"?" +deleteAreYouSure: "Er du sikker på at du vil slette \"{x}\"?" saved: "Lagret" upload: "Laste opp" explore: "Utforsk" messageRead: "Lest" agree: "Jeg godtar" +termsOfService: "Vilkår for bruk" home: "Hjem" +activity: "Aktivitet" images: "Bilder" image: "Bilder" birthday: "Bursdag" @@ -127,19 +189,42 @@ renameFolder: "Endre mappenavn" deleteFolder: "Slett mappe" addFile: "Legg til fil" emptyFolder: "Denne mappen er tom" +unableToDelete: "Kan ikke slette" +circularReferenceFolder: "Målmappen er en undermappe til mappen du ønsker å flytte." +hasChildFilesOrFolders: "Siden denne mappen ikke er tom, kan den ikke slettes." copyUrl: "Kopier URL" rename: "Endre navn" +avatar: "Avatar" +banner: "Banner" doNothing: "Gjør ingenting" accept: "Tillatt" reject: "Avslå" instanceName: "Servernavn" +instanceDescription: "Serverbeskrivelse" thisYear: "I år" +thisMonth: "Måned" today: "I dag" +dayX: "{day}" +monthX: "{month}" +yearX: "{year}" pages: "Sider" +integration: "Integrasjon" +enableLocalTimeline: "Aktiver lokal tidslinje" +enableGlobalTimeline: "Aktiver global tidslinje" +disablingTimelinesInfo: "Administratorer og Moderatorer vil alltid ha tilgang til alle tidslinjer, selv om de ikke er aktivert." +registration: "Registrer" +enableRegistration: "Aktiver registrering av nye brukere" +invite: "Inviter" +basicInfo: "Grunnleggende informasjon" pinnedUsers: "Festete brukrere" +pinnedUsersDescription: "Liste over brukernavn atskilt med linjeskift som skal festes i \"Utforsk\" fanen." pinnedPages: "Festete sider" hcaptcha: "hCaptcha" +enableHcaptcha: "Aktiver hCaptcha" recaptcha: "reCAPTCHA" +enableRecaptcha: "Aktiver reCAPTCHA" +turnstile: "Turnstile" +enableTurnstile: "Aktiver Turnstile" name: "Navn" popularUsers: "Populære brukere" exploreUsersCount: "Det finnes {count} brukere" @@ -149,10 +234,13 @@ aboutMisskey: "Om Misskey" share: "Del" help: "Hjelp" close: "Lukk" +invites: "Inviter" members: "Medlemmer" +title: "Tittel" text: "Tekst" next: "Neste" retype: "Gjenta" +invitations: "Inviter" available: "Tilgjengelig" unavailable: "Utilgjengelig" tooShort: "For kort" @@ -234,6 +322,7 @@ manageAccounts: "Administrer konto" classic: "Klassisk" muteThread: "Skjul denne tråden" unmuteThread: "Vis denne tråden" +hide: "Skjul" tablet: "Nettbrett" auto: "Automatisk" size: "Størrelse" @@ -312,10 +401,24 @@ _achievements: title: "Rett og slett heldig" _setNameToSyuilo: description: "Du har satt navnet ditt til \"syuilo\"" + _passedSinceAccountCreated1: + title: "Ett års jubileum" + description: "Det har gått ett år siden kontoen din ble opprettet" + _passedSinceAccountCreated2: + title: "To års jubileum" + description: "Det har gått to år siden kontoen din ble opprettet" + _passedSinceAccountCreated3: + title: "Tre års jubileum" + description: "Det har gått tre år siden kontoen din ble opprettet" _loggedInOnBirthday: title: "Gratulerer med dagen" + description: "Du logget inn på bursdagen din" _loggedInOnNewYearsDay: title: "Godt nytt år" + description: "Du logget inn på årets første dag" + _cookieClicked: + description: "Du klikket på kjeksen" + flavor: "Er du på riktig nettsted?" _brainDiver: title: "Brain Diver" flavor: "Misskey-Misskey La-Tu-Ma" @@ -333,6 +436,9 @@ _ad: _gallery: like: "Liker!" unlike: "Liker ikke" +_email: + _follow: + title: "fulgte deg" _preferencesBackups: saveNew: "Lagre som ny" cannotSave: "Kunne ikke lagre" @@ -351,6 +457,8 @@ _channel: featured: "Populært" following: "Følger" nameAndDescription: "Navn og beskrivelse" +_menuDisplay: + hide: "Skjul" _wordMute: soft: "Myk" hard: "Hard" @@ -397,13 +505,16 @@ _widgets: calendar: "Kalender" trends: "Populært" clock: "Klokke" + activity: "Aktivitet" photos: "Bilder" + federation: "Føderasjon" button: "Knapp" aiscriptApp: "AiScript App" userList: "Brukerliste" _userList: chooseList: "Velg liste" _cw: + hide: "Skjul" show: "Vis mer" _poll: noOnlyOneChoice: "Trenger minst to valger." @@ -431,6 +542,7 @@ _exportOrImport: blockingList: "Blokker" userLists: "Lister" _charts: + federation: "Føderasjon" filesIncDec: "Forskjell på antall filer" _instanceCharts: users: "Forskjell på antall brukere" @@ -442,14 +554,18 @@ _play: new: "Opprett Play" edit: "Rediger Play" featured: "Populært" + title: "Tittel" summary: "Beskrivelse" _pages: + invalidNameText: "Pass på at sidetittelen ikke er tom" like: "Liker" unlike: "Liker ikke" my: "Mine sider" featured: "Populært" contents: "Innhold" + title: "Tittel" url: "Side URL" + hideTitleWhenPinned: "Skjul sidetittel når festet til profil" fontSerif: "Serif" fontSansSerif: "Sans Serif" selectType: "Velg type" @@ -459,6 +575,7 @@ _pages: image: "Bilde" button: "Knapp" _notification: + youWereFollowed: "fulgte deg" _types: follow: "Følg" reply: "Svar" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index a123ad7266..8c79a4502d 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -560,6 +560,7 @@ accountDeletedDescription: "Эта учетная запись удалена" menu: "Меню" divider: "Линия-разделитель" addItem: "Добавить элемент" +rearrange: "Сортировать по" relays: "Ретрансляторы" addRelay: "Добавить ретранслятор" inboxUrl: "URL ящика входящих сообщений" @@ -989,6 +990,7 @@ rolesAssignedToMe: "Мои роли" resetPasswordConfirm: "Сбросить пароль?" sensitiveWords: "Чувствительные слова" sensitiveWordsDescription: "Установите общедоступный диапазон заметки, содержащей заданное слово, на домашний. Можно сделать несколько настроек, разделив их переносами строк." +sensitiveWordsDescription2: "Разделение пробелом создаёт спецификацию AND, а разделение косой чертой создаёт регулярное выражение." notesSearchNotAvailable: "Поиск заметок недоступен" license: "Лицензия" unfavoriteConfirm: "Удалить избранное?" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 22f110ebad..d8e68202d7 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -560,6 +560,7 @@ accountDeletedDescription: "บัญชีนี้ถูกลบไปแล menu: "เมนู" divider: "ตัวแบ่ง" addItem: "เพิ่มรายการ" +rearrange: "จัดใหม่" relays: "รีเลย์" addRelay: "เพิ่มรีเลย์" inboxUrl: "อินบ็อกซ์ URL" @@ -1030,6 +1031,7 @@ continue: "ดำเนินการต่อ" preservedUsernames: "ชื่อผู้ใช้ที่สงวนไว้" preservedUsernamesDescription: "ลิสต์ชื่อผู้ใช้ที่จะสำรองโดยคั่นด้วยการแบ่งบรรทัดนั้น เพราะสิ่งเหล่านี้จะไม่สามารถทำได้ในระหว่างการสร้างบัญชีตามปกติ บัญชีที่มีอยู่แล้วนั้นโดยใช้ชื่อผู้ใช้เหล่านี้จะไม่ได้รับผลกระทบอะไร" createNoteFromTheFile: "เรียบเรียงโน้ตจากไฟล์นี้" +archive: "เก็บถาวร" youFollowing: "ติดตามแล้ว" options: "ตัวเลือกบทบาท" _serverRules: @@ -1329,6 +1331,7 @@ _role: canInvite: "สร้างรหัสเชิญอินสแตนซ์" canManageCustomEmojis: "จัดการอีโมจิแบบกำหนดเอง" driveCapacity: "ความจุของไดรฟ์" + alwaysMarkNsfw: "ทำเครื่องหมายไฟล์ว่าเป็น NSFW เสมอ" pinMax: "จํานวนสูงสุดของโน้ตที่ปักหมุดไว้" antennaMax: "จำนวนสูงสุดของเสาอากาศ" wordMuteMax: "จำนวนอักขระสูงสุดที่อนุญาตในการปิดเสียงคำ" @@ -1580,6 +1583,12 @@ _time: minute: "นาที" hour: "ชั่วโมง" day: "วัน" +_timelineTutorial: + title: "วิธีใช้งาน Misskey" + step3_1: "เสร็จสิ้นการโพสต์โน้ตย่อแรกของคุณแล้วอย่างงั้นหรอ?" + step3_2: "ไชโย! ตอนนี้โน้ตย่อแรกของคุณได้ปรากฏบนไทม์ไลน์ของคุณแล้วนะ" + step4_1: "คุณยังสามารถแนบ \"ปฏิกิริยา\" ไปกับโน้ตได้อีกด้วยนะค่ะ" + step4_2: "หากต้องการแนบการแสดงความรู้สึก ให้กดเครื่องหมาย \"+\" บนโน้ตแล้วเลือกอิโมจิที่คุณต้องการแสดงความรู้สึกที่ตนเองชอบได้เลย" _2fa: alreadyRegistered: "คุณได้ลงทะเบียนอุปกรณ์ยืนยันตัวตนแบบ 2 ชั้นแล้ว" registerTOTP: "ลงทะเบียนแอพตัวตรวจสอบสิทธิ์" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 638cc1cf8a..f7d5ab0e6c 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -560,6 +560,7 @@ accountDeletedDescription: "此帐户已经被删除。" menu: "菜单" divider: "分割线" addItem: "添加项目" +rearrange: "排序方式" relays: "中继" addRelay: "添加中继" inboxUrl: "Inbox URL" @@ -989,6 +990,7 @@ rolesAssignedToMe: "指派给自己的角色" resetPasswordConfirm: "确定重置密码?" sensitiveWords: "敏感词" sensitiveWordsDescription: "将包含设置词的帖子的可见范围设置为首页。可以通过用换行符分隔来设置多个。" +sensitiveWordsDescription2: "用空格分割关键词作为AND格式,用斜线包裹关键字来构成正则表达式。" notesSearchNotAvailable: "帖子检索不可用" license: "许可信息" unfavoriteConfirm: "确定要取消收藏吗?" @@ -1028,28 +1030,49 @@ pleaseConfirmBelowBeforeSignup: "在这个服务器上注册账号前,请确 pleaseAgreeAllToContinue: "必须全部勾选「同意」才能够继续。" continue: "继续" preservedUsernames: "保留的用户名" +preservedUsernamesDescription: "列出需要保留的用户名,使用换行来作为分割。被指定的用户名在建立账户时无法使用,但由管理员所创建的账户不受该限制。此外,现有的账户也不会受到影响。" createNoteFromTheFile: "从文件创建帖子" +archive: "归档" +channelArchiveConfirmTitle: "要将{name}归档吗?" +channelArchiveConfirmDescription: "归档后,在频道列表与搜索结果中不会显示,也无法发布新的贴文。" +thisChannelArchived: "该频道已被归档。" +displayOfNote: "显示帖子" +initialAccountSetting: "初始设置" youFollowing: "正在关注" +preventAiLearning: "拒绝接受生成式AI的学习" +preventAiLearningDescription: "要求文章生成AI或图像生成AI不能够以发布的帖子和图像等内容作为学习对象。这是通过在HTML响应中包含noai标志来实现的,这不能完全阻止AI学习你的发布内容,并不是所有AI都会遵守这类请求。" options: "选项" +specifyUser: "用户指定" _initialAccountSetting: accountCreated: "账户创建完成了!" letsStartAccountSetup: "来进行帐户的初始设置吧。" letsFillYourProfile: "首先,来设定你的个人档案吧!" profileSetting: "个人资料设置" + privacySetting: "隐私设置" theseSettingsCanEditLater: "也可以在稍后修改这里的设置。" + youCanEditMoreSettingsInSettingsPageLater: "还可以在「设置」页面进行其它各种设置,稍后就来确认一下看看吧。" + followUsers: "为了建立属于你自己的时间线,试着去关注你感兴趣的用户吧。" + pushNotificationDescription: "启用推送通知的话,就可以在设备上受到来自{name}的通知了。" + initialAccountSettingCompleted: "初始设定已经完成了!" + haveFun: "希望{name}在这里玩得开心!" + ifYouNeedLearnMore: "关于{name}(Misskey)的使用方法,详见{link}。" + skipAreYouSure: "要跳过初始设置吗?" _serverRules: description: "在新用户注册前显示服务器的简单规则。推荐显示服务条款的主要内容。" _accountMigration: moveFrom: "从别的账号迁移到此账户" + moveFromSub: "为另一个账户建立别名" moveFromLabel: "迁移前的账户" moveFromDescription: "如果迁移时需要继承其他账户的关注者,请在此创造别名。此操作需要在实行迁移之前完成!请如已下输入需要迁移的账户:@person@instance.com" moveTo: "把这个账户迁移到新的账户" moveToLabel: "迁移后的账户" moveCannotBeUndone: "一旦迁移账户,就无法撤销。" moveAccountDescription: "此操作无法取消。请先确认您已在迁移后的账户上,为此账户创造了别名。创造别名后,请如以下输入您的迁移后的账户:@person@instance.com" + moveAccountHowTo: "要进行账户迁移,请现在目标账户中为此账户建立一个别名。\n建立别名后,请像这样输入目标账户:@username@server.example.com" startMigration: "迁移" migrationConfirm: "确定要把此账户迁移到{account}吗?一旦确定后,此操作无法取消,此账户也无法以原来的状态使用。\n同时,请确认迁移后的账户,已创造别名。" movedAndCannotBeUndone: "该账户已被迁移。\n迁移操作无法撤销。" + postMigrationNote: "这个账户的关注会在迁移操作后的24小时后解除。该账户的「关注中」和「关注者」皆会变为0。由于不会解除关注关系,你的关注者仍然可以继续查看该账户发补给关注者的帖子。" movedTo: "迁移后的账户" _achievements: earnedAt: "达成时间" @@ -1331,6 +1354,7 @@ _role: canInvite: "发放服务器邀请码" canManageCustomEmojis: "管理自定义表情符号" driveCapacity: "网盘容量" + alwaysMarkNsfw: "总是将文件标记为NSFW" pinMax: "帖子置顶数量限制" antennaMax: "可创建的最大天线数量" wordMuteMax: "屏蔽词的字数限制" @@ -1583,8 +1607,15 @@ _time: hour: "小时" day: "日" _timelineTutorial: + title: "Misskey的使用方法" + step1_1: "这个画面是「时间线」。{name}的投稿会按照帖子的发布时间顺序来显示。" + step1_2: "时间线有许多种类,比如在「首页时间线」中展现的是你关注的人的贴文;而在「本地时间线」中展现的是{name}里全部用户的贴文。" + step2_1: "那么接下来,试着写一些什么东西来发布吧!你可以通过点击屏幕上的铅笔图标来打开投稿页面。" + step2_2: "第一次发布的帖子内容,建议包含自我介绍,以及「开始使用{name}了」。" step3_1: "将想说的话发出去了吗?" step3_2: "太棒了!现在你可以在你的时间线中看到刚刚发布的帖子了。" + step4_1: "试着对帖子使用「回应」吧!" + step4_2: "在他人的帖子上按下「+」图标,即可选择想要的表情来进行「回应」。" _2fa: alreadyRegistered: "此设备已被注册" registerTOTP: "开始设置认证应用" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index d2b42313a7..6ab6736d45 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1039,14 +1039,16 @@ thisChannelArchived: "這個頻道已被封存。" displayOfNote: "顯示貼文" initialAccountSetting: "初始設定" youFollowing: "追隨中" -preventAiLearning: "拒絕接受產生式AI的學習" -preventAiLearningDescription: "要求外部的文章產生AI或圖像產生AI不以發布的貼文和圖像等內容為學習對象。這是透過在HTML響應中包含noai旗標來實現的,但不能完全防止AI的學習,因為這要看該AI是否遵守這個要求。" +preventAiLearning: "拒絕接受生成式AI的訓練" +preventAiLearningDescription: "要求外部的文章生成式AI或圖像生成式AI不以發布的貼文和圖像等內容為學習對象。這是透過在HTML響應中包含noai旗標來實現的,但不能完全防止AI的學習,因為這要看該AI是否遵守這個要求。" options: "選項" +specifyUser: "指定使用者" _initialAccountSetting: accountCreated: "帳戶已建立完成!" letsStartAccountSetup: "來進行帳戶的初始設定吧。" letsFillYourProfile: "首先,來設定您的個人檔案吧。" profileSetting: "個人檔案設定" + privacySetting: "隱私設定" theseSettingsCanEditLater: "這裡的設定可以在之後變更。" youCanEditMoreSettingsInSettingsPageLater: "除此之外,還可以在「設定」頁面進行各種設定。之後請確認看看。" followUsers: "為了構築時間軸,試著追蹤您感興趣的使用者吧。" From 3097bb6c7d59df700387a95624e3a4ccbfadd1fd Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 18:22:15 +0900 Subject: [PATCH 114/213] refactor --- .../src/components/MkNoteDetailed.vue | 678 ++++++++---------- 1 file changed, 303 insertions(+), 375 deletions(-) diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index fe39328e14..3ce516b267 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -4,25 +4,25 @@ v-show="!isDeleted" ref="el" v-hotkey="keymap" - class="lxwezrsl" - :tabindex="!isDeleted ? '-1' : null" - :class="{ renote: isRenote }" + :class="[$style.root, { [$style.renote]: isRenote }]" > - <MkNoteSub v-for="note in conversation" :key="note.id" class="reply-to-more" :note="note"/> - <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to"/> - <div v-if="isRenote" class="renote"> - <MkAvatar class="avatar" :user="note.user" link preview/> - <i class="ti ti-repeat"></i> - <I18n :src="i18n.ts.renotedBy" tag="span"> - <template #user> - <MkA v-user-preview="note.userId" class="name" :to="userPage(note.user)"> - <MkUserName :user="note.user"/> - </MkA> - </template> - </I18n> - <div class="info"> - <button ref="renoteTime" class="_button time" @click="showRenoteMenu()"> - <i v-if="isMyRenote" class="ti ti-dots dropdownIcon"></i> + <MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/> + <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/> + <div v-if="isRenote" :class="$style.renote"> + <MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/> + <i class="ti ti-repeat" style="margin-right: 4px;"></i> + <span :class="$style.renoteText"> + <I18n :src="i18n.ts.renotedBy" tag="span"> + <template #user> + <MkA v-user-preview="note.userId" :class="$style.renoteName" :to="userPage(note.user)"> + <MkUserName :user="note.user"/> + </MkA> + </template> + </I18n> + </span> + <div :class="$style.renoteInfo"> + <button ref="renoteTime" class="_button" :class="$style.renoteTime" @click="showRenoteMenu()"> + <i v-if="isMyRenote" class="ti ti-dots" style="margin-right: 4px;"></i> <MkTime :time="note.createdAt"/> </button> <span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]"> @@ -33,16 +33,16 @@ <span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span> </div> </div> - <article class="article" @contextmenu.stop="onContextmenu"> - <header class="header"> - <MkAvatar class="avatar" :user="appearNote.user" indicator link preview/> - <div class="body"> - <div class="top"> - <MkA v-user-preview="appearNote.user.id" class="name" :to="userPage(appearNote.user)"> + <article :class="$style.note" @contextmenu.stop="onContextmenu"> + <header :class="$style.noteHeader"> + <MkAvatar :class="$style.noteHeaderAvatar" :user="appearNote.user" indicator link preview/> + <div :class="$style.noteHeaderBody"> + <div> + <MkA v-user-preview="appearNote.user.id" :class="$style.noteHeaderName" :to="userPage(appearNote.user)"> <MkUserName :nowrap="false" :user="appearNote.user"/> </MkA> - <span v-if="appearNote.user.isBot" class="is-bot">bot</span> - <div class="info"> + <span v-if="appearNote.user.isBot" :class="$style.isBot">bot</span> + <div :class="$style.noteHeaderInfo"> <span v-if="appearNote.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[appearNote.visibility]"> <i v-if="appearNote.visibility === 'home'" class="ti ti-home"></i> <i v-else-if="appearNote.visibility === 'followers'" class="ti ti-lock"></i> @@ -51,84 +51,81 @@ <span v-if="appearNote.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['disableFederation']"><i class="ti ti-rocket-off"></i></span> </div> </div> - <div class="username"><MkAcct :user="appearNote.user"/></div> - <MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/> + <div :class="$style.noteHeaderUsername"><MkAcct :user="appearNote.user"/></div> + <MkInstanceTicker v-if="showTicker" :class="$style.ticker" :instance="appearNote.user.instance"/> </div> </header> - <div class="main"> - <div class="body"> - <p v-if="appearNote.cw != null" class="cw"> - <Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i"/> - <MkCwButton v-model="showContent" :note="appearNote"/> - </p> - <div v-show="appearNote.cw == null || showContent" class="content"> - <div class="text"> - <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> - <MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> - <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> - <a v-if="appearNote.renote != null" class="rp">RN:</a> - <div v-if="translating || translation" class="translation"> - <MkLoading v-if="translating" mini/> - <div v-else class="translated"> - <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b> - <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> - </div> - </div> + <div :class="$style.noteContent"> + <p v-if="appearNote.cw != null" :class="$style.cw"> + <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :i="$i"/> + <MkCwButton v-model="showContent" :note="appearNote"/> + </p> + <div v-show="appearNote.cw == null || showContent"> + <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> + <MkA v-if="appearNote.replyId" :class="$style.noteReplyTarget" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> + <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> + <a v-if="appearNote.renote != null" :class="$style.rn">RN:</a> + <div v-if="translating || translation" :class="$style.translation"> + <MkLoading v-if="translating" mini/> + <div v-else> + <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b> + <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> </div> - <div v-if="appearNote.files.length > 0" class="files"> - <MkMediaList :mediaList="appearNote.files"/> - </div> - <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/> - <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" class="url-preview"/> - <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote" class="note"/></div> </div> - <MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA> + <div v-if="appearNote.files.length > 0" :class="$style.files"> + <MkMediaList :mediaList="appearNote.files"/> + </div> + <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" :class="$style.poll"/> + <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="true" style="margin-top: 6px;"/> + <div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div> </div> - <footer class="footer"> - <div class="info"> - <MkA class="created-at" :to="notePage(appearNote)"> - <MkTime :time="appearNote.createdAt" mode="detail"/> - </MkA> - </div> - <MkReactionsViewer ref="reactionsViewer" :note="appearNote"/> - <button class="button _button" @click="reply()"> - <i class="ti ti-arrow-back-up"></i> - <p v-if="appearNote.repliesCount > 0" class="count">{{ appearNote.repliesCount }}</p> - </button> - <button - v-if="canRenote" - ref="renoteButton" - class="button _button" - @mousedown="renote()" - > - <i class="ti ti-repeat"></i> - <p v-if="appearNote.renoteCount > 0" class="count">{{ appearNote.renoteCount }}</p> - </button> - <button v-else class="button _button" disabled> - <i class="ti ti-ban"></i> - </button> - <button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()"> - <i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> - <i v-else class="ti ti-plus"></i> - </button> - <button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)"> - <i class="ti ti-minus"></i> - </button> - <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="button _button" @mousedown="clip()"> - <i class="ti ti-paperclip"></i> - </button> - <button ref="menuButton" class="button _button" @mousedown="menu()"> - <i class="ti ti-dots"></i> - </button> - </footer> + <MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA> </div> + <footer> + <div :class="$style.noteFooterInfo"> + <MkA :to="notePage(appearNote)"> + <MkTime :time="appearNote.createdAt" mode="detail"/> + </MkA> + </div> + <MkReactionsViewer ref="reactionsViewer" :note="appearNote"/> + <button class="_button" :class="$style.noteFooterButton" @click="reply()"> + <i class="ti ti-arrow-back-up"></i> + <p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.repliesCount }}</p> + </button> + <button + v-if="canRenote" + ref="renoteButton" + class="_button" + :class="$style.noteFooterButton" + @mousedown="renote()" + > + <i class="ti ti-repeat"></i> + <p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ appearNote.renoteCount }}</p> + </button> + <button v-else class="_button" :class="$style.noteFooterButton" disabled> + <i class="ti ti-ban"></i> + </button> + <button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.noteFooterButton" class="_button" @mousedown="react()"> + <i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i> + <i v-else class="ti ti-plus"></i> + </button> + <button v-if="appearNote.myReaction != null" ref="reactButton" class="_button" :class="[$style.noteFooterButton, $style.reacted]" @click="undoReact(appearNote)"> + <i class="ti ti-minus"></i> + </button> + <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()"> + <i class="ti ti-paperclip"></i> + </button> + <button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown="menu()"> + <i class="ti ti-dots"></i> + </button> + </footer> </article> - <MkNoteSub v-for="note in replies" :key="note.id" :note="note" class="reply" :detail="true"/> + <MkNoteSub v-for="note in replies" :key="note.id" :note="note" :class="$style.reply" :detail="true"/> </div> -<div v-else class="_panel muted" @click="muted = false"> +<div v-else class="_panel" :class="$style.muted" @click="muted = false"> <I18n :src="i18n.ts.userSaysSomething" tag="small"> <template #name> - <MkA v-user-preview="appearNote.userId" class="name" :to="userPage(appearNote.user)"> + <MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)"> <MkUserName :user="appearNote.user"/> </MkA> </template> @@ -438,318 +435,249 @@ if (appearNote.replyId) { } </script> -<style lang="scss" scoped> -.lxwezrsl { +<style lang="scss" module> +.root { position: relative; transition: box-shadow 0.1s ease; overflow: clip; contain: content; +} - &:focus-visible { - outline: none; +.replyTo { + opacity: 0.7; + padding-bottom: 0; +} - &:after { - content: ""; - pointer-events: none; - display: block; - position: absolute; - z-index: 10; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - width: calc(100% - 8px); - height: calc(100% - 8px); - border: dashed 1px var(--focus); - border-radius: var(--radius); - box-sizing: border-box; - } - } +.replyToMore { + opacity: 0.7; +} - &:hover > .article > .main > .footer > .button { +.renote { + display: flex; + align-items: center; + padding: 16px 32px 8px 32px; + line-height: 28px; + white-space: pre; + color: var(--renote); +} + +.renoteAvatar { + flex-shrink: 0; + display: inline-block; + width: 28px; + height: 28px; + margin: 0 8px 0 0; + border-radius: 6px; +} + +.renoteText { + overflow: hidden; + flex-shrink: 1; + text-overflow: ellipsis; + white-space: nowrap; +} + +.renoteName { + font-weight: bold; +} + +.renoteInfo { + margin-left: auto; + font-size: 0.9em; +} + +.renoteTime { + flex-shrink: 0; + color: inherit; +} + +.renote + .note { + padding-top: 8px; +} + +.note { + padding: 32px; + font-size: 1.2em; + + &:hover > .main > .footer > .button { opacity: 1; } - - > .reply-to { - opacity: 0.7; - padding-bottom: 0; - } - - > .reply-to-more { - opacity: 0.7; - } - - > .renote { - display: flex; - align-items: center; - padding: 16px 32px 8px 32px; - line-height: 28px; - white-space: pre; - color: var(--renote); - - > .avatar { - flex-shrink: 0; - display: inline-block; - width: 28px; - height: 28px; - margin: 0 8px 0 0; - border-radius: 6px; - } - - > i { - margin-right: 4px; - } - - > span { - overflow: hidden; - flex-shrink: 1; - text-overflow: ellipsis; - white-space: nowrap; - - > .name { - font-weight: bold; - } - } - - > .info { - margin-left: auto; - font-size: 0.9em; - - > .time { - flex-shrink: 0; - color: inherit; - - > .dropdownIcon { - margin-right: 4px; - } - } - } - } - - > .renote + .article { - padding-top: 8px; - } - - > .article { - padding: 32px; - font-size: 1.2em; - - > .header { - display: flex; - position: relative; - margin-bottom: 16px; - align-items: center; - - > .avatar { - display: block; - flex-shrink: 0; - width: 58px; - height: 58px; - } - - > .body { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - padding-left: 16px; - font-size: 0.95em; - - > .top { - > .name { - font-weight: bold; - line-height: 1.3; - } - - > .is-bot { - display: inline-block; - margin: 0 0.5em; - padding: 4px 6px; - font-size: 80%; - line-height: 1; - border: solid 0.5px var(--divider); - border-radius: 4px; - } - - > .info { - float: right; - } - } - - > .username { - margin-bottom: 2px; - line-height: 1.3; - word-wrap: anywhere; - } - } - } - - > .main { - > .body { - container-type: inline-size; - - > .cw { - cursor: default; - display: block; - margin: 0; - padding: 0; - overflow-wrap: break-word; - - > .text { - margin-right: 8px; - } - } - - > .content { - > .text { - overflow-wrap: break-word; - - > .reply { - color: var(--accent); - margin-right: 0.5em; - } - - > .rp { - margin-left: 4px; - font-style: oblique; - color: var(--renote); - } - - > .translation { - border: solid 0.5px var(--divider); - border-radius: var(--radius); - padding: 12px; - margin-top: 8px; - } - } - - > .url-preview { - margin-top: 8px; - } - - > .poll { - font-size: 80%; - } - - > .renote { - padding: 8px 0; - - > .note { - padding: 16px; - border: dashed 1px var(--renote); - border-radius: 8px; - } - } - } - - > .channel { - opacity: 0.7; - font-size: 80%; - } - } - - > .footer { - > .info { - margin: 16px 0; - opacity: 0.7; - font-size: 0.9em; - } - - > .button { - margin: 0; - padding: 8px; - opacity: 0.7; - - &:not(:last-child) { - margin-right: 28px; - } - - &:hover { - color: var(--fgHighlighted); - } - - > .count { - display: inline; - margin: 0 0 0 8px; - opacity: 0.7; - } - - &.reacted { - color: var(--accent); - } - } - } - } - } - - > .reply { - border-top: solid 0.5px var(--divider); - } +} + +.noteHeader { + display: flex; + position: relative; + margin-bottom: 16px; + align-items: center; +} + +.noteHeaderAvatar { + display: block; + flex-shrink: 0; + width: 58px; + height: 58px; +} + +.noteHeaderBody { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + padding-left: 16px; + font-size: 0.95em; +} + +.noteHeaderName { + font-weight: bold; + line-height: 1.3; +} + +.isBot { + display: inline-block; + margin: 0 0.5em; + padding: 4px 6px; + font-size: 80%; + line-height: 1; + border: solid 0.5px var(--divider); + border-radius: 4px; +} + +.noteHeaderInfo { + float: right; +} + +.noteHeaderUsername { + margin-bottom: 2px; + line-height: 1.3; + word-wrap: anywhere; +} + +.noteContent { + container-type: inline-size; + overflow-wrap: break-word; +} + +.cw { + cursor: default; + display: block; + margin: 0; + padding: 0; + overflow-wrap: break-word; +} + +.noteReplyTarget { + color: var(--accent); + margin-right: 0.5em; +} + +.rn { + margin-left: 4px; + font-style: oblique; + color: var(--renote); +} + +.translation { + border: solid 0.5px var(--divider); + border-radius: var(--radius); + padding: 12px; + margin-top: 8px; +} + +.poll { + font-size: 80%; +} + +.quote { + padding: 8px 0; +} + +.quoteNote { + padding: 16px; + border: dashed 1px var(--renote); + border-radius: 8px; +} + +.channel { + opacity: 0.7; + font-size: 80%; +} + +.noteFooterInfo { + margin: 16px 0; + opacity: 0.7; + font-size: 0.9em; +} + +.noteFooterButton { + margin: 0; + padding: 8px; + opacity: 0.7; + + &:not(:last-child) { + margin-right: 28px; + } + + &:hover { + color: var(--fgHighlighted); + } +} + +.noteFooterButtonCount { + display: inline; + margin: 0 0 0 8px; + opacity: 0.7; + + &.reacted { + color: var(--accent); + } +} + +.reply { + border-top: solid 0.5px var(--divider); } @container (max-width: 500px) { - .lxwezrsl { + .root { font-size: 0.9em; } } @container (max-width: 450px) { - .lxwezrsl { - > .renote { - padding: 8px 16px 0 16px; - } + .renote { + padding: 8px 16px 0 16px; + } - > .article { - padding: 16px; + .note { + padding: 16px; + } - > .header { - > .avatar { - width: 50px; - height: 50px; - } - } - } + .noteHeaderAvatar { + width: 50px; + height: 50px; } } @container (max-width: 350px) { - .lxwezrsl { - > .article { - > .main { - > .footer { - > .button { - &:not(:last-child) { - margin-right: 18px; - } - } - } - } + .noteFooterButton { + &:not(:last-child) { + margin-right: 18px; } } } @container (max-width: 300px) { - .lxwezrsl { + .root { font-size: 0.825em; + } - > .article { - > .header { - > .avatar { - width: 50px; - height: 50px; - } - } + .noteHeaderAvatar { + width: 50px; + height: 50px; + } - > .main { - > .footer { - > .button { - &:not(:last-child) { - margin-right: 12px; - } - } - } - } + .noteFooterButton { + &:not(:last-child) { + margin-right: 12px; } } } From 7f235275c95675f4ee0db779332b3c9fb577f4e2 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 19:35:11 +0900 Subject: [PATCH 115/213] :art: --- packages/frontend/src/ui/deck/column.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 073b036cb9..2c75577ba4 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -296,8 +296,10 @@ function onDrop(ev) { } > .body { + background: transparent !important; + &::-webkit-scrollbar-track { - background: inherit; + background: transparent; } } } @@ -306,6 +308,8 @@ function onDrop(ev) { background: var(--bg) !important; > .body { + background: var(--bg) !important; + &::-webkit-scrollbar-track { background: inherit; } From bd66a3f1483cf59b0fb0ea0a262a2593ecdd45b5 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 19:37:03 +0900 Subject: [PATCH 116/213] :art: --- packages/frontend/src/ui/deck.vue | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 126aa807a8..51cb803397 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -330,11 +330,7 @@ async function deleteProfile() { flex-shrink: 0; padding-top: var(--columnGap); padding-bottom: var(--columnGap); - padding-right: var(--columnGap); - - &:first-of-type { - padding-left: var(--columnGap); - } + padding-left: var(--columnGap); > .column:not(:last-of-type) { margin-bottom: var(--columnGap); From 19b96ff65011d8f3051aeebaf255ea5b78b5fbee Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 19:56:17 +0900 Subject: [PATCH 117/213] refactor --- packages/frontend/src/components/MkDrive.vue | 264 ++++++++----------- 1 file changed, 117 insertions(+), 147 deletions(-) diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index 86534dae43..52aef450d9 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -1,9 +1,9 @@ <template> -<div class="yfudmmck"> - <nav> - <div class="path" @contextmenu.prevent.stop="() => {}"> +<div :class="$style.root"> + <nav :class="$style.nav"> + <div :class="$style.navPath" @contextmenu.prevent.stop="() => {}"> <XNavFolder - :class="{ current: folder == null }" + :class="[$style.navPathItem, { [$style.navCurrent]: folder == null }]" :parentFolder="folder" @move="move" @upload="upload" @@ -11,37 +11,38 @@ @removeFolder="removeFolder" /> <template v-for="f in hierarchyFolders"> - <span class="separator"><i class="ti ti-chevron-right"></i></span> + <span :class="[$style.navPathItem, $style.navSeparator]"><i class="ti ti-chevron-right"></i></span> <XNavFolder :folder="f" :parentFolder="folder" + :class="[$style.navPathItem]" @move="move" @upload="upload" @removeFile="removeFile" @removeFolder="removeFolder" /> </template> - <span v-if="folder != null" class="separator"><i class="ti ti-chevron-right"></i></span> - <span v-if="folder != null" class="folder current">{{ folder.name }}</span> + <span v-if="folder != null" :class="[$style.navPathItem, $style.navSeparator]"><i class="ti ti-chevron-right"></i></span> + <span v-if="folder != null" :class="[$style.navPathItem, $style.navCurrent]">{{ folder.name }}</span> </div> - <button class="menu _button" @click="showMenu"><i class="ti ti-dots"></i></button> + <button class="_button" :class="$style.navMenu" @click="showMenu"><i class="ti ti-dots"></i></button> </nav> <div - ref="main" class="main" - :class="{ uploading: uploadings.length > 0, fetching }" + ref="main" + :class="[$style.main, { [$style.uploading]: uploadings.length > 0, [$style.fetching]: fetching }]" @dragover.prevent.stop="onDragover" @dragenter="onDragenter" @dragleave="onDragleave" @drop.prevent.stop="onDrop" @contextmenu.stop="onContextmenu" > - <div ref="contents" class="contents"> - <div v-show="folders.length > 0" ref="foldersContainer" class="folders"> + <div ref="contents"> + <div v-show="folders.length > 0" ref="foldersContainer" :class="$style.folders"> <XFolder v-for="(f, i) in folders" :key="f.id" v-anim="i" - class="folder" + :class="$style.folder" :folder="f" :selectMode="select === 'folder'" :isSelected="selectedFolders.some(x => x.id === f.id)" @@ -54,15 +55,15 @@ @dragend="isDragSource = false" /> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid --> - <div v-for="(n, i) in 16" :key="i" class="padding"></div> + <div v-for="(n, i) in 16" :key="i" :class="$style.padding"></div> <MkButton v-if="moreFolders" ref="moreFolders">{{ i18n.ts.loadMore }}</MkButton> </div> - <div v-show="files.length > 0" ref="filesContainer" class="files"> + <div v-show="files.length > 0" ref="filesContainer" :class="$style.files"> <XFile v-for="(file, i) in files" :key="file.id" v-anim="i" - class="file" + :class="$style.file" :file="file" :selectMode="select === 'file'" :isSelected="selectedFiles.some(x => x.id === file.id)" @@ -71,19 +72,19 @@ @dragend="isDragSource = false" /> <!-- SEE: https://stackoverflow.com/questions/18744164/flex-box-align-last-row-to-grid --> - <div v-for="(n, i) in 16" :key="i" class="padding"></div> + <div v-for="(n, i) in 16" :key="i" :class="$style.padding"></div> <MkButton v-show="moreFiles" ref="loadMoreFiles" @click="fetchMoreFiles">{{ i18n.ts.loadMore }}</MkButton> </div> - <div v-if="files.length == 0 && folders.length == 0 && !fetching" class="empty"> - <p v-if="draghover">{{ i18n.t('empty-draghover') }}</p> - <p v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong><br/>{{ i18n.t('empty-drive-description') }}</p> - <p v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</p> + <div v-if="files.length == 0 && folders.length == 0 && !fetching" :class="$style.empty"> + <div v-if="draghover">{{ i18n.t('empty-draghover') }}</div> + <div v-if="!draghover && folder == null"><strong>{{ i18n.ts.emptyDrive }}</strong><br/>{{ i18n.t('empty-drive-description') }}</div> + <div v-if="!draghover && folder != null">{{ i18n.ts.emptyFolder }}</div> </div> </div> <MkLoading v-if="fetching"/> </div> - <div v-if="draghover" class="dropzone"></div> - <input ref="fileInput" type="file" accept="*/*" multiple tabindex="-1" @change="onChangeFileInput"/> + <div v-if="draghover" :class="$style.dropzone"></div> + <input ref="fileInput" style="display: none;" type="file" accept="*/*" multiple tabindex="-1" @change="onChangeFileInput"/> </div> </template> @@ -658,147 +659,116 @@ onBeforeUnmount(() => { }); </script> -<style lang="scss" scoped> -.yfudmmck { +<style lang="scss" module> +.root { display: flex; flex-direction: column; height: 100%; +} - > nav { - display: flex; - z-index: 2; - width: 100%; - padding: 0 8px; - box-sizing: border-box; - overflow: auto; - font-size: 0.9em; - box-shadow: 0 1px 0 var(--divider); +.nav { + display: flex; + z-index: 2; + width: 100%; + padding: 0 8px; + box-sizing: border-box; + overflow: auto; + font-size: 0.9em; + box-shadow: 0 1px 0 var(--divider); + user-select: none; +} - &, * { - user-select: none; - } +.navPath { + display: inline-block; + vertical-align: bottom; + line-height: 42px; + white-space: nowrap; +} - > .path { - display: inline-block; - vertical-align: bottom; - line-height: 42px; - white-space: nowrap; +.navPathItem { + display: inline-block; + margin: 0; + padding: 0 8px; + line-height: 42px; + cursor: pointer; - > * { - display: inline-block; - margin: 0; - padding: 0 8px; - line-height: 42px; - cursor: pointer; + &:hover { + text-decoration: underline; + } - * { - pointer-events: none; - } + &.navCurrent { + font-weight: bold; + cursor: default; - &:hover { - text-decoration: underline; - } - - &.current { - font-weight: bold; - cursor: default; - - &:hover { - text-decoration: none; - } - } - - &.separator { - margin: 0; - padding: 0; - opacity: 0.5; - cursor: default; - - > i { - margin: 0; - } - } - } - } - - > .menu { - margin-left: auto; - padding: 0 12px; + &:hover { + text-decoration: none; } } - > .main { - flex: 1; - overflow: auto; - padding: var(--margin); - - &, * { - user-select: none; - } - - &.fetching { - cursor: wait !important; - - * { - pointer-events: none; - } - - > .contents { - opacity: 0.5; - } - } - - &.uploading { - height: calc(100% - 38px - 100px); - } - - > .contents { - - > .folders, - > .files { - display: flex; - flex-wrap: wrap; - - > .folder, - > .file { - flex-grow: 1; - width: 128px; - margin: 4px; - box-sizing: border-box; - } - - > .padding { - flex-grow: 1; - pointer-events: none; - width: 128px + 8px; - } - } - - > .empty { - padding: 16px; - text-align: center; - pointer-events: none; - opacity: 0.5; - - > p { - margin: 0; - } - } - } + &.navSeparator { + margin: 0; + padding: 0; + opacity: 0.5; + cursor: default; } +} - > .dropzone { - position: absolute; - left: 0; - top: 38px; - width: 100%; - height: calc(100% - 38px); - border: dashed 2px var(--focus); +.navMenu { + margin-left: auto; + padding: 0 12px; +} + +.main { + flex: 1; + overflow: auto; + padding: var(--margin); + user-select: none; + + &.fetching { + cursor: wait !important; + opacity: 0.5; pointer-events: none; } - > input { - display: none; + &.uploading { + height: calc(100% - 38px - 100px); } } + +.folders, +.files { + display: flex; + flex-wrap: wrap; +} + +.folder, +.file { + flex-grow: 1; + width: 128px; + margin: 4px; + box-sizing: border-box; +} + +.padding { + flex-grow: 1; + pointer-events: none; + width: 128px + 8px; +} + +.empty { + padding: 16px; + text-align: center; + pointer-events: none; + opacity: 0.5; +} + +.dropzone { + position: absolute; + left: 0; + top: 38px; + width: 100%; + height: calc(100% - 38px); + border: dashed 2px var(--focus); + pointer-events: none; +} </style> From 101e8d7adba6226437cccc96d18d7914eed125d8 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 20:05:46 +0900 Subject: [PATCH 118/213] refactor --- .../frontend/src/components/MkDrive.file.vue | 188 +++++++++--------- .../src/components/MkDrive.folder.vue | 86 ++++---- 2 files changed, 128 insertions(+), 146 deletions(-) diff --git a/packages/frontend/src/components/MkDrive.file.vue b/packages/frontend/src/components/MkDrive.file.vue index ab408b5008..f0641161be 100644 --- a/packages/frontend/src/components/MkDrive.file.vue +++ b/packages/frontend/src/components/MkDrive.file.vue @@ -1,7 +1,6 @@ <template> <div - class="ncvczrfv" - :class="{ isSelected }" + :class="[$style.root, { [$style.isSelected]: isSelected }]" draggable="true" :title="title" @click="onClick" @@ -9,25 +8,27 @@ @dragstart="onDragstart" @dragend="onDragend" > - <div v-if="$i?.avatarId == file.id" class="label"> - <img src="/client-assets/label.svg"/> - <p>{{ i18n.ts.avatar }}</p> - </div> - <div v-if="$i?.bannerId == file.id" class="label"> - <img src="/client-assets/label.svg"/> - <p>{{ i18n.ts.banner }}</p> - </div> - <div v-if="file.isSensitive" class="label red"> - <img src="/client-assets/label-red.svg"/> - <p>{{ i18n.ts.nsfw }}</p> - </div> + <div style="pointer-events: none;"> + <div v-if="$i?.avatarId == file.id" :class="[$style.label]"> + <img :class="$style.labelImg" src="/client-assets/label.svg"/> + <p :class="$style.labelText">{{ i18n.ts.avatar }}</p> + </div> + <div v-if="$i?.bannerId == file.id" :class="[$style.label]"> + <img :class="$style.labelImg" src="/client-assets/label.svg"/> + <p :class="$style.labelText">{{ i18n.ts.banner }}</p> + </div> + <div v-if="file.isSensitive" :class="[$style.label, $style.red]"> + <img :class="$style.labelImg" src="/client-assets/label-red.svg"/> + <p :class="$style.labelText">{{ i18n.ts.nsfw }}</p> + </div> - <MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/> + <MkDriveFileThumbnail :class="$style.thumbnail" :file="file" fit="contain"/> - <p class="name"> - <span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span> - <span v-if="file.name.lastIndexOf('.') != -1" class="ext">{{ file.name.substr(file.name.lastIndexOf('.')) }}</span> - </p> + <p :class="$style.name"> + <span>{{ file.name.lastIndexOf('.') != -1 ? file.name.substr(0, file.name.lastIndexOf('.')) : file.name }}</span> + <span v-if="file.name.lastIndexOf('.') != -1" style="opacity: 0.5;">{{ file.name.substr(file.name.lastIndexOf('.')) }}</span> + </p> + </div> </div> </template> @@ -88,20 +89,13 @@ function onDragend() { } </script> -<style lang="scss" scoped> -.ncvczrfv { +<style lang="scss" module> +.root { position: relative; padding: 8px 0 0 0; min-height: 180px; border-radius: 8px; - - &, * { - cursor: pointer; - } - - > * { - pointer-events: none; - } + cursor: pointer; &:hover { background: rgba(#000, 0.05); @@ -165,82 +159,78 @@ function onDragend() { color: #fff; } } +} - > .label { +.label { + position: absolute; + top: 0; + left: 0; + pointer-events: none; + + &:before, + &:after { + content: ""; + display: block; position: absolute; - top: 0; - left: 0; - pointer-events: none; + z-index: 1; + background: #0c7ac9; + } + &:before { + top: 0; + left: 57px; + width: 28px; + height: 8px; + } + + &:after { + top: 57px; + left: 0; + width: 8px; + height: 28px; + } + + &.red { &:before, &:after { - content: ""; - display: block; - position: absolute; - z-index: 1; - background: #0c7ac9; - } - - &:before { - top: 0; - left: 57px; - width: 28px; - height: 8px; - } - - &:after { - top: 57px; - left: 0; - width: 8px; - height: 28px; - } - - &.red { - &:before, - &:after { - background: #c12113; - } - } - - > img { - position: absolute; - z-index: 2; - top: 0; - left: 0; - } - - > p { - position: absolute; - z-index: 3; - top: 19px; - left: -28px; - width: 120px; - margin: 0; - text-align: center; - line-height: 28px; - color: #fff; - transform: rotate(-45deg); - } - } - - > .thumbnail { - width: 110px; - height: 110px; - margin: auto; - } - - > .name { - display: block; - margin: 4px 0 0 0; - font-size: 0.8em; - text-align: center; - word-break: break-all; - color: var(--fg); - overflow: hidden; - - > .ext { - opacity: 0.5; + background: #c12113; } } } + +.labelImg { + position: absolute; + z-index: 2; + top: 0; + left: 0; +} + +.labelText { + position: absolute; + z-index: 3; + top: 19px; + left: -28px; + width: 120px; + margin: 0; + text-align: center; + line-height: 28px; + color: #fff; + transform: rotate(-45deg); +} + +.thumbnail { + width: 110px; + height: 110px; + margin: auto; +} + +.name { + display: block; + margin: 4px 0 0 0; + font-size: 0.8em; + text-align: center; + word-break: break-all; + color: var(--fg); + overflow: hidden; +} </style> diff --git a/packages/frontend/src/components/MkDrive.folder.vue b/packages/frontend/src/components/MkDrive.folder.vue index 156013b9aa..1969342402 100644 --- a/packages/frontend/src/components/MkDrive.folder.vue +++ b/packages/frontend/src/components/MkDrive.folder.vue @@ -1,7 +1,6 @@ <template> <div - class="rghtznwe" - :class="{ draghover }" + :class="[$style.root, { [$style.draghover]: draghover }]" draggable="true" :title="title" @click="onClick" @@ -15,15 +14,15 @@ @dragstart="onDragstart" @dragend="onDragend" > - <p class="name"> - <template v-if="hover"><i class="ti ti-folder ti-fw"></i></template> - <template v-if="!hover"><i class="ti ti-folder ti-fw"></i></template> + <p :class="$style.name"> + <template v-if="hover"><i :class="$style.icon" class="ti ti-folder ti-fw"></i></template> + <template v-if="!hover"><i :class="$style.icon" class="ti ti-folder ti-fw"></i></template> {{ folder.name }} </p> - <p v-if="defaultStore.state.uploadFolder == folder.id" class="upload"> + <p v-if="defaultStore.state.uploadFolder == folder.id" :class="$style.upload"> {{ i18n.ts.uploadFolder }} </p> - <button v-if="selectMode" class="checkbox _button" :class="{ checked: isSelected }" @click.prevent.stop="checkboxClicked"></button> + <button v-if="selectMode" class="_button" :class="[$style.checkbox, { [$style.checked]: isSelected }]" @click.prevent.stop="checkboxClicked"></button> </div> </template> @@ -267,35 +266,14 @@ function onContextmenu(ev: MouseEvent) { } </script> -<style lang="scss" scoped> -.rghtznwe { +<style lang="scss" module> +.root { position: relative; padding: 8px; height: 64px; background: var(--driveFolderBg); border-radius: 4px; - - &, * { - cursor: pointer; - } - - *:not(.checkbox) { - pointer-events: none; - } - - > .checkbox { - position: absolute; - bottom: 8px; - right: 8px; - width: 16px; - height: 16px; - background: #fff; - border: solid 1px #000; - - &.checked { - background: var(--accent); - } - } + cursor: pointer; &.draghover { &:after { @@ -310,24 +288,38 @@ function onContextmenu(ev: MouseEvent) { border-radius: 4px; } } +} - > .name { - margin: 0; - font-size: 0.9em; - color: var(--desktopDriveFolderFg); +.checkbox { + position: absolute; + bottom: 8px; + right: 8px; + width: 16px; + height: 16px; + background: #fff; + border: solid 1px #000; - > i { - margin-right: 4px; - margin-left: 2px; - text-align: left; - } - } - - > .upload { - margin: 4px 4px; - font-size: 0.8em; - text-align: right; - color: var(--desktopDriveFolderFg); + &.checked { + background: var(--accent); } } + +.name { + margin: 0; + font-size: 0.9em; + color: var(--desktopDriveFolderFg); +} + +.icon { + margin-right: 4px; + margin-left: 2px; + text-align: left; +} + +.upload { + margin: 4px 4px; + font-size: 0.8em; + text-align: right; + color: var(--desktopDriveFolderFg); +} </style> From c6ea7f754c26f4e3d4b6871c9a275fca0e1eb170 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 29 May 2023 20:08:31 +0900 Subject: [PATCH 119/213] New Crowdin updates (#10917) * New translations ja-JP.yml (German) * New translations ja-JP.yml (Chinese Traditional) * New translations ja-JP.yml (English) --- locales/de-DE.yml | 18 ++++++++++++++++++ locales/en-US.yml | 18 ++++++++++++++++++ locales/zh-TW.yml | 12 ++++++++++++ 3 files changed, 48 insertions(+) diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 843470cf46..8001a55764 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -52,6 +52,8 @@ addToList: "Zu Liste hinzufügen" sendMessage: "Nachricht senden" copyRSS: "RSS kopieren" copyUsername: "Benutzernamen kopieren" +copyUserId: "Benutzer-ID kopieren" +copyNoteId: "Notiz-ID kopieren" searchUser: "Nach einem Benutzer suchen" reply: "Antworten" loadMore: "Mehr laden" @@ -790,6 +792,7 @@ noMaintainerInformationWarning: "Betreiberinformationen sind nicht konfiguriert. noBotProtectionWarning: "Schutz vor Bots ist nicht konfiguriert." configure: "Konfigurieren" postToGallery: "Neuen Galeriebeitrag erstellen" +postToHashtag: "Mit diesem Hashtag senden" gallery: "Galerie" recentPosts: "Neue Beiträge" popularPosts: "Beliebte Beiträge" @@ -823,6 +826,7 @@ translatedFrom: "Aus {x} übersetzt" accountDeletionInProgress: "Die Löschung deines Benutzerkontos ist momentan in Bearbeitung." usernameInfo: "Ein Name, durch den dein Benutzerkonto auf diesem Server identifiziert werden kann. Du kannst das Alphabet (a~z, A~Z), Ziffern (0~9) oder Unterstriche (_) verwenden. Benutzernamen können später nicht geändert werden." aiChanMode: "Ai-Modus" +devMode: "Entwicklermodus" keepCw: "Inhaltswarnungen beibehalten" pubSub: "Pub/Sub Benutzerkonten" lastCommunication: "Letzte Kommunikation" @@ -832,6 +836,8 @@ breakFollow: "Follower entfernen" breakFollowConfirm: "Diesen Follower wirklich entfernen?" itsOn: "Eingeschaltet" itsOff: "Ausgeschaltet" +on: "An" +off: "Aus" emailRequiredForSignup: "Angabe einer Email-Adresse als benötigt markieren" unread: "Ungelesen" filter: "Filter" @@ -986,6 +992,8 @@ cannotBeChangedLater: "Kann später nicht mehr geändert werden." reactionAcceptance: "Reaktionsannahme" likeOnly: "Nur \"Gefällt mir\"" likeOnlyForRemote: "Nur \"Gefällt mir\" für fremde Instanzen" +nonSensitiveOnly: "Keine Sensitiven" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "Keine Sensitiven (Nur \"Gefällt mir\" von fremden Instanzen)" rolesAssignedToMe: "Mir zugewiesene Rollen" resetPasswordConfirm: "Wirklich Passwort zurücksetzen?" sensitiveWords: "Sensible Wörter" @@ -1043,6 +1051,15 @@ preventAiLearning: "Verwendung in machinellem Lernen (Generative bzw. Prediktive preventAiLearningDescription: "Fordert Crawler auf, gepostetes Text- oder Bildmaterial usw. nicht in Datensätzen für maschinelles Lernen (Generative bzw. Prediktive AI/KI) zu verwenden. Dies wird durch das Hinzufügen einer \"noai\"-Flag in der HTML-Antwort des jeweiligen Inhalts erreicht. Da diese Flag jedoch ignoriert werden kann, ist eine vollständige Verhinderung hierdurch nicht möglich." options: "Optionen" specifyUser: "Spezifischer Benutzer" +failedToPreviewUrl: "Vorschau nicht anzeigbar" +update: "Aktualisieren" +rolesThatCanBeUsedThisEmojiAsReaction: "Rollen, die dieses Emoji als Reaktion verwenden können" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Sind keine Rollen angegeben, kann jeder dieses Emoji als Reaktion verwenden." +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Diese Rollen müssen öffentlich sein." +cancelReactionConfirm: "Möchtest du deine Reaktion wirklich löschen?" +changeReactionConfirm: "Möchtest du deine Reaktion wirklich ändern?" +later: "Später" +goToMisskey: "Zu Misskey" _initialAccountSetting: accountCreated: "Dein Konto wurde erfolgreich erstellt!" letsStartAccountSetup: "Lass uns nun dein Konto einrichten." @@ -1057,6 +1074,7 @@ _initialAccountSetting: haveFun: "Viel Spaß mit {name}!" ifYouNeedLearnMore: "Besuche {link}, falls du mehr über {name} (Misskey) lernen möchtest." skipAreYouSure: "Die Kontoeinrichtung wirklich überspringen?" + laterAreYouSure: "Die Kontoeinrichtung wirklich später erledigen?" _serverRules: description: "Eine Reihe von Regeln, die vor der Registrierung angezeigt werden. Eine Zusammenfassung der Nutzungsbedingungen anzuzeigen ist empfohlen." _accountMigration: diff --git a/locales/en-US.yml b/locales/en-US.yml index 3ea2313b2f..1af33cb5a7 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -52,6 +52,8 @@ addToList: "Add to list" sendMessage: "Send a message" copyRSS: "Copy RSS" copyUsername: "Copy username" +copyUserId: "Copy user ID" +copyNoteId: "Copy note ID" searchUser: "Search for a user" reply: "Reply" loadMore: "Load more" @@ -790,6 +792,7 @@ noMaintainerInformationWarning: "Maintainer information is not configured." noBotProtectionWarning: "Bot protection is not configured." configure: "Configure" postToGallery: "Create new gallery post" +postToHashtag: "Post to this hashtag" gallery: "Gallery" recentPosts: "Recent posts" popularPosts: "Popular posts" @@ -823,6 +826,7 @@ translatedFrom: "Translated from {x}" accountDeletionInProgress: "Account deletion is currently in progress" usernameInfo: "A name that identifies your account from others on this server. You can use the alphabet (a~z, A~Z), digits (0~9) or underscores (_). Usernames cannot be changed later." aiChanMode: "Ai Mode" +devMode: "Developer mode" keepCw: "Keep content warnings" pubSub: "Pub/Sub Accounts" lastCommunication: "Last communication" @@ -832,6 +836,8 @@ breakFollow: "Remove follower" breakFollowConfirm: "Really remove this follower?" itsOn: "Enabled" itsOff: "Disabled" +on: "On" +off: "Off" emailRequiredForSignup: "Require email address for sign-up" unread: "Unread" filter: "Filter" @@ -986,6 +992,8 @@ cannotBeChangedLater: "This cannot be changed later." reactionAcceptance: "Reaction Acceptance" likeOnly: "Only likes" likeOnlyForRemote: "Only likes for remote instances" +nonSensitiveOnly: "Non-sensitive only" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "Non-sensitive only (Only likes from remote)" rolesAssignedToMe: "Roles assigned to me" resetPasswordConfirm: "Really reset your password?" sensitiveWords: "Sensitive words" @@ -1043,6 +1051,15 @@ preventAiLearning: "Reject usage in Machine Learning (Generative AI)" preventAiLearningDescription: "Requests crawlers to not use posted text or image material etc. in machine learning (Predictive / Generative AI) data sets. This is achieved by adding a \"noai\" HTML-Response flag to the respective content. A complete prevention can however not be achieved through this flag, as it may simply be ignored." options: "Options" specifyUser: "Specific user" +failedToPreviewUrl: "Could not preview" +update: "Update" +rolesThatCanBeUsedThisEmojiAsReaction: "Roles that can use this emoji as reaction" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "If no roles are specified, anyone can use this emoji as reaction." +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "These roles must be public." +cancelReactionConfirm: "Really delete your reaction?" +changeReactionConfirm: "Really change your reaction?" +later: "Later" +goToMisskey: "To Misskey" _initialAccountSetting: accountCreated: "Your account was successfully created!" letsStartAccountSetup: "For starters, let's set up your profile." @@ -1057,6 +1074,7 @@ _initialAccountSetting: haveFun: "Enjoy {name}!" ifYouNeedLearnMore: "If you'd like to learn more about how to use {name} (Misskey), please visit {link}." skipAreYouSure: "Really skip profile setup?" + laterAreYouSure: "Really do profile setup later?" _serverRules: description: "A set of rules to be displayed before registration. Setting a summary of the Terms of Service is recommended." _accountMigration: diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 6ab6736d45..6044a6532f 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -52,6 +52,8 @@ addToList: "加入至清單" sendMessage: "發送訊息" copyRSS: "複製RSS" copyUsername: "複製使用者名稱" +copyUserId: "複製使用者ID" +copyNoteId: "複製貼文ID" searchUser: "搜尋使用者" reply: "回覆" loadMore: "載入更多" @@ -790,6 +792,7 @@ noMaintainerInformationWarning: "尚未設定管理員信息。" noBotProtectionWarning: "尚未設定Bot防護。" configure: "設定" postToGallery: "發佈到相簿" +postToHashtag: "以此主題標籤發布" gallery: "相簿" recentPosts: "最新貼文" popularPosts: "熱門的貼文" @@ -823,6 +826,7 @@ translatedFrom: "從 {x} 翻譯" accountDeletionInProgress: "正在刪除帳戶" usernameInfo: "在伺服器上您的帳戶是唯一的識別名稱。您可以使用字母 (a ~ z, A ~ Z)、數字 (0 ~ 9) 和下底線 (_)。之後帳戶名是不能更改的。" aiChanMode: "小藍模式" +devMode: "開發者模式" keepCw: "保持CW" pubSub: "Pub/Sub 帳戶" lastCommunication: "最近的通信" @@ -832,6 +836,8 @@ breakFollow: "解除追隨者" breakFollowConfirm: "確定要取消被追隨嗎?" itsOn: "已開啟" itsOff: "已關閉" +on: "開啟" +off: "關閉" emailRequiredForSignup: "註冊帳戶需要電子郵件地址" unread: "未讀" filter: "篩選" @@ -986,6 +992,8 @@ cannotBeChangedLater: "之後不能變更。" reactionAcceptance: "接受表情反應" likeOnly: "僅限讚" likeOnlyForRemote: "遠端僅限讚" +nonSensitiveOnly: "僅限非敏感" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "僅限非敏感(遠端僅限按讚)" rolesAssignedToMe: "指派給自己的角色" resetPasswordConfirm: "重設密碼?" sensitiveWords: "敏感詞" @@ -1043,6 +1051,10 @@ preventAiLearning: "拒絕接受生成式AI的訓練" preventAiLearningDescription: "要求外部的文章生成式AI或圖像生成式AI不以發布的貼文和圖像等內容為學習對象。這是透過在HTML響應中包含noai旗標來實現的,但不能完全防止AI的學習,因為這要看該AI是否遵守這個要求。" options: "選項" specifyUser: "指定使用者" +failedToPreviewUrl: "無法預覽" +update: "更新" +rolesThatCanBeUsedThisEmojiAsReaction: "可以當成反應使用的角色" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "如果是未指定角色的情況,則任何人都可以被當成反應來使用。" _initialAccountSetting: accountCreated: "帳戶已建立完成!" letsStartAccountSetup: "來進行帳戶的初始設定吧。" From 3c07d3fc0896abaae8fc5f72958212baa839c0b2 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Mon, 29 May 2023 13:05:43 +0000 Subject: [PATCH 120/213] use pnpm@8.6.0 --- package.json | 2 +- pnpm-lock.yaml | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 58257a8b0f..81522f1e5c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "git", "url": "https://github.com/misskey-dev/misskey.git" }, - "packageManager": "pnpm@8.5.1", + "packageManager": "pnpm@8.6.0", "workspaces": [ "packages/frontend", "packages/backend", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d836499ef..cd565cd33b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,8 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false overrides: chokidar: 3.5.3 From 0a2ac58b82b4671a16bd004ab19d172aa99477a0 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 10:20:06 +0900 Subject: [PATCH 121/213] refactor --- .../src/components/MkChannelFollowButton.vue | 22 +++++++------- .../src/components/MkFollowButton.vue | 26 ++++++++--------- .../frontend/src/pages/settings/drive.vue | 29 +++++++------------ 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/packages/frontend/src/components/MkChannelFollowButton.vue b/packages/frontend/src/components/MkChannelFollowButton.vue index 9e275d6172..7b7bef4787 100644 --- a/packages/frontend/src/components/MkChannelFollowButton.vue +++ b/packages/frontend/src/components/MkChannelFollowButton.vue @@ -1,20 +1,20 @@ <template> <button - class="hdcaacmi _button" - :class="{ wait, active: isFollowing, full }" + class="_button" + :class="[$style.root, { [$style.wait]: wait, [$style.active]: isFollowing, [$style.full]: full }]" :disabled="wait" @click="onClick" > <template v-if="!wait"> <template v-if="isFollowing"> - <span v-if="full">{{ i18n.ts.unfollow }}</span><i class="ti ti-minus"></i> + <span v-if="full" :class="$style.text">{{ i18n.ts.unfollow }}</span><i class="ti ti-minus"></i> </template> <template v-else> - <span v-if="full">{{ i18n.ts.follow }}</span><i class="ti ti-plus"></i> + <span v-if="full" :class="$style.text">{{ i18n.ts.follow }}</span><i class="ti ti-plus"></i> </template> </template> <template v-else> - <span v-if="full">{{ i18n.ts.processing }}</span><MkLoading :em="true"/> + <span v-if="full" :class="$style.text">{{ i18n.ts.processing }}</span><MkLoading :em="true"/> </template> </button> </template> @@ -57,8 +57,8 @@ async function onClick() { } </script> -<style lang="scss" scoped> -.hdcaacmi { +<style lang="scss" module> +.root { position: relative; display: inline-block; font-weight: bold; @@ -103,7 +103,7 @@ async function onClick() { } &.active { - color: #fff; + color: var(--fgOnAccent); background: var(--accent); &:hover { @@ -121,9 +121,9 @@ async function onClick() { cursor: wait !important; opacity: 0.7; } +} - > span { - margin-right: 6px; - } +.text { + margin-right: 6px; } </style> diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index 7d066fd033..c4e13441e0 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -1,30 +1,30 @@ <template> <button - class="kpoogebi _button" - :class="{ wait, active: isFollowing || hasPendingFollowRequestFromYou, full, large }" + class="_button" + :class="[$style.root, { [$style.wait]: wait, [$style.active]: isFollowing || hasPendingFollowRequestFromYou, [$style.full]: full, [$style.large]: large }]" :disabled="wait" @click="onClick" > <template v-if="!wait"> <template v-if="hasPendingFollowRequestFromYou && user.isLocked"> - <span v-if="full">{{ i18n.ts.followRequestPending }}</span><i class="ti ti-hourglass-empty"></i> + <span v-if="full" :class="$style.text">{{ i18n.ts.followRequestPending }}</span><i class="ti ti-hourglass-empty"></i> </template> <template v-else-if="hasPendingFollowRequestFromYou && !user.isLocked"> <!-- つまりリモートフォローの場合。 --> - <span v-if="full">{{ i18n.ts.processing }}</span><MkLoading :em="true" :colored="false"/> + <span v-if="full" :class="$style.text">{{ i18n.ts.processing }}</span><MkLoading :em="true" :colored="false"/> </template> <template v-else-if="isFollowing"> - <span v-if="full">{{ i18n.ts.unfollow }}</span><i class="ti ti-minus"></i> + <span v-if="full" :class="$style.text">{{ i18n.ts.unfollow }}</span><i class="ti ti-minus"></i> </template> <template v-else-if="!isFollowing && user.isLocked"> - <span v-if="full">{{ i18n.ts.followRequest }}</span><i class="ti ti-plus"></i> + <span v-if="full" :class="$style.text">{{ i18n.ts.followRequest }}</span><i class="ti ti-plus"></i> </template> <template v-else-if="!isFollowing && !user.isLocked"> - <span v-if="full">{{ i18n.ts.follow }}</span><i class="ti ti-plus"></i> + <span v-if="full" :class="$style.text">{{ i18n.ts.follow }}</span><i class="ti ti-plus"></i> </template> </template> <template v-else> - <span v-if="full">{{ i18n.ts.processing }}</span><MkLoading :em="true" :colored="false"/> + <span v-if="full" :class="$style.text">{{ i18n.ts.processing }}</span><MkLoading :em="true" :colored="false"/> </template> </button> </template> @@ -126,8 +126,8 @@ onBeforeUnmount(() => { }); </script> -<style lang="scss" scoped> -.kpoogebi { +<style lang="scss" module> +.root { position: relative; display: inline-block; font-weight: bold; @@ -196,9 +196,9 @@ onBeforeUnmount(() => { cursor: wait !important; opacity: 0.7; } +} - > span { - margin-right: 6px; - } +.text { + margin-right: 6px; } </style> diff --git a/packages/frontend/src/pages/settings/drive.vue b/packages/frontend/src/pages/settings/drive.vue index 6ff98bc977..6fa3871205 100644 --- a/packages/frontend/src/pages/settings/drive.vue +++ b/packages/frontend/src/pages/settings/drive.vue @@ -4,8 +4,8 @@ <template #label>{{ i18n.ts.usageAmount }}</template> <div class="_gaps_m"> - <div class="uawsfosz"> - <div class="meter"><div :style="meterStyle"></div></div> + <div> + <div :class="$style.meter"><div :class="$style.meterValue" :style="meterStyle"></div></div> </div> <FormSplit> <MkKeyValue> @@ -139,22 +139,15 @@ definePageMetadata({ }); </script> -<style lang="scss" scoped> +<style lang="scss" module> +.meter { + background: rgba(0, 0, 0, 0.1); + border-radius: 999px; + overflow: clip; +} -@use "sass:math"; - -.uawsfosz { - - > .meter { - $size: 12px; - background: rgba(0, 0, 0, 0.1); - border-radius: math.div($size, 2); - overflow: hidden; - - > div { - height: $size; - border-radius: math.div($size, 2); - } - } +.meterValue { + height: 100%; + border-radius: 999px; } </style> From dc031b1d07dfe02e777a715c2104283924509466 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 11:18:40 +0900 Subject: [PATCH 122/213] =?UTF-8?q?perf(frontend):=20emojilist=E3=81=AE?= =?UTF-8?q?=E3=82=B5=E3=82=A4=E3=82=BA=E5=89=8A=E6=B8=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/MkAutocomplete.vue | 13 - .../frontend/src/components/MkEmojiPicker.vue | 19 +- packages/frontend/src/emojilist.json | 3565 ++++++++--------- packages/frontend/src/scripts/emojilist.ts | 12 +- 4 files changed, 1792 insertions(+), 1817 deletions(-) diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 663c57623d..4338a8f8e6 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -71,19 +71,6 @@ const emojiDb = computed(() => { url: char2path(x.char), })); - for (const x of lib) { - if (x.keywords) { - for (const k of x.keywords) { - unicodeEmojiDB.push({ - emoji: x.char, - name: k, - aliasOf: x.name, - url: char2path(x.char), - }); - } - } - } - unicodeEmojiDB.sort((a, b) => a.name.length - b.name.length); //#endregion diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index 093a1ec6d4..d489b3e9b9 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -232,9 +232,9 @@ watch(q, () => { } if (matches.size >= max) return matches; - // 名前またはエイリアスにキーワードが含まれている + // 名前にキーワードが含まれている for (const emoji of emojis) { - if (keywords.every(keyword => emoji.name.includes(keyword) || emoji.keywords.some(alias => alias.includes(keyword)))) { + if (keywords.every(keyword => emoji.name.includes(keyword))) { matches.add(emoji); if (matches.size >= max) break; } @@ -248,14 +248,6 @@ watch(q, () => { } if (matches.size >= max) return matches; - for (const emoji of emojis) { - if (emoji.keywords.some(keyword => keyword.startsWith(newQ))) { - matches.add(emoji); - if (matches.size >= max) break; - } - } - if (matches.size >= max) return matches; - for (const emoji of emojis) { if (emoji.name.includes(newQ)) { matches.add(emoji); @@ -263,13 +255,6 @@ watch(q, () => { } } if (matches.size >= max) return matches; - - for (const emoji of emojis) { - if (emoji.keywords.some(keyword => keyword.includes(newQ))) { - matches.add(emoji); - if (matches.size >= max) break; - } - } } return matches; diff --git a/packages/frontend/src/emojilist.json b/packages/frontend/src/emojilist.json index 402e82e33b..fde06a4aa0 100644 --- a/packages/frontend/src/emojilist.json +++ b/packages/frontend/src/emojilist.json @@ -1,1785 +1,1784 @@ [ - { "category": "face", "char": "😀", "name": "grinning", "keywords": ["face", "smile", "happy", "joy", ": D", "grin"] }, - { "category": "face", "char": "😬", "name": "grimacing", "keywords": ["face", "grimace", "teeth"] }, - { "category": "face", "char": "😁", "name": "grin", "keywords": ["face", "happy", "smile", "joy", "kawaii"] }, - { "category": "face", "char": "😂", "name": "joy", "keywords": ["face", "cry", "tears", "weep", "happy", "happytears", "haha"] }, - { "category": "face", "char": "🤣", "name": "rofl", "keywords": ["face", "rolling", "floor", "laughing", "lol", "haha"] }, - { "category": "face", "char": "🥳", "name": "partying", "keywords": ["face", "celebration", "woohoo"] }, - { "category": "face", "char": "😃", "name": "smiley", "keywords": ["face", "happy", "joy", "haha", ": D", ": )", "smile", "funny"] }, - { "category": "face", "char": "😄", "name": "smile", "keywords": ["face", "happy", "joy", "funny", "haha", "laugh", "like", ": D", ": )"] }, - { "category": "face", "char": "😅", "name": "sweat_smile", "keywords": ["face", "hot", "happy", "laugh", "sweat", "smile", "relief"] }, - { "category": "face", "char": "🥲", "name": "smiling_face_with_tear", "keywords": ["face"] }, - { "category": "face", "char": "😆", "name": "laughing", "keywords": ["happy", "joy", "lol", "satisfied", "haha", "face", "glad", "XD", "laugh"] }, - { "category": "face", "char": "😇", "name": "innocent", "keywords": ["face", "angel", "heaven", "halo"] }, - { "category": "face", "char": "😉", "name": "wink", "keywords": ["face", "happy", "mischievous", "secret", ";)", "smile", "eye"] }, - { "category": "face", "char": "😊", "name": "blush", "keywords": ["face", "smile", "happy", "flushed", "crush", "embarrassed", "shy", "joy"] }, - { "category": "face", "char": "🙂", "name": "slightly_smiling_face", "keywords": ["face", "smile"] }, - { "category": "face", "char": "🙃", "name": "upside_down_face", "keywords": ["face", "flipped", "silly", "smile"] }, - { "category": "face", "char": "☺️", "name": "relaxed", "keywords": ["face", "blush", "massage", "happiness"] }, - { "category": "face", "char": "😋", "name": "yum", "keywords": ["happy", "joy", "tongue", "smile", "face", "silly", "yummy", "nom", "delicious", "savouring"] }, - { "category": "face", "char": "😌", "name": "relieved", "keywords": ["face", "relaxed", "phew", "massage", "happiness"] }, - { "category": "face", "char": "😍", "name": "heart_eyes", "keywords": ["face", "love", "like", "affection", "valentines", "infatuation", "crush", "heart"] }, - { "category": "face", "char": "🥰", "name": "smiling_face_with_three_hearts", "keywords": ["face", "love", "like", "affection", "valentines", "infatuation", "crush", "hearts", "adore"] }, - { "category": "face", "char": "😘", "name": "kissing_heart", "keywords": ["face", "love", "like", "affection", "valentines", "infatuation", "kiss"] }, - { "category": "face", "char": "😗", "name": "kissing", "keywords": ["love", "like", "face", "3", "valentines", "infatuation", "kiss"] }, - { "category": "face", "char": "😙", "name": "kissing_smiling_eyes", "keywords": ["face", "affection", "valentines", "infatuation", "kiss"] }, - { "category": "face", "char": "😚", "name": "kissing_closed_eyes", "keywords": ["face", "love", "like", "affection", "valentines", "infatuation", "kiss"] }, - { "category": "face", "char": "😜", "name": "stuck_out_tongue_winking_eye", "keywords": ["face", "prank", "childish", "playful", "mischievous", "smile", "wink", "tongue"] }, - { "category": "face", "char": "🤪", "name": "zany", "keywords": ["face", "goofy", "crazy"] }, - { "category": "face", "char": "🤨", "name": "raised_eyebrow", "keywords": ["face", "distrust", "scepticism", "disapproval", "disbelief", "surprise"] }, - { "category": "face", "char": "🧐", "name": "monocle", "keywords": ["face", "stuffy", "wealthy"] }, - { "category": "face", "char": "😝", "name": "stuck_out_tongue_closed_eyes", "keywords": ["face", "prank", "playful", "mischievous", "smile", "tongue"] }, - { "category": "face", "char": "😛", "name": "stuck_out_tongue", "keywords": ["face", "prank", "childish", "playful", "mischievous", "smile", "tongue"] }, - { "category": "face", "char": "🤑", "name": "money_mouth_face", "keywords": ["face", "rich", "dollar", "money"] }, - { "category": "face", "char": "🤓", "name": "nerd_face", "keywords": ["face", "nerdy", "geek", "dork"] }, - { "category": "face", "char": "🥸", "name": "disguised_face", "keywords": ["face", "nose", "glasses", "incognito"] }, - { "category": "face", "char": "😎", "name": "sunglasses", "keywords": ["face", "cool", "smile", "summer", "beach", "sunglass"] }, - { "category": "face", "char": "🤩", "name": "star_struck", "keywords": ["face", "smile", "starry", "eyes", "grinning"] }, - { "category": "face", "char": "🤡", "name": "clown_face", "keywords": ["face"] }, - { "category": "face", "char": "🤠", "name": "cowboy_hat_face", "keywords": ["face", "cowgirl", "hat"] }, - { "category": "face", "char": "🤗", "name": "hugs", "keywords": ["face", "smile", "hug"] }, - { "category": "face", "char": "😏", "name": "smirk", "keywords": ["face", "smile", "mean", "prank", "smug", "sarcasm"] }, - { "category": "face", "char": "😶", "name": "no_mouth", "keywords": ["face", "hellokitty"] }, - { "category": "face", "char": "😐", "name": "neutral_face", "keywords": ["indifference", "meh", ": |", "neutral"] }, - { "category": "face", "char": "😑", "name": "expressionless", "keywords": ["face", "indifferent", "-_-", "meh", "deadpan"] }, - { "category": "face", "char": "😒", "name": "unamused", "keywords": ["indifference", "bored", "straight face", "serious", "sarcasm", "unimpressed", "skeptical", "dubious", "side_eye"] }, - { "category": "face", "char": "🙄", "name": "roll_eyes", "keywords": ["face", "eyeroll", "frustrated"] }, - { "category": "face", "char": "🤔", "name": "thinking", "keywords": ["face", "hmmm", "think", "consider"] }, - { "category": "face", "char": "🤥", "name": "lying_face", "keywords": ["face", "lie", "pinocchio"] }, - { "category": "face", "char": "🤭", "name": "hand_over_mouth", "keywords": ["face", "whoops", "shock", "surprise"] }, - { "category": "face", "char": "🤫", "name": "shushing", "keywords": ["face", "quiet", "shhh"] }, - { "category": "face", "char": "🤬", "name": "symbols_over_mouth", "keywords": ["face", "swearing", "cursing", "cussing", "profanity", "expletive"] }, - { "category": "face", "char": "🤯", "name": "exploding_head", "keywords": ["face", "shocked", "mind", "blown"] }, - { "category": "face", "char": "😳", "name": "flushed", "keywords": ["face", "blush", "shy", "flattered"] }, - { "category": "face", "char": "😞", "name": "disappointed", "keywords": ["face", "sad", "upset", "depressed", ": ("] }, - { "category": "face", "char": "😟", "name": "worried", "keywords": ["face", "concern", "nervous", ": ("] }, - { "category": "face", "char": "😠", "name": "angry", "keywords": ["mad", "face", "annoyed", "frustrated"] }, - { "category": "face", "char": "😡", "name": "rage", "keywords": ["angry", "mad", "hate", "despise"] }, - { "category": "face", "char": "😔", "name": "pensive", "keywords": ["face", "sad", "depressed", "upset"] }, - { "category": "face", "char": "😕", "name": "confused", "keywords": ["face", "indifference", "huh", "weird", "hmmm", ": /"] }, - { "category": "face", "char": "🙁", "name": "slightly_frowning_face", "keywords": ["face", "frowning", "disappointed", "sad", "upset"] }, - { "category": "face", "char": "☹", "name": "frowning_face", "keywords": ["face", "sad", "upset", "frown"] }, - { "category": "face", "char": "😣", "name": "persevere", "keywords": ["face", "sick", "no", "upset", "oops"] }, - { "category": "face", "char": "😖", "name": "confounded", "keywords": ["face", "confused", "sick", "unwell", "oops", ": S"] }, - { "category": "face", "char": "😫", "name": "tired_face", "keywords": ["sick", "whine", "upset", "frustrated"] }, - { "category": "face", "char": "😩", "name": "weary", "keywords": ["face", "tired", "sleepy", "sad", "frustrated", "upset"] }, - { "category": "face", "char": "🥺", "name": "pleading", "keywords": ["face", "begging", "mercy"] }, - { "category": "face", "char": "😤", "name": "triumph", "keywords": ["face", "gas", "phew", "proud", "pride"] }, - { "category": "face", "char": "😮", "name": "open_mouth", "keywords": ["face", "surprise", "impressed", "wow", "whoa", ": O"] }, - { "category": "face", "char": "😱", "name": "scream", "keywords": ["face", "munch", "scared", "omg"] }, - { "category": "face", "char": "😨", "name": "fearful", "keywords": ["face", "scared", "terrified", "nervous", "oops", "huh"] }, - { "category": "face", "char": "😰", "name": "cold_sweat", "keywords": ["face", "nervous", "sweat"] }, - { "category": "face", "char": "😯", "name": "hushed", "keywords": ["face", "woo", "shh"] }, - { "category": "face", "char": "😦", "name": "frowning", "keywords": ["face", "aw", "what"] }, - { "category": "face", "char": "😧", "name": "anguished", "keywords": ["face", "stunned", "nervous"] }, - { "category": "face", "char": "😢", "name": "cry", "keywords": ["face", "tears", "sad", "depressed", "upset", ": '("] }, - { "category": "face", "char": "😥", "name": "disappointed_relieved", "keywords": ["face", "phew", "sweat", "nervous"] }, - { "category": "face", "char": "🤤", "name": "drooling_face", "keywords": ["face"] }, - { "category": "face", "char": "😪", "name": "sleepy", "keywords": ["face", "tired", "rest", "nap"] }, - { "category": "face", "char": "😓", "name": "sweat", "keywords": ["face", "hot", "sad", "tired", "exercise"] }, - { "category": "face", "char": "🥵", "name": "hot", "keywords": ["face", "feverish", "heat", "red", "sweating"] }, - { "category": "face", "char": "🥶", "name": "cold", "keywords": ["face", "blue", "freezing", "frozen", "frostbite", "icicles"] }, - { "category": "face", "char": "😭", "name": "sob", "keywords": ["face", "cry", "tears", "sad", "upset", "depressed"] }, - { "category": "face", "char": "😵", "name": "dizzy_face", "keywords": ["spent", "unconscious", "xox", "dizzy"] }, - { "category": "face", "char": "😲", "name": "astonished", "keywords": ["face", "xox", "surprised", "poisoned"] }, - { "category": "face", "char": "🤐", "name": "zipper_mouth_face", "keywords": ["face", "sealed", "zipper", "secret"] }, - { "category": "face", "char": "🤢", "name": "nauseated_face", "keywords": ["face", "vomit", "gross", "green", "sick", "throw up", "ill"] }, - { "category": "face", "char": "🤧", "name": "sneezing_face", "keywords": ["face", "gesundheit", "sneeze", "sick", "allergy"] }, - { "category": "face", "char": "🤮", "name": "vomiting", "keywords": ["face", "sick"] }, - { "category": "face", "char": "😷", "name": "mask", "keywords": ["face", "sick", "ill", "disease"] }, - { "category": "face", "char": "🤒", "name": "face_with_thermometer", "keywords": ["sick", "temperature", "thermometer", "cold", "fever"] }, - { "category": "face", "char": "🤕", "name": "face_with_head_bandage", "keywords": ["injured", "clumsy", "bandage", "hurt"] }, - { "category": "face", "char": "🥴", "name": "woozy", "keywords": ["face", "dizzy", "intoxicated", "tipsy", "wavy"] }, - { "category": "face", "char": "🥱", "name": "yawning", "keywords": ["face", "tired", "yawning"] }, - { "category": "face", "char": "😴", "name": "sleeping", "keywords": ["face", "tired", "sleepy", "night", "zzz"] }, - { "category": "face", "char": "💤", "name": "zzz", "keywords": ["sleepy", "tired", "dream"] }, - { "category": "face", "char": "\uD83D\uDE36\u200D\uD83C\uDF2B\uFE0F", "name": "face_in_clouds", "keywords": [] }, - { "category": "face", "char": "\uD83D\uDE2E\u200D\uD83D\uDCA8", "name": "face_exhaling", "keywords": [] }, - { "category": "face", "char": "\uD83D\uDE35\u200D\uD83D\uDCAB", "name": "face_with_spiral_eyes", "keywords": [] }, - { "category": "face", "char": "\uD83E\uDEE0", "name": "melting_face", "keywords": ["disappear", "dissolve", "liquid", "melt", "toketa"] }, - { "category": "face", "char": "\uD83E\uDEE2", "name": "face_with_open_eyes_and_hand_over_mouth", "keywords": ["amazement", "awe", "disbelief", "embarrass", "scared", "surprise", "ohoho"] }, - { "category": "face", "char": "\uD83E\uDEE3", "name": "face_with_peeking_eye", "keywords": ["captivated", "peep", "stare", "chunibyo"] }, - { "category": "face", "char": "\uD83E\uDEE1", "name": "saluting_face", "keywords": ["ok", "salute", "sunny", "troops", "yes", "raja"] }, - { "category": "face", "char": "\uD83E\uDEE5", "name": "dotted_line_face", "keywords": ["depressed", "disappear", "hide", "introvert", "invisible", "tensen"] }, - { "category": "face", "char": "\uD83E\uDEE4", "name": "face_with_diagonal_mouth", "keywords": ["disappointed", "meh", "skeptical", "unsure"] }, - { "category": "face", "char": "\uD83E\uDD79", "name": "face_holding_back_tears", "keywords": ["angry", "cry", "proud", "resist", "sad"] }, - { "category": "face", "char": "💩", "name": "poop", "keywords": ["hankey", "shitface", "fail", "turd", "shit"] }, - { "category": "face", "char": "😈", "name": "smiling_imp", "keywords": ["devil", "horns"] }, - { "category": "face", "char": "👿", "name": "imp", "keywords": ["devil", "angry", "horns"] }, - { "category": "face", "char": "👹", "name": "japanese_ogre", "keywords": ["monster", "red", "mask", "halloween", "scary", "creepy", "devil", "demon", "japanese", "ogre"] }, - { "category": "face", "char": "👺", "name": "japanese_goblin", "keywords": ["red", "evil", "mask", "monster", "scary", "creepy", "japanese", "goblin"] }, - { "category": "face", "char": "💀", "name": "skull", "keywords": ["dead", "skeleton", "creepy", "death"] }, - { "category": "face", "char": "👻", "name": "ghost", "keywords": ["halloween", "spooky", "scary"] }, - { "category": "face", "char": "👽", "name": "alien", "keywords": ["UFO", "paul", "weird", "outer_space"] }, - { "category": "face", "char": "🤖", "name": "robot", "keywords": ["computer", "machine", "bot"] }, - { "category": "face", "char": "😺", "name": "smiley_cat", "keywords": ["animal", "cats", "happy", "smile"] }, - { "category": "face", "char": "😸", "name": "smile_cat", "keywords": ["animal", "cats", "smile"] }, - { "category": "face", "char": "😹", "name": "joy_cat", "keywords": ["animal", "cats", "haha", "happy", "tears"] }, - { "category": "face", "char": "😻", "name": "heart_eyes_cat", "keywords": ["animal", "love", "like", "affection", "cats", "valentines", "heart"] }, - { "category": "face", "char": "😼", "name": "smirk_cat", "keywords": ["animal", "cats", "smirk"] }, - { "category": "face", "char": "😽", "name": "kissing_cat", "keywords": ["animal", "cats", "kiss"] }, - { "category": "face", "char": "🙀", "name": "scream_cat", "keywords": ["animal", "cats", "munch", "scared", "scream"] }, - { "category": "face", "char": "😿", "name": "crying_cat_face", "keywords": ["animal", "tears", "weep", "sad", "cats", "upset", "cry"] }, - { "category": "face", "char": "😾", "name": "pouting_cat", "keywords": ["animal", "cats"] }, - { "category": "people", "char": "🤲", "name": "palms_up", "keywords": ["hands", "gesture", "cupped", "prayer"] }, - { "category": "people", "char": "🙌", "name": "raised_hands", "keywords": ["gesture", "hooray", "yea", "celebration", "hands"] }, - { "category": "people", "char": "👏", "name": "clap", "keywords": ["hands", "praise", "applause", "congrats", "yay"] }, - { "category": "people", "char": "👋", "name": "wave", "keywords": ["hands", "gesture", "goodbye", "solong", "farewell", "hello", "hi", "palm"] }, - { "category": "people", "char": "🤙", "name": "call_me_hand", "keywords": ["hands", "gesture"] }, - { "category": "people", "char": "👍", "name": "+1", "keywords": ["thumbsup", "yes", "awesome", "good", "agree", "accept", "cool", "hand", "like"] }, - { "category": "people", "char": "👎", "name": "-1", "keywords": ["thumbsdown", "no", "dislike", "hand"] }, - { "category": "people", "char": "👊", "name": "facepunch", "keywords": ["angry", "violence", "fist", "hit", "attack", "hand"] }, - { "category": "people", "char": "✊", "name": "fist", "keywords": ["fingers", "hand", "grasp"] }, - { "category": "people", "char": "🤛", "name": "fist_left", "keywords": ["hand", "fistbump"] }, - { "category": "people", "char": "🤜", "name": "fist_right", "keywords": ["hand", "fistbump"] }, - { "category": "people", "char": "✌", "name": "v", "keywords": ["fingers", "ohyeah", "hand", "peace", "victory", "two"] }, - { "category": "people", "char": "👌", "name": "ok_hand", "keywords": ["fingers", "limbs", "perfect", "ok", "okay"] }, - { "category": "people", "char": "✋", "name": "raised_hand", "keywords": ["fingers", "stop", "highfive", "palm", "ban"] }, - { "category": "people", "char": "🤚", "name": "raised_back_of_hand", "keywords": ["fingers", "raised", "backhand"] }, - { "category": "people", "char": "👐", "name": "open_hands", "keywords": ["fingers", "butterfly", "hands", "open"] }, - { "category": "people", "char": "💪", "name": "muscle", "keywords": ["arm", "flex", "hand", "summer", "strong", "biceps"] }, - { "category": "people", "char": "🦾", "name": "mechanical_arm", "keywords": ["flex", "hand", "strong", "biceps"] }, - { "category": "people", "char": "🙏", "name": "pray", "keywords": ["please", "hope", "wish", "namaste", "highfive"] }, - { "category": "people", "char": "🦶", "name": "foot", "keywords": ["kick", "stomp"] }, - { "category": "people", "char": "🦵", "name": "leg", "keywords": ["kick", "limb"] }, - { "category": "people", "char": "🦿", "name": "mechanical_leg", "keywords": ["kick", "limb"] }, - { "category": "people", "char": "🤝", "name": "handshake", "keywords": ["agreement", "shake"] }, - { "category": "people", "char": "☝", "name": "point_up", "keywords": ["hand", "fingers", "direction", "up"] }, - { "category": "people", "char": "👆", "name": "point_up_2", "keywords": ["fingers", "hand", "direction", "up"] }, - { "category": "people", "char": "👇", "name": "point_down", "keywords": ["fingers", "hand", "direction", "down"] }, - { "category": "people", "char": "👈", "name": "point_left", "keywords": ["direction", "fingers", "hand", "left"] }, - { "category": "people", "char": "👉", "name": "point_right", "keywords": ["fingers", "hand", "direction", "right"] }, - { "category": "people", "char": "🖕", "name": "fu", "keywords": ["hand", "fingers", "rude", "middle", "flipping"] }, - { "category": "people", "char": "🖐", "name": "raised_hand_with_fingers_splayed", "keywords": ["hand", "fingers", "palm"] }, - { "category": "people", "char": "🤟", "name": "love_you", "keywords": ["hand", "fingers", "gesture"] }, - { "category": "people", "char": "🤘", "name": "metal", "keywords": ["hand", "fingers", "evil_eye", "sign_of_horns", "rock_on"] }, - { "category": "people", "char": "🤞", "name": "crossed_fingers", "keywords": ["good", "lucky"] }, - { "category": "people", "char": "🖖", "name": "vulcan_salute", "keywords": ["hand", "fingers", "spock", "star trek"] }, - { "category": "people", "char": "✍", "name": "writing_hand", "keywords": ["lower_left_ballpoint_pen", "stationery", "write", "compose"] }, - { "category": "people", "char": "\uD83E\uDEF0", "name": "hand_with_index_finger_and_thumb_crossed", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEF1", "name": "rightwards_hand", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEF2", "name": "leftwards_hand", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEF3", "name": "palm_down_hand", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEF4", "name": "palm_up_hand", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEF5", "name": "index_pointing_at_the_viewer", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEF6", "name": "heart_hands", "keywords": ["moemoekyun"] }, - { "category": "people", "char": "🤏", "name": "pinching_hand", "keywords": ["hand", "fingers"] }, - { "category": "people", "char": "🤌", "name": "pinched_fingers", "keywords": ["hand", "fingers"] }, - { "category": "people", "char": "🤳", "name": "selfie", "keywords": ["camera", "phone"] }, - { "category": "people", "char": "💅", "name": "nail_care", "keywords": ["beauty", "manicure", "finger", "fashion", "nail"] }, - { "category": "people", "char": "👄", "name": "lips", "keywords": ["mouth", "kiss"] }, - { "category": "people", "char": "\uD83E\uDEE6", "name": "biting_lip", "keywords": [] }, - { "category": "people", "char": "🦷", "name": "tooth", "keywords": ["teeth", "dentist"] }, - { "category": "people", "char": "👅", "name": "tongue", "keywords": ["mouth", "playful"] }, - { "category": "people", "char": "👂", "name": "ear", "keywords": ["face", "hear", "sound", "listen"] }, - { "category": "people", "char": "🦻", "name": "ear_with_hearing_aid", "keywords": ["face", "hear", "sound", "listen"] }, - { "category": "people", "char": "👃", "name": "nose", "keywords": ["smell", "sniff"] }, - { "category": "people", "char": "👁", "name": "eye", "keywords": ["face", "look", "see", "watch", "stare"] }, - { "category": "people", "char": "👀", "name": "eyes", "keywords": ["look", "watch", "stalk", "peek", "see"] }, - { "category": "people", "char": "🧠", "name": "brain", "keywords": ["smart", "intelligent"] }, - { "category": "people", "char": "🫀", "name": "anatomical_heart", "keywords": [] }, - { "category": "people", "char": "🫁", "name": "lungs", "keywords": [] }, - { "category": "people", "char": "👤", "name": "bust_in_silhouette", "keywords": ["user", "person", "human"] }, - { "category": "people", "char": "👥", "name": "busts_in_silhouette", "keywords": ["user", "person", "human", "group", "team"] }, - { "category": "people", "char": "🗣", "name": "speaking_head", "keywords": ["user", "person", "human", "sing", "say", "talk"] }, - { "category": "people", "char": "👶", "name": "baby", "keywords": ["child", "boy", "girl", "toddler"] }, - { "category": "people", "char": "🧒", "name": "child", "keywords": ["gender-neutral", "young"] }, - { "category": "people", "char": "👦", "name": "boy", "keywords": ["man", "male", "guy", "teenager"] }, - { "category": "people", "char": "👧", "name": "girl", "keywords": ["female", "woman", "teenager"] }, - { "category": "people", "char": "🧑", "name": "adult", "keywords": ["gender-neutral", "person"] }, - { "category": "people", "char": "👨", "name": "man", "keywords": ["mustache", "father", "dad", "guy", "classy", "sir", "moustache"] }, - { "category": "people", "char": "👩", "name": "woman", "keywords": ["female", "girls", "lady"] }, - { "category": "people", "char": "🧑🦱", "name": "curly_hair", "keywords": ["curly", "afro", "braids", "ringlets"] }, - { "category": "people", "char": "👩🦱", "name": "curly_hair_woman", "keywords": ["woman", "female", "girl", "curly", "afro", "braids", "ringlets"] }, - { "category": "people", "char": "👨🦱", "name": "curly_hair_man", "keywords": ["man", "male", "boy", "guy", "curly", "afro", "braids", "ringlets"] }, - { "category": "people", "char": "🧑🦰", "name": "red_hair", "keywords": ["redhead"] }, - { "category": "people", "char": "👩🦰", "name": "red_hair_woman", "keywords": ["woman", "female", "girl", "ginger", "redhead"] }, - { "category": "people", "char": "👨🦰", "name": "red_hair_man", "keywords": ["man", "male", "boy", "guy", "ginger", "redhead"] }, - { "category": "people", "char": "👱♀️", "name": "blonde_woman", "keywords": ["woman", "female", "girl", "blonde", "person"] }, - { "category": "people", "char": "👱", "name": "blonde_man", "keywords": ["man", "male", "boy", "blonde", "guy", "person"] }, - { "category": "people", "char": "🧑🦳", "name": "white_hair", "keywords": ["gray", "old", "white"] }, - { "category": "people", "char": "👩🦳", "name": "white_hair_woman", "keywords": ["woman", "female", "girl", "gray", "old", "white"] }, - { "category": "people", "char": "👨🦳", "name": "white_hair_man", "keywords": ["man", "male", "boy", "guy", "gray", "old", "white"] }, - { "category": "people", "char": "🧑🦲", "name": "bald", "keywords": ["bald", "chemotherapy", "hairless", "shaven"] }, - { "category": "people", "char": "👩🦲", "name": "bald_woman", "keywords": ["woman", "female", "girl", "bald", "chemotherapy", "hairless", "shaven"] }, - { "category": "people", "char": "👨🦲", "name": "bald_man", "keywords": ["man", "male", "boy", "guy", "bald", "chemotherapy", "hairless", "shaven"] }, - { "category": "people", "char": "🧔", "name": "bearded_person", "keywords": ["person", "bewhiskered"] }, - { "category": "people", "char": "🧓", "name": "older_adult", "keywords": ["human", "elder", "senior", "gender-neutral"] }, - { "category": "people", "char": "👴", "name": "older_man", "keywords": ["human", "male", "men", "old", "elder", "senior"] }, - { "category": "people", "char": "👵", "name": "older_woman", "keywords": ["human", "female", "women", "lady", "old", "elder", "senior"] }, - { "category": "people", "char": "👲", "name": "man_with_gua_pi_mao", "keywords": ["male", "boy", "chinese"] }, - { "category": "people", "char": "🧕", "name": "woman_with_headscarf", "keywords": ["female", "hijab", "mantilla", "tichel"] }, - { "category": "people", "char": "👳♀️", "name": "woman_with_turban", "keywords": ["female", "indian", "hinduism", "arabs", "woman"] }, - { "category": "people", "char": "👳", "name": "man_with_turban", "keywords": ["male", "indian", "hinduism", "arabs"] }, - { "category": "people", "char": "👮♀️", "name": "policewoman", "keywords": ["woman", "police", "law", "legal", "enforcement", "arrest", "911", "female"] }, - { "category": "people", "char": "👮", "name": "policeman", "keywords": ["man", "police", "law", "legal", "enforcement", "arrest", "911"] }, - { "category": "people", "char": "👷♀️", "name": "construction_worker_woman", "keywords": ["female", "human", "wip", "build", "construction", "worker", "labor", "woman"] }, - { "category": "people", "char": "👷", "name": "construction_worker_man", "keywords": ["male", "human", "wip", "guy", "build", "construction", "worker", "labor"] }, - { "category": "people", "char": "💂♀️", "name": "guardswoman", "keywords": ["uk", "gb", "british", "female", "royal", "woman"] }, - { "category": "people", "char": "💂", "name": "guardsman", "keywords": ["uk", "gb", "british", "male", "guy", "royal"] }, - { "category": "people", "char": "🕵️♀️", "name": "female_detective", "keywords": ["human", "spy", "detective", "female", "woman"] }, - { "category": "people", "char": "🕵", "name": "male_detective", "keywords": ["human", "spy", "detective"] }, - { "category": "people", "char": "🧑⚕️", "name": "health_worker", "keywords": ["doctor", "nurse", "therapist", "healthcare", "human"] }, - { "category": "people", "char": "👩⚕️", "name": "woman_health_worker", "keywords": ["doctor", "nurse", "therapist", "healthcare", "woman", "human"] }, - { "category": "people", "char": "👨⚕️", "name": "man_health_worker", "keywords": ["doctor", "nurse", "therapist", "healthcare", "man", "human"] }, - { "category": "people", "char": "🧑🌾", "name": "farmer", "keywords": ["rancher", "gardener", "human"] }, - { "category": "people", "char": "👩🌾", "name": "woman_farmer", "keywords": ["rancher", "gardener", "woman", "human"] }, - { "category": "people", "char": "👨🌾", "name": "man_farmer", "keywords": ["rancher", "gardener", "man", "human"] }, - { "category": "people", "char": "🧑🍳", "name": "cook", "keywords": ["chef", "human"] }, - { "category": "people", "char": "👩🍳", "name": "woman_cook", "keywords": ["chef", "woman", "human"] }, - { "category": "people", "char": "👨🍳", "name": "man_cook", "keywords": ["chef", "man", "human"] }, - { "category": "people", "char": "🧑🎓", "name": "student", "keywords": ["graduate", "human"] }, - { "category": "people", "char": "👩🎓", "name": "woman_student", "keywords": ["graduate", "woman", "human"] }, - { "category": "people", "char": "👨🎓", "name": "man_student", "keywords": ["graduate", "man", "human"] }, - { "category": "people", "char": "🧑🎤", "name": "singer", "keywords": ["rockstar", "entertainer", "human"] }, - { "category": "people", "char": "👩🎤", "name": "woman_singer", "keywords": ["rockstar", "entertainer", "woman", "human"] }, - { "category": "people", "char": "👨🎤", "name": "man_singer", "keywords": ["rockstar", "entertainer", "man", "human"] }, - { "category": "people", "char": "🧑🏫", "name": "teacher", "keywords": ["instructor", "professor", "human"] }, - { "category": "people", "char": "👩🏫", "name": "woman_teacher", "keywords": ["instructor", "professor", "woman", "human"] }, - { "category": "people", "char": "👨🏫", "name": "man_teacher", "keywords": ["instructor", "professor", "man", "human"] }, - { "category": "people", "char": "🧑🏭", "name": "factory_worker", "keywords": ["assembly", "industrial", "human"] }, - { "category": "people", "char": "👩🏭", "name": "woman_factory_worker", "keywords": ["assembly", "industrial", "woman", "human"] }, - { "category": "people", "char": "👨🏭", "name": "man_factory_worker", "keywords": ["assembly", "industrial", "man", "human"] }, - { "category": "people", "char": "🧑💻", "name": "technologist", "keywords": ["coder", "developer", "engineer", "programmer", "software", "human", "laptop", "computer"] }, - { "category": "people", "char": "👩💻", "name": "woman_technologist", "keywords": ["coder", "developer", "engineer", "programmer", "software", "woman", "human", "laptop", "computer"] }, - { "category": "people", "char": "👨💻", "name": "man_technologist", "keywords": ["coder", "developer", "engineer", "programmer", "software", "man", "human", "laptop", "computer"] }, - { "category": "people", "char": "🧑💼", "name": "office_worker", "keywords": ["business", "manager", "human"] }, - { "category": "people", "char": "👩💼", "name": "woman_office_worker", "keywords": ["business", "manager", "woman", "human"] }, - { "category": "people", "char": "👨💼", "name": "man_office_worker", "keywords": ["business", "manager", "man", "human"] }, - { "category": "people", "char": "🧑🔧", "name": "mechanic", "keywords": ["plumber", "human", "wrench"] }, - { "category": "people", "char": "👩🔧", "name": "woman_mechanic", "keywords": ["plumber", "woman", "human", "wrench"] }, - { "category": "people", "char": "👨🔧", "name": "man_mechanic", "keywords": ["plumber", "man", "human", "wrench"] }, - { "category": "people", "char": "🧑🔬", "name": "scientist", "keywords": ["biologist", "chemist", "engineer", "physicist", "human"] }, - { "category": "people", "char": "👩🔬", "name": "woman_scientist", "keywords": ["biologist", "chemist", "engineer", "physicist", "woman", "human"] }, - { "category": "people", "char": "👨🔬", "name": "man_scientist", "keywords": ["biologist", "chemist", "engineer", "physicist", "man", "human"] }, - { "category": "people", "char": "🧑🎨", "name": "artist", "keywords": ["painter", "human"] }, - { "category": "people", "char": "👩🎨", "name": "woman_artist", "keywords": ["painter", "woman", "human"] }, - { "category": "people", "char": "👨🎨", "name": "man_artist", "keywords": ["painter", "man", "human"] }, - { "category": "people", "char": "🧑🚒", "name": "firefighter", "keywords": ["fireman", "human"] }, - { "category": "people", "char": "👩🚒", "name": "woman_firefighter", "keywords": ["fireman", "woman", "human"] }, - { "category": "people", "char": "👨🚒", "name": "man_firefighter", "keywords": ["fireman", "man", "human"] }, - { "category": "people", "char": "🧑✈️", "name": "pilot", "keywords": ["aviator", "plane", "human"] }, - { "category": "people", "char": "👩✈️", "name": "woman_pilot", "keywords": ["aviator", "plane", "woman", "human"] }, - { "category": "people", "char": "👨✈️", "name": "man_pilot", "keywords": ["aviator", "plane", "man", "human"] }, - { "category": "people", "char": "🧑🚀", "name": "astronaut", "keywords": ["space", "rocket", "human"] }, - { "category": "people", "char": "👩🚀", "name": "woman_astronaut", "keywords": ["space", "rocket", "woman", "human"] }, - { "category": "people", "char": "👨🚀", "name": "man_astronaut", "keywords": ["space", "rocket", "man", "human"] }, - { "category": "people", "char": "🧑⚖️", "name": "judge", "keywords": ["justice", "court", "human"] }, - { "category": "people", "char": "👩⚖️", "name": "woman_judge", "keywords": ["justice", "court", "woman", "human"] }, - { "category": "people", "char": "👨⚖️", "name": "man_judge", "keywords": ["justice", "court", "man", "human"] }, - { "category": "people", "char": "🦸♀️", "name": "woman_superhero", "keywords": ["woman", "female", "good", "heroine", "superpowers"] }, - { "category": "people", "char": "🦸♂️", "name": "man_superhero", "keywords": ["man", "male", "good", "hero", "superpowers"] }, - { "category": "people", "char": "🦹♀️", "name": "woman_supervillain", "keywords": ["woman", "female", "evil", "bad", "criminal", "heroine", "superpowers"] }, - { "category": "people", "char": "🦹♂️", "name": "man_supervillain", "keywords": ["man", "male", "evil", "bad", "criminal", "hero", "superpowers"] }, - { "category": "people", "char": "🤶", "name": "mrs_claus", "keywords": ["woman", "female", "xmas", "mother christmas"] }, - { "category": "people", "char": "\uD83E\uDDD1\u200D\uD83C\uDF84", "name": "mx_claus", "keywords": ["xmas", "christmas"] }, - { "category": "people", "char": "🎅", "name": "santa", "keywords": ["festival", "man", "male", "xmas", "father christmas"] }, - { "category": "people", "char": "🥷", "name": "ninja", "keywords": [] }, - { "category": "people", "char": "🧙♀️", "name": "sorceress", "keywords": ["woman", "female", "mage", "witch"] }, - { "category": "people", "char": "🧙♂️", "name": "wizard", "keywords": ["man", "male", "mage", "sorcerer"] }, - { "category": "people", "char": "🧝♀️", "name": "woman_elf", "keywords": ["woman", "female"] }, - { "category": "people", "char": "🧝♂️", "name": "man_elf", "keywords": ["man", "male"] }, - { "category": "people", "char": "🧛♀️", "name": "woman_vampire", "keywords": ["woman", "female"] }, - { "category": "people", "char": "🧛♂️", "name": "man_vampire", "keywords": ["man", "male", "dracula"] }, - { "category": "people", "char": "🧟♀️", "name": "woman_zombie", "keywords": ["woman", "female", "undead", "walking dead"] }, - { "category": "people", "char": "🧟♂️", "name": "man_zombie", "keywords": ["man", "male", "dracula", "undead", "walking dead"] }, - { "category": "people", "char": "🧞♀️", "name": "woman_genie", "keywords": ["woman", "female"] }, - { "category": "people", "char": "🧞♂️", "name": "man_genie", "keywords": ["man", "male"] }, - { "category": "people", "char": "🧜♀️", "name": "mermaid", "keywords": ["woman", "female", "merwoman", "ariel"] }, - { "category": "people", "char": "🧜♂️", "name": "merman", "keywords": ["man", "male", "triton"] }, - { "category": "people", "char": "🧚♀️", "name": "woman_fairy", "keywords": ["woman", "female"] }, - { "category": "people", "char": "🧚♂️", "name": "man_fairy", "keywords": ["man", "male"] }, - { "category": "people", "char": "👼", "name": "angel", "keywords": ["heaven", "wings", "halo"] }, - { "category": "people", "char": "\uD83E\uDDCC", "name": "troll", "keywords": [] }, - { "category": "people", "char": "🤰", "name": "pregnant_woman", "keywords": ["baby"] }, - { "category": "people", "char": "\uD83E\uDEC3", "name": "pregnant_man", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEC4", "name": "pregnant_person", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDEC5", "name": "person_with_crown", "keywords": [] }, - { "category": "people", "char": "🤱", "name": "breastfeeding", "keywords": ["nursing", "baby"] }, - { "category": "people", "char": "\uD83D\uDC69\u200D\uD83C\uDF7C", "name": "woman_feeding_baby", "keywords": [] }, - { "category": "people", "char": "\uD83D\uDC68\u200D\uD83C\uDF7C", "name": "man_feeding_baby", "keywords": [] }, - { "category": "people", "char": "\uD83E\uDDD1\u200D\uD83C\uDF7C", "name": "person_feeding_baby", "keywords": [] }, - { "category": "people", "char": "👸", "name": "princess", "keywords": ["girl", "woman", "female", "blond", "crown", "royal", "queen"] }, - { "category": "people", "char": "🤴", "name": "prince", "keywords": ["boy", "man", "male", "crown", "royal", "king"] }, - { "category": "people", "char": "👰", "name": "person_with_veil", "keywords": ["couple", "marriage", "wedding", "woman", "bride"] }, - { "category": "people", "char": "👰", "name": "bride_with_veil", "keywords": ["couple", "marriage", "wedding", "woman", "bride"] }, - { "category": "people", "char": "🤵", "name": "person_in_tuxedo", "keywords": ["couple", "marriage", "wedding", "groom"] }, - { "category": "people", "char": "🤵", "name": "man_in_tuxedo", "keywords": ["couple", "marriage", "wedding", "groom"] }, - { "category": "people", "char": "🏃♀️", "name": "running_woman", "keywords": ["woman", "walking", "exercise", "race", "running", "female"] }, - { "category": "people", "char": "🏃", "name": "running_man", "keywords": ["man", "walking", "exercise", "race", "running"] }, - { "category": "people", "char": "🚶♀️", "name": "walking_woman", "keywords": ["human", "feet", "steps", "woman", "female"] }, - { "category": "people", "char": "🚶", "name": "walking_man", "keywords": ["human", "feet", "steps"] }, - { "category": "people", "char": "💃", "name": "dancer", "keywords": ["female", "girl", "woman", "fun"] }, - { "category": "people", "char": "🕺", "name": "man_dancing", "keywords": ["male", "boy", "fun", "dancer"] }, - { "category": "people", "char": "👯", "name": "dancing_women", "keywords": ["female", "bunny", "women", "girls"] }, - { "category": "people", "char": "👯♂️", "name": "dancing_men", "keywords": ["male", "bunny", "men", "boys"] }, - { "category": "people", "char": "👫", "name": "couple", "keywords": ["pair", "people", "human", "love", "date", "dating", "like", "affection", "valentines", "marriage"] }, - { "category": "people", "char": "\uD83E\uDDD1\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1", "name": "people_holding_hands", "keywords": ["pair", "couple", "love", "like", "bromance", "friendship", "people", "human"] }, - { "category": "people", "char": "👬", "name": "two_men_holding_hands", "keywords": ["pair", "couple", "love", "like", "bromance", "friendship", "people", "man", "human"] }, - { "category": "people", "char": "👭", "name": "two_women_holding_hands", "keywords": ["pair", "couple", "love", "like", "bromance", "friendship", "people", "female", "human"] }, - { "category": "people", "char": "🫂", "name": "people_hugging", "keywords": [] }, - { "category": "people", "char": "🙇♀️", "name": "bowing_woman", "keywords": ["woman", "female", "girl"] }, - { "category": "people", "char": "🙇", "name": "bowing_man", "keywords": ["man", "male", "boy"] }, - { "category": "people", "char": "🤦♂️", "name": "man_facepalming", "keywords": ["man", "male", "boy", "disbelief"] }, - { "category": "people", "char": "🤦♀️", "name": "woman_facepalming", "keywords": ["woman", "female", "girl", "disbelief"] }, - { "category": "people", "char": "🤷", "name": "woman_shrugging", "keywords": ["woman", "female", "girl", "confused", "indifferent", "doubt"] }, - { "category": "people", "char": "🤷♂️", "name": "man_shrugging", "keywords": ["man", "male", "boy", "confused", "indifferent", "doubt"] }, - { "category": "people", "char": "💁", "name": "tipping_hand_woman", "keywords": ["female", "girl", "woman", "human", "information"] }, - { "category": "people", "char": "💁♂️", "name": "tipping_hand_man", "keywords": ["male", "boy", "man", "human", "information"] }, - { "category": "people", "char": "🙅", "name": "no_good_woman", "keywords": ["female", "girl", "woman", "nope"] }, - { "category": "people", "char": "🙅♂️", "name": "no_good_man", "keywords": ["male", "boy", "man", "nope"] }, - { "category": "people", "char": "🙆", "name": "ok_woman", "keywords": ["women", "girl", "female", "pink", "human", "woman"] }, - { "category": "people", "char": "🙆♂️", "name": "ok_man", "keywords": ["men", "boy", "male", "blue", "human", "man"] }, - { "category": "people", "char": "🙋", "name": "raising_hand_woman", "keywords": ["female", "girl", "woman"] }, - { "category": "people", "char": "🙋♂️", "name": "raising_hand_man", "keywords": ["male", "boy", "man"] }, - { "category": "people", "char": "🙎", "name": "pouting_woman", "keywords": ["female", "girl", "woman"] }, - { "category": "people", "char": "🙎♂️", "name": "pouting_man", "keywords": ["male", "boy", "man"] }, - { "category": "people", "char": "🙍", "name": "frowning_woman", "keywords": ["female", "girl", "woman", "sad", "depressed", "discouraged", "unhappy"] }, - { "category": "people", "char": "🙍♂️", "name": "frowning_man", "keywords": ["male", "boy", "man", "sad", "depressed", "discouraged", "unhappy"] }, - { "category": "people", "char": "💇", "name": "haircut_woman", "keywords": ["female", "girl", "woman"] }, - { "category": "people", "char": "💇♂️", "name": "haircut_man", "keywords": ["male", "boy", "man"] }, - { "category": "people", "char": "💆", "name": "massage_woman", "keywords": ["female", "girl", "woman", "head"] }, - { "category": "people", "char": "💆♂️", "name": "massage_man", "keywords": ["male", "boy", "man", "head"] }, - { "category": "people", "char": "🧖♀️", "name": "woman_in_steamy_room", "keywords": ["female", "woman", "spa", "steamroom", "sauna"] }, - { "category": "people", "char": "🧖♂️", "name": "man_in_steamy_room", "keywords": ["male", "man", "spa", "steamroom", "sauna"] }, - { "category": "people", "char": "🧏♀️", "name": "woman_deaf", "keywords": ["woman", "female"] }, - { "category": "people", "char": "🧏♂️", "name": "man_deaf", "keywords": ["man", "male"] }, - { "category": "people", "char": "🧍♀️", "name": "woman_standing", "keywords": ["woman", "female"] }, - { "category": "people", "char": "🧍♂️", "name": "man_standing", "keywords": ["man", "male"] }, - { "category": "people", "char": "🧎♀️", "name": "woman_kneeling", "keywords": ["woman", "female"] }, - { "category": "people", "char": "🧎♂️", "name": "man_kneeling", "keywords": ["man", "male"] }, - { "category": "people", "char": "🧑🦯", "name": "person_with_probing_cane", "keywords": ["accessibility", "blind"] }, - { "category": "people", "char": "👩🦯", "name": "woman_with_probing_cane", "keywords": ["woman", "female", "accessibility", "blind"] }, - { "category": "people", "char": "👨🦯", "name": "man_with_probing_cane", "keywords": ["man", "male", "accessibility", "blind"] }, - { "category": "people", "char": "🧑🦼", "name": "person_in_motorized_wheelchair", "keywords": ["accessibility"] }, - { "category": "people", "char": "👩🦼", "name": "woman_in_motorized_wheelchair", "keywords": ["woman", "female", "accessibility"] }, - { "category": "people", "char": "👨🦼", "name": "man_in_motorized_wheelchair", "keywords": ["man", "male", "accessibility"] }, - { "category": "people", "char": "🧑🦽", "name": "person_in_manual_wheelchair", "keywords": ["accessibility"] }, - { "category": "people", "char": "👩🦽", "name": "woman_in_manual_wheelchair", "keywords": ["woman", "female", "accessibility"] }, - { "category": "people", "char": "👨🦽", "name": "man_in_manual_wheelchair", "keywords": ["man", "male", "accessibility"] }, - { "category": "people", "char": "💑", "name": "couple_with_heart_woman_man", "keywords": ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"] }, - { "category": "people", "char": "👩❤️👩", "name": "couple_with_heart_woman_woman", "keywords": ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"] }, - { "category": "people", "char": "👨❤️👨", "name": "couple_with_heart_man_man", "keywords": ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"] }, - { "category": "people", "char": "💏", "name": "couplekiss_man_woman", "keywords": ["pair", "valentines", "love", "like", "dating", "marriage"] }, - { "category": "people", "char": "👩❤️💋👩", "name": "couplekiss_woman_woman", "keywords": ["pair", "valentines", "love", "like", "dating", "marriage"] }, - { "category": "people", "char": "👨❤️💋👨", "name": "couplekiss_man_man", "keywords": ["pair", "valentines", "love", "like", "dating", "marriage"] }, - { "category": "people", "char": "👪", "name": "family_man_woman_boy", "keywords": ["home", "parents", "child", "mom", "dad", "father", "mother", "people", "human"] }, - { "category": "people", "char": "👨👩👧", "name": "family_man_woman_girl", "keywords": ["home", "parents", "people", "human", "child"] }, - { "category": "people", "char": "👨👩👧👦", "name": "family_man_woman_girl_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👨👩👦👦", "name": "family_man_woman_boy_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👨👩👧👧", "name": "family_man_woman_girl_girl", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👩👩👦", "name": "family_woman_woman_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👩👩👧", "name": "family_woman_woman_girl", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👩👩👧👦", "name": "family_woman_woman_girl_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👩👩👦👦", "name": "family_woman_woman_boy_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👩👩👧👧", "name": "family_woman_woman_girl_girl", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👨👨👦", "name": "family_man_man_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👨👨👧", "name": "family_man_man_girl", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👨👨👧👦", "name": "family_man_man_girl_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👨👨👦👦", "name": "family_man_man_boy_boy", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👨👨👧👧", "name": "family_man_man_girl_girl", "keywords": ["home", "parents", "people", "human", "children"] }, - { "category": "people", "char": "👩👦", "name": "family_woman_boy", "keywords": ["home", "parent", "people", "human", "child"] }, - { "category": "people", "char": "👩👧", "name": "family_woman_girl", "keywords": ["home", "parent", "people", "human", "child"] }, - { "category": "people", "char": "👩👧👦", "name": "family_woman_girl_boy", "keywords": ["home", "parent", "people", "human", "children"] }, - { "category": "people", "char": "👩👦👦", "name": "family_woman_boy_boy", "keywords": ["home", "parent", "people", "human", "children"] }, - { "category": "people", "char": "👩👧👧", "name": "family_woman_girl_girl", "keywords": ["home", "parent", "people", "human", "children"] }, - { "category": "people", "char": "👨👦", "name": "family_man_boy", "keywords": ["home", "parent", "people", "human", "child"] }, - { "category": "people", "char": "👨👧", "name": "family_man_girl", "keywords": ["home", "parent", "people", "human", "child"] }, - { "category": "people", "char": "👨👧👦", "name": "family_man_girl_boy", "keywords": ["home", "parent", "people", "human", "children"] }, - { "category": "people", "char": "👨👦👦", "name": "family_man_boy_boy", "keywords": ["home", "parent", "people", "human", "children"] }, - { "category": "people", "char": "👨👧👧", "name": "family_man_girl_girl", "keywords": ["home", "parent", "people", "human", "children"] }, - { "category": "people", "char": "🧶", "name": "yarn", "keywords": ["ball", "crochet", "knit"] }, - { "category": "people", "char": "🧵", "name": "thread", "keywords": ["needle", "sewing", "spool", "string"] }, - { "category": "people", "char": "🧥", "name": "coat", "keywords": ["jacket"] }, - { "category": "people", "char": "🥼", "name": "labcoat", "keywords": ["doctor", "experiment", "scientist", "chemist"] }, - { "category": "people", "char": "👚", "name": "womans_clothes", "keywords": ["fashion", "shopping_bags", "female"] }, - { "category": "people", "char": "👕", "name": "tshirt", "keywords": ["fashion", "cloth", "casual", "shirt", "tee"] }, - { "category": "people", "char": "👖", "name": "jeans", "keywords": ["fashion", "shopping"] }, - { "category": "people", "char": "👔", "name": "necktie", "keywords": ["shirt", "suitup", "formal", "fashion", "cloth", "business"] }, - { "category": "people", "char": "👗", "name": "dress", "keywords": ["clothes", "fashion", "shopping"] }, - { "category": "people", "char": "👙", "name": "bikini", "keywords": ["swimming", "female", "woman", "girl", "fashion", "beach", "summer"] }, - { "category": "people", "char": "🩱", "name": "one_piece_swimsuit", "keywords": ["swimming", "female", "woman", "girl", "fashion", "beach", "summer"] }, - { "category": "people", "char": "👘", "name": "kimono", "keywords": ["dress", "fashion", "women", "female", "japanese"] }, - { "category": "people", "char": "🥻", "name": "sari", "keywords": ["dress", "fashion", "women", "female"] }, - { "category": "people", "char": "🩲", "name": "briefs", "keywords": ["dress", "fashion"] }, - { "category": "people", "char": "🩳", "name": "shorts", "keywords": ["dress", "fashion"] }, - { "category": "people", "char": "💄", "name": "lipstick", "keywords": ["female", "girl", "fashion", "woman"] }, - { "category": "people", "char": "💋", "name": "kiss", "keywords": ["face", "lips", "love", "like", "affection", "valentines"] }, - { "category": "people", "char": "👣", "name": "footprints", "keywords": ["feet", "tracking", "walking", "beach"] }, - { "category": "people", "char": "🥿", "name": "flat_shoe", "keywords": ["ballet", "slip-on", "slipper"] }, - { "category": "people", "char": "👠", "name": "high_heel", "keywords": ["fashion", "shoes", "female", "pumps", "stiletto"] }, - { "category": "people", "char": "👡", "name": "sandal", "keywords": ["shoes", "fashion", "flip flops"] }, - { "category": "people", "char": "👢", "name": "boot", "keywords": ["shoes", "fashion"] }, - { "category": "people", "char": "👞", "name": "mans_shoe", "keywords": ["fashion", "male"] }, - { "category": "people", "char": "👟", "name": "athletic_shoe", "keywords": ["shoes", "sports", "sneakers"] }, - { "category": "people", "char": "🩴", "name": "thong_sandal", "keywords": [] }, - { "category": "people", "char": "🩰", "name": "ballet_shoes", "keywords": ["shoes", "sports"] }, - { "category": "people", "char": "🧦", "name": "socks", "keywords": ["stockings", "clothes"] }, - { "category": "people", "char": "🧤", "name": "gloves", "keywords": ["hands", "winter", "clothes"] }, - { "category": "people", "char": "🧣", "name": "scarf", "keywords": ["neck", "winter", "clothes"] }, - { "category": "people", "char": "👒", "name": "womans_hat", "keywords": ["fashion", "accessories", "female", "lady", "spring"] }, - { "category": "people", "char": "🎩", "name": "tophat", "keywords": ["magic", "gentleman", "classy", "circus"] }, - { "category": "people", "char": "🧢", "name": "billed_hat", "keywords": ["cap", "baseball"] }, - { "category": "people", "char": "⛑", "name": "rescue_worker_helmet", "keywords": ["construction", "build"] }, - { "category": "people", "char": "🪖", "name": "military_helmet", "keywords": [] }, - { "category": "people", "char": "🎓", "name": "mortar_board", "keywords": ["school", "college", "degree", "university", "graduation", "cap", "hat", "legal", "learn", "education"] }, - { "category": "people", "char": "👑", "name": "crown", "keywords": ["king", "kod", "leader", "royalty", "lord"] }, - { "category": "people", "char": "🎒", "name": "school_satchel", "keywords": ["student", "education", "bag", "backpack"] }, - { "category": "people", "char": "🧳", "name": "luggage", "keywords": ["packing", "travel"] }, - { "category": "people", "char": "👝", "name": "pouch", "keywords": ["bag", "accessories", "shopping"] }, - { "category": "people", "char": "👛", "name": "purse", "keywords": ["fashion", "accessories", "money", "sales", "shopping"] }, - { "category": "people", "char": "👜", "name": "handbag", "keywords": ["fashion", "accessory", "accessories", "shopping"] }, - { "category": "people", "char": "💼", "name": "briefcase", "keywords": ["business", "documents", "work", "law", "legal", "job", "career"] }, - { "category": "people", "char": "👓", "name": "eyeglasses", "keywords": ["fashion", "accessories", "eyesight", "nerdy", "dork", "geek"] }, - { "category": "people", "char": "🕶", "name": "dark_sunglasses", "keywords": ["face", "cool", "accessories"] }, - { "category": "people", "char": "🥽", "name": "goggles", "keywords": ["eyes", "protection", "safety"] }, - { "category": "people", "char": "💍", "name": "ring", "keywords": ["wedding", "propose", "marriage", "valentines", "diamond", "fashion", "jewelry", "gem", "engagement"] }, - { "category": "people", "char": "🌂", "name": "closed_umbrella", "keywords": ["weather", "rain", "drizzle"] }, - { "category": "animals_and_nature", "char": "🐶", "name": "dog", "keywords": ["animal", "friend", "nature", "woof", "puppy", "pet", "faithful"] }, - { "category": "animals_and_nature", "char": "🐱", "name": "cat", "keywords": ["animal", "meow", "nature", "pet", "kitten"] }, - { "category": "animals_and_nature", "char": "🐈⬛", "name": "black_cat", "keywords": ["animal", "meow", "nature", "pet", "kitten"] }, - { "category": "animals_and_nature", "char": "🐭", "name": "mouse", "keywords": ["animal", "nature", "cheese_wedge", "rodent"] }, - { "category": "animals_and_nature", "char": "🐹", "name": "hamster", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐰", "name": "rabbit", "keywords": ["animal", "nature", "pet", "spring", "magic", "bunny"] }, - { "category": "animals_and_nature", "char": "🦊", "name": "fox_face", "keywords": ["animal", "nature", "face"] }, - { "category": "animals_and_nature", "char": "🐻", "name": "bear", "keywords": ["animal", "nature", "wild"] }, - { "category": "animals_and_nature", "char": "🐼", "name": "panda_face", "keywords": ["animal", "nature", "panda"] }, - { "category": "animals_and_nature", "char": "🐨", "name": "koala", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐯", "name": "tiger", "keywords": ["animal", "cat", "danger", "wild", "nature", "roar"] }, - { "category": "animals_and_nature", "char": "🦁", "name": "lion", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐮", "name": "cow", "keywords": ["beef", "ox", "animal", "nature", "moo", "milk"] }, - { "category": "animals_and_nature", "char": "🐷", "name": "pig", "keywords": ["animal", "oink", "nature"] }, - { "category": "animals_and_nature", "char": "🐽", "name": "pig_nose", "keywords": ["animal", "oink"] }, - { "category": "animals_and_nature", "char": "🐸", "name": "frog", "keywords": ["animal", "nature", "croak", "toad"] }, - { "category": "animals_and_nature", "char": "🦑", "name": "squid", "keywords": ["animal", "nature", "ocean", "sea"] }, - { "category": "animals_and_nature", "char": "🐙", "name": "octopus", "keywords": ["animal", "creature", "ocean", "sea", "nature", "beach"] }, - { "category": "animals_and_nature", "char": "🦐", "name": "shrimp", "keywords": ["animal", "ocean", "nature", "seafood"] }, - { "category": "animals_and_nature", "char": "🐵", "name": "monkey_face", "keywords": ["animal", "nature", "circus"] }, - { "category": "animals_and_nature", "char": "🦍", "name": "gorilla", "keywords": ["animal", "nature", "circus"] }, - { "category": "animals_and_nature", "char": "🙈", "name": "see_no_evil", "keywords": ["monkey", "animal", "nature", "haha"] }, - { "category": "animals_and_nature", "char": "🙉", "name": "hear_no_evil", "keywords": ["animal", "monkey", "nature"] }, - { "category": "animals_and_nature", "char": "🙊", "name": "speak_no_evil", "keywords": ["monkey", "animal", "nature", "omg"] }, - { "category": "animals_and_nature", "char": "🐒", "name": "monkey", "keywords": ["animal", "nature", "banana", "circus"] }, - { "category": "animals_and_nature", "char": "🐔", "name": "chicken", "keywords": ["animal", "cluck", "nature", "bird"] }, - { "category": "animals_and_nature", "char": "🐧", "name": "penguin", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐦", "name": "bird", "keywords": ["animal", "nature", "fly", "tweet", "spring"] }, - { "category": "animals_and_nature", "char": "🐤", "name": "baby_chick", "keywords": ["animal", "chicken", "bird"] }, - { "category": "animals_and_nature", "char": "🐣", "name": "hatching_chick", "keywords": ["animal", "chicken", "egg", "born", "baby", "bird"] }, - { "category": "animals_and_nature", "char": "🐥", "name": "hatched_chick", "keywords": ["animal", "chicken", "baby", "bird"] }, - { "category": "animals_and_nature", "char": "🦆", "name": "duck", "keywords": ["animal", "nature", "bird", "mallard"] }, - { "category": "animals_and_nature", "char": "🦅", "name": "eagle", "keywords": ["animal", "nature", "bird"] }, - { "category": "animals_and_nature", "char": "🦉", "name": "owl", "keywords": ["animal", "nature", "bird", "hoot"] }, - { "category": "animals_and_nature", "char": "🦇", "name": "bat", "keywords": ["animal", "nature", "blind", "vampire"] }, - { "category": "animals_and_nature", "char": "🐺", "name": "wolf", "keywords": ["animal", "nature", "wild"] }, - { "category": "animals_and_nature", "char": "🐗", "name": "boar", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐴", "name": "horse", "keywords": ["animal", "brown", "nature"] }, - { "category": "animals_and_nature", "char": "🦄", "name": "unicorn", "keywords": ["animal", "nature", "mystical"] }, - { "category": "animals_and_nature", "char": "🐝", "name": "honeybee", "keywords": ["animal", "insect", "nature", "bug", "spring", "honey"] }, - { "category": "animals_and_nature", "char": "🐛", "name": "bug", "keywords": ["animal", "insect", "nature", "worm"] }, - { "category": "animals_and_nature", "char": "🦋", "name": "butterfly", "keywords": ["animal", "insect", "nature", "caterpillar"] }, - { "category": "animals_and_nature", "char": "🐌", "name": "snail", "keywords": ["slow", "animal", "shell"] }, - { "category": "animals_and_nature", "char": "🐞", "name": "lady_beetle", "keywords": ["animal", "insect", "nature", "ladybug"] }, - { "category": "animals_and_nature", "char": "🐜", "name": "ant", "keywords": ["animal", "insect", "nature", "bug"] }, - { "category": "animals_and_nature", "char": "🦗", "name": "grasshopper", "keywords": ["animal", "cricket", "chirp"] }, - { "category": "animals_and_nature", "char": "🕷", "name": "spider", "keywords": ["animal", "arachnid"] }, - { "category": "animals_and_nature", "char": "🪲", "name": "beetle", "keywords": ["animal"] }, - { "category": "animals_and_nature", "char": "🪳", "name": "cockroach", "keywords": ["animal"] }, - { "category": "animals_and_nature", "char": "🪰", "name": "fly", "keywords": ["animal"] }, - { "category": "animals_and_nature", "char": "🪱", "name": "worm", "keywords": ["animal"] }, - { "category": "animals_and_nature", "char": "🦂", "name": "scorpion", "keywords": ["animal", "arachnid"] }, - { "category": "animals_and_nature", "char": "🦀", "name": "crab", "keywords": ["animal", "crustacean"] }, - { "category": "animals_and_nature", "char": "🐍", "name": "snake", "keywords": ["animal", "evil", "nature", "hiss", "python"] }, - { "category": "animals_and_nature", "char": "🦎", "name": "lizard", "keywords": ["animal", "nature", "reptile"] }, - { "category": "animals_and_nature", "char": "🦖", "name": "t-rex", "keywords": ["animal", "nature", "dinosaur", "tyrannosaurus", "extinct"] }, - { "category": "animals_and_nature", "char": "🦕", "name": "sauropod", "keywords": ["animal", "nature", "dinosaur", "brachiosaurus", "brontosaurus", "diplodocus", "extinct"] }, - { "category": "animals_and_nature", "char": "🐢", "name": "turtle", "keywords": ["animal", "slow", "nature", "tortoise"] }, - { "category": "animals_and_nature", "char": "🐠", "name": "tropical_fish", "keywords": ["animal", "swim", "ocean", "beach", "nemo"] }, - { "category": "animals_and_nature", "char": "🐟", "name": "fish", "keywords": ["animal", "food", "nature"] }, - { "category": "animals_and_nature", "char": "🐡", "name": "blowfish", "keywords": ["animal", "nature", "food", "sea", "ocean"] }, - { "category": "animals_and_nature", "char": "🐬", "name": "dolphin", "keywords": ["animal", "nature", "fish", "sea", "ocean", "flipper", "fins", "beach"] }, - { "category": "animals_and_nature", "char": "🦈", "name": "shark", "keywords": ["animal", "nature", "fish", "sea", "ocean", "jaws", "fins", "beach"] }, - { "category": "animals_and_nature", "char": "🐳", "name": "whale", "keywords": ["animal", "nature", "sea", "ocean"] }, - { "category": "animals_and_nature", "char": "🐋", "name": "whale2", "keywords": ["animal", "nature", "sea", "ocean"] }, - { "category": "animals_and_nature", "char": "🐊", "name": "crocodile", "keywords": ["animal", "nature", "reptile", "lizard", "alligator"] }, - { "category": "animals_and_nature", "char": "🐆", "name": "leopard", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦓", "name": "zebra", "keywords": ["animal", "nature", "stripes", "safari"] }, - { "category": "animals_and_nature", "char": "🐅", "name": "tiger2", "keywords": ["animal", "nature", "roar"] }, - { "category": "animals_and_nature", "char": "🐃", "name": "water_buffalo", "keywords": ["animal", "nature", "ox", "cow"] }, - { "category": "animals_and_nature", "char": "🐂", "name": "ox", "keywords": ["animal", "cow", "beef"] }, - { "category": "animals_and_nature", "char": "🐄", "name": "cow2", "keywords": ["beef", "ox", "animal", "nature", "moo", "milk"] }, - { "category": "animals_and_nature", "char": "🦌", "name": "deer", "keywords": ["animal", "nature", "horns", "venison"] }, - { "category": "animals_and_nature", "char": "🐪", "name": "dromedary_camel", "keywords": ["animal", "hot", "desert", "hump"] }, - { "category": "animals_and_nature", "char": "🐫", "name": "camel", "keywords": ["animal", "nature", "hot", "desert", "hump"] }, - { "category": "animals_and_nature", "char": "🦒", "name": "giraffe", "keywords": ["animal", "nature", "spots", "safari"] }, - { "category": "animals_and_nature", "char": "🐘", "name": "elephant", "keywords": ["animal", "nature", "nose", "th", "circus"] }, - { "category": "animals_and_nature", "char": "🦏", "name": "rhinoceros", "keywords": ["animal", "nature", "horn"] }, - { "category": "animals_and_nature", "char": "🐐", "name": "goat", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐏", "name": "ram", "keywords": ["animal", "sheep", "nature"] }, - { "category": "animals_and_nature", "char": "🐑", "name": "sheep", "keywords": ["animal", "nature", "wool", "shipit"] }, - { "category": "animals_and_nature", "char": "🐎", "name": "racehorse", "keywords": ["animal", "gamble", "luck"] }, - { "category": "animals_and_nature", "char": "🐖", "name": "pig2", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐀", "name": "rat", "keywords": ["animal", "mouse", "rodent"] }, - { "category": "animals_and_nature", "char": "🐁", "name": "mouse2", "keywords": ["animal", "nature", "rodent"] }, - { "category": "animals_and_nature", "char": "🐓", "name": "rooster", "keywords": ["animal", "nature", "chicken"] }, - { "category": "animals_and_nature", "char": "🦃", "name": "turkey", "keywords": ["animal", "bird"] }, - { "category": "animals_and_nature", "char": "🕊", "name": "dove", "keywords": ["animal", "bird"] }, - { "category": "animals_and_nature", "char": "🐕", "name": "dog2", "keywords": ["animal", "nature", "friend", "doge", "pet", "faithful"] }, - { "category": "animals_and_nature", "char": "🐩", "name": "poodle", "keywords": ["dog", "animal", "101", "nature", "pet"] }, - { "category": "animals_and_nature", "char": "🐈", "name": "cat2", "keywords": ["animal", "meow", "pet", "cats"] }, - { "category": "animals_and_nature", "char": "🐇", "name": "rabbit2", "keywords": ["animal", "nature", "pet", "magic", "spring"] }, - { "category": "animals_and_nature", "char": "🐿", "name": "chipmunk", "keywords": ["animal", "nature", "rodent", "squirrel"] }, - { "category": "animals_and_nature", "char": "🦔", "name": "hedgehog", "keywords": ["animal", "nature", "spiny"] }, - { "category": "animals_and_nature", "char": "🦝", "name": "raccoon", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦙", "name": "llama", "keywords": ["animal", "nature", "alpaca"] }, - { "category": "animals_and_nature", "char": "🦛", "name": "hippopotamus", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦘", "name": "kangaroo", "keywords": ["animal", "nature", "australia", "joey", "hop", "marsupial"] }, - { "category": "animals_and_nature", "char": "🦡", "name": "badger", "keywords": ["animal", "nature", "honey"] }, - { "category": "animals_and_nature", "char": "🦢", "name": "swan", "keywords": ["animal", "nature", "bird"] }, - { "category": "animals_and_nature", "char": "🦚", "name": "peacock", "keywords": ["animal", "nature", "peahen", "bird"] }, - { "category": "animals_and_nature", "char": "🦜", "name": "parrot", "keywords": ["animal", "nature", "bird", "pirate", "talk"] }, - { "category": "animals_and_nature", "char": "🦞", "name": "lobster", "keywords": ["animal", "nature", "bisque", "claws", "seafood"] }, - { "category": "animals_and_nature", "char": "🦠", "name": "microbe", "keywords": ["amoeba", "bacteria", "germs"] }, - { "category": "animals_and_nature", "char": "🦟", "name": "mosquito", "keywords": ["animal", "nature", "insect", "malaria"] }, - { "category": "animals_and_nature", "char": "🦬", "name": "bison", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦣", "name": "mammoth", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦫", "name": "beaver", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐻❄️", "name": "polar_bear", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦤", "name": "dodo", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🪶", "name": "feather", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦭", "name": "seal", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐾", "name": "paw_prints", "keywords": ["animal", "tracking", "footprints", "dog", "cat", "pet", "feet"] }, - { "category": "animals_and_nature", "char": "🐉", "name": "dragon", "keywords": ["animal", "myth", "nature", "chinese", "green"] }, - { "category": "animals_and_nature", "char": "🐲", "name": "dragon_face", "keywords": ["animal", "myth", "nature", "chinese", "green"] }, - { "category": "animals_and_nature", "char": "🦧", "name": "orangutan", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦮", "name": "guide_dog", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🐕🦺", "name": "service_dog", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦥", "name": "sloth", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦦", "name": "otter", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦨", "name": "skunk", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🦩", "name": "flamingo", "keywords": ["animal", "nature"] }, - { "category": "animals_and_nature", "char": "🌵", "name": "cactus", "keywords": ["vegetable", "plant", "nature"] }, - { "category": "animals_and_nature", "char": "🎄", "name": "christmas_tree", "keywords": ["festival", "vacation", "december", "xmas", "celebration"] }, - { "category": "animals_and_nature", "char": "🌲", "name": "evergreen_tree", "keywords": ["plant", "nature"] }, - { "category": "animals_and_nature", "char": "🌳", "name": "deciduous_tree", "keywords": ["plant", "nature"] }, - { "category": "animals_and_nature", "char": "🌴", "name": "palm_tree", "keywords": ["plant", "vegetable", "nature", "summer", "beach", "mojito", "tropical"] }, - { "category": "animals_and_nature", "char": "🌱", "name": "seedling", "keywords": ["plant", "nature", "grass", "lawn", "spring"] }, - { "category": "animals_and_nature", "char": "🌿", "name": "herb", "keywords": ["vegetable", "plant", "medicine", "weed", "grass", "lawn"] }, - { "category": "animals_and_nature", "char": "☘", "name": "shamrock", "keywords": ["vegetable", "plant", "nature", "irish", "clover"] }, - { "category": "animals_and_nature", "char": "🍀", "name": "four_leaf_clover", "keywords": ["vegetable", "plant", "nature", "lucky", "irish"] }, - { "category": "animals_and_nature", "char": "🎍", "name": "bamboo", "keywords": ["plant", "nature", "vegetable", "panda", "pine_decoration"] }, - { "category": "animals_and_nature", "char": "🎋", "name": "tanabata_tree", "keywords": ["plant", "nature", "branch", "summer"] }, - { "category": "animals_and_nature", "char": "🍃", "name": "leaves", "keywords": ["nature", "plant", "tree", "vegetable", "grass", "lawn", "spring"] }, - { "category": "animals_and_nature", "char": "🍂", "name": "fallen_leaf", "keywords": ["nature", "plant", "vegetable", "leaves"] }, - { "category": "animals_and_nature", "char": "🍁", "name": "maple_leaf", "keywords": ["nature", "plant", "vegetable", "ca", "fall"] }, - { "category": "animals_and_nature", "char": "🌾", "name": "ear_of_rice", "keywords": ["nature", "plant"] }, - { "category": "animals_and_nature", "char": "🌺", "name": "hibiscus", "keywords": ["plant", "vegetable", "flowers", "beach"] }, - { "category": "animals_and_nature", "char": "🌻", "name": "sunflower", "keywords": ["nature", "plant", "fall"] }, - { "category": "animals_and_nature", "char": "🌹", "name": "rose", "keywords": ["flowers", "valentines", "love", "spring"] }, - { "category": "animals_and_nature", "char": "🥀", "name": "wilted_flower", "keywords": ["plant", "nature", "flower"] }, - { "category": "animals_and_nature", "char": "🌷", "name": "tulip", "keywords": ["flowers", "plant", "nature", "summer", "spring"] }, - { "category": "animals_and_nature", "char": "🌼", "name": "blossom", "keywords": ["nature", "flowers", "yellow"] }, - { "category": "animals_and_nature", "char": "🌸", "name": "cherry_blossom", "keywords": ["nature", "plant", "spring", "flower"] }, - { "category": "animals_and_nature", "char": "💐", "name": "bouquet", "keywords": ["flowers", "nature", "spring"] }, - { "category": "animals_and_nature", "char": "🍄", "name": "mushroom", "keywords": ["plant", "vegetable"] }, - { "category": "animals_and_nature", "char": "🪴", "name": "potted_plant", "keywords": ["plant"] }, - { "category": "animals_and_nature", "char": "🌰", "name": "chestnut", "keywords": ["food", "squirrel"] }, - { "category": "animals_and_nature", "char": "🎃", "name": "jack_o_lantern", "keywords": ["halloween", "light", "pumpkin", "creepy", "fall"] }, - { "category": "animals_and_nature", "char": "🐚", "name": "shell", "keywords": ["nature", "sea", "beach"] }, - { "category": "animals_and_nature", "char": "🕸", "name": "spider_web", "keywords": ["animal", "insect", "arachnid", "silk"] }, - { "category": "animals_and_nature", "char": "🌎", "name": "earth_americas", "keywords": ["globe", "world", "USA", "international"] }, - { "category": "animals_and_nature", "char": "🌍", "name": "earth_africa", "keywords": ["globe", "world", "international"] }, - { "category": "animals_and_nature", "char": "🌏", "name": "earth_asia", "keywords": ["globe", "world", "east", "international"] }, - { "category": "animals_and_nature", "char": "🪐", "name": "ringed_planet", "keywords": ["saturn"] }, - { "category": "animals_and_nature", "char": "🌕", "name": "full_moon", "keywords": ["nature", "yellow", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌖", "name": "waning_gibbous_moon", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep", "waxing_gibbous_moon"] }, - { "category": "animals_and_nature", "char": "🌗", "name": "last_quarter_moon", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌘", "name": "waning_crescent_moon", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌑", "name": "new_moon", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌒", "name": "waxing_crescent_moon", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌓", "name": "first_quarter_moon", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌔", "name": "waxing_gibbous_moon", "keywords": ["nature", "night", "sky", "gray", "twilight", "planet", "space", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌚", "name": "new_moon_with_face", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌝", "name": "full_moon_with_face", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌛", "name": "first_quarter_moon_with_face", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌜", "name": "last_quarter_moon_with_face", "keywords": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"] }, - { "category": "animals_and_nature", "char": "🌞", "name": "sun_with_face", "keywords": ["nature", "morning", "sky"] }, - { "category": "animals_and_nature", "char": "🌙", "name": "crescent_moon", "keywords": ["night", "sleep", "sky", "evening", "magic"] }, - { "category": "animals_and_nature", "char": "⭐", "name": "star", "keywords": ["night", "yellow"] }, - { "category": "animals_and_nature", "char": "🌟", "name": "star2", "keywords": ["night", "sparkle", "awesome", "good", "magic"] }, - { "category": "animals_and_nature", "char": "💫", "name": "dizzy", "keywords": ["star", "sparkle", "shoot", "magic"] }, - { "category": "animals_and_nature", "char": "✨", "name": "sparkles", "keywords": ["stars", "shine", "shiny", "cool", "awesome", "good", "magic"] }, - { "category": "animals_and_nature", "char": "☄", "name": "comet", "keywords": ["space"] }, - { "category": "animals_and_nature", "char": "☀️", "name": "sunny", "keywords": ["weather", "nature", "brightness", "summer", "beach", "spring"] }, - { "category": "animals_and_nature", "char": "🌤", "name": "sun_behind_small_cloud", "keywords": ["weather"] }, - { "category": "animals_and_nature", "char": "⛅", "name": "partly_sunny", "keywords": ["weather", "nature", "cloudy", "morning", "fall", "spring"] }, - { "category": "animals_and_nature", "char": "🌥", "name": "sun_behind_large_cloud", "keywords": ["weather"] }, - { "category": "animals_and_nature", "char": "🌦", "name": "sun_behind_rain_cloud", "keywords": ["weather"] }, - { "category": "animals_and_nature", "char": "☁️", "name": "cloud", "keywords": ["weather", "sky"] }, - { "category": "animals_and_nature", "char": "🌧", "name": "cloud_with_rain", "keywords": ["weather"] }, - { "category": "animals_and_nature", "char": "⛈", "name": "cloud_with_lightning_and_rain", "keywords": ["weather", "lightning"] }, - { "category": "animals_and_nature", "char": "🌩", "name": "cloud_with_lightning", "keywords": ["weather", "thunder"] }, - { "category": "animals_and_nature", "char": "⚡", "name": "zap", "keywords": ["thunder", "weather", "lightning bolt", "fast"] }, - { "category": "animals_and_nature", "char": "🔥", "name": "fire", "keywords": ["hot", "cook", "flame"] }, - { "category": "animals_and_nature", "char": "💥", "name": "boom", "keywords": ["bomb", "explode", "explosion", "collision", "blown"] }, - { "category": "animals_and_nature", "char": "❄️", "name": "snowflake", "keywords": ["winter", "season", "cold", "weather", "christmas", "xmas"] }, - { "category": "animals_and_nature", "char": "🌨", "name": "cloud_with_snow", "keywords": ["weather"] }, - { "category": "animals_and_nature", "char": "⛄", "name": "snowman", "keywords": ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen", "without_snow"] }, - { "category": "animals_and_nature", "char": "☃", "name": "snowman_with_snow", "keywords": ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen"] }, - { "category": "animals_and_nature", "char": "🌬", "name": "wind_face", "keywords": ["gust", "air"] }, - { "category": "animals_and_nature", "char": "💨", "name": "dash", "keywords": ["wind", "air", "fast", "shoo", "fart", "smoke", "puff"] }, - { "category": "animals_and_nature", "char": "🌪", "name": "tornado", "keywords": ["weather", "cyclone", "twister"] }, - { "category": "animals_and_nature", "char": "🌫", "name": "fog", "keywords": ["weather"] }, - { "category": "animals_and_nature", "char": "☂", "name": "open_umbrella", "keywords": ["weather", "spring"] }, - { "category": "animals_and_nature", "char": "☔", "name": "umbrella", "keywords": ["rainy", "weather", "spring"] }, - { "category": "animals_and_nature", "char": "💧", "name": "droplet", "keywords": ["water", "drip", "faucet", "spring"] }, - { "category": "animals_and_nature", "char": "💦", "name": "sweat_drops", "keywords": ["water", "drip", "oops"] }, - { "category": "animals_and_nature", "char": "🌊", "name": "ocean", "keywords": ["sea", "water", "wave", "nature", "tsunami", "disaster"] }, - { "category": "animals_and_nature", "char": "\uD83E\uDEB7", "name": "lotus", "keywords": [] }, - { "category": "animals_and_nature", "char": "\uD83E\uDEB8", "name": "coral", "keywords": [] }, - { "category": "animals_and_nature", "char": "\uD83E\uDEB9", "name": "empty_nest", "keywords": [] }, - { "category": "animals_and_nature", "char": "\uD83E\uDEBA", "name": "nest_with_eggs", "keywords": [] }, - { "category": "food_and_drink", "char": "🍏", "name": "green_apple", "keywords": ["fruit", "nature"] }, - { "category": "food_and_drink", "char": "🍎", "name": "apple", "keywords": ["fruit", "mac", "school"] }, - { "category": "food_and_drink", "char": "🍐", "name": "pear", "keywords": ["fruit", "nature", "food"] }, - { "category": "food_and_drink", "char": "🍊", "name": "tangerine", "keywords": ["food", "fruit", "nature", "orange"] }, - { "category": "food_and_drink", "char": "🍋", "name": "lemon", "keywords": ["fruit", "nature"] }, - { "category": "food_and_drink", "char": "🍌", "name": "banana", "keywords": ["fruit", "food", "monkey"] }, - { "category": "food_and_drink", "char": "🍉", "name": "watermelon", "keywords": ["fruit", "food", "picnic", "summer"] }, - { "category": "food_and_drink", "char": "🍇", "name": "grapes", "keywords": ["fruit", "food", "wine"] }, - { "category": "food_and_drink", "char": "🍓", "name": "strawberry", "keywords": ["fruit", "food", "nature"] }, - { "category": "food_and_drink", "char": "🍈", "name": "melon", "keywords": ["fruit", "nature", "food"] }, - { "category": "food_and_drink", "char": "🍒", "name": "cherries", "keywords": ["food", "fruit"] }, - { "category": "food_and_drink", "char": "🍑", "name": "peach", "keywords": ["fruit", "nature", "food"] }, - { "category": "food_and_drink", "char": "🍍", "name": "pineapple", "keywords": ["fruit", "nature", "food"] }, - { "category": "food_and_drink", "char": "🥥", "name": "coconut", "keywords": ["fruit", "nature", "food", "palm"] }, - { "category": "food_and_drink", "char": "🥝", "name": "kiwi_fruit", "keywords": ["fruit", "food"] }, - { "category": "food_and_drink", "char": "🥭", "name": "mango", "keywords": ["fruit", "food", "tropical"] }, - { "category": "food_and_drink", "char": "🥑", "name": "avocado", "keywords": ["fruit", "food"] }, - { "category": "food_and_drink", "char": "🥦", "name": "broccoli", "keywords": ["fruit", "food", "vegetable"] }, - { "category": "food_and_drink", "char": "🍅", "name": "tomato", "keywords": ["fruit", "vegetable", "nature", "food"] }, - { "category": "food_and_drink", "char": "🍆", "name": "eggplant", "keywords": ["vegetable", "nature", "food", "aubergine"] }, - { "category": "food_and_drink", "char": "🥒", "name": "cucumber", "keywords": ["fruit", "food", "pickle"] }, - { "category": "food_and_drink", "char": "🫐", "name": "blueberries", "keywords": ["fruit", "food"] }, - { "category": "food_and_drink", "char": "🫒", "name": "olive", "keywords": ["fruit", "food"] }, - { "category": "food_and_drink", "char": "🫑", "name": "bell_pepper", "keywords": ["fruit", "food"] }, - { "category": "food_and_drink", "char": "🥕", "name": "carrot", "keywords": ["vegetable", "food", "orange"] }, - { "category": "food_and_drink", "char": "🌶", "name": "hot_pepper", "keywords": ["food", "spicy", "chilli", "chili"] }, - { "category": "food_and_drink", "char": "🥔", "name": "potato", "keywords": ["food", "tuber", "vegatable", "starch"] }, - { "category": "food_and_drink", "char": "🌽", "name": "corn", "keywords": ["food", "vegetable", "plant"] }, - { "category": "food_and_drink", "char": "🥬", "name": "leafy_greens", "keywords": ["food", "vegetable", "plant", "bok choy", "cabbage", "kale", "lettuce"] }, - { "category": "food_and_drink", "char": "🍠", "name": "sweet_potato", "keywords": ["food", "nature"] }, - { "category": "food_and_drink", "char": "🥜", "name": "peanuts", "keywords": ["food", "nut"] }, - { "category": "food_and_drink", "char": "🧄", "name": "garlic", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🧅", "name": "onion", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🍯", "name": "honey_pot", "keywords": ["bees", "sweet", "kitchen"] }, - { "category": "food_and_drink", "char": "🥐", "name": "croissant", "keywords": ["food", "bread", "french"] }, - { "category": "food_and_drink", "char": "🍞", "name": "bread", "keywords": ["food", "wheat", "breakfast", "toast"] }, - { "category": "food_and_drink", "char": "🥖", "name": "baguette_bread", "keywords": ["food", "bread", "french"] }, - { "category": "food_and_drink", "char": "🥯", "name": "bagel", "keywords": ["food", "bread", "bakery", "schmear"] }, - { "category": "food_and_drink", "char": "🥨", "name": "pretzel", "keywords": ["food", "bread", "twisted"] }, - { "category": "food_and_drink", "char": "🧀", "name": "cheese", "keywords": ["food", "chadder"] }, - { "category": "food_and_drink", "char": "🥚", "name": "egg", "keywords": ["food", "chicken", "breakfast"] }, - { "category": "food_and_drink", "char": "🥓", "name": "bacon", "keywords": ["food", "breakfast", "pork", "pig", "meat"] }, - { "category": "food_and_drink", "char": "🥩", "name": "steak", "keywords": ["food", "cow", "meat", "cut", "chop", "lambchop", "porkchop"] }, - { "category": "food_and_drink", "char": "🥞", "name": "pancakes", "keywords": ["food", "breakfast", "flapjacks", "hotcakes"] }, - { "category": "food_and_drink", "char": "🍗", "name": "poultry_leg", "keywords": ["food", "meat", "drumstick", "bird", "chicken", "turkey"] }, - { "category": "food_and_drink", "char": "🍖", "name": "meat_on_bone", "keywords": ["good", "food", "drumstick"] }, - { "category": "food_and_drink", "char": "🦴", "name": "bone", "keywords": ["skeleton"] }, - { "category": "food_and_drink", "char": "🍤", "name": "fried_shrimp", "keywords": ["food", "animal", "appetizer", "summer"] }, - { "category": "food_and_drink", "char": "🍳", "name": "fried_egg", "keywords": ["food", "breakfast", "kitchen", "egg"] }, - { "category": "food_and_drink", "char": "🍔", "name": "hamburger", "keywords": ["meat", "fast food", "beef", "cheeseburger", "mcdonalds", "burger king"] }, - { "category": "food_and_drink", "char": "🍟", "name": "fries", "keywords": ["chips", "snack", "fast food"] }, - { "category": "food_and_drink", "char": "🥙", "name": "stuffed_flatbread", "keywords": ["food", "flatbread", "stuffed", "gyro"] }, - { "category": "food_and_drink", "char": "🌭", "name": "hotdog", "keywords": ["food", "frankfurter"] }, - { "category": "food_and_drink", "char": "🍕", "name": "pizza", "keywords": ["food", "party"] }, - { "category": "food_and_drink", "char": "🥪", "name": "sandwich", "keywords": ["food", "lunch", "bread"] }, - { "category": "food_and_drink", "char": "🥫", "name": "canned_food", "keywords": ["food", "soup"] }, - { "category": "food_and_drink", "char": "🍝", "name": "spaghetti", "keywords": ["food", "italian", "noodle"] }, - { "category": "food_and_drink", "char": "🌮", "name": "taco", "keywords": ["food", "mexican"] }, - { "category": "food_and_drink", "char": "🌯", "name": "burrito", "keywords": ["food", "mexican"] }, - { "category": "food_and_drink", "char": "🥗", "name": "green_salad", "keywords": ["food", "healthy", "lettuce"] }, - { "category": "food_and_drink", "char": "🥘", "name": "shallow_pan_of_food", "keywords": ["food", "cooking", "casserole", "paella"] }, - { "category": "food_and_drink", "char": "🍜", "name": "ramen", "keywords": ["food", "japanese", "noodle", "chopsticks"] }, - { "category": "food_and_drink", "char": "🍲", "name": "stew", "keywords": ["food", "meat", "soup"] }, - { "category": "food_and_drink", "char": "🍥", "name": "fish_cake", "keywords": ["food", "japan", "sea", "beach", "narutomaki", "pink", "swirl", "kamaboko", "surimi", "ramen"] }, - { "category": "food_and_drink", "char": "🥠", "name": "fortune_cookie", "keywords": ["food", "prophecy"] }, - { "category": "food_and_drink", "char": "🍣", "name": "sushi", "keywords": ["food", "fish", "japanese", "rice"] }, - { "category": "food_and_drink", "char": "🍱", "name": "bento", "keywords": ["food", "japanese", "box"] }, - { "category": "food_and_drink", "char": "🍛", "name": "curry", "keywords": ["food", "spicy", "hot", "indian"] }, - { "category": "food_and_drink", "char": "🍙", "name": "rice_ball", "keywords": ["food", "japanese"] }, - { "category": "food_and_drink", "char": "🍚", "name": "rice", "keywords": ["food", "china", "asian"] }, - { "category": "food_and_drink", "char": "🍘", "name": "rice_cracker", "keywords": ["food", "japanese"] }, - { "category": "food_and_drink", "char": "🍢", "name": "oden", "keywords": ["food", "japanese"] }, - { "category": "food_and_drink", "char": "🍡", "name": "dango", "keywords": ["food", "dessert", "sweet", "japanese", "barbecue", "meat"] }, - { "category": "food_and_drink", "char": "🍧", "name": "shaved_ice", "keywords": ["hot", "dessert", "summer"] }, - { "category": "food_and_drink", "char": "🍨", "name": "ice_cream", "keywords": ["food", "hot", "dessert"] }, - { "category": "food_and_drink", "char": "🍦", "name": "icecream", "keywords": ["food", "hot", "dessert", "summer"] }, - { "category": "food_and_drink", "char": "🥧", "name": "pie", "keywords": ["food", "dessert", "pastry"] }, - { "category": "food_and_drink", "char": "🍰", "name": "cake", "keywords": ["food", "dessert"] }, - { "category": "food_and_drink", "char": "🧁", "name": "cupcake", "keywords": ["food", "dessert", "bakery", "sweet"] }, - { "category": "food_and_drink", "char": "🥮", "name": "moon_cake", "keywords": ["food", "autumn"] }, - { "category": "food_and_drink", "char": "🎂", "name": "birthday", "keywords": ["food", "dessert", "cake"] }, - { "category": "food_and_drink", "char": "🍮", "name": "custard", "keywords": ["dessert", "food"] }, - { "category": "food_and_drink", "char": "🍬", "name": "candy", "keywords": ["snack", "dessert", "sweet", "lolly"] }, - { "category": "food_and_drink", "char": "🍭", "name": "lollipop", "keywords": ["food", "snack", "candy", "sweet"] }, - { "category": "food_and_drink", "char": "🍫", "name": "chocolate_bar", "keywords": ["food", "snack", "dessert", "sweet"] }, - { "category": "food_and_drink", "char": "🍿", "name": "popcorn", "keywords": ["food", "movie theater", "films", "snack"] }, - { "category": "food_and_drink", "char": "🥟", "name": "dumpling", "keywords": ["food", "empanada", "pierogi", "potsticker"] }, - { "category": "food_and_drink", "char": "🍩", "name": "doughnut", "keywords": ["food", "dessert", "snack", "sweet", "donut"] }, - { "category": "food_and_drink", "char": "🍪", "name": "cookie", "keywords": ["food", "snack", "oreo", "chocolate", "sweet", "dessert"] }, - { "category": "food_and_drink", "char": "🧇", "name": "waffle", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🧆", "name": "falafel", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🧈", "name": "butter", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🦪", "name": "oyster", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🫓", "name": "flatbread", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🫔", "name": "tamale", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🫕", "name": "fondue", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🥛", "name": "milk_glass", "keywords": ["beverage", "drink", "cow"] }, - { "category": "food_and_drink", "char": "🍺", "name": "beer", "keywords": ["relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"] }, - { "category": "food_and_drink", "char": "🍻", "name": "beers", "keywords": ["relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"] }, - { "category": "food_and_drink", "char": "🥂", "name": "clinking_glasses", "keywords": ["beverage", "drink", "party", "alcohol", "celebrate", "cheers", "wine", "champagne", "toast"] }, - { "category": "food_and_drink", "char": "🍷", "name": "wine_glass", "keywords": ["drink", "beverage", "drunk", "alcohol", "booze"] }, - { "category": "food_and_drink", "char": "🥃", "name": "tumbler_glass", "keywords": ["drink", "beverage", "drunk", "alcohol", "liquor", "booze", "bourbon", "scotch", "whisky", "glass", "shot"] }, - { "category": "food_and_drink", "char": "🍸", "name": "cocktail", "keywords": ["drink", "drunk", "alcohol", "beverage", "booze", "mojito"] }, - { "category": "food_and_drink", "char": "🍹", "name": "tropical_drink", "keywords": ["beverage", "cocktail", "summer", "beach", "alcohol", "booze", "mojito"] }, - { "category": "food_and_drink", "char": "🍾", "name": "champagne", "keywords": ["drink", "wine", "bottle", "celebration"] }, - { "category": "food_and_drink", "char": "🍶", "name": "sake", "keywords": ["wine", "drink", "drunk", "beverage", "japanese", "alcohol", "booze"] }, - { "category": "food_and_drink", "char": "🍵", "name": "tea", "keywords": ["drink", "bowl", "breakfast", "green", "british"] }, - { "category": "food_and_drink", "char": "🥤", "name": "cup_with_straw", "keywords": ["drink", "soda"] }, - { "category": "food_and_drink", "char": "☕", "name": "coffee", "keywords": ["beverage", "caffeine", "latte", "espresso"] }, - { "category": "food_and_drink", "char": "🫖", "name": "teapot", "keywords": [] }, - { "category": "food_and_drink", "char": "🧋", "name": "bubble_tea", "keywords": ["tapioca"] }, - { "category": "food_and_drink", "char": "🍼", "name": "baby_bottle", "keywords": ["food", "container", "milk"] }, - { "category": "food_and_drink", "char": "🧃", "name": "beverage_box", "keywords": ["food", "drink"] }, - { "category": "food_and_drink", "char": "🧉", "name": "mate", "keywords": ["food", "drink"] }, - { "category": "food_and_drink", "char": "🧊", "name": "ice_cube", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "🧂", "name": "salt", "keywords": ["condiment", "shaker"] }, - { "category": "food_and_drink", "char": "🥄", "name": "spoon", "keywords": ["cutlery", "kitchen", "tableware"] }, - { "category": "food_and_drink", "char": "🍴", "name": "fork_and_knife", "keywords": ["cutlery", "kitchen"] }, - { "category": "food_and_drink", "char": "🍽", "name": "plate_with_cutlery", "keywords": ["food", "eat", "meal", "lunch", "dinner", "restaurant"] }, - { "category": "food_and_drink", "char": "🥣", "name": "bowl_with_spoon", "keywords": ["food", "breakfast", "cereal", "oatmeal", "porridge"] }, - { "category": "food_and_drink", "char": "🥡", "name": "takeout_box", "keywords": ["food", "leftovers"] }, - { "category": "food_and_drink", "char": "🥢", "name": "chopsticks", "keywords": ["food"] }, - { "category": "food_and_drink", "char": "\uD83E\uDED7", "name": "pouring_liquid", "keywords": [] }, - { "category": "food_and_drink", "char": "\uD83E\uDED8", "name": "beans", "keywords": [] }, - { "category": "food_and_drink", "char": "\uD83E\uDED9", "name": "jar", "keywords": [] }, - { "category": "activity", "char": "⚽", "name": "soccer", "keywords": ["sports", "football"] }, - { "category": "activity", "char": "🏀", "name": "basketball", "keywords": ["sports", "balls", "NBA"] }, - { "category": "activity", "char": "🏈", "name": "football", "keywords": ["sports", "balls", "NFL"] }, - { "category": "activity", "char": "⚾", "name": "baseball", "keywords": ["sports", "balls"] }, - { "category": "activity", "char": "🥎", "name": "softball", "keywords": ["sports", "balls"] }, - { "category": "activity", "char": "🎾", "name": "tennis", "keywords": ["sports", "balls", "green"] }, - { "category": "activity", "char": "🏐", "name": "volleyball", "keywords": ["sports", "balls"] }, - { "category": "activity", "char": "🏉", "name": "rugby_football", "keywords": ["sports", "team"] }, - { "category": "activity", "char": "🥏", "name": "flying_disc", "keywords": ["sports", "frisbee", "ultimate"] }, - { "category": "activity", "char": "🎱", "name": "8ball", "keywords": ["pool", "hobby", "game", "luck", "magic"] }, - { "category": "activity", "char": "⛳", "name": "golf", "keywords": ["sports", "business", "flag", "hole", "summer"] }, - { "category": "activity", "char": "🏌️♀️", "name": "golfing_woman", "keywords": ["sports", "business", "woman", "female"] }, - { "category": "activity", "char": "🏌", "name": "golfing_man", "keywords": ["sports", "business"] }, - { "category": "activity", "char": "🏓", "name": "ping_pong", "keywords": ["sports", "pingpong"] }, - { "category": "activity", "char": "🏸", "name": "badminton", "keywords": ["sports"] }, - { "category": "activity", "char": "🥅", "name": "goal_net", "keywords": ["sports"] }, - { "category": "activity", "char": "🏒", "name": "ice_hockey", "keywords": ["sports"] }, - { "category": "activity", "char": "🏑", "name": "field_hockey", "keywords": ["sports"] }, - { "category": "activity", "char": "🥍", "name": "lacrosse", "keywords": ["sports", "ball", "stick"] }, - { "category": "activity", "char": "🏏", "name": "cricket", "keywords": ["sports"] }, - { "category": "activity", "char": "🎿", "name": "ski", "keywords": ["sports", "winter", "cold", "snow"] }, - { "category": "activity", "char": "⛷", "name": "skier", "keywords": ["sports", "winter", "snow"] }, - { "category": "activity", "char": "🏂", "name": "snowboarder", "keywords": ["sports", "winter"] }, - { "category": "activity", "char": "🤺", "name": "person_fencing", "keywords": ["sports", "fencing", "sword"] }, - { "category": "activity", "char": "🤼♀️", "name": "women_wrestling", "keywords": ["sports", "wrestlers"] }, - { "category": "activity", "char": "🤼♂️", "name": "men_wrestling", "keywords": ["sports", "wrestlers"] }, - { "category": "activity", "char": "🤸♀️", "name": "woman_cartwheeling", "keywords": ["gymnastics"] }, - { "category": "activity", "char": "🤸♂️", "name": "man_cartwheeling", "keywords": ["gymnastics"] }, - { "category": "activity", "char": "🤾♀️", "name": "woman_playing_handball", "keywords": ["sports"] }, - { "category": "activity", "char": "🤾♂️", "name": "man_playing_handball", "keywords": ["sports"] }, - { "category": "activity", "char": "⛸", "name": "ice_skate", "keywords": ["sports"] }, - { "category": "activity", "char": "🥌", "name": "curling_stone", "keywords": ["sports"] }, - { "category": "activity", "char": "🛹", "name": "skateboard", "keywords": ["board"] }, - { "category": "activity", "char": "🛷", "name": "sled", "keywords": ["sleigh", "luge", "toboggan"] }, - { "category": "activity", "char": "🏹", "name": "bow_and_arrow", "keywords": ["sports"] }, - { "category": "activity", "char": "🎣", "name": "fishing_pole_and_fish", "keywords": ["food", "hobby", "summer"] }, - { "category": "activity", "char": "🥊", "name": "boxing_glove", "keywords": ["sports", "fighting"] }, - { "category": "activity", "char": "🥋", "name": "martial_arts_uniform", "keywords": ["judo", "karate", "taekwondo"] }, - { "category": "activity", "char": "🚣♀️", "name": "rowing_woman", "keywords": ["sports", "hobby", "water", "ship", "woman", "female"] }, - { "category": "activity", "char": "🚣", "name": "rowing_man", "keywords": ["sports", "hobby", "water", "ship"] }, - { "category": "activity", "char": "🧗♀️", "name": "climbing_woman", "keywords": ["sports", "hobby", "woman", "female", "rock"] }, - { "category": "activity", "char": "🧗♂️", "name": "climbing_man", "keywords": ["sports", "hobby", "man", "male", "rock"] }, - { "category": "activity", "char": "🏊♀️", "name": "swimming_woman", "keywords": ["sports", "exercise", "human", "athlete", "water", "summer", "woman", "female"] }, - { "category": "activity", "char": "🏊", "name": "swimming_man", "keywords": ["sports", "exercise", "human", "athlete", "water", "summer"] }, - { "category": "activity", "char": "🤽♀️", "name": "woman_playing_water_polo", "keywords": ["sports", "pool"] }, - { "category": "activity", "char": "🤽♂️", "name": "man_playing_water_polo", "keywords": ["sports", "pool"] }, - { "category": "activity", "char": "🧘♀️", "name": "woman_in_lotus_position", "keywords": ["woman", "female", "meditation", "yoga", "serenity", "zen", "mindfulness"] }, - { "category": "activity", "char": "🧘♂️", "name": "man_in_lotus_position", "keywords": ["man", "male", "meditation", "yoga", "serenity", "zen", "mindfulness"] }, - { "category": "activity", "char": "🏄♀️", "name": "surfing_woman", "keywords": ["sports", "ocean", "sea", "summer", "beach", "woman", "female"] }, - { "category": "activity", "char": "🏄", "name": "surfing_man", "keywords": ["sports", "ocean", "sea", "summer", "beach"] }, - { "category": "activity", "char": "🛀", "name": "bath", "keywords": ["clean", "shower", "bathroom"] }, - { "category": "activity", "char": "⛹️♀️", "name": "basketball_woman", "keywords": ["sports", "human", "woman", "female"] }, - { "category": "activity", "char": "⛹", "name": "basketball_man", "keywords": ["sports", "human"] }, - { "category": "activity", "char": "🏋️♀️", "name": "weight_lifting_woman", "keywords": ["sports", "training", "exercise", "woman", "female"] }, - { "category": "activity", "char": "🏋", "name": "weight_lifting_man", "keywords": ["sports", "training", "exercise"] }, - { "category": "activity", "char": "🚴♀️", "name": "biking_woman", "keywords": ["sports", "bike", "exercise", "hipster", "woman", "female"] }, - { "category": "activity", "char": "🚴", "name": "biking_man", "keywords": ["sports", "bike", "exercise", "hipster"] }, - { "category": "activity", "char": "🚵♀️", "name": "mountain_biking_woman", "keywords": ["transportation", "sports", "human", "race", "bike", "woman", "female"] }, - { "category": "activity", "char": "🚵", "name": "mountain_biking_man", "keywords": ["transportation", "sports", "human", "race", "bike"] }, - { "category": "activity", "char": "🏇", "name": "horse_racing", "keywords": ["animal", "betting", "competition", "gambling", "luck"] }, - { "category": "activity", "char": "🤿", "name": "diving_mask", "keywords": ["sports"] }, - { "category": "activity", "char": "🪀", "name": "yo_yo", "keywords": ["sports"] }, - { "category": "activity", "char": "🪁", "name": "kite", "keywords": ["sports"] }, - { "category": "activity", "char": "🦺", "name": "safety_vest", "keywords": ["sports"] }, - { "category": "activity", "char": "🪡", "name": "sewing_needle", "keywords": [] }, - { "category": "activity", "char": "🪢", "name": "knot", "keywords": [] }, - { "category": "activity", "char": "🕴", "name": "business_suit_levitating", "keywords": ["suit", "business", "levitate", "hover", "jump"] }, - { "category": "activity", "char": "🏆", "name": "trophy", "keywords": ["win", "award", "contest", "place", "ftw", "ceremony"] }, - { "category": "activity", "char": "🎽", "name": "running_shirt_with_sash", "keywords": ["play", "pageant"] }, - { "category": "activity", "char": "🏅", "name": "medal_sports", "keywords": ["award", "winning"] }, - { "category": "activity", "char": "🎖", "name": "medal_military", "keywords": ["award", "winning", "army"] }, - { "category": "activity", "char": "🥇", "name": "1st_place_medal", "keywords": ["award", "winning", "first"] }, - { "category": "activity", "char": "🥈", "name": "2nd_place_medal", "keywords": ["award", "second"] }, - { "category": "activity", "char": "🥉", "name": "3rd_place_medal", "keywords": ["award", "third"] }, - { "category": "activity", "char": "🎗", "name": "reminder_ribbon", "keywords": ["sports", "cause", "support", "awareness"] }, - { "category": "activity", "char": "🏵", "name": "rosette", "keywords": ["flower", "decoration", "military"] }, - { "category": "activity", "char": "🎫", "name": "ticket", "keywords": ["event", "concert", "pass"] }, - { "category": "activity", "char": "🎟", "name": "tickets", "keywords": ["sports", "concert", "entrance"] }, - { "category": "activity", "char": "🎭", "name": "performing_arts", "keywords": ["acting", "theater", "drama"] }, - { "category": "activity", "char": "🎨", "name": "art", "keywords": ["design", "paint", "draw", "colors"] }, - { "category": "activity", "char": "🎪", "name": "circus_tent", "keywords": ["festival", "carnival", "party"] }, - { "category": "activity", "char": "🤹♀️", "name": "woman_juggling", "keywords": ["juggle", "balance", "skill", "multitask"] }, - { "category": "activity", "char": "🤹♂️", "name": "man_juggling", "keywords": ["juggle", "balance", "skill", "multitask"] }, - { "category": "activity", "char": "🎤", "name": "microphone", "keywords": ["sound", "music", "PA", "sing", "talkshow"] }, - { "category": "activity", "char": "🎧", "name": "headphones", "keywords": ["music", "score", "gadgets"] }, - { "category": "activity", "char": "🎼", "name": "musical_score", "keywords": ["treble", "clef", "compose"] }, - { "category": "activity", "char": "🎹", "name": "musical_keyboard", "keywords": ["piano", "instrument", "compose"] }, - { "category": "activity", "char": "🥁", "name": "drum", "keywords": ["music", "instrument", "drumsticks", "snare"] }, - { "category": "activity", "char": "🎷", "name": "saxophone", "keywords": ["music", "instrument", "jazz", "blues"] }, - { "category": "activity", "char": "🎺", "name": "trumpet", "keywords": ["music", "brass"] }, - { "category": "activity", "char": "🎸", "name": "guitar", "keywords": ["music", "instrument"] }, - { "category": "activity", "char": "🎻", "name": "violin", "keywords": ["music", "instrument", "orchestra", "symphony"] }, - { "category": "activity", "char": "🪕", "name": "banjo", "keywords": ["music", "instrument"] }, - { "category": "activity", "char": "🪗", "name": "accordion", "keywords": ["music", "instrument"] }, - { "category": "activity", "char": "🪘", "name": "long_drum", "keywords": ["music", "instrument"] }, - { "category": "activity", "char": "🎬", "name": "clapper", "keywords": ["movie", "film", "record"] }, - { "category": "activity", "char": "🎮", "name": "video_game", "keywords": ["play", "console", "PS4", "controller"] }, - { "category": "activity", "char": "👾", "name": "space_invader", "keywords": ["game", "arcade", "play"] }, - { "category": "activity", "char": "🎯", "name": "dart", "keywords": ["game", "play", "bar", "target", "bullseye"] }, - { "category": "activity", "char": "🎲", "name": "game_die", "keywords": ["dice", "random", "tabletop", "play", "luck"] }, - { "category": "activity", "char": "♟️", "name": "chess_pawn", "keywords": ["expendable"] }, - { "category": "activity", "char": "🎰", "name": "slot_machine", "keywords": ["bet", "gamble", "vegas", "fruit machine", "luck", "casino"] }, - { "category": "activity", "char": "🧩", "name": "jigsaw", "keywords": ["interlocking", "puzzle", "piece"] }, - { "category": "activity", "char": "🎳", "name": "bowling", "keywords": ["sports", "fun", "play"] }, - { "category": "activity", "char": "🪄", "name": "magic_wand", "keywords": [] }, - { "category": "activity", "char": "🪅", "name": "pinata", "keywords": [] }, - { "category": "activity", "char": "🪆", "name": "nesting_dolls", "keywords": [] }, - { "category": "activity", "char": "\uD83E\uDEAC", "name": "hamsa", "keywords": [] }, - { "category": "activity", "char": "\uD83E\uDEA9", "name": "mirror_ball", "keywords": [] }, - { "category": "travel_and_places", "char": "🚗", "name": "red_car", "keywords": ["red", "transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚕", "name": "taxi", "keywords": ["uber", "vehicle", "cars", "transportation"] }, - { "category": "travel_and_places", "char": "🚙", "name": "blue_car", "keywords": ["transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚌", "name": "bus", "keywords": ["car", "vehicle", "transportation"] }, - { "category": "travel_and_places", "char": "🚎", "name": "trolleybus", "keywords": ["bart", "transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🏎", "name": "racing_car", "keywords": ["sports", "race", "fast", "formula", "f1"] }, - { "category": "travel_and_places", "char": "🚓", "name": "police_car", "keywords": ["vehicle", "cars", "transportation", "law", "legal", "enforcement"] }, - { "category": "travel_and_places", "char": "🚑", "name": "ambulance", "keywords": ["health", "911", "hospital"] }, - { "category": "travel_and_places", "char": "🚒", "name": "fire_engine", "keywords": ["transportation", "cars", "vehicle"] }, - { "category": "travel_and_places", "char": "🚐", "name": "minibus", "keywords": ["vehicle", "car", "transportation"] }, - { "category": "travel_and_places", "char": "🚚", "name": "truck", "keywords": ["cars", "transportation"] }, - { "category": "travel_and_places", "char": "🚛", "name": "articulated_lorry", "keywords": ["vehicle", "cars", "transportation", "express"] }, - { "category": "travel_and_places", "char": "🚜", "name": "tractor", "keywords": ["vehicle", "car", "farming", "agriculture"] }, - { "category": "travel_and_places", "char": "🛴", "name": "kick_scooter", "keywords": ["vehicle", "kick", "razor"] }, - { "category": "travel_and_places", "char": "🏍", "name": "motorcycle", "keywords": ["race", "sports", "fast"] }, - { "category": "travel_and_places", "char": "🚲", "name": "bike", "keywords": ["sports", "bicycle", "exercise", "hipster"] }, - { "category": "travel_and_places", "char": "🛵", "name": "motor_scooter", "keywords": ["vehicle", "vespa", "sasha"] }, - { "category": "travel_and_places", "char": "🦽", "name": "manual_wheelchair", "keywords": ["vehicle"] }, - { "category": "travel_and_places", "char": "🦼", "name": "motorized_wheelchair", "keywords": ["vehicle"] }, - { "category": "travel_and_places", "char": "🛺", "name": "auto_rickshaw", "keywords": ["vehicle"] }, - { "category": "travel_and_places", "char": "🪂", "name": "parachute", "keywords": ["vehicle"] }, - { "category": "travel_and_places", "char": "🚨", "name": "rotating_light", "keywords": ["police", "ambulance", "911", "emergency", "alert", "error", "pinged", "law", "legal"] }, - { "category": "travel_and_places", "char": "🚔", "name": "oncoming_police_car", "keywords": ["vehicle", "law", "legal", "enforcement", "911"] }, - { "category": "travel_and_places", "char": "🚍", "name": "oncoming_bus", "keywords": ["vehicle", "transportation"] }, - { "category": "travel_and_places", "char": "🚘", "name": "oncoming_automobile", "keywords": ["car", "vehicle", "transportation"] }, - { "category": "travel_and_places", "char": "🚖", "name": "oncoming_taxi", "keywords": ["vehicle", "cars", "uber"] }, - { "category": "travel_and_places", "char": "🚡", "name": "aerial_tramway", "keywords": ["transportation", "vehicle", "ski"] }, - { "category": "travel_and_places", "char": "🚠", "name": "mountain_cableway", "keywords": ["transportation", "vehicle", "ski"] }, - { "category": "travel_and_places", "char": "🚟", "name": "suspension_railway", "keywords": ["vehicle", "transportation"] }, - { "category": "travel_and_places", "char": "🚃", "name": "railway_car", "keywords": ["transportation", "vehicle", "train"] }, - { "category": "travel_and_places", "char": "🚋", "name": "train", "keywords": ["transportation", "vehicle", "carriage", "public", "travel"] }, - { "category": "travel_and_places", "char": "🚝", "name": "monorail", "keywords": ["transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚄", "name": "bullettrain_side", "keywords": ["transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚅", "name": "bullettrain_front", "keywords": ["transportation", "vehicle", "speed", "fast", "public", "travel"] }, - { "category": "travel_and_places", "char": "🚈", "name": "light_rail", "keywords": ["transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚞", "name": "mountain_railway", "keywords": ["transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚂", "name": "steam_locomotive", "keywords": ["transportation", "vehicle", "train"] }, - { "category": "travel_and_places", "char": "🚆", "name": "train2", "keywords": ["transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚇", "name": "metro", "keywords": ["transportation", "blue-square", "mrt", "underground", "tube"] }, - { "category": "travel_and_places", "char": "🚊", "name": "tram", "keywords": ["transportation", "vehicle"] }, - { "category": "travel_and_places", "char": "🚉", "name": "station", "keywords": ["transportation", "vehicle", "public"] }, - { "category": "travel_and_places", "char": "🛸", "name": "flying_saucer", "keywords": ["transportation", "vehicle", "ufo"] }, - { "category": "travel_and_places", "char": "🚁", "name": "helicopter", "keywords": ["transportation", "vehicle", "fly"] }, - { "category": "travel_and_places", "char": "🛩", "name": "small_airplane", "keywords": ["flight", "transportation", "fly", "vehicle"] }, - { "category": "travel_and_places", "char": "✈️", "name": "airplane", "keywords": ["vehicle", "transportation", "flight", "fly"] }, - { "category": "travel_and_places", "char": "🛫", "name": "flight_departure", "keywords": ["airport", "flight", "landing"] }, - { "category": "travel_and_places", "char": "🛬", "name": "flight_arrival", "keywords": ["airport", "flight", "boarding"] }, - { "category": "travel_and_places", "char": "⛵", "name": "sailboat", "keywords": ["ship", "summer", "transportation", "water", "sailing"] }, - { "category": "travel_and_places", "char": "🛥", "name": "motor_boat", "keywords": ["ship"] }, - { "category": "travel_and_places", "char": "🚤", "name": "speedboat", "keywords": ["ship", "transportation", "vehicle", "summer"] }, - { "category": "travel_and_places", "char": "⛴", "name": "ferry", "keywords": ["boat", "ship", "yacht"] }, - { "category": "travel_and_places", "char": "🛳", "name": "passenger_ship", "keywords": ["yacht", "cruise", "ferry"] }, - { "category": "travel_and_places", "char": "🚀", "name": "rocket", "keywords": ["launch", "ship", "staffmode", "NASA", "outer space", "outer_space", "fly"] }, - { "category": "travel_and_places", "char": "🛰", "name": "artificial_satellite", "keywords": ["communication", "gps", "orbit", "spaceflight", "NASA", "ISS"] }, - { "category": "travel_and_places", "char": "🛻", "name": "pickup_truck", "keywords": ["car"] }, - { "category": "travel_and_places", "char": "🛼", "name": "roller_skate", "keywords": [] }, - { "category": "travel_and_places", "char": "💺", "name": "seat", "keywords": ["sit", "airplane", "transport", "bus", "flight", "fly"] }, - { "category": "travel_and_places", "char": "🛶", "name": "canoe", "keywords": ["boat", "paddle", "water", "ship"] }, - { "category": "travel_and_places", "char": "⚓", "name": "anchor", "keywords": ["ship", "ferry", "sea", "boat"] }, - { "category": "travel_and_places", "char": "🚧", "name": "construction", "keywords": ["wip", "progress", "caution", "warning"] }, - { "category": "travel_and_places", "char": "⛽", "name": "fuelpump", "keywords": ["gas station", "petroleum"] }, - { "category": "travel_and_places", "char": "🚏", "name": "busstop", "keywords": ["transportation", "wait"] }, - { "category": "travel_and_places", "char": "🚦", "name": "vertical_traffic_light", "keywords": ["transportation", "driving"] }, - { "category": "travel_and_places", "char": "🚥", "name": "traffic_light", "keywords": ["transportation", "signal"] }, - { "category": "travel_and_places", "char": "🏁", "name": "checkered_flag", "keywords": ["contest", "finishline", "race", "gokart"] }, - { "category": "travel_and_places", "char": "🚢", "name": "ship", "keywords": ["transportation", "titanic", "deploy"] }, - { "category": "travel_and_places", "char": "🎡", "name": "ferris_wheel", "keywords": ["photo", "carnival", "londoneye"] }, - { "category": "travel_and_places", "char": "🎢", "name": "roller_coaster", "keywords": ["carnival", "playground", "photo", "fun"] }, - { "category": "travel_and_places", "char": "🎠", "name": "carousel_horse", "keywords": ["photo", "carnival"] }, - { "category": "travel_and_places", "char": "🏗", "name": "building_construction", "keywords": ["wip", "working", "progress"] }, - { "category": "travel_and_places", "char": "🌁", "name": "foggy", "keywords": ["photo", "mountain"] }, - { "category": "travel_and_places", "char": "🏭", "name": "factory", "keywords": ["building", "industry", "pollution", "smoke"] }, - { "category": "travel_and_places", "char": "⛲", "name": "fountain", "keywords": ["photo", "summer", "water", "fresh"] }, - { "category": "travel_and_places", "char": "🎑", "name": "rice_scene", "keywords": ["photo", "japan", "asia", "tsukimi"] }, - { "category": "travel_and_places", "char": "⛰", "name": "mountain", "keywords": ["photo", "nature", "environment"] }, - { "category": "travel_and_places", "char": "🏔", "name": "mountain_snow", "keywords": ["photo", "nature", "environment", "winter", "cold"] }, - { "category": "travel_and_places", "char": "🗻", "name": "mount_fuji", "keywords": ["photo", "mountain", "nature", "japanese"] }, - { "category": "travel_and_places", "char": "🌋", "name": "volcano", "keywords": ["photo", "nature", "disaster"] }, - { "category": "travel_and_places", "char": "🗾", "name": "japan", "keywords": ["nation", "country", "japanese", "asia"] }, - { "category": "travel_and_places", "char": "🏕", "name": "camping", "keywords": ["photo", "outdoors", "tent"] }, - { "category": "travel_and_places", "char": "⛺", "name": "tent", "keywords": ["photo", "camping", "outdoors"] }, - { "category": "travel_and_places", "char": "🏞", "name": "national_park", "keywords": ["photo", "environment", "nature"] }, - { "category": "travel_and_places", "char": "🛣", "name": "motorway", "keywords": ["road", "cupertino", "interstate", "highway"] }, - { "category": "travel_and_places", "char": "🛤", "name": "railway_track", "keywords": ["train", "transportation"] }, - { "category": "travel_and_places", "char": "🌅", "name": "sunrise", "keywords": ["morning", "view", "vacation", "photo"] }, - { "category": "travel_and_places", "char": "🌄", "name": "sunrise_over_mountains", "keywords": ["view", "vacation", "photo"] }, - { "category": "travel_and_places", "char": "🏜", "name": "desert", "keywords": ["photo", "warm", "saharah"] }, - { "category": "travel_and_places", "char": "🏖", "name": "beach_umbrella", "keywords": ["weather", "summer", "sunny", "sand", "mojito"] }, - { "category": "travel_and_places", "char": "🏝", "name": "desert_island", "keywords": ["photo", "tropical", "mojito"] }, - { "category": "travel_and_places", "char": "🌇", "name": "city_sunrise", "keywords": ["photo", "good morning", "dawn"] }, - { "category": "travel_and_places", "char": "🌆", "name": "city_sunset", "keywords": ["photo", "evening", "sky", "buildings"] }, - { "category": "travel_and_places", "char": "🏙", "name": "cityscape", "keywords": ["photo", "night life", "urban"] }, - { "category": "travel_and_places", "char": "🌃", "name": "night_with_stars", "keywords": ["evening", "city", "downtown"] }, - { "category": "travel_and_places", "char": "🌉", "name": "bridge_at_night", "keywords": ["photo", "sanfrancisco"] }, - { "category": "travel_and_places", "char": "🌌", "name": "milky_way", "keywords": ["photo", "space", "stars"] }, - { "category": "travel_and_places", "char": "🌠", "name": "stars", "keywords": ["night", "photo"] }, - { "category": "travel_and_places", "char": "🎇", "name": "sparkler", "keywords": ["stars", "night", "shine"] }, - { "category": "travel_and_places", "char": "🎆", "name": "fireworks", "keywords": ["photo", "festival", "carnival", "congratulations"] }, - { "category": "travel_and_places", "char": "🌈", "name": "rainbow", "keywords": ["nature", "happy", "unicorn_face", "photo", "sky", "spring"] }, - { "category": "travel_and_places", "char": "🏘", "name": "houses", "keywords": ["buildings", "photo"] }, - { "category": "travel_and_places", "char": "🏰", "name": "european_castle", "keywords": ["building", "royalty", "history"] }, - { "category": "travel_and_places", "char": "🏯", "name": "japanese_castle", "keywords": ["photo", "building"] }, - { "category": "travel_and_places", "char": "🗼", "name": "tokyo_tower", "keywords": ["photo", "japanese"] }, - { "category": "travel_and_places", "char": "", "name": "shibuya_109", "keywords": ["photo", "japanese"] }, - { "category": "travel_and_places", "char": "🏟", "name": "stadium", "keywords": ["photo", "place", "sports", "concert", "venue"] }, - { "category": "travel_and_places", "char": "🗽", "name": "statue_of_liberty", "keywords": ["american", "newyork"] }, - { "category": "travel_and_places", "char": "🏠", "name": "house", "keywords": ["building", "home"] }, - { "category": "travel_and_places", "char": "🏡", "name": "house_with_garden", "keywords": ["home", "plant", "nature"] }, - { "category": "travel_and_places", "char": "🏚", "name": "derelict_house", "keywords": ["abandon", "evict", "broken", "building"] }, - { "category": "travel_and_places", "char": "🏢", "name": "office", "keywords": ["building", "bureau", "work"] }, - { "category": "travel_and_places", "char": "🏬", "name": "department_store", "keywords": ["building", "shopping", "mall"] }, - { "category": "travel_and_places", "char": "🏣", "name": "post_office", "keywords": ["building", "envelope", "communication"] }, - { "category": "travel_and_places", "char": "🏤", "name": "european_post_office", "keywords": ["building", "email"] }, - { "category": "travel_and_places", "char": "🏥", "name": "hospital", "keywords": ["building", "health", "surgery", "doctor"] }, - { "category": "travel_and_places", "char": "🏦", "name": "bank", "keywords": ["building", "money", "sales", "cash", "business", "enterprise"] }, - { "category": "travel_and_places", "char": "🏨", "name": "hotel", "keywords": ["building", "accomodation", "checkin"] }, - { "category": "travel_and_places", "char": "🏪", "name": "convenience_store", "keywords": ["building", "shopping", "groceries"] }, - { "category": "travel_and_places", "char": "🏫", "name": "school", "keywords": ["building", "student", "education", "learn", "teach"] }, - { "category": "travel_and_places", "char": "🏩", "name": "love_hotel", "keywords": ["like", "affection", "dating"] }, - { "category": "travel_and_places", "char": "💒", "name": "wedding", "keywords": ["love", "like", "affection", "couple", "marriage", "bride", "groom"] }, - { "category": "travel_and_places", "char": "🏛", "name": "classical_building", "keywords": ["art", "culture", "history"] }, - { "category": "travel_and_places", "char": "⛪", "name": "church", "keywords": ["building", "religion", "christ"] }, - { "category": "travel_and_places", "char": "🕌", "name": "mosque", "keywords": ["islam", "worship", "minaret"] }, - { "category": "travel_and_places", "char": "🕍", "name": "synagogue", "keywords": ["judaism", "worship", "temple", "jewish"] }, - { "category": "travel_and_places", "char": "🕋", "name": "kaaba", "keywords": ["mecca", "mosque", "islam"] }, - { "category": "travel_and_places", "char": "⛩", "name": "shinto_shrine", "keywords": ["temple", "japan", "kyoto"] }, - { "category": "travel_and_places", "char": "🛕", "name": "hindu_temple", "keywords": ["temple"] }, - { "category": "travel_and_places", "char": "🪨", "name": "rock", "keywords": [] }, - { "category": "travel_and_places", "char": "🪵", "name": "wood", "keywords": [] }, - { "category": "travel_and_places", "char": "🛖", "name": "hut", "keywords": [] }, - { "category": "travel_and_places", "char": "\uD83D\uDEDD", "name": "playground_slide", "keywords": [] }, - { "category": "travel_and_places", "char": "\uD83D\uDEDE", "name": "wheel", "keywords": [] }, - { "category": "travel_and_places", "char": "\uD83D\uDEDF", "name": "ring_buoy", "keywords": [] }, - { "category": "objects", "char": "⌚", "name": "watch", "keywords": ["time", "accessories"] }, - { "category": "objects", "char": "📱", "name": "iphone", "keywords": ["technology", "apple", "gadgets", "dial"] }, - { "category": "objects", "char": "📲", "name": "calling", "keywords": ["iphone", "incoming"] }, - { "category": "objects", "char": "💻", "name": "computer", "keywords": ["technology", "laptop", "screen", "display", "monitor"] }, - { "category": "objects", "char": "⌨", "name": "keyboard", "keywords": ["technology", "computer", "type", "input", "text"] }, - { "category": "objects", "char": "🖥", "name": "desktop_computer", "keywords": ["technology", "computing", "screen"] }, - { "category": "objects", "char": "🖨", "name": "printer", "keywords": ["paper", "ink"] }, - { "category": "objects", "char": "🖱", "name": "computer_mouse", "keywords": ["click"] }, - { "category": "objects", "char": "🖲", "name": "trackball", "keywords": ["technology", "trackpad"] }, - { "category": "objects", "char": "🕹", "name": "joystick", "keywords": ["game", "play"] }, - { "category": "objects", "char": "🗜", "name": "clamp", "keywords": ["tool"] }, - { "category": "objects", "char": "💽", "name": "minidisc", "keywords": ["technology", "record", "data", "disk", "90s"] }, - { "category": "objects", "char": "💾", "name": "floppy_disk", "keywords": ["oldschool", "technology", "save", "90s", "80s"] }, - { "category": "objects", "char": "💿", "name": "cd", "keywords": ["technology", "dvd", "disk", "disc", "90s"] }, - { "category": "objects", "char": "📀", "name": "dvd", "keywords": ["cd", "disk", "disc"] }, - { "category": "objects", "char": "📼", "name": "vhs", "keywords": ["record", "video", "oldschool", "90s", "80s"] }, - { "category": "objects", "char": "📷", "name": "camera", "keywords": ["gadgets", "photography"] }, - { "category": "objects", "char": "📸", "name": "camera_flash", "keywords": ["photography", "gadgets"] }, - { "category": "objects", "char": "📹", "name": "video_camera", "keywords": ["film", "record"] }, - { "category": "objects", "char": "🎥", "name": "movie_camera", "keywords": ["film", "record"] }, - { "category": "objects", "char": "📽", "name": "film_projector", "keywords": ["video", "tape", "record", "movie"] }, - { "category": "objects", "char": "🎞", "name": "film_strip", "keywords": ["movie"] }, - { "category": "objects", "char": "📞", "name": "telephone_receiver", "keywords": ["technology", "communication", "dial"] }, - { "category": "objects", "char": "☎️", "name": "phone", "keywords": ["technology", "communication", "dial", "telephone"] }, - { "category": "objects", "char": "📟", "name": "pager", "keywords": ["bbcall", "oldschool", "90s"] }, - { "category": "objects", "char": "📠", "name": "fax", "keywords": ["communication", "technology"] }, - { "category": "objects", "char": "📺", "name": "tv", "keywords": ["technology", "program", "oldschool", "show", "television"] }, - { "category": "objects", "char": "📻", "name": "radio", "keywords": ["communication", "music", "podcast", "program"] }, - { "category": "objects", "char": "🎙", "name": "studio_microphone", "keywords": ["sing", "recording", "artist", "talkshow"] }, - { "category": "objects", "char": "🎚", "name": "level_slider", "keywords": ["scale"] }, - { "category": "objects", "char": "🎛", "name": "control_knobs", "keywords": ["dial"] }, - { "category": "objects", "char": "🧭", "name": "compass", "keywords": ["magnetic", "navigation", "orienteering"] }, - { "category": "objects", "char": "⏱", "name": "stopwatch", "keywords": ["time", "deadline"] }, - { "category": "objects", "char": "⏲", "name": "timer_clock", "keywords": ["alarm"] }, - { "category": "objects", "char": "⏰", "name": "alarm_clock", "keywords": ["time", "wake"] }, - { "category": "objects", "char": "🕰", "name": "mantelpiece_clock", "keywords": ["time"] }, - { "category": "objects", "char": "⏳", "name": "hourglass_flowing_sand", "keywords": ["oldschool", "time", "countdown"] }, - { "category": "objects", "char": "⌛", "name": "hourglass", "keywords": ["time", "clock", "oldschool", "limit", "exam", "quiz", "test"] }, - { "category": "objects", "char": "📡", "name": "satellite", "keywords": ["communication", "future", "radio", "space"] }, - { "category": "objects", "char": "🔋", "name": "battery", "keywords": ["power", "energy", "sustain"] }, - { "category": "objects", "char": "\uD83E\uDEAB", "name": "battery", "keywords": [] }, - { "category": "objects", "char": "🔌", "name": "electric_plug", "keywords": ["charger", "power"] }, - { "category": "objects", "char": "💡", "name": "bulb", "keywords": ["light", "electricity", "idea"] }, - { "category": "objects", "char": "🔦", "name": "flashlight", "keywords": ["dark", "camping", "sight", "night"] }, - { "category": "objects", "char": "🕯", "name": "candle", "keywords": ["fire", "wax"] }, - { "category": "objects", "char": "🧯", "name": "fire_extinguisher", "keywords": ["quench"] }, - { "category": "objects", "char": "🗑", "name": "wastebasket", "keywords": ["bin", "trash", "rubbish", "garbage", "toss"] }, - { "category": "objects", "char": "🛢", "name": "oil_drum", "keywords": ["barrell"] }, - { "category": "objects", "char": "💸", "name": "money_with_wings", "keywords": ["dollar", "bills", "payment", "sale"] }, - { "category": "objects", "char": "💵", "name": "dollar", "keywords": ["money", "sales", "bill", "currency"] }, - { "category": "objects", "char": "💴", "name": "yen", "keywords": ["money", "sales", "japanese", "dollar", "currency"] }, - { "category": "objects", "char": "💶", "name": "euro", "keywords": ["money", "sales", "dollar", "currency"] }, - { "category": "objects", "char": "💷", "name": "pound", "keywords": ["british", "sterling", "money", "sales", "bills", "uk", "england", "currency"] }, - { "category": "objects", "char": "💰", "name": "moneybag", "keywords": ["dollar", "payment", "coins", "sale"] }, - { "category": "objects", "char": "🪙", "name": "coin", "keywords": ["dollar", "payment", "coins", "sale"] }, - { "category": "objects", "char": "💳", "name": "credit_card", "keywords": ["money", "sales", "dollar", "bill", "payment", "shopping"] }, - { "category": "objects", "char": "\uD83E\uDEAB", "name": "identification_card", "keywords": [] }, - { "category": "objects", "char": "💎", "name": "gem", "keywords": ["blue", "ruby", "diamond", "jewelry"] }, - { "category": "objects", "char": "⚖", "name": "balance_scale", "keywords": ["law", "fairness", "weight"] }, - { "category": "objects", "char": "🧰", "name": "toolbox", "keywords": ["tools", "diy", "fix", "maintainer", "mechanic"] }, - { "category": "objects", "char": "🔧", "name": "wrench", "keywords": ["tools", "diy", "ikea", "fix", "maintainer"] }, - { "category": "objects", "char": "🔨", "name": "hammer", "keywords": ["tools", "build", "create"] }, - { "category": "objects", "char": "⚒", "name": "hammer_and_pick", "keywords": ["tools", "build", "create"] }, - { "category": "objects", "char": "🛠", "name": "hammer_and_wrench", "keywords": ["tools", "build", "create"] }, - { "category": "objects", "char": "⛏", "name": "pick", "keywords": ["tools", "dig"] }, - { "category": "objects", "char": "🪓", "name": "axe", "keywords": ["tools"] }, - { "category": "objects", "char": "🦯", "name": "probing_cane", "keywords": ["tools"] }, - { "category": "objects", "char": "🔩", "name": "nut_and_bolt", "keywords": ["handy", "tools", "fix"] }, - { "category": "objects", "char": "⚙", "name": "gear", "keywords": ["cog"] }, - { "category": "objects", "char": "🪃", "name": "boomerang", "keywords": ["tool"] }, - { "category": "objects", "char": "🪚", "name": "carpentry_saw", "keywords": ["tool"] }, - { "category": "objects", "char": "🪛", "name": "screwdriver", "keywords": ["tool"] }, - { "category": "objects", "char": "🪝", "name": "hook", "keywords": ["tool"] }, - { "category": "objects", "char": "🪜", "name": "ladder", "keywords": ["tool"] }, - { "category": "objects", "char": "🧱", "name": "brick", "keywords": ["bricks"] }, - { "category": "objects", "char": "⛓", "name": "chains", "keywords": ["lock", "arrest"] }, - { "category": "objects", "char": "🧲", "name": "magnet", "keywords": ["attraction", "magnetic"] }, - { "category": "objects", "char": "🔫", "name": "gun", "keywords": ["violence", "weapon", "pistol", "revolver"] }, - { "category": "objects", "char": "💣", "name": "bomb", "keywords": ["boom", "explode", "explosion", "terrorism"] }, - { "category": "objects", "char": "🧨", "name": "firecracker", "keywords": ["dynamite", "boom", "explode", "explosion", "explosive"] }, - { "category": "objects", "char": "🔪", "name": "hocho", "keywords": ["knife", "blade", "cutlery", "kitchen", "weapon"] }, - { "category": "objects", "char": "🗡", "name": "dagger", "keywords": ["weapon"] }, - { "category": "objects", "char": "⚔", "name": "crossed_swords", "keywords": ["weapon"] }, - { "category": "objects", "char": "🛡", "name": "shield", "keywords": ["protection", "security"] }, - { "category": "objects", "char": "🚬", "name": "smoking", "keywords": ["kills", "tobacco", "cigarette", "joint", "smoke"] }, - { "category": "objects", "char": "☠", "name": "skull_and_crossbones", "keywords": ["poison", "danger", "deadly", "scary", "death", "pirate", "evil"] }, - { "category": "objects", "char": "⚰", "name": "coffin", "keywords": ["vampire", "dead", "die", "death", "rip", "graveyard", "cemetery", "casket", "funeral", "box"] }, - { "category": "objects", "char": "⚱", "name": "funeral_urn", "keywords": ["dead", "die", "death", "rip", "ashes"] }, - { "category": "objects", "char": "🏺", "name": "amphora", "keywords": ["vase", "jar"] }, - { "category": "objects", "char": "🔮", "name": "crystal_ball", "keywords": ["disco", "party", "magic", "circus", "fortune_teller"] }, - { "category": "objects", "char": "📿", "name": "prayer_beads", "keywords": ["dhikr", "religious"] }, - { "category": "objects", "char": "🧿", "name": "nazar_amulet", "keywords": ["bead", "charm"] }, - { "category": "objects", "char": "💈", "name": "barber", "keywords": ["hair", "salon", "style"] }, - { "category": "objects", "char": "⚗", "name": "alembic", "keywords": ["distilling", "science", "experiment", "chemistry"] }, - { "category": "objects", "char": "🔭", "name": "telescope", "keywords": ["stars", "space", "zoom", "science", "astronomy"] }, - { "category": "objects", "char": "🔬", "name": "microscope", "keywords": ["laboratory", "experiment", "zoomin", "science", "study"] }, - { "category": "objects", "char": "🕳", "name": "hole", "keywords": ["embarrassing"] }, - { "category": "objects", "char": "💊", "name": "pill", "keywords": ["health", "medicine", "doctor", "pharmacy", "drug"] }, - { "category": "objects", "char": "💉", "name": "syringe", "keywords": ["health", "hospital", "drugs", "blood", "medicine", "needle", "doctor", "nurse"] }, - { "category": "objects", "char": "🩸", "name": "drop_of_blood", "keywords": ["health", "hospital", "medicine", "needle", "doctor", "nurse"] }, - { "category": "objects", "char": "🩹", "name": "adhesive_bandage", "keywords": ["health", "hospital", "medicine", "needle", "doctor", "nurse"] }, - { "category": "objects", "char": "🩺", "name": "stethoscope", "keywords": ["health", "hospital", "medicine", "needle", "doctor", "nurse"] }, - { "category": "objects", "char": "🪒", "name": "razor", "keywords": ["health"] }, - { "category": "objects", "char": "\uD83E\uDE7B", "name": "xray", "keywords": [] }, - { "category": "objects", "char": "\uD83E\uDE7C", "name": "crutch", "keywords": [] }, - { "category": "objects", "char": "🧬", "name": "dna", "keywords": ["biologist", "genetics", "life"] }, - { "category": "objects", "char": "🧫", "name": "petri_dish", "keywords": ["bacteria", "biology", "culture", "lab"] }, - { "category": "objects", "char": "🧪", "name": "test_tube", "keywords": ["chemistry", "experiment", "lab", "science"] }, - { "category": "objects", "char": "🌡", "name": "thermometer", "keywords": ["weather", "temperature", "hot", "cold"] }, - { "category": "objects", "char": "🧹", "name": "broom", "keywords": ["cleaning", "sweeping", "witch"] }, - { "category": "objects", "char": "🧺", "name": "basket", "keywords": ["laundry"] }, - { "category": "objects", "char": "🧻", "name": "toilet_paper", "keywords": ["roll"] }, - { "category": "objects", "char": "🏷", "name": "label", "keywords": ["sale", "tag"] }, - { "category": "objects", "char": "🔖", "name": "bookmark", "keywords": ["favorite", "label", "save"] }, - { "category": "objects", "char": "🚽", "name": "toilet", "keywords": ["restroom", "wc", "washroom", "bathroom", "potty"] }, - { "category": "objects", "char": "🚿", "name": "shower", "keywords": ["clean", "water", "bathroom"] }, - { "category": "objects", "char": "🛁", "name": "bathtub", "keywords": ["clean", "shower", "bathroom"] }, - { "category": "objects", "char": "🧼", "name": "soap", "keywords": ["bar", "bathing", "cleaning", "lather"] }, - { "category": "objects", "char": "🧽", "name": "sponge", "keywords": ["absorbing", "cleaning", "porous"] }, - { "category": "objects", "char": "🧴", "name": "lotion_bottle", "keywords": ["moisturizer", "sunscreen"] }, - { "category": "objects", "char": "🔑", "name": "key", "keywords": ["lock", "door", "password"] }, - { "category": "objects", "char": "🗝", "name": "old_key", "keywords": ["lock", "door", "password"] }, - { "category": "objects", "char": "🛋", "name": "couch_and_lamp", "keywords": ["read", "chill"] }, - { "category": "objects", "char": "🪔", "name": "diya_Lamp", "keywords": ["light", "oil"] }, - { "category": "objects", "char": "🛌", "name": "sleeping_bed", "keywords": ["bed", "rest"] }, - { "category": "objects", "char": "🛏", "name": "bed", "keywords": ["sleep", "rest"] }, - { "category": "objects", "char": "🚪", "name": "door", "keywords": ["house", "entry", "exit"] }, - { "category": "objects", "char": "🪑", "name": "chair", "keywords": ["house", "desk"] }, - { "category": "objects", "char": "🛎", "name": "bellhop_bell", "keywords": ["service"] }, - { "category": "objects", "char": "🧸", "name": "teddy_bear", "keywords": ["plush", "stuffed"] }, - { "category": "objects", "char": "🖼", "name": "framed_picture", "keywords": ["photography"] }, - { "category": "objects", "char": "🗺", "name": "world_map", "keywords": ["location", "direction"] }, - { "category": "objects", "char": "🛗", "name": "elevator", "keywords": ["household"] }, - { "category": "objects", "char": "🪞", "name": "mirror", "keywords": ["household"] }, - { "category": "objects", "char": "🪟", "name": "window", "keywords": ["household"] }, - { "category": "objects", "char": "🪠", "name": "plunger", "keywords": ["household"] }, - { "category": "objects", "char": "🪤", "name": "mouse_trap", "keywords": ["household"] }, - { "category": "objects", "char": "🪣", "name": "bucket", "keywords": ["household"] }, - { "category": "objects", "char": "🪥", "name": "toothbrush", "keywords": ["household"] }, - { "category": "objects", "char": "\uD83E\uDEE7", "name": "bubbles", "keywords": [] }, - { "category": "objects", "char": "⛱", "name": "parasol_on_ground", "keywords": ["weather", "summer"] }, - { "category": "objects", "char": "🗿", "name": "moyai", "keywords": ["rock", "easter island", "moai"] }, - { "category": "objects", "char": "🛍", "name": "shopping", "keywords": ["mall", "buy", "purchase"] }, - { "category": "objects", "char": "🛒", "name": "shopping_cart", "keywords": ["trolley"] }, - { "category": "objects", "char": "🎈", "name": "balloon", "keywords": ["party", "celebration", "birthday", "circus"] }, - { "category": "objects", "char": "🎏", "name": "flags", "keywords": ["fish", "japanese", "koinobori", "carp", "banner"] }, - { "category": "objects", "char": "🎀", "name": "ribbon", "keywords": ["decoration", "pink", "girl", "bowtie"] }, - { "category": "objects", "char": "🎁", "name": "gift", "keywords": ["present", "birthday", "christmas", "xmas"] }, - { "category": "objects", "char": "🎊", "name": "confetti_ball", "keywords": ["festival", "party", "birthday", "circus"] }, - { "category": "objects", "char": "🎉", "name": "tada", "keywords": ["party", "congratulations", "birthday", "magic", "circus", "celebration"] }, - { "category": "objects", "char": "🎎", "name": "dolls", "keywords": ["japanese", "toy", "kimono"] }, - { "category": "objects", "char": "🎐", "name": "wind_chime", "keywords": ["nature", "ding", "spring", "bell"] }, - { "category": "objects", "char": "🎌", "name": "crossed_flags", "keywords": ["japanese", "nation", "country", "border"] }, - { "category": "objects", "char": "🏮", "name": "izakaya_lantern", "keywords": ["light", "paper", "halloween", "spooky"] }, - { "category": "objects", "char": "🧧", "name": "red_envelope", "keywords": ["gift"] }, - { "category": "objects", "char": "✉️", "name": "email", "keywords": ["letter", "postal", "inbox", "communication"] }, - { "category": "objects", "char": "📩", "name": "envelope_with_arrow", "keywords": ["email", "communication"] }, - { "category": "objects", "char": "📨", "name": "incoming_envelope", "keywords": ["email", "inbox"] }, - { "category": "objects", "char": "📧", "name": "e-mail", "keywords": ["communication", "inbox"] }, - { "category": "objects", "char": "💌", "name": "love_letter", "keywords": ["email", "like", "affection", "envelope", "valentines"] }, - { "category": "objects", "char": "📮", "name": "postbox", "keywords": ["email", "letter", "envelope"] }, - { "category": "objects", "char": "📪", "name": "mailbox_closed", "keywords": ["email", "communication", "inbox"] }, - { "category": "objects", "char": "📫", "name": "mailbox", "keywords": ["email", "inbox", "communication"] }, - { "category": "objects", "char": "📬", "name": "mailbox_with_mail", "keywords": ["email", "inbox", "communication"] }, - { "category": "objects", "char": "📭", "name": "mailbox_with_no_mail", "keywords": ["email", "inbox"] }, - { "category": "objects", "char": "📦", "name": "package", "keywords": ["mail", "gift", "cardboard", "box", "moving"] }, - { "category": "objects", "char": "📯", "name": "postal_horn", "keywords": ["instrument", "music"] }, - { "category": "objects", "char": "📥", "name": "inbox_tray", "keywords": ["email", "documents"] }, - { "category": "objects", "char": "📤", "name": "outbox_tray", "keywords": ["inbox", "email"] }, - { "category": "objects", "char": "📜", "name": "scroll", "keywords": ["documents", "ancient", "history", "paper"] }, - { "category": "objects", "char": "📃", "name": "page_with_curl", "keywords": ["documents", "office", "paper"] }, - { "category": "objects", "char": "📑", "name": "bookmark_tabs", "keywords": ["favorite", "save", "order", "tidy"] }, - { "category": "objects", "char": "🧾", "name": "receipt", "keywords": ["accounting", "expenses"] }, - { "category": "objects", "char": "📊", "name": "bar_chart", "keywords": ["graph", "presentation", "stats"] }, - { "category": "objects", "char": "📈", "name": "chart_with_upwards_trend", "keywords": ["graph", "presentation", "stats", "recovery", "business", "economics", "money", "sales", "good", "success"] }, - { "category": "objects", "char": "📉", "name": "chart_with_downwards_trend", "keywords": ["graph", "presentation", "stats", "recession", "business", "economics", "money", "sales", "bad", "failure"] }, - { "category": "objects", "char": "📄", "name": "page_facing_up", "keywords": ["documents", "office", "paper", "information"] }, - { "category": "objects", "char": "📅", "name": "date", "keywords": ["calendar", "schedule"] }, - { "category": "objects", "char": "📆", "name": "calendar", "keywords": ["schedule", "date", "planning"] }, - { "category": "objects", "char": "🗓", "name": "spiral_calendar", "keywords": ["date", "schedule", "planning"] }, - { "category": "objects", "char": "📇", "name": "card_index", "keywords": ["business", "stationery"] }, - { "category": "objects", "char": "🗃", "name": "card_file_box", "keywords": ["business", "stationery"] }, - { "category": "objects", "char": "🗳", "name": "ballot_box", "keywords": ["election", "vote"] }, - { "category": "objects", "char": "🗄", "name": "file_cabinet", "keywords": ["filing", "organizing"] }, - { "category": "objects", "char": "📋", "name": "clipboard", "keywords": ["stationery", "documents"] }, - { "category": "objects", "char": "🗒", "name": "spiral_notepad", "keywords": ["memo", "stationery"] }, - { "category": "objects", "char": "📁", "name": "file_folder", "keywords": ["documents", "business", "office"] }, - { "category": "objects", "char": "📂", "name": "open_file_folder", "keywords": ["documents", "load"] }, - { "category": "objects", "char": "🗂", "name": "card_index_dividers", "keywords": ["organizing", "business", "stationery"] }, - { "category": "objects", "char": "🗞", "name": "newspaper_roll", "keywords": ["press", "headline"] }, - { "category": "objects", "char": "📰", "name": "newspaper", "keywords": ["press", "headline"] }, - { "category": "objects", "char": "📓", "name": "notebook", "keywords": ["stationery", "record", "notes", "paper", "study"] }, - { "category": "objects", "char": "📕", "name": "closed_book", "keywords": ["read", "library", "knowledge", "textbook", "learn"] }, - { "category": "objects", "char": "📗", "name": "green_book", "keywords": ["read", "library", "knowledge", "study"] }, - { "category": "objects", "char": "📘", "name": "blue_book", "keywords": ["read", "library", "knowledge", "learn", "study"] }, - { "category": "objects", "char": "📙", "name": "orange_book", "keywords": ["read", "library", "knowledge", "textbook", "study"] }, - { "category": "objects", "char": "📔", "name": "notebook_with_decorative_cover", "keywords": ["classroom", "notes", "record", "paper", "study"] }, - { "category": "objects", "char": "📒", "name": "ledger", "keywords": ["notes", "paper"] }, - { "category": "objects", "char": "📚", "name": "books", "keywords": ["literature", "library", "study"] }, - { "category": "objects", "char": "📖", "name": "open_book", "keywords": ["book", "read", "library", "knowledge", "literature", "learn", "study"] }, - { "category": "objects", "char": "🧷", "name": "safety_pin", "keywords": ["diaper"] }, - { "category": "objects", "char": "🔗", "name": "link", "keywords": ["rings", "url"] }, - { "category": "objects", "char": "📎", "name": "paperclip", "keywords": ["documents", "stationery"] }, - { "category": "objects", "char": "🖇", "name": "paperclips", "keywords": ["documents", "stationery"] }, - { "category": "objects", "char": "✂️", "name": "scissors", "keywords": ["stationery", "cut"] }, - { "category": "objects", "char": "📐", "name": "triangular_ruler", "keywords": ["stationery", "math", "architect", "sketch"] }, - { "category": "objects", "char": "📏", "name": "straight_ruler", "keywords": ["stationery", "calculate", "length", "math", "school", "drawing", "architect", "sketch"] }, - { "category": "objects", "char": "🧮", "name": "abacus", "keywords": ["calculation"] }, - { "category": "objects", "char": "📌", "name": "pushpin", "keywords": ["stationery", "mark", "here"] }, - { "category": "objects", "char": "📍", "name": "round_pushpin", "keywords": ["stationery", "location", "map", "here"] }, - { "category": "objects", "char": "🚩", "name": "triangular_flag_on_post", "keywords": ["mark", "milestone", "place"] }, - { "category": "objects", "char": "🏳", "name": "white_flag", "keywords": ["losing", "loser", "lost", "surrender", "give up", "fail"] }, - { "category": "objects", "char": "🏴", "name": "black_flag", "keywords": ["pirate"] }, - { "category": "objects", "char": "🏳️🌈", "name": "rainbow_flag", "keywords": ["flag", "rainbow", "pride", "gay", "lgbt", "glbt", "queer", "homosexual", "lesbian", "bisexual", "transgender"] }, - { "category": "objects", "char": "🏳️⚧️", "name": "transgender_flag", "keywords": ["flag", "transgender"] }, - { "category": "objects", "char": "🔐", "name": "closed_lock_with_key", "keywords": ["security", "privacy"] }, - { "category": "objects", "char": "🔒", "name": "lock", "keywords": ["security", "password", "padlock"] }, - { "category": "objects", "char": "🔓", "name": "unlock", "keywords": ["privacy", "security"] }, - { "category": "objects", "char": "🔏", "name": "lock_with_ink_pen", "keywords": ["security", "secret"] }, - { "category": "objects", "char": "🖊", "name": "pen", "keywords": ["stationery", "writing", "write"] }, - { "category": "objects", "char": "🖋", "name": "fountain_pen", "keywords": ["stationery", "writing", "write"] }, - { "category": "objects", "char": "✒️", "name": "black_nib", "keywords": ["pen", "stationery", "writing", "write"] }, - { "category": "objects", "char": "📝", "name": "memo", "keywords": ["write", "documents", "stationery", "pencil", "paper", "writing", "legal", "exam", "quiz", "test", "study", "compose"] }, - { "category": "objects", "char": "✏️", "name": "pencil2", "keywords": ["stationery", "write", "paper", "writing", "school", "study"] }, - { "category": "objects", "char": "🖍", "name": "crayon", "keywords": ["drawing", "creativity"] }, - { "category": "objects", "char": "🖌", "name": "paintbrush", "keywords": ["drawing", "creativity", "art"] }, - { "category": "objects", "char": "🔍", "name": "mag", "keywords": ["search", "zoom", "find", "detective"] }, - { "category": "objects", "char": "🔎", "name": "mag_right", "keywords": ["search", "zoom", "find", "detective"] }, - { "category": "objects", "char": "🪦", "name": "headstone", "keywords": [] }, - { "category": "objects", "char": "🪧", "name": "placard", "keywords": [] }, - { "category": "symbols", "char": "💯", "name": "100", "keywords": ["score", "perfect", "numbers", "century", "exam", "quiz", "test", "pass", "hundred"] }, - { "category": "symbols", "char": "🔢", "name": "1234", "keywords": ["numbers", "blue-square"] }, - { "category": "symbols", "char": "❤️", "name": "heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "🧡", "name": "orange_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "💛", "name": "yellow_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "💚", "name": "green_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "💙", "name": "blue_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "💜", "name": "purple_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "🤎", "name": "brown_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "🖤", "name": "black_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "🤍", "name": "white_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "💔", "name": "broken_heart", "keywords": ["sad", "sorry", "break", "heart", "heartbreak"] }, - { "category": "symbols", "char": "❣", "name": "heavy_heart_exclamation", "keywords": ["decoration", "love"] }, - { "category": "symbols", "char": "💕", "name": "two_hearts", "keywords": ["love", "like", "affection", "valentines", "heart"] }, - { "category": "symbols", "char": "💞", "name": "revolving_hearts", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "💓", "name": "heartbeat", "keywords": ["love", "like", "affection", "valentines", "pink", "heart"] }, - { "category": "symbols", "char": "💗", "name": "heartpulse", "keywords": ["like", "love", "affection", "valentines", "pink"] }, - { "category": "symbols", "char": "💖", "name": "sparkling_heart", "keywords": ["love", "like", "affection", "valentines"] }, - { "category": "symbols", "char": "💘", "name": "cupid", "keywords": ["love", "like", "heart", "affection", "valentines"] }, - { "category": "symbols", "char": "💝", "name": "gift_heart", "keywords": ["love", "valentines"] }, - { "category": "symbols", "char": "💟", "name": "heart_decoration", "keywords": ["purple-square", "love", "like"] }, - { "category": "symbols", "char": "\u2764\uFE0F\u200D\uD83D\uDD25", "name": "heart_on_fire", "keywords": [] }, - { "category": "symbols", "char": "\u2764\uFE0F\u200D\uD83E\uDE79", "name": "mending_heart", "keywords": [] }, - { "category": "symbols", "char": "☮", "name": "peace_symbol", "keywords": ["hippie"] }, - { "category": "symbols", "char": "✝", "name": "latin_cross", "keywords": ["christianity"] }, - { "category": "symbols", "char": "☪", "name": "star_and_crescent", "keywords": ["islam"] }, - { "category": "symbols", "char": "🕉", "name": "om", "keywords": ["hinduism", "buddhism", "sikhism", "jainism"] }, - { "category": "symbols", "char": "☸", "name": "wheel_of_dharma", "keywords": ["hinduism", "buddhism", "sikhism", "jainism"] }, - { "category": "symbols", "char": "✡", "name": "star_of_david", "keywords": ["judaism"] }, - { "category": "symbols", "char": "🔯", "name": "six_pointed_star", "keywords": ["purple-square", "religion", "jewish", "hexagram"] }, - { "category": "symbols", "char": "🕎", "name": "menorah", "keywords": ["hanukkah", "candles", "jewish"] }, - { "category": "symbols", "char": "☯", "name": "yin_yang", "keywords": ["balance"] }, - { "category": "symbols", "char": "☦", "name": "orthodox_cross", "keywords": ["suppedaneum", "religion"] }, - { "category": "symbols", "char": "🛐", "name": "place_of_worship", "keywords": ["religion", "church", "temple", "prayer"] }, - { "category": "symbols", "char": "⛎", "name": "ophiuchus", "keywords": ["sign", "purple-square", "constellation", "astrology"] }, - { "category": "symbols", "char": "♈", "name": "aries", "keywords": ["sign", "purple-square", "zodiac", "astrology"] }, - { "category": "symbols", "char": "♉", "name": "taurus", "keywords": ["purple-square", "sign", "zodiac", "astrology"] }, - { "category": "symbols", "char": "♊", "name": "gemini", "keywords": ["sign", "zodiac", "purple-square", "astrology"] }, - { "category": "symbols", "char": "♋", "name": "cancer", "keywords": ["sign", "zodiac", "purple-square", "astrology"] }, - { "category": "symbols", "char": "♌", "name": "leo", "keywords": ["sign", "purple-square", "zodiac", "astrology"] }, - { "category": "symbols", "char": "♍", "name": "virgo", "keywords": ["sign", "zodiac", "purple-square", "astrology"] }, - { "category": "symbols", "char": "♎", "name": "libra", "keywords": ["sign", "purple-square", "zodiac", "astrology"] }, - { "category": "symbols", "char": "♏", "name": "scorpius", "keywords": ["sign", "zodiac", "purple-square", "astrology", "scorpio"] }, - { "category": "symbols", "char": "♐", "name": "sagittarius", "keywords": ["sign", "zodiac", "purple-square", "astrology"] }, - { "category": "symbols", "char": "♑", "name": "capricorn", "keywords": ["sign", "zodiac", "purple-square", "astrology"] }, - { "category": "symbols", "char": "♒", "name": "aquarius", "keywords": ["sign", "purple-square", "zodiac", "astrology"] }, - { "category": "symbols", "char": "♓", "name": "pisces", "keywords": ["purple-square", "sign", "zodiac", "astrology"] }, - { "category": "symbols", "char": "🆔", "name": "id", "keywords": ["purple-square", "words"] }, - { "category": "symbols", "char": "⚛", "name": "atom_symbol", "keywords": ["science", "physics", "chemistry"] }, - { "category": "symbols", "char": "⚧️", "name": "transgender_symbol", "keywords": ["purple-square", "woman", "female", "toilet", "loo", "restroom", "gender"] }, - { "category": "symbols", "char": "🈳", "name": "u7a7a", "keywords": ["kanji", "japanese", "chinese", "empty", "sky", "blue-square", "aki"] }, - { "category": "symbols", "char": "🈹", "name": "u5272", "keywords": ["cut", "divide", "chinese", "kanji", "pink-square", "waribiki"] }, - { "category": "symbols", "char": "☢", "name": "radioactive", "keywords": ["nuclear", "danger"] }, - { "category": "symbols", "char": "☣", "name": "biohazard", "keywords": ["danger"] }, - { "category": "symbols", "char": "📴", "name": "mobile_phone_off", "keywords": ["mute", "orange-square", "silence", "quiet"] }, - { "category": "symbols", "char": "📳", "name": "vibration_mode", "keywords": ["orange-square", "phone"] }, - { "category": "symbols", "char": "🈶", "name": "u6709", "keywords": ["orange-square", "chinese", "have", "kanji", "ari"] }, - { "category": "symbols", "char": "🈚", "name": "u7121", "keywords": ["nothing", "chinese", "kanji", "japanese", "orange-square", "nashi"] }, - { "category": "symbols", "char": "🈸", "name": "u7533", "keywords": ["chinese", "japanese", "kanji", "orange-square", "moushikomi"] }, - { "category": "symbols", "char": "🈺", "name": "u55b6", "keywords": ["japanese", "opening hours", "orange-square", "eigyo"] }, - { "category": "symbols", "char": "🈷️", "name": "u6708", "keywords": ["chinese", "month", "moon", "japanese", "orange-square", "kanji", "tsuki", "tsukigime", "getsugaku"] }, - { "category": "symbols", "char": "✴️", "name": "eight_pointed_black_star", "keywords": ["orange-square", "shape", "polygon"] }, - { "category": "symbols", "char": "🆚", "name": "vs", "keywords": ["words", "orange-square"] }, - { "category": "symbols", "char": "🉑", "name": "accept", "keywords": ["ok", "good", "chinese", "kanji", "agree", "yes", "orange-circle"] }, - { "category": "symbols", "char": "💮", "name": "white_flower", "keywords": ["japanese", "spring"] }, - { "category": "symbols", "char": "🉐", "name": "ideograph_advantage", "keywords": ["chinese", "kanji", "obtain", "get", "circle"] }, - { "category": "symbols", "char": "㊙️", "name": "secret", "keywords": ["privacy", "chinese", "sshh", "kanji", "red-circle"] }, - { "category": "symbols", "char": "㊗️", "name": "congratulations", "keywords": ["chinese", "kanji", "japanese", "red-circle"] }, - { "category": "symbols", "char": "🈴", "name": "u5408", "keywords": ["japanese", "chinese", "join", "kanji", "red-square", "goukaku", "pass"] }, - { "category": "symbols", "char": "🈵", "name": "u6e80", "keywords": ["full", "chinese", "japanese", "red-square", "kanji", "man"] }, - { "category": "symbols", "char": "🈲", "name": "u7981", "keywords": ["kanji", "japanese", "chinese", "forbidden", "limit", "restricted", "red-square", "kinshi"] }, - { "category": "symbols", "char": "🅰️", "name": "a", "keywords": ["red-square", "alphabet", "letter"] }, - { "category": "symbols", "char": "🅱️", "name": "b", "keywords": ["red-square", "alphabet", "letter"] }, - { "category": "symbols", "char": "🆎", "name": "ab", "keywords": ["red-square", "alphabet"] }, - { "category": "symbols", "char": "🆑", "name": "cl", "keywords": ["alphabet", "words", "red-square"] }, - { "category": "symbols", "char": "🅾️", "name": "o2", "keywords": ["alphabet", "red-square", "letter"] }, - { "category": "symbols", "char": "🆘", "name": "sos", "keywords": ["help", "red-square", "words", "emergency", "911"] }, - { "category": "symbols", "char": "⛔", "name": "no_entry", "keywords": ["limit", "security", "privacy", "bad", "denied", "stop", "circle"] }, - { "category": "symbols", "char": "📛", "name": "name_badge", "keywords": ["fire", "forbid"] }, - { "category": "symbols", "char": "🚫", "name": "no_entry_sign", "keywords": ["forbid", "stop", "limit", "denied", "disallow", "circle"] }, - { "category": "symbols", "char": "❌", "name": "x", "keywords": ["no", "delete", "remove", "cancel", "red"] }, - { "category": "symbols", "char": "⭕", "name": "o", "keywords": ["circle", "round"] }, - { "category": "symbols", "char": "🛑", "name": "stop_sign", "keywords": ["stop"] }, - { "category": "symbols", "char": "💢", "name": "anger", "keywords": ["angry", "mad"] }, - { "category": "symbols", "char": "♨️", "name": "hotsprings", "keywords": ["bath", "warm", "relax"] }, - { "category": "symbols", "char": "🚷", "name": "no_pedestrians", "keywords": ["rules", "crossing", "walking", "circle"] }, - { "category": "symbols", "char": "🚯", "name": "do_not_litter", "keywords": ["trash", "bin", "garbage", "circle"] }, - { "category": "symbols", "char": "🚳", "name": "no_bicycles", "keywords": ["cyclist", "prohibited", "circle"] }, - { "category": "symbols", "char": "🚱", "name": "non-potable_water", "keywords": ["drink", "faucet", "tap", "circle"] }, - { "category": "symbols", "char": "🔞", "name": "underage", "keywords": ["18", "drink", "pub", "night", "minor", "circle"] }, - { "category": "symbols", "char": "📵", "name": "no_mobile_phones", "keywords": ["iphone", "mute", "circle"] }, - { "category": "symbols", "char": "❗", "name": "exclamation", "keywords": ["heavy_exclamation_mark", "danger", "surprise", "punctuation", "wow", "warning"] }, - { "category": "symbols", "char": "❕", "name": "grey_exclamation", "keywords": ["surprise", "punctuation", "gray", "wow", "warning"] }, - { "category": "symbols", "char": "❓", "name": "question", "keywords": ["doubt", "confused"] }, - { "category": "symbols", "char": "❔", "name": "grey_question", "keywords": ["doubts", "gray", "huh", "confused"] }, - { "category": "symbols", "char": "‼️", "name": "bangbang", "keywords": ["exclamation", "surprise"] }, - { "category": "symbols", "char": "⁉️", "name": "interrobang", "keywords": ["wat", "punctuation", "surprise"] }, - { "category": "symbols", "char": "🔅", "name": "low_brightness", "keywords": ["sun", "afternoon", "warm", "summer"] }, - { "category": "symbols", "char": "🔆", "name": "high_brightness", "keywords": ["sun", "light"] }, - { "category": "symbols", "char": "🔱", "name": "trident", "keywords": ["weapon", "spear"] }, - { "category": "symbols", "char": "⚜", "name": "fleur_de_lis", "keywords": ["decorative", "scout"] }, - { "category": "symbols", "char": "〽️", "name": "part_alternation_mark", "keywords": ["graph", "presentation", "stats", "business", "economics", "bad"] }, - { "category": "symbols", "char": "⚠️", "name": "warning", "keywords": ["exclamation", "wip", "alert", "error", "problem", "issue"] }, - { "category": "symbols", "char": "🚸", "name": "children_crossing", "keywords": ["school", "warning", "danger", "sign", "driving", "yellow-diamond"] }, - { "category": "symbols", "char": "🔰", "name": "beginner", "keywords": ["badge", "shield"] }, - { "category": "symbols", "char": "♻️", "name": "recycle", "keywords": ["arrow", "environment", "garbage", "trash"] }, - { "category": "symbols", "char": "🈯", "name": "u6307", "keywords": ["chinese", "point", "green-square", "kanji", "reserved", "shiteiseki"] }, - { "category": "symbols", "char": "💹", "name": "chart", "keywords": ["green-square", "graph", "presentation", "stats"] }, - { "category": "symbols", "char": "❇️", "name": "sparkle", "keywords": ["stars", "green-square", "awesome", "good", "fireworks"] }, - { "category": "symbols", "char": "✳️", "name": "eight_spoked_asterisk", "keywords": ["star", "sparkle", "green-square"] }, - { "category": "symbols", "char": "❎", "name": "negative_squared_cross_mark", "keywords": ["x", "green-square", "no", "deny"] }, - { "category": "symbols", "char": "✅", "name": "white_check_mark", "keywords": ["green-square", "ok", "agree", "vote", "election", "answer", "tick"] }, - { "category": "symbols", "char": "💠", "name": "diamond_shape_with_a_dot_inside", "keywords": ["jewel", "blue", "gem", "crystal", "fancy"] }, - { "category": "symbols", "char": "🌀", "name": "cyclone", "keywords": ["weather", "swirl", "blue", "cloud", "vortex", "spiral", "whirlpool", "spin", "tornado", "hurricane", "typhoon"] }, - { "category": "symbols", "char": "➿", "name": "loop", "keywords": ["tape", "cassette"] }, - { "category": "symbols", "char": "🌐", "name": "globe_with_meridians", "keywords": ["earth", "international", "world", "internet", "interweb", "i18n"] }, - { "category": "symbols", "char": "Ⓜ️", "name": "m", "keywords": ["alphabet", "blue-circle", "letter"] }, - { "category": "symbols", "char": "🏧", "name": "atm", "keywords": ["money", "sales", "cash", "blue-square", "payment", "bank"] }, - { "category": "symbols", "char": "🈂️", "name": "sa", "keywords": ["japanese", "blue-square", "katakana"] }, - { "category": "symbols", "char": "🛂", "name": "passport_control", "keywords": ["custom", "blue-square"] }, - { "category": "symbols", "char": "🛃", "name": "customs", "keywords": ["passport", "border", "blue-square"] }, - { "category": "symbols", "char": "🛄", "name": "baggage_claim", "keywords": ["blue-square", "airport", "transport"] }, - { "category": "symbols", "char": "🛅", "name": "left_luggage", "keywords": ["blue-square", "travel"] }, - { "category": "symbols", "char": "♿", "name": "wheelchair", "keywords": ["blue-square", "disabled", "a11y", "accessibility"] }, - { "category": "symbols", "char": "🚭", "name": "no_smoking", "keywords": ["cigarette", "blue-square", "smell", "smoke"] }, - { "category": "symbols", "char": "🚾", "name": "wc", "keywords": ["toilet", "restroom", "blue-square"] }, - { "category": "symbols", "char": "🅿️", "name": "parking", "keywords": ["cars", "blue-square", "alphabet", "letter"] }, - { "category": "symbols", "char": "🚰", "name": "potable_water", "keywords": ["blue-square", "liquid", "restroom", "cleaning", "faucet"] }, - { "category": "symbols", "char": "🚹", "name": "mens", "keywords": ["toilet", "restroom", "wc", "blue-square", "gender", "male"] }, - { "category": "symbols", "char": "🚺", "name": "womens", "keywords": ["purple-square", "woman", "female", "toilet", "loo", "restroom", "gender"] }, - { "category": "symbols", "char": "🚼", "name": "baby_symbol", "keywords": ["orange-square", "child"] }, - { "category": "symbols", "char": "🚻", "name": "restroom", "keywords": ["blue-square", "toilet", "refresh", "wc", "gender"] }, - { "category": "symbols", "char": "🚮", "name": "put_litter_in_its_place", "keywords": ["blue-square", "sign", "human", "info"] }, - { "category": "symbols", "char": "🎦", "name": "cinema", "keywords": ["blue-square", "record", "film", "movie", "curtain", "stage", "theater"] }, - { "category": "symbols", "char": "📶", "name": "signal_strength", "keywords": ["blue-square", "reception", "phone", "internet", "connection", "wifi", "bluetooth", "bars"] }, - { "category": "symbols", "char": "🈁", "name": "koko", "keywords": ["blue-square", "here", "katakana", "japanese", "destination"] }, - { "category": "symbols", "char": "🆖", "name": "ng", "keywords": ["blue-square", "words", "shape", "icon"] }, - { "category": "symbols", "char": "🆗", "name": "ok", "keywords": ["good", "agree", "yes", "blue-square"] }, - { "category": "symbols", "char": "🆙", "name": "up", "keywords": ["blue-square", "above", "high"] }, - { "category": "symbols", "char": "🆒", "name": "cool", "keywords": ["words", "blue-square"] }, - { "category": "symbols", "char": "🆕", "name": "new", "keywords": ["blue-square", "words", "start"] }, - { "category": "symbols", "char": "🆓", "name": "free", "keywords": ["blue-square", "words"] }, - { "category": "symbols", "char": "0️⃣", "name": "zero", "keywords": ["0", "numbers", "blue-square", "null"] }, - { "category": "symbols", "char": "1️⃣", "name": "one", "keywords": ["blue-square", "numbers", "1"] }, - { "category": "symbols", "char": "2️⃣", "name": "two", "keywords": ["numbers", "2", "prime", "blue-square"] }, - { "category": "symbols", "char": "3️⃣", "name": "three", "keywords": ["3", "numbers", "prime", "blue-square"] }, - { "category": "symbols", "char": "4️⃣", "name": "four", "keywords": ["4", "numbers", "blue-square"] }, - { "category": "symbols", "char": "5️⃣", "name": "five", "keywords": ["5", "numbers", "blue-square", "prime"] }, - { "category": "symbols", "char": "6️⃣", "name": "six", "keywords": ["6", "numbers", "blue-square"] }, - { "category": "symbols", "char": "7️⃣", "name": "seven", "keywords": ["7", "numbers", "blue-square", "prime"] }, - { "category": "symbols", "char": "8️⃣", "name": "eight", "keywords": ["8", "blue-square", "numbers"] }, - { "category": "symbols", "char": "9️⃣", "name": "nine", "keywords": ["blue-square", "numbers", "9"] }, - { "category": "symbols", "char": "🔟", "name": "keycap_ten", "keywords": ["numbers", "10", "blue-square"] }, - { "category": "symbols", "char": "*⃣", "name": "asterisk", "keywords": ["star", "keycap"] }, - { "category": "symbols", "char": "⏏️", "name": "eject_button", "keywords": ["blue-square"] }, - { "category": "symbols", "char": "▶️", "name": "arrow_forward", "keywords": ["blue-square", "right", "direction", "play"] }, - { "category": "symbols", "char": "⏸", "name": "pause_button", "keywords": ["pause", "blue-square"] }, - { "category": "symbols", "char": "⏭", "name": "next_track_button", "keywords": ["forward", "next", "blue-square"] }, - { "category": "symbols", "char": "⏹", "name": "stop_button", "keywords": ["blue-square"] }, - { "category": "symbols", "char": "⏺", "name": "record_button", "keywords": ["blue-square"] }, - { "category": "symbols", "char": "⏯", "name": "play_or_pause_button", "keywords": ["blue-square", "play", "pause"] }, - { "category": "symbols", "char": "⏮", "name": "previous_track_button", "keywords": ["backward"] }, - { "category": "symbols", "char": "⏩", "name": "fast_forward", "keywords": ["blue-square", "play", "speed", "continue"] }, - { "category": "symbols", "char": "⏪", "name": "rewind", "keywords": ["play", "blue-square"] }, - { "category": "symbols", "char": "🔀", "name": "twisted_rightwards_arrows", "keywords": ["blue-square", "shuffle", "music", "random"] }, - { "category": "symbols", "char": "🔁", "name": "repeat", "keywords": ["loop", "record"] }, - { "category": "symbols", "char": "🔂", "name": "repeat_one", "keywords": ["blue-square", "loop"] }, - { "category": "symbols", "char": "◀️", "name": "arrow_backward", "keywords": ["blue-square", "left", "direction"] }, - { "category": "symbols", "char": "🔼", "name": "arrow_up_small", "keywords": ["blue-square", "triangle", "direction", "point", "forward", "top"] }, - { "category": "symbols", "char": "🔽", "name": "arrow_down_small", "keywords": ["blue-square", "direction", "bottom"] }, - { "category": "symbols", "char": "⏫", "name": "arrow_double_up", "keywords": ["blue-square", "direction", "top"] }, - { "category": "symbols", "char": "⏬", "name": "arrow_double_down", "keywords": ["blue-square", "direction", "bottom"] }, - { "category": "symbols", "char": "➡️", "name": "arrow_right", "keywords": ["blue-square", "next"] }, - { "category": "symbols", "char": "⬅️", "name": "arrow_left", "keywords": ["blue-square", "previous", "back"] }, - { "category": "symbols", "char": "⬆️", "name": "arrow_up", "keywords": ["blue-square", "continue", "top", "direction"] }, - { "category": "symbols", "char": "⬇️", "name": "arrow_down", "keywords": ["blue-square", "direction", "bottom"] }, - { "category": "symbols", "char": "↗️", "name": "arrow_upper_right", "keywords": ["blue-square", "point", "direction", "diagonal", "northeast"] }, - { "category": "symbols", "char": "↘️", "name": "arrow_lower_right", "keywords": ["blue-square", "direction", "diagonal", "southeast"] }, - { "category": "symbols", "char": "↙️", "name": "arrow_lower_left", "keywords": ["blue-square", "direction", "diagonal", "southwest"] }, - { "category": "symbols", "char": "↖️", "name": "arrow_upper_left", "keywords": ["blue-square", "point", "direction", "diagonal", "northwest"] }, - { "category": "symbols", "char": "↕️", "name": "arrow_up_down", "keywords": ["blue-square", "direction", "way", "vertical"] }, - { "category": "symbols", "char": "↔️", "name": "left_right_arrow", "keywords": ["shape", "direction", "horizontal", "sideways"] }, - { "category": "symbols", "char": "🔄", "name": "arrows_counterclockwise", "keywords": ["blue-square", "sync", "cycle"] }, - { "category": "symbols", "char": "↪️", "name": "arrow_right_hook", "keywords": ["blue-square", "return", "rotate", "direction"] }, - { "category": "symbols", "char": "↩️", "name": "leftwards_arrow_with_hook", "keywords": ["back", "return", "blue-square", "undo", "enter"] }, - { "category": "symbols", "char": "⤴️", "name": "arrow_heading_up", "keywords": ["blue-square", "direction", "top"] }, - { "category": "symbols", "char": "⤵️", "name": "arrow_heading_down", "keywords": ["blue-square", "direction", "bottom"] }, - { "category": "symbols", "char": "#️⃣", "name": "hash", "keywords": ["symbol", "blue-square", "twitter"] }, - { "category": "symbols", "char": "ℹ️", "name": "information_source", "keywords": ["blue-square", "alphabet", "letter"] }, - { "category": "symbols", "char": "🔤", "name": "abc", "keywords": ["blue-square", "alphabet"] }, - { "category": "symbols", "char": "🔡", "name": "abcd", "keywords": ["blue-square", "alphabet"] }, - { "category": "symbols", "char": "🔠", "name": "capital_abcd", "keywords": ["alphabet", "words", "blue-square"] }, - { "category": "symbols", "char": "🔣", "name": "symbols", "keywords": ["blue-square", "music", "note", "ampersand", "percent", "glyphs", "characters"] }, - { "category": "symbols", "char": "🎵", "name": "musical_note", "keywords": ["score", "tone", "sound"] }, - { "category": "symbols", "char": "🎶", "name": "notes", "keywords": ["music", "score"] }, - { "category": "symbols", "char": "〰️", "name": "wavy_dash", "keywords": ["draw", "line", "moustache", "mustache", "squiggle", "scribble"] }, - { "category": "symbols", "char": "➰", "name": "curly_loop", "keywords": ["scribble", "draw", "shape", "squiggle"] }, - { "category": "symbols", "char": "✔️", "name": "heavy_check_mark", "keywords": ["ok", "nike", "answer", "yes", "tick"] }, - { "category": "symbols", "char": "🔃", "name": "arrows_clockwise", "keywords": ["sync", "cycle", "round", "repeat"] }, - { "category": "symbols", "char": "➕", "name": "heavy_plus_sign", "keywords": ["math", "calculation", "addition", "more", "increase"] }, - { "category": "symbols", "char": "➖", "name": "heavy_minus_sign", "keywords": ["math", "calculation", "subtract", "less"] }, - { "category": "symbols", "char": "➗", "name": "heavy_division_sign", "keywords": ["divide", "math", "calculation"] }, - { "category": "symbols", "char": "✖️", "name": "heavy_multiplication_x", "keywords": ["math", "calculation"] }, - { "category": "symbols", "char": "\uD83D\uDFF0", "name": "heavy_equals_sign", "keywords": [] }, - { "category": "symbols", "char": "♾", "name": "infinity", "keywords": ["forever"] }, - { "category": "symbols", "char": "💲", "name": "heavy_dollar_sign", "keywords": ["money", "sales", "payment", "currency", "buck"] }, - { "category": "symbols", "char": "💱", "name": "currency_exchange", "keywords": ["money", "sales", "dollar", "travel"] }, - { "category": "symbols", "char": "©️", "name": "copyright", "keywords": ["ip", "license", "circle", "law", "legal"] }, - { "category": "symbols", "char": "®️", "name": "registered", "keywords": ["alphabet", "circle"] }, - { "category": "symbols", "char": "™️", "name": "tm", "keywords": ["trademark", "brand", "law", "legal"] }, - { "category": "symbols", "char": "🔚", "name": "end", "keywords": ["words", "arrow"] }, - { "category": "symbols", "char": "🔙", "name": "back", "keywords": ["arrow", "words", "return"] }, - { "category": "symbols", "char": "🔛", "name": "on", "keywords": ["arrow", "words"] }, - { "category": "symbols", "char": "🔝", "name": "top", "keywords": ["words", "blue-square"] }, - { "category": "symbols", "char": "🔜", "name": "soon", "keywords": ["arrow", "words"] }, - { "category": "symbols", "char": "☑️", "name": "ballot_box_with_check", "keywords": ["ok", "agree", "confirm", "black-square", "vote", "election", "yes", "tick"] }, - { "category": "symbols", "char": "🔘", "name": "radio_button", "keywords": ["input", "old", "music", "circle"] }, - { "category": "symbols", "char": "⚫", "name": "black_circle", "keywords": ["shape", "button", "round"] }, - { "category": "symbols", "char": "⚪", "name": "white_circle", "keywords": ["shape", "round"] }, - { "category": "symbols", "char": "🔴", "name": "red_circle", "keywords": ["shape", "error", "danger"] }, - { "category": "symbols", "char": "🟠", "name": "orange_circle", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟡", "name": "yellow_circle", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟢", "name": "green_circle", "keywords": ["shape"] }, - { "category": "symbols", "char": "🔵", "name": "large_blue_circle", "keywords": ["shape", "icon", "button"] }, - { "category": "symbols", "char": "🟣", "name": "purple_circle", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟤", "name": "brown_circle", "keywords": ["shape"] }, - { "category": "symbols", "char": "🔸", "name": "small_orange_diamond", "keywords": ["shape", "jewel", "gem"] }, - { "category": "symbols", "char": "🔹", "name": "small_blue_diamond", "keywords": ["shape", "jewel", "gem"] }, - { "category": "symbols", "char": "🔶", "name": "large_orange_diamond", "keywords": ["shape", "jewel", "gem"] }, - { "category": "symbols", "char": "🔷", "name": "large_blue_diamond", "keywords": ["shape", "jewel", "gem"] }, - { "category": "symbols", "char": "🔺", "name": "small_red_triangle", "keywords": ["shape", "direction", "up", "top"] }, - { "category": "symbols", "char": "▪️", "name": "black_small_square", "keywords": ["shape", "icon"] }, - { "category": "symbols", "char": "▫️", "name": "white_small_square", "keywords": ["shape", "icon"] }, - { "category": "symbols", "char": "⬛", "name": "black_large_square", "keywords": ["shape", "icon", "button"] }, - { "category": "symbols", "char": "⬜", "name": "white_large_square", "keywords": ["shape", "icon", "stone", "button"] }, - { "category": "symbols", "char": "🟥", "name": "red_square", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟧", "name": "orange_square", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟨", "name": "yellow_square", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟩", "name": "green_square", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟦", "name": "blue_square", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟪", "name": "purple_square", "keywords": ["shape"] }, - { "category": "symbols", "char": "🟫", "name": "brown_square", "keywords": ["shape"] }, - { "category": "symbols", "char": "🔻", "name": "small_red_triangle_down", "keywords": ["shape", "direction", "bottom"] }, - { "category": "symbols", "char": "◼️", "name": "black_medium_square", "keywords": ["shape", "button", "icon"] }, - { "category": "symbols", "char": "◻️", "name": "white_medium_square", "keywords": ["shape", "stone", "icon"] }, - { "category": "symbols", "char": "◾", "name": "black_medium_small_square", "keywords": ["icon", "shape", "button"] }, - { "category": "symbols", "char": "◽", "name": "white_medium_small_square", "keywords": ["shape", "stone", "icon", "button"] }, - { "category": "symbols", "char": "🔲", "name": "black_square_button", "keywords": ["shape", "input", "frame"] }, - { "category": "symbols", "char": "🔳", "name": "white_square_button", "keywords": ["shape", "input"] }, - { "category": "symbols", "char": "🔈", "name": "speaker", "keywords": ["sound", "volume", "silence", "broadcast"] }, - { "category": "symbols", "char": "🔉", "name": "sound", "keywords": ["volume", "speaker", "broadcast"] }, - { "category": "symbols", "char": "🔊", "name": "loud_sound", "keywords": ["volume", "noise", "noisy", "speaker", "broadcast"] }, - { "category": "symbols", "char": "🔇", "name": "mute", "keywords": ["sound", "volume", "silence", "quiet"] }, - { "category": "symbols", "char": "📣", "name": "mega", "keywords": ["sound", "speaker", "volume"] }, - { "category": "symbols", "char": "📢", "name": "loudspeaker", "keywords": ["volume", "sound"] }, - { "category": "symbols", "char": "🔔", "name": "bell", "keywords": ["sound", "notification", "christmas", "xmas", "chime"] }, - { "category": "symbols", "char": "🔕", "name": "no_bell", "keywords": ["sound", "volume", "mute", "quiet", "silent"] }, - { "category": "symbols", "char": "🃏", "name": "black_joker", "keywords": ["poker", "cards", "game", "play", "magic"] }, - { "category": "symbols", "char": "🀄", "name": "mahjong", "keywords": ["game", "play", "chinese", "kanji"] }, - { "category": "symbols", "char": "♠️", "name": "spades", "keywords": ["poker", "cards", "suits", "magic"] }, - { "category": "symbols", "char": "♣️", "name": "clubs", "keywords": ["poker", "cards", "magic", "suits"] }, - { "category": "symbols", "char": "♥️", "name": "hearts", "keywords": ["poker", "cards", "magic", "suits"] }, - { "category": "symbols", "char": "♦️", "name": "diamonds", "keywords": ["poker", "cards", "magic", "suits"] }, - { "category": "symbols", "char": "🎴", "name": "flower_playing_cards", "keywords": ["game", "sunset", "red"] }, - { "category": "symbols", "char": "💭", "name": "thought_balloon", "keywords": ["bubble", "cloud", "speech", "thinking", "dream"] }, - { "category": "symbols", "char": "🗯", "name": "right_anger_bubble", "keywords": ["caption", "speech", "thinking", "mad"] }, - { "category": "symbols", "char": "💬", "name": "speech_balloon", "keywords": ["bubble", "words", "message", "talk", "chatting"] }, - { "category": "symbols", "char": "🗨", "name": "left_speech_bubble", "keywords": ["words", "message", "talk", "chatting"] }, - { "category": "symbols", "char": "🕐", "name": "clock1", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕑", "name": "clock2", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕒", "name": "clock3", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕓", "name": "clock4", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕔", "name": "clock5", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕕", "name": "clock6", "keywords": ["time", "late", "early", "schedule", "dawn", "dusk"] }, - { "category": "symbols", "char": "🕖", "name": "clock7", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕗", "name": "clock8", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕘", "name": "clock9", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕙", "name": "clock10", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕚", "name": "clock11", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕛", "name": "clock12", "keywords": ["time", "noon", "midnight", "midday", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕜", "name": "clock130", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕝", "name": "clock230", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕞", "name": "clock330", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕟", "name": "clock430", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕠", "name": "clock530", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕡", "name": "clock630", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕢", "name": "clock730", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕣", "name": "clock830", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕤", "name": "clock930", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕥", "name": "clock1030", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕦", "name": "clock1130", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "symbols", "char": "🕧", "name": "clock1230", "keywords": ["time", "late", "early", "schedule"] }, - { "category": "flags", "char": "🇦🇫", "name": "afghanistan", "keywords": ["af", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇽", "name": "aland_islands", "keywords": ["Åland", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇱", "name": "albania", "keywords": ["al", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇩🇿", "name": "algeria", "keywords": ["dz", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇸", "name": "american_samoa", "keywords": ["american", "ws", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇩", "name": "andorra", "keywords": ["ad", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇴", "name": "angola", "keywords": ["ao", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇮", "name": "anguilla", "keywords": ["ai", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇶", "name": "antarctica", "keywords": ["aq", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇬", "name": "antigua_barbuda", "keywords": ["antigua", "barbuda", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇷", "name": "argentina", "keywords": ["ar", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇲", "name": "armenia", "keywords": ["am", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇼", "name": "aruba", "keywords": ["aw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇨", "name": "ascension_island", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇺", "name": "australia", "keywords": ["au", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇹", "name": "austria", "keywords": ["at", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇿", "name": "azerbaijan", "keywords": ["az", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇸", "name": "bahamas", "keywords": ["bs", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇭", "name": "bahrain", "keywords": ["bh", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇩", "name": "bangladesh", "keywords": ["bd", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇧", "name": "barbados", "keywords": ["bb", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇾", "name": "belarus", "keywords": ["by", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇪", "name": "belgium", "keywords": ["be", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇿", "name": "belize", "keywords": ["bz", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇯", "name": "benin", "keywords": ["bj", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇲", "name": "bermuda", "keywords": ["bm", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇹", "name": "bhutan", "keywords": ["bt", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇴", "name": "bolivia", "keywords": ["bo", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇶", "name": "caribbean_netherlands", "keywords": ["bonaire", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇦", "name": "bosnia_herzegovina", "keywords": ["bosnia", "herzegovina", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇼", "name": "botswana", "keywords": ["bw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇷", "name": "brazil", "keywords": ["br", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇴", "name": "british_indian_ocean_territory", "keywords": ["british", "indian", "ocean", "territory", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇻🇬", "name": "british_virgin_islands", "keywords": ["british", "virgin", "islands", "bvi", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇳", "name": "brunei", "keywords": ["bn", "darussalam", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇬", "name": "bulgaria", "keywords": ["bg", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇫", "name": "burkina_faso", "keywords": ["burkina", "faso", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇮", "name": "burundi", "keywords": ["bi", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇻", "name": "cape_verde", "keywords": ["cabo", "verde", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇭", "name": "cambodia", "keywords": ["kh", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇲", "name": "cameroon", "keywords": ["cm", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇦", "name": "canada", "keywords": ["ca", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇨", "name": "canary_islands", "keywords": ["canary", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇾", "name": "cayman_islands", "keywords": ["cayman", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇫", "name": "central_african_republic", "keywords": ["central", "african", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇩", "name": "chad", "keywords": ["td", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇱", "name": "chile", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇳", "name": "cn", "keywords": ["china", "chinese", "prc", "flag", "country", "nation", "banner"] }, - { "category": "flags", "char": "🇨🇽", "name": "christmas_island", "keywords": ["christmas", "island", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇨", "name": "cocos_islands", "keywords": ["cocos", "keeling", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇴", "name": "colombia", "keywords": ["co", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇲", "name": "comoros", "keywords": ["km", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇬", "name": "congo_brazzaville", "keywords": ["congo", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇩", "name": "congo_kinshasa", "keywords": ["congo", "democratic", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇰", "name": "cook_islands", "keywords": ["cook", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇷", "name": "costa_rica", "keywords": ["costa", "rica", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇭🇷", "name": "croatia", "keywords": ["hr", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇺", "name": "cuba", "keywords": ["cu", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇼", "name": "curacao", "keywords": ["curaçao", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇾", "name": "cyprus", "keywords": ["cy", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇿", "name": "czech_republic", "keywords": ["cz", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇩🇰", "name": "denmark", "keywords": ["dk", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇩🇯", "name": "djibouti", "keywords": ["dj", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇩🇲", "name": "dominica", "keywords": ["dm", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇩🇴", "name": "dominican_republic", "keywords": ["dominican", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇨", "name": "ecuador", "keywords": ["ec", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇬", "name": "egypt", "keywords": ["eg", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇻", "name": "el_salvador", "keywords": ["el", "salvador", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇶", "name": "equatorial_guinea", "keywords": ["equatorial", "gn", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇷", "name": "eritrea", "keywords": ["er", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇪", "name": "estonia", "keywords": ["ee", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇹", "name": "ethiopia", "keywords": ["et", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇺", "name": "eu", "keywords": ["european", "union", "flag", "banner"] }, - { "category": "flags", "char": "🇫🇰", "name": "falkland_islands", "keywords": ["falkland", "islands", "malvinas", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇫🇴", "name": "faroe_islands", "keywords": ["faroe", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇫🇯", "name": "fiji", "keywords": ["fj", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇫🇮", "name": "finland", "keywords": ["fi", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇫🇷", "name": "fr", "keywords": ["banner", "flag", "nation", "france", "french", "country"] }, - { "category": "flags", "char": "🇬🇫", "name": "french_guiana", "keywords": ["french", "guiana", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇫", "name": "french_polynesia", "keywords": ["french", "polynesia", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇫", "name": "french_southern_territories", "keywords": ["french", "southern", "territories", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇦", "name": "gabon", "keywords": ["ga", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇲", "name": "gambia", "keywords": ["gm", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇪", "name": "georgia", "keywords": ["ge", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇩🇪", "name": "de", "keywords": ["german", "nation", "flag", "country", "banner"] }, - { "category": "flags", "char": "🇬🇭", "name": "ghana", "keywords": ["gh", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇮", "name": "gibraltar", "keywords": ["gi", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇷", "name": "greece", "keywords": ["gr", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇱", "name": "greenland", "keywords": ["gl", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇩", "name": "grenada", "keywords": ["gd", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇵", "name": "guadeloupe", "keywords": ["gp", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇺", "name": "guam", "keywords": ["gu", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇹", "name": "guatemala", "keywords": ["gt", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇬", "name": "guernsey", "keywords": ["gg", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇳", "name": "guinea", "keywords": ["gn", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇼", "name": "guinea_bissau", "keywords": ["gw", "bissau", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇾", "name": "guyana", "keywords": ["gy", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇭🇹", "name": "haiti", "keywords": ["ht", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇭🇳", "name": "honduras", "keywords": ["hn", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇭🇰", "name": "hong_kong", "keywords": ["hong", "kong", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇭🇺", "name": "hungary", "keywords": ["hu", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇸", "name": "iceland", "keywords": ["is", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇳", "name": "india", "keywords": ["in", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇩", "name": "indonesia", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇷", "name": "iran", "keywords": ["iran, ", "islamic", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇶", "name": "iraq", "keywords": ["iq", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇪", "name": "ireland", "keywords": ["ie", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇲", "name": "isle_of_man", "keywords": ["isle", "man", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇱", "name": "israel", "keywords": ["il", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇮🇹", "name": "it", "keywords": ["italy", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇮", "name": "cote_divoire", "keywords": ["ivory", "coast", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇯🇲", "name": "jamaica", "keywords": ["jm", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇯🇵", "name": "jp", "keywords": ["japanese", "nation", "flag", "country", "banner"] }, - { "category": "flags", "char": "🇯🇪", "name": "jersey", "keywords": ["je", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇯🇴", "name": "jordan", "keywords": ["jo", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇿", "name": "kazakhstan", "keywords": ["kz", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇪", "name": "kenya", "keywords": ["ke", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇮", "name": "kiribati", "keywords": ["ki", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇽🇰", "name": "kosovo", "keywords": ["xk", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇼", "name": "kuwait", "keywords": ["kw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇬", "name": "kyrgyzstan", "keywords": ["kg", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇦", "name": "laos", "keywords": ["lao", "democratic", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇻", "name": "latvia", "keywords": ["lv", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇧", "name": "lebanon", "keywords": ["lb", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇸", "name": "lesotho", "keywords": ["ls", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇷", "name": "liberia", "keywords": ["lr", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇾", "name": "libya", "keywords": ["ly", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇮", "name": "liechtenstein", "keywords": ["li", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇹", "name": "lithuania", "keywords": ["lt", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇺", "name": "luxembourg", "keywords": ["lu", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇴", "name": "macau", "keywords": ["macao", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇰", "name": "macedonia", "keywords": ["macedonia, ", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇬", "name": "madagascar", "keywords": ["mg", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇼", "name": "malawi", "keywords": ["mw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇾", "name": "malaysia", "keywords": ["my", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇻", "name": "maldives", "keywords": ["mv", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇱", "name": "mali", "keywords": ["ml", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇹", "name": "malta", "keywords": ["mt", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇭", "name": "marshall_islands", "keywords": ["marshall", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇶", "name": "martinique", "keywords": ["mq", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇷", "name": "mauritania", "keywords": ["mr", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇺", "name": "mauritius", "keywords": ["mu", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇾🇹", "name": "mayotte", "keywords": ["yt", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇽", "name": "mexico", "keywords": ["mx", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇫🇲", "name": "micronesia", "keywords": ["micronesia, ", "federated", "states", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇩", "name": "moldova", "keywords": ["moldova, ", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇨", "name": "monaco", "keywords": ["mc", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇳", "name": "mongolia", "keywords": ["mn", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇪", "name": "montenegro", "keywords": ["me", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇸", "name": "montserrat", "keywords": ["ms", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇦", "name": "morocco", "keywords": ["ma", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇿", "name": "mozambique", "keywords": ["mz", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇲", "name": "myanmar", "keywords": ["mm", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇦", "name": "namibia", "keywords": ["na", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇷", "name": "nauru", "keywords": ["nr", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇵", "name": "nepal", "keywords": ["np", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇱", "name": "netherlands", "keywords": ["nl", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇨", "name": "new_caledonia", "keywords": ["new", "caledonia", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇿", "name": "new_zealand", "keywords": ["new", "zealand", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇮", "name": "nicaragua", "keywords": ["ni", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇪", "name": "niger", "keywords": ["ne", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇬", "name": "nigeria", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇺", "name": "niue", "keywords": ["nu", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇳🇫", "name": "norfolk_island", "keywords": ["norfolk", "island", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇲🇵", "name": "northern_mariana_islands", "keywords": ["northern", "mariana", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇵", "name": "north_korea", "keywords": ["north", "korea", "nation", "flag", "country", "banner"] }, - { "category": "flags", "char": "🇳🇴", "name": "norway", "keywords": ["no", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇴🇲", "name": "oman", "keywords": ["om_symbol", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇰", "name": "pakistan", "keywords": ["pk", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇼", "name": "palau", "keywords": ["pw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇸", "name": "palestinian_territories", "keywords": ["palestine", "palestinian", "territories", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇦", "name": "panama", "keywords": ["pa", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇬", "name": "papua_new_guinea", "keywords": ["papua", "new", "guinea", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇾", "name": "paraguay", "keywords": ["py", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇪", "name": "peru", "keywords": ["pe", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇭", "name": "philippines", "keywords": ["ph", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇳", "name": "pitcairn_islands", "keywords": ["pitcairn", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇱", "name": "poland", "keywords": ["pl", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇹", "name": "portugal", "keywords": ["pt", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇷", "name": "puerto_rico", "keywords": ["puerto", "rico", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇶🇦", "name": "qatar", "keywords": ["qa", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇷🇪", "name": "reunion", "keywords": ["réunion", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇷🇴", "name": "romania", "keywords": ["ro", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇷🇺", "name": "ru", "keywords": ["russian", "federation", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇷🇼", "name": "rwanda", "keywords": ["rw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇧🇱", "name": "st_barthelemy", "keywords": ["saint", "barthélemy", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇭", "name": "st_helena", "keywords": ["saint", "helena", "ascension", "tristan", "cunha", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇳", "name": "st_kitts_nevis", "keywords": ["saint", "kitts", "nevis", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇨", "name": "st_lucia", "keywords": ["saint", "lucia", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇵🇲", "name": "st_pierre_miquelon", "keywords": ["saint", "pierre", "miquelon", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇻🇨", "name": "st_vincent_grenadines", "keywords": ["saint", "vincent", "grenadines", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇼🇸", "name": "samoa", "keywords": ["ws", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇲", "name": "san_marino", "keywords": ["san", "marino", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇹", "name": "sao_tome_principe", "keywords": ["sao", "tome", "principe", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇦", "name": "saudi_arabia", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇳", "name": "senegal", "keywords": ["sn", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇷🇸", "name": "serbia", "keywords": ["rs", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇨", "name": "seychelles", "keywords": ["sc", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇱", "name": "sierra_leone", "keywords": ["sierra", "leone", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇬", "name": "singapore", "keywords": ["sg", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇽", "name": "sint_maarten", "keywords": ["sint", "maarten", "dutch", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇰", "name": "slovakia", "keywords": ["sk", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇮", "name": "slovenia", "keywords": ["si", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇧", "name": "solomon_islands", "keywords": ["solomon", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇴", "name": "somalia", "keywords": ["so", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇿🇦", "name": "south_africa", "keywords": ["south", "africa", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇸", "name": "south_georgia_south_sandwich_islands", "keywords": ["south", "georgia", "sandwich", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇰🇷", "name": "kr", "keywords": ["south", "korea", "nation", "flag", "country", "banner"] }, - { "category": "flags", "char": "🇸🇸", "name": "south_sudan", "keywords": ["south", "sd", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇸", "name": "es", "keywords": ["spain", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇱🇰", "name": "sri_lanka", "keywords": ["sri", "lanka", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇩", "name": "sudan", "keywords": ["sd", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇷", "name": "suriname", "keywords": ["sr", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇿", "name": "swaziland", "keywords": ["sz", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇪", "name": "sweden", "keywords": ["se", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇨🇭", "name": "switzerland", "keywords": ["ch", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇸🇾", "name": "syria", "keywords": ["syrian", "arab", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇼", "name": "taiwan", "keywords": ["tw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇯", "name": "tajikistan", "keywords": ["tj", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇿", "name": "tanzania", "keywords": ["tanzania, ", "united", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇭", "name": "thailand", "keywords": ["th", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇱", "name": "timor_leste", "keywords": ["timor", "leste", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇬", "name": "togo", "keywords": ["tg", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇰", "name": "tokelau", "keywords": ["tk", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇴", "name": "tonga", "keywords": ["to", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇹", "name": "trinidad_tobago", "keywords": ["trinidad", "tobago", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇦", "name": "tristan_da_cunha", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇳", "name": "tunisia", "keywords": ["tn", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇷", "name": "tr", "keywords": ["turkey", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇲", "name": "turkmenistan", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇨", "name": "turks_caicos_islands", "keywords": ["turks", "caicos", "islands", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇹🇻", "name": "tuvalu", "keywords": ["flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇺🇬", "name": "uganda", "keywords": ["ug", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇺🇦", "name": "ukraine", "keywords": ["ua", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇦🇪", "name": "united_arab_emirates", "keywords": ["united", "arab", "emirates", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇬🇧", "name": "uk", "keywords": ["united", "kingdom", "great", "britain", "northern", "ireland", "flag", "nation", "country", "banner", "british", "UK", "english", "england", "union jack"] }, - { "category": "flags", "char": "🏴", "name": "england", "keywords": ["flag", "english"] }, - { "category": "flags", "char": "🏴", "name": "scotland", "keywords": ["flag", "scottish"] }, - { "category": "flags", "char": "🏴", "name": "wales", "keywords": ["flag", "welsh"] }, - { "category": "flags", "char": "🇺🇸", "name": "us", "keywords": ["united", "states", "america", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇻🇮", "name": "us_virgin_islands", "keywords": ["virgin", "islands", "us", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇺🇾", "name": "uruguay", "keywords": ["uy", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇺🇿", "name": "uzbekistan", "keywords": ["uz", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇻🇺", "name": "vanuatu", "keywords": ["vu", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇻🇦", "name": "vatican_city", "keywords": ["vatican", "city", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇻🇪", "name": "venezuela", "keywords": ["ve", "bolivarian", "republic", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇻🇳", "name": "vietnam", "keywords": ["viet", "nam", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇼🇫", "name": "wallis_futuna", "keywords": ["wallis", "futuna", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇪🇭", "name": "western_sahara", "keywords": ["western", "sahara", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇾🇪", "name": "yemen", "keywords": ["ye", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇿🇲", "name": "zambia", "keywords": ["zm", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇿🇼", "name": "zimbabwe", "keywords": ["zw", "flag", "nation", "country", "banner"] }, - { "category": "flags", "char": "🇺🇳", "name": "united_nations", "keywords": ["un", "flag", "banner"] }, - { "category": "flags", "char": "🏴☠️", "name": "pirate_flag", "keywords": ["skull", "crossbones", "flag", "banner"] } + ["😀", "grinning", 0], + ["😬", "grimacing", 0], + ["😁", "grin", 0], + ["😂", "joy", 0], + ["🤣", "rofl", 0], + ["🥳", "partying", 0], + ["😃", "smiley", 0], + ["😄", "smile", 0], + ["😅", "sweat_smile", 0], + ["🥲", "smiling_face_with_tear", 0], + ["😆", "laughing", 0], + ["😇", "innocent", 0], + ["😉", "wink", 0], + ["😊", "blush", 0], + ["🙂", "slightly_smiling_face", 0], + ["🙃", "upside_down_face", 0], + ["☺️", "relaxed", 0], + ["😋", "yum", 0], + ["😌", "relieved", 0], + ["😍", "heart_eyes", 0], + ["🥰", "smiling_face_with_three_hearts", 0], + ["😘", "kissing_heart", 0], + ["😗", "kissing", 0], + ["😙", "kissing_smiling_eyes", 0], + ["😚", "kissing_closed_eyes", 0], + ["😜", "stuck_out_tongue_winking_eye", 0], + ["🤪", "zany", 0], + ["🤨", "raised_eyebrow", 0], + ["🧐", "monocle", 0], + ["😝", "stuck_out_tongue_closed_eyes", 0], + ["😛", "stuck_out_tongue", 0], + ["🤑", "money_mouth_face", 0], + ["🤓", "nerd_face", 0], + ["🥸", "disguised_face", 0], + ["😎", "sunglasses", 0], + ["🤩", "star_struck", 0], + ["🤡", "clown_face", 0], + ["🤠", "cowboy_hat_face", 0], + ["🤗", "hugs", 0], + ["😏", "smirk", 0], + ["😶", "no_mouth", 0], + ["😐", "neutral_face", 0], + ["😑", "expressionless", 0], + ["😒", "unamused", 0], + ["🙄", "roll_eyes", 0], + ["🤔", "thinking", 0], + ["🤥", "lying_face", 0], + ["🤭", "hand_over_mouth", 0], + ["🤫", "shushing", 0], + ["🤬", "symbols_over_mouth", 0], + ["🤯", "exploding_head", 0], + ["😳", "flushed", 0], + ["😞", "disappointed", 0], + ["😟", "worried", 0], + ["😠", "angry", 0], + ["😡", "rage", 0], + ["😔", "pensive", 0], + ["😕", "confused", 0], + ["🙁", "slightly_frowning_face", 0], + ["☹", "frowning_face", 0], + ["😣", "persevere", 0], + ["😖", "confounded", 0], + ["😫", "tired_face", 0], + ["😩", "weary", 0], + ["🥺", "pleading", 0], + ["😤", "triumph", 0], + ["😮", "open_mouth", 0], + ["😱", "scream", 0], + ["😨", "fearful", 0], + ["😰", "cold_sweat", 0], + ["😯", "hushed", 0], + ["😦", "frowning", 0], + ["😧", "anguished", 0], + ["😢", "cry", 0], + ["😥", "disappointed_relieved", 0], + ["🤤", "drooling_face", 0], + ["😪", "sleepy", 0], + ["😓", "sweat", 0], + ["🥵", "hot", 0], + ["🥶", "cold", 0], + ["😭", "sob", 0], + ["😵", "dizzy_face", 0], + ["😲", "astonished", 0], + ["🤐", "zipper_mouth_face", 0], + ["🤢", "nauseated_face", 0], + ["🤧", "sneezing_face", 0], + ["🤮", "vomiting", 0], + ["😷", "mask", 0], + ["🤒", "face_with_thermometer", 0], + ["🤕", "face_with_head_bandage", 0], + ["🥴", "woozy", 0], + ["🥱", "yawning", 0], + ["😴", "sleeping", 0], + ["💤", "zzz", 0], + ["😶🌫️", "face_in_clouds", 0], + ["😮💨", "face_exhaling", 0], + ["😵💫", "face_with_spiral_eyes", 0], + ["🫠", "melting_face", 0], + ["🫢", "face_with_open_eyes_and_hand_over_mouth", 0], + ["🫣", "face_with_peeking_eye", 0], + ["🫡", "saluting_face", 0], + ["🫥", "dotted_line_face", 0], + ["🫤", "face_with_diagonal_mouth", 0], + ["🥹", "face_holding_back_tears", 0], + ["💩", "poop", 0], + ["😈", "smiling_imp", 0], + ["👿", "imp", 0], + ["👹", "japanese_ogre", 0], + ["👺", "japanese_goblin", 0], + ["💀", "skull", 0], + ["👻", "ghost", 0], + ["👽", "alien", 0], + ["🤖", "robot", 0], + ["😺", "smiley_cat", 0], + ["😸", "smile_cat", 0], + ["😹", "joy_cat", 0], + ["😻", "heart_eyes_cat", 0], + ["😼", "smirk_cat", 0], + ["😽", "kissing_cat", 0], + ["🙀", "scream_cat", 0], + ["😿", "crying_cat_face", 0], + ["😾", "pouting_cat", 0], + ["🤲", "palms_up", 1], + ["🙌", "raised_hands", 1], + ["👏", "clap", 1], + ["👋", "wave", 1], + ["🤙", "call_me_hand", 1], + ["👍", "+1", 1], + ["👎", "-1", 1], + ["👊", "facepunch", 1], + ["✊", "fist", 1], + ["🤛", "fist_left", 1], + ["🤜", "fist_right", 1], + ["✌", "v", 1], + ["👌", "ok_hand", 1], + ["✋", "raised_hand", 1], + ["🤚", "raised_back_of_hand", 1], + ["👐", "open_hands", 1], + ["💪", "muscle", 1], + ["🦾", "mechanical_arm", 1], + ["🙏", "pray", 1], + ["🦶", "foot", 1], + ["🦵", "leg", 1], + ["🦿", "mechanical_leg", 1], + ["🤝", "handshake", 1], + ["☝", "point_up", 1], + ["👆", "point_up_2", 1], + ["👇", "point_down", 1], + ["👈", "point_left", 1], + ["👉", "point_right", 1], + ["🖕", "fu", 1], + ["🖐", "raised_hand_with_fingers_splayed", 1], + ["🤟", "love_you", 1], + ["🤘", "metal", 1], + ["🤞", "crossed_fingers", 1], + ["🖖", "vulcan_salute", 1], + ["✍", "writing_hand", 1], + ["🫰", "hand_with_index_finger_and_thumb_crossed", 1], + ["🫱", "rightwards_hand", 1], + ["🫲", "leftwards_hand", 1], + ["🫳", "palm_down_hand", 1], + ["🫴", "palm_up_hand", 1], + ["🫵", "index_pointing_at_the_viewer", 1], + ["🫶", "heart_hands", 1], + ["🤏", "pinching_hand", 1], + ["🤌", "pinched_fingers", 1], + ["🤳", "selfie", 1], + ["💅", "nail_care", 1], + ["👄", "lips", 1], + ["🫦", "biting_lip", 1], + ["🦷", "tooth", 1], + ["👅", "tongue", 1], + ["👂", "ear", 1], + ["🦻", "ear_with_hearing_aid", 1], + ["👃", "nose", 1], + ["👁", "eye", 1], + ["👀", "eyes", 1], + ["🧠", "brain", 1], + ["🫀", "anatomical_heart", 1], + ["🫁", "lungs", 1], + ["👤", "bust_in_silhouette", 1], + ["👥", "busts_in_silhouette", 1], + ["🗣", "speaking_head", 1], + ["👶", "baby", 1], + ["🧒", "child", 1], + ["👦", "boy", 1], + ["👧", "girl", 1], + ["🧑", "adult", 1], + ["👨", "man", 1], + ["👩", "woman", 1], + ["🧑🦱", "curly_hair", 1], + ["👩🦱", "curly_hair_woman", 1], + ["👨🦱", "curly_hair_man", 1], + ["🧑🦰", "red_hair", 1], + ["👩🦰", "red_hair_woman", 1], + ["👨🦰", "red_hair_man", 1], + ["👱♀️", "blonde_woman", 1], + ["👱", "blonde_man", 1], + ["🧑🦳", "white_hair", 1], + ["👩🦳", "white_hair_woman", 1], + ["👨🦳", "white_hair_man", 1], + ["🧑🦲", "bald", 1], + ["👩🦲", "bald_woman", 1], + ["👨🦲", "bald_man", 1], + ["🧔", "bearded_person", 1], + ["🧓", "older_adult", 1], + ["👴", "older_man", 1], + ["👵", "older_woman", 1], + ["👲", "man_with_gua_pi_mao", 1], + ["🧕", "woman_with_headscarf", 1], + ["👳♀️", "woman_with_turban", 1], + ["👳", "man_with_turban", 1], + ["👮♀️", "policewoman", 1], + ["👮", "policeman", 1], + ["👷♀️", "construction_worker_woman", 1], + ["👷", "construction_worker_man", 1], + ["💂♀️", "guardswoman", 1], + ["💂", "guardsman", 1], + ["🕵️♀️", "female_detective", 1], + ["🕵", "male_detective", 1], + ["🧑⚕️", "health_worker", 1], + ["👩⚕️", "woman_health_worker", 1], + ["👨⚕️", "man_health_worker", 1], + ["🧑🌾", "farmer", 1], + ["👩🌾", "woman_farmer", 1], + ["👨🌾", "man_farmer", 1], + ["🧑🍳", "cook", 1], + ["👩🍳", "woman_cook", 1], + ["👨🍳", "man_cook", 1], + ["🧑🎓", "student", 1], + ["👩🎓", "woman_student", 1], + ["👨🎓", "man_student", 1], + ["🧑🎤", "singer", 1], + ["👩🎤", "woman_singer", 1], + ["👨🎤", "man_singer", 1], + ["🧑🏫", "teacher", 1], + ["👩🏫", "woman_teacher", 1], + ["👨🏫", "man_teacher", 1], + ["🧑🏭", "factory_worker", 1], + ["👩🏭", "woman_factory_worker", 1], + ["👨🏭", "man_factory_worker", 1], + ["🧑💻", "technologist", 1], + ["👩💻", "woman_technologist", 1], + ["👨💻", "man_technologist", 1], + ["🧑💼", "office_worker", 1], + ["👩💼", "woman_office_worker", 1], + ["👨💼", "man_office_worker", 1], + ["🧑🔧", "mechanic", 1], + ["👩🔧", "woman_mechanic", 1], + ["👨🔧", "man_mechanic", 1], + ["🧑🔬", "scientist", 1], + ["👩🔬", "woman_scientist", 1], + ["👨🔬", "man_scientist", 1], + ["🧑🎨", "artist", 1], + ["👩🎨", "woman_artist", 1], + ["👨🎨", "man_artist", 1], + ["🧑🚒", "firefighter", 1], + ["👩🚒", "woman_firefighter", 1], + ["👨🚒", "man_firefighter", 1], + ["🧑✈️", "pilot", 1], + ["👩✈️", "woman_pilot", 1], + ["👨✈️", "man_pilot", 1], + ["🧑🚀", "astronaut", 1], + ["👩🚀", "woman_astronaut", 1], + ["👨🚀", "man_astronaut", 1], + ["🧑⚖️", "judge", 1], + ["👩⚖️", "woman_judge", 1], + ["👨⚖️", "man_judge", 1], + ["🦸♀️", "woman_superhero", 1], + ["🦸♂️", "man_superhero", 1], + ["🦹♀️", "woman_supervillain", 1], + ["🦹♂️", "man_supervillain", 1], + ["🤶", "mrs_claus", 1], + ["🧑🎄", "mx_claus", 1], + ["🎅", "santa", 1], + ["🥷", "ninja", 1], + ["🧙♀️", "sorceress", 1], + ["🧙♂️", "wizard", 1], + ["🧝♀️", "woman_elf", 1], + ["🧝♂️", "man_elf", 1], + ["🧛♀️", "woman_vampire", 1], + ["🧛♂️", "man_vampire", 1], + ["🧟♀️", "woman_zombie", 1], + ["🧟♂️", "man_zombie", 1], + ["🧞♀️", "woman_genie", 1], + ["🧞♂️", "man_genie", 1], + ["🧜♀️", "mermaid", 1], + ["🧜♂️", "merman", 1], + ["🧚♀️", "woman_fairy", 1], + ["🧚♂️", "man_fairy", 1], + ["👼", "angel", 1], + ["🧌", "troll", 1], + ["🤰", "pregnant_woman", 1], + ["🫃", "pregnant_man", 1], + ["🫄", "pregnant_person", 1], + ["🫅", "person_with_crown", 1], + ["🤱", "breastfeeding", 1], + ["👩🍼", "woman_feeding_baby", 1], + ["👨🍼", "man_feeding_baby", 1], + ["🧑🍼", "person_feeding_baby", 1], + ["👸", "princess", 1], + ["🤴", "prince", 1], + ["👰", "person_with_veil", 1], + ["👰", "bride_with_veil", 1], + ["🤵", "person_in_tuxedo", 1], + ["🤵", "man_in_tuxedo", 1], + ["🏃♀️", "running_woman", 1], + ["🏃", "running_man", 1], + ["🚶♀️", "walking_woman", 1], + ["🚶", "walking_man", 1], + ["💃", "dancer", 1], + ["🕺", "man_dancing", 1], + ["👯", "dancing_women", 1], + ["👯♂️", "dancing_men", 1], + ["👫", "couple", 1], + ["🧑🤝🧑", "people_holding_hands", 1], + ["👬", "two_men_holding_hands", 1], + ["👭", "two_women_holding_hands", 1], + ["🫂", "people_hugging", 1], + ["🙇♀️", "bowing_woman", 1], + ["🙇", "bowing_man", 1], + ["🤦♂️", "man_facepalming", 1], + ["🤦♀️", "woman_facepalming", 1], + ["🤷", "woman_shrugging", 1], + ["🤷♂️", "man_shrugging", 1], + ["💁", "tipping_hand_woman", 1], + ["💁♂️", "tipping_hand_man", 1], + ["🙅", "no_good_woman", 1], + ["🙅♂️", "no_good_man", 1], + ["🙆", "ok_woman", 1], + ["🙆♂️", "ok_man", 1], + ["🙋", "raising_hand_woman", 1], + ["🙋♂️", "raising_hand_man", 1], + ["🙎", "pouting_woman", 1], + ["🙎♂️", "pouting_man", 1], + ["🙍", "frowning_woman", 1], + ["🙍♂️", "frowning_man", 1], + ["💇", "haircut_woman", 1], + ["💇♂️", "haircut_man", 1], + ["💆", "massage_woman", 1], + ["💆♂️", "massage_man", 1], + ["🧖♀️", "woman_in_steamy_room", 1], + ["🧖♂️", "man_in_steamy_room", 1], + ["🧏♀️", "woman_deaf", 1], + ["🧏♂️", "man_deaf", 1], + ["🧍♀️", "woman_standing", 1], + ["🧍♂️", "man_standing", 1], + ["🧎♀️", "woman_kneeling", 1], + ["🧎♂️", "man_kneeling", 1], + ["🧑🦯", "person_with_probing_cane", 1], + ["👩🦯", "woman_with_probing_cane", 1], + ["👨🦯", "man_with_probing_cane", 1], + ["🧑🦼", "person_in_motorized_wheelchair", 1], + ["👩🦼", "woman_in_motorized_wheelchair", 1], + ["👨🦼", "man_in_motorized_wheelchair", 1], + ["🧑🦽", "person_in_manual_wheelchair", 1], + ["👩🦽", "woman_in_manual_wheelchair", 1], + ["👨🦽", "man_in_manual_wheelchair", 1], + ["💑", "couple_with_heart_woman_man", 1], + ["👩❤️👩", "couple_with_heart_woman_woman", 1], + ["👨❤️👨", "couple_with_heart_man_man", 1], + ["💏", "couplekiss_man_woman", 1], + ["👩❤️💋👩", "couplekiss_woman_woman", 1], + ["👨❤️💋👨", "couplekiss_man_man", 1], + ["👪", "family_man_woman_boy", 1], + ["👨👩👧", "family_man_woman_girl", 1], + ["👨👩👧👦", "family_man_woman_girl_boy", 1], + ["👨👩👦👦", "family_man_woman_boy_boy", 1], + ["👨👩👧👧", "family_man_woman_girl_girl", 1], + ["👩👩👦", "family_woman_woman_boy", 1], + ["👩👩👧", "family_woman_woman_girl", 1], + ["👩👩👧👦", "family_woman_woman_girl_boy", 1], + ["👩👩👦👦", "family_woman_woman_boy_boy", 1], + ["👩👩👧👧", "family_woman_woman_girl_girl", 1], + ["👨👨👦", "family_man_man_boy", 1], + ["👨👨👧", "family_man_man_girl", 1], + ["👨👨👧👦", "family_man_man_girl_boy", 1], + ["👨👨👦👦", "family_man_man_boy_boy", 1], + ["👨👨👧👧", "family_man_man_girl_girl", 1], + ["👩👦", "family_woman_boy", 1], + ["👩👧", "family_woman_girl", 1], + ["👩👧👦", "family_woman_girl_boy", 1], + ["👩👦👦", "family_woman_boy_boy", 1], + ["👩👧👧", "family_woman_girl_girl", 1], + ["👨👦", "family_man_boy", 1], + ["👨👧", "family_man_girl", 1], + ["👨👧👦", "family_man_girl_boy", 1], + ["👨👦👦", "family_man_boy_boy", 1], + ["👨👧👧", "family_man_girl_girl", 1], + ["🧶", "yarn", 1], + ["🧵", "thread", 1], + ["🧥", "coat", 1], + ["🥼", "labcoat", 1], + ["👚", "womans_clothes", 1], + ["👕", "tshirt", 1], + ["👖", "jeans", 1], + ["👔", "necktie", 1], + ["👗", "dress", 1], + ["👙", "bikini", 1], + ["🩱", "one_piece_swimsuit", 1], + ["👘", "kimono", 1], + ["🥻", "sari", 1], + ["🩲", "briefs", 1], + ["🩳", "shorts", 1], + ["💄", "lipstick", 1], + ["💋", "kiss", 1], + ["👣", "footprints", 1], + ["🥿", "flat_shoe", 1], + ["👠", "high_heel", 1], + ["👡", "sandal", 1], + ["👢", "boot", 1], + ["👞", "mans_shoe", 1], + ["👟", "athletic_shoe", 1], + ["🩴", "thong_sandal", 1], + ["🩰", "ballet_shoes", 1], + ["🧦", "socks", 1], + ["🧤", "gloves", 1], + ["🧣", "scarf", 1], + ["👒", "womans_hat", 1], + ["🎩", "tophat", 1], + ["🧢", "billed_hat", 1], + ["⛑", "rescue_worker_helmet", 1], + ["🪖", "military_helmet", 1], + ["🎓", "mortar_board", 1], + ["👑", "crown", 1], + ["🎒", "school_satchel", 1], + ["🧳", "luggage", 1], + ["👝", "pouch", 1], + ["👛", "purse", 1], + ["👜", "handbag", 1], + ["💼", "briefcase", 1], + ["👓", "eyeglasses", 1], + ["🕶", "dark_sunglasses", 1], + ["🥽", "goggles", 1], + ["💍", "ring", 1], + ["🌂", "closed_umbrella", 1], + ["🐶", "dog", 2], + ["🐱", "cat", 2], + ["🐈⬛", "black_cat", 2], + ["🐭", "mouse", 2], + ["🐹", "hamster", 2], + ["🐰", "rabbit", 2], + ["🦊", "fox_face", 2], + ["🐻", "bear", 2], + ["🐼", "panda_face", 2], + ["🐨", "koala", 2], + ["🐯", "tiger", 2], + ["🦁", "lion", 2], + ["🐮", "cow", 2], + ["🐷", "pig", 2], + ["🐽", "pig_nose", 2], + ["🐸", "frog", 2], + ["🦑", "squid", 2], + ["🐙", "octopus", 2], + ["🦐", "shrimp", 2], + ["🐵", "monkey_face", 2], + ["🦍", "gorilla", 2], + ["🙈", "see_no_evil", 2], + ["🙉", "hear_no_evil", 2], + ["🙊", "speak_no_evil", 2], + ["🐒", "monkey", 2], + ["🐔", "chicken", 2], + ["🐧", "penguin", 2], + ["🐦", "bird", 2], + ["🐤", "baby_chick", 2], + ["🐣", "hatching_chick", 2], + ["🐥", "hatched_chick", 2], + ["🦆", "duck", 2], + ["🦅", "eagle", 2], + ["🦉", "owl", 2], + ["🦇", "bat", 2], + ["🐺", "wolf", 2], + ["🐗", "boar", 2], + ["🐴", "horse", 2], + ["🦄", "unicorn", 2], + ["🐝", "honeybee", 2], + ["🐛", "bug", 2], + ["🦋", "butterfly", 2], + ["🐌", "snail", 2], + ["🐞", "lady_beetle", 2], + ["🐜", "ant", 2], + ["🦗", "grasshopper", 2], + ["🕷", "spider", 2], + ["🪲", "beetle", 2], + ["🪳", "cockroach", 2], + ["🪰", "fly", 2], + ["🪱", "worm", 2], + ["🦂", "scorpion", 2], + ["🦀", "crab", 2], + ["🐍", "snake", 2], + ["🦎", "lizard", 2], + ["🦖", "t-rex", 2], + ["🦕", "sauropod", 2], + ["🐢", "turtle", 2], + ["🐠", "tropical_fish", 2], + ["🐟", "fish", 2], + ["🐡", "blowfish", 2], + ["🐬", "dolphin", 2], + ["🦈", "shark", 2], + ["🐳", "whale", 2], + ["🐋", "whale2", 2], + ["🐊", "crocodile", 2], + ["🐆", "leopard", 2], + ["🦓", "zebra", 2], + ["🐅", "tiger2", 2], + ["🐃", "water_buffalo", 2], + ["🐂", "ox", 2], + ["🐄", "cow2", 2], + ["🦌", "deer", 2], + ["🐪", "dromedary_camel", 2], + ["🐫", "camel", 2], + ["🦒", "giraffe", 2], + ["🐘", "elephant", 2], + ["🦏", "rhinoceros", 2], + ["🐐", "goat", 2], + ["🐏", "ram", 2], + ["🐑", "sheep", 2], + ["🐎", "racehorse", 2], + ["🐖", "pig2", 2], + ["🐀", "rat", 2], + ["🐁", "mouse2", 2], + ["🐓", "rooster", 2], + ["🦃", "turkey", 2], + ["🕊", "dove", 2], + ["🐕", "dog2", 2], + ["🐩", "poodle", 2], + ["🐈", "cat2", 2], + ["🐇", "rabbit2", 2], + ["🐿", "chipmunk", 2], + ["🦔", "hedgehog", 2], + ["🦝", "raccoon", 2], + ["🦙", "llama", 2], + ["🦛", "hippopotamus", 2], + ["🦘", "kangaroo", 2], + ["🦡", "badger", 2], + ["🦢", "swan", 2], + ["🦚", "peacock", 2], + ["🦜", "parrot", 2], + ["🦞", "lobster", 2], + ["🦠", "microbe", 2], + ["🦟", "mosquito", 2], + ["🦬", "bison", 2], + ["🦣", "mammoth", 2], + ["🦫", "beaver", 2], + ["🐻❄️", "polar_bear", 2], + ["🦤", "dodo", 2], + ["🪶", "feather", 2], + ["🦭", "seal", 2], + ["🐾", "paw_prints", 2], + ["🐉", "dragon", 2], + ["🐲", "dragon_face", 2], + ["🦧", "orangutan", 2], + ["🦮", "guide_dog", 2], + ["🐕🦺", "service_dog", 2], + ["🦥", "sloth", 2], + ["🦦", "otter", 2], + ["🦨", "skunk", 2], + ["🦩", "flamingo", 2], + ["🌵", "cactus", 2], + ["🎄", "christmas_tree", 2], + ["🌲", "evergreen_tree", 2], + ["🌳", "deciduous_tree", 2], + ["🌴", "palm_tree", 2], + ["🌱", "seedling", 2], + ["🌿", "herb", 2], + ["☘", "shamrock", 2], + ["🍀", "four_leaf_clover", 2], + ["🎍", "bamboo", 2], + ["🎋", "tanabata_tree", 2], + ["🍃", "leaves", 2], + ["🍂", "fallen_leaf", 2], + ["🍁", "maple_leaf", 2], + ["🌾", "ear_of_rice", 2], + ["🌺", "hibiscus", 2], + ["🌻", "sunflower", 2], + ["🌹", "rose", 2], + ["🥀", "wilted_flower", 2], + ["🌷", "tulip", 2], + ["🌼", "blossom", 2], + ["🌸", "cherry_blossom", 2], + ["💐", "bouquet", 2], + ["🍄", "mushroom", 2], + ["🪴", "potted_plant", 2], + ["🌰", "chestnut", 2], + ["🎃", "jack_o_lantern", 2], + ["🐚", "shell", 2], + ["🕸", "spider_web", 2], + ["🌎", "earth_americas", 2], + ["🌍", "earth_africa", 2], + ["🌏", "earth_asia", 2], + ["🪐", "ringed_planet", 2], + ["🌕", "full_moon", 2], + ["🌖", "waning_gibbous_moon", 2], + ["🌗", "last_quarter_moon", 2], + ["🌘", "waning_crescent_moon", 2], + ["🌑", "new_moon", 2], + ["🌒", "waxing_crescent_moon", 2], + ["🌓", "first_quarter_moon", 2], + ["🌔", "waxing_gibbous_moon", 2], + ["🌚", "new_moon_with_face", 2], + ["🌝", "full_moon_with_face", 2], + ["🌛", "first_quarter_moon_with_face", 2], + ["🌜", "last_quarter_moon_with_face", 2], + ["🌞", "sun_with_face", 2], + ["🌙", "crescent_moon", 2], + ["⭐", "star", 2], + ["🌟", "star2", 2], + ["💫", "dizzy", 2], + ["✨", "sparkles", 2], + ["☄", "comet", 2], + ["☀️", "sunny", 2], + ["🌤", "sun_behind_small_cloud", 2], + ["⛅", "partly_sunny", 2], + ["🌥", "sun_behind_large_cloud", 2], + ["🌦", "sun_behind_rain_cloud", 2], + ["☁️", "cloud", 2], + ["🌧", "cloud_with_rain", 2], + ["⛈", "cloud_with_lightning_and_rain", 2], + ["🌩", "cloud_with_lightning", 2], + ["⚡", "zap", 2], + ["🔥", "fire", 2], + ["💥", "boom", 2], + ["❄️", "snowflake", 2], + ["🌨", "cloud_with_snow", 2], + ["⛄", "snowman", 2], + ["☃", "snowman_with_snow", 2], + ["🌬", "wind_face", 2], + ["💨", "dash", 2], + ["🌪", "tornado", 2], + ["🌫", "fog", 2], + ["☂", "open_umbrella", 2], + ["☔", "umbrella", 2], + ["💧", "droplet", 2], + ["💦", "sweat_drops", 2], + ["🌊", "ocean", 2], + ["🪷", "lotus", 2], + ["🪸", "coral", 2], + ["🪹", "empty_nest", 2], + ["🪺", "nest_with_eggs", 2], + ["🍏", "green_apple", 3], + ["🍎", "apple", 3], + ["🍐", "pear", 3], + ["🍊", "tangerine", 3], + ["🍋", "lemon", 3], + ["🍌", "banana", 3], + ["🍉", "watermelon", 3], + ["🍇", "grapes", 3], + ["🍓", "strawberry", 3], + ["🍈", "melon", 3], + ["🍒", "cherries", 3], + ["🍑", "peach", 3], + ["🍍", "pineapple", 3], + ["🥥", "coconut", 3], + ["🥝", "kiwi_fruit", 3], + ["🥭", "mango", 3], + ["🥑", "avocado", 3], + ["🥦", "broccoli", 3], + ["🍅", "tomato", 3], + ["🍆", "eggplant", 3], + ["🥒", "cucumber", 3], + ["🫐", "blueberries", 3], + ["🫒", "olive", 3], + ["🫑", "bell_pepper", 3], + ["🥕", "carrot", 3], + ["🌶", "hot_pepper", 3], + ["🥔", "potato", 3], + ["🌽", "corn", 3], + ["🥬", "leafy_greens", 3], + ["🍠", "sweet_potato", 3], + ["🥜", "peanuts", 3], + ["🧄", "garlic", 3], + ["🧅", "onion", 3], + ["🍯", "honey_pot", 3], + ["🥐", "croissant", 3], + ["🍞", "bread", 3], + ["🥖", "baguette_bread", 3], + ["🥯", "bagel", 3], + ["🥨", "pretzel", 3], + ["🧀", "cheese", 3], + ["🥚", "egg", 3], + ["🥓", "bacon", 3], + ["🥩", "steak", 3], + ["🥞", "pancakes", 3], + ["🍗", "poultry_leg", 3], + ["🍖", "meat_on_bone", 3], + ["🦴", "bone", 3], + ["🍤", "fried_shrimp", 3], + ["🍳", "fried_egg", 3], + ["🍔", "hamburger", 3], + ["🍟", "fries", 3], + ["🥙", "stuffed_flatbread", 3], + ["🌭", "hotdog", 3], + ["🍕", "pizza", 3], + ["🥪", "sandwich", 3], + ["🥫", "canned_food", 3], + ["🍝", "spaghetti", 3], + ["🌮", "taco", 3], + ["🌯", "burrito", 3], + ["🥗", "green_salad", 3], + ["🥘", "shallow_pan_of_food", 3], + ["🍜", "ramen", 3], + ["🍲", "stew", 3], + ["🍥", "fish_cake", 3], + ["🥠", "fortune_cookie", 3], + ["🍣", "sushi", 3], + ["🍱", "bento", 3], + ["🍛", "curry", 3], + ["🍙", "rice_ball", 3], + ["🍚", "rice", 3], + ["🍘", "rice_cracker", 3], + ["🍢", "oden", 3], + ["🍡", "dango", 3], + ["🍧", "shaved_ice", 3], + ["🍨", "ice_cream", 3], + ["🍦", "icecream", 3], + ["🥧", "pie", 3], + ["🍰", "cake", 3], + ["🧁", "cupcake", 3], + ["🥮", "moon_cake", 3], + ["🎂", "birthday", 3], + ["🍮", "custard", 3], + ["🍬", "candy", 3], + ["🍭", "lollipop", 3], + ["🍫", "chocolate_bar", 3], + ["🍿", "popcorn", 3], + ["🥟", "dumpling", 3], + ["🍩", "doughnut", 3], + ["🍪", "cookie", 3], + ["🧇", "waffle", 3], + ["🧆", "falafel", 3], + ["🧈", "butter", 3], + ["🦪", "oyster", 3], + ["🫓", "flatbread", 3], + ["🫔", "tamale", 3], + ["🫕", "fondue", 3], + ["🥛", "milk_glass", 3], + ["🍺", "beer", 3], + ["🍻", "beers", 3], + ["🥂", "clinking_glasses", 3], + ["🍷", "wine_glass", 3], + ["🥃", "tumbler_glass", 3], + ["🍸", "cocktail", 3], + ["🍹", "tropical_drink", 3], + ["🍾", "champagne", 3], + ["🍶", "sake", 3], + ["🍵", "tea", 3], + ["🥤", "cup_with_straw", 3], + ["☕", "coffee", 3], + ["🫖", "teapot", 3], + ["🧋", "bubble_tea", 3], + ["🍼", "baby_bottle", 3], + ["🧃", "beverage_box", 3], + ["🧉", "mate", 3], + ["🧊", "ice_cube", 3], + ["🧂", "salt", 3], + ["🥄", "spoon", 3], + ["🍴", "fork_and_knife", 3], + ["🍽", "plate_with_cutlery", 3], + ["🥣", "bowl_with_spoon", 3], + ["🥡", "takeout_box", 3], + ["🥢", "chopsticks", 3], + ["🫗", "pouring_liquid", 3], + ["🫘", "beans", 3], + ["🫙", "jar", 3], + ["⚽", "soccer", 4], + ["🏀", "basketball", 4], + ["🏈", "football", 4], + ["⚾", "baseball", 4], + ["🥎", "softball", 4], + ["🎾", "tennis", 4], + ["🏐", "volleyball", 4], + ["🏉", "rugby_football", 4], + ["🥏", "flying_disc", 4], + ["🎱", "8ball", 4], + ["⛳", "golf", 4], + ["🏌️♀️", "golfing_woman", 4], + ["🏌", "golfing_man", 4], + ["🏓", "ping_pong", 4], + ["🏸", "badminton", 4], + ["🥅", "goal_net", 4], + ["🏒", "ice_hockey", 4], + ["🏑", "field_hockey", 4], + ["🥍", "lacrosse", 4], + ["🏏", "cricket", 4], + ["🎿", "ski", 4], + ["⛷", "skier", 4], + ["🏂", "snowboarder", 4], + ["🤺", "person_fencing", 4], + ["🤼♀️", "women_wrestling", 4], + ["🤼♂️", "men_wrestling", 4], + ["🤸♀️", "woman_cartwheeling", 4], + ["🤸♂️", "man_cartwheeling", 4], + ["🤾♀️", "woman_playing_handball", 4], + ["🤾♂️", "man_playing_handball", 4], + ["⛸", "ice_skate", 4], + ["🥌", "curling_stone", 4], + ["🛹", "skateboard", 4], + ["🛷", "sled", 4], + ["🏹", "bow_and_arrow", 4], + ["🎣", "fishing_pole_and_fish", 4], + ["🥊", "boxing_glove", 4], + ["🥋", "martial_arts_uniform", 4], + ["🚣♀️", "rowing_woman", 4], + ["🚣", "rowing_man", 4], + ["🧗♀️", "climbing_woman", 4], + ["🧗♂️", "climbing_man", 4], + ["🏊♀️", "swimming_woman", 4], + ["🏊", "swimming_man", 4], + ["🤽♀️", "woman_playing_water_polo", 4], + ["🤽♂️", "man_playing_water_polo", 4], + ["🧘♀️", "woman_in_lotus_position", 4], + ["🧘♂️", "man_in_lotus_position", 4], + ["🏄♀️", "surfing_woman", 4], + ["🏄", "surfing_man", 4], + ["🛀", "bath", 4], + ["⛹️♀️", "basketball_woman", 4], + ["⛹", "basketball_man", 4], + ["🏋️♀️", "weight_lifting_woman", 4], + ["🏋", "weight_lifting_man", 4], + ["🚴♀️", "biking_woman", 4], + ["🚴", "biking_man", 4], + ["🚵♀️", "mountain_biking_woman", 4], + ["🚵", "mountain_biking_man", 4], + ["🏇", "horse_racing", 4], + ["🤿", "diving_mask", 4], + ["🪀", "yo_yo", 4], + ["🪁", "kite", 4], + ["🦺", "safety_vest", 4], + ["🪡", "sewing_needle", 4], + ["🪢", "knot", 4], + ["🕴", "business_suit_levitating", 4], + ["🏆", "trophy", 4], + ["🎽", "running_shirt_with_sash", 4], + ["🏅", "medal_sports", 4], + ["🎖", "medal_military", 4], + ["🥇", "1st_place_medal", 4], + ["🥈", "2nd_place_medal", 4], + ["🥉", "3rd_place_medal", 4], + ["🎗", "reminder_ribbon", 4], + ["🏵", "rosette", 4], + ["🎫", "ticket", 4], + ["🎟", "tickets", 4], + ["🎭", "performing_arts", 4], + ["🎨", "art", 4], + ["🎪", "circus_tent", 4], + ["🤹♀️", "woman_juggling", 4], + ["🤹♂️", "man_juggling", 4], + ["🎤", "microphone", 4], + ["🎧", "headphones", 4], + ["🎼", "musical_score", 4], + ["🎹", "musical_keyboard", 4], + ["🥁", "drum", 4], + ["🎷", "saxophone", 4], + ["🎺", "trumpet", 4], + ["🎸", "guitar", 4], + ["🎻", "violin", 4], + ["🪕", "banjo", 4], + ["🪗", "accordion", 4], + ["🪘", "long_drum", 4], + ["🎬", "clapper", 4], + ["🎮", "video_game", 4], + ["👾", "space_invader", 4], + ["🎯", "dart", 4], + ["🎲", "game_die", 4], + ["♟️", "chess_pawn", 4], + ["🎰", "slot_machine", 4], + ["🧩", "jigsaw", 4], + ["🎳", "bowling", 4], + ["🪄", "magic_wand", 4], + ["🪅", "pinata", 4], + ["🪆", "nesting_dolls", 4], + ["🪬", "hamsa", 4], + ["🪩", "mirror_ball", 4], + ["🚗", "red_car", 5], + ["🚕", "taxi", 5], + ["🚙", "blue_car", 5], + ["🚌", "bus", 5], + ["🚎", "trolleybus", 5], + ["🏎", "racing_car", 5], + ["🚓", "police_car", 5], + ["🚑", "ambulance", 5], + ["🚒", "fire_engine", 5], + ["🚐", "minibus", 5], + ["🚚", "truck", 5], + ["🚛", "articulated_lorry", 5], + ["🚜", "tractor", 5], + ["🛴", "kick_scooter", 5], + ["🏍", "motorcycle", 5], + ["🚲", "bike", 5], + ["🛵", "motor_scooter", 5], + ["🦽", "manual_wheelchair", 5], + ["🦼", "motorized_wheelchair", 5], + ["🛺", "auto_rickshaw", 5], + ["🪂", "parachute", 5], + ["🚨", "rotating_light", 5], + ["🚔", "oncoming_police_car", 5], + ["🚍", "oncoming_bus", 5], + ["🚘", "oncoming_automobile", 5], + ["🚖", "oncoming_taxi", 5], + ["🚡", "aerial_tramway", 5], + ["🚠", "mountain_cableway", 5], + ["🚟", "suspension_railway", 5], + ["🚃", "railway_car", 5], + ["🚋", "train", 5], + ["🚝", "monorail", 5], + ["🚄", "bullettrain_side", 5], + ["🚅", "bullettrain_front", 5], + ["🚈", "light_rail", 5], + ["🚞", "mountain_railway", 5], + ["🚂", "steam_locomotive", 5], + ["🚆", "train2", 5], + ["🚇", "metro", 5], + ["🚊", "tram", 5], + ["🚉", "station", 5], + ["🛸", "flying_saucer", 5], + ["🚁", "helicopter", 5], + ["🛩", "small_airplane", 5], + ["✈️", "airplane", 5], + ["🛫", "flight_departure", 5], + ["🛬", "flight_arrival", 5], + ["⛵", "sailboat", 5], + ["🛥", "motor_boat", 5], + ["🚤", "speedboat", 5], + ["⛴", "ferry", 5], + ["🛳", "passenger_ship", 5], + ["🚀", "rocket", 5], + ["🛰", "artificial_satellite", 5], + ["🛻", "pickup_truck", 5], + ["🛼", "roller_skate", 5], + ["💺", "seat", 5], + ["🛶", "canoe", 5], + ["⚓", "anchor", 5], + ["🚧", "construction", 5], + ["⛽", "fuelpump", 5], + ["🚏", "busstop", 5], + ["🚦", "vertical_traffic_light", 5], + ["🚥", "traffic_light", 5], + ["🏁", "checkered_flag", 5], + ["🚢", "ship", 5], + ["🎡", "ferris_wheel", 5], + ["🎢", "roller_coaster", 5], + ["🎠", "carousel_horse", 5], + ["🏗", "building_construction", 5], + ["🌁", "foggy", 5], + ["🏭", "factory", 5], + ["⛲", "fountain", 5], + ["🎑", "rice_scene", 5], + ["⛰", "mountain", 5], + ["🏔", "mountain_snow", 5], + ["🗻", "mount_fuji", 5], + ["🌋", "volcano", 5], + ["🗾", "japan", 5], + ["🏕", "camping", 5], + ["⛺", "tent", 5], + ["🏞", "national_park", 5], + ["🛣", "motorway", 5], + ["🛤", "railway_track", 5], + ["🌅", "sunrise", 5], + ["🌄", "sunrise_over_mountains", 5], + ["🏜", "desert", 5], + ["🏖", "beach_umbrella", 5], + ["🏝", "desert_island", 5], + ["🌇", "city_sunrise", 5], + ["🌆", "city_sunset", 5], + ["🏙", "cityscape", 5], + ["🌃", "night_with_stars", 5], + ["🌉", "bridge_at_night", 5], + ["🌌", "milky_way", 5], + ["🌠", "stars", 5], + ["🎇", "sparkler", 5], + ["🎆", "fireworks", 5], + ["🌈", "rainbow", 5], + ["🏘", "houses", 5], + ["🏰", "european_castle", 5], + ["🏯", "japanese_castle", 5], + ["🗼", "tokyo_tower", 5], + ["", "shibuya_109", 5], + ["🏟", "stadium", 5], + ["🗽", "statue_of_liberty", 5], + ["🏠", "house", 5], + ["🏡", "house_with_garden", 5], + ["🏚", "derelict_house", 5], + ["🏢", "office", 5], + ["🏬", "department_store", 5], + ["🏣", "post_office", 5], + ["🏤", "european_post_office", 5], + ["🏥", "hospital", 5], + ["🏦", "bank", 5], + ["🏨", "hotel", 5], + ["🏪", "convenience_store", 5], + ["🏫", "school", 5], + ["🏩", "love_hotel", 5], + ["💒", "wedding", 5], + ["🏛", "classical_building", 5], + ["⛪", "church", 5], + ["🕌", "mosque", 5], + ["🕍", "synagogue", 5], + ["🕋", "kaaba", 5], + ["⛩", "shinto_shrine", 5], + ["🛕", "hindu_temple", 5], + ["🪨", "rock", 5], + ["🪵", "wood", 5], + ["🛖", "hut", 5], + ["🛝", "playground_slide", 5], + ["🛞", "wheel", 5], + ["🛟", "ring_buoy", 5], + ["⌚", "watch", 6], + ["📱", "iphone", 6], + ["📲", "calling", 6], + ["💻", "computer", 6], + ["⌨", "keyboard", 6], + ["🖥", "desktop_computer", 6], + ["🖨", "printer", 6], + ["🖱", "computer_mouse", 6], + ["🖲", "trackball", 6], + ["🕹", "joystick", 6], + ["🗜", "clamp", 6], + ["💽", "minidisc", 6], + ["💾", "floppy_disk", 6], + ["💿", "cd", 6], + ["📀", "dvd", 6], + ["📼", "vhs", 6], + ["📷", "camera", 6], + ["📸", "camera_flash", 6], + ["📹", "video_camera", 6], + ["🎥", "movie_camera", 6], + ["📽", "film_projector", 6], + ["🎞", "film_strip", 6], + ["📞", "telephone_receiver", 6], + ["☎️", "phone", 6], + ["📟", "pager", 6], + ["📠", "fax", 6], + ["📺", "tv", 6], + ["📻", "radio", 6], + ["🎙", "studio_microphone", 6], + ["🎚", "level_slider", 6], + ["🎛", "control_knobs", 6], + ["🧭", "compass", 6], + ["⏱", "stopwatch", 6], + ["⏲", "timer_clock", 6], + ["⏰", "alarm_clock", 6], + ["🕰", "mantelpiece_clock", 6], + ["⏳", "hourglass_flowing_sand", 6], + ["⌛", "hourglass", 6], + ["📡", "satellite", 6], + ["🔋", "battery", 6], + ["🪫", "battery", 6], + ["🔌", "electric_plug", 6], + ["💡", "bulb", 6], + ["🔦", "flashlight", 6], + ["🕯", "candle", 6], + ["🧯", "fire_extinguisher", 6], + ["🗑", "wastebasket", 6], + ["🛢", "oil_drum", 6], + ["💸", "money_with_wings", 6], + ["💵", "dollar", 6], + ["💴", "yen", 6], + ["💶", "euro", 6], + ["💷", "pound", 6], + ["💰", "moneybag", 6], + ["🪙", "coin", 6], + ["💳", "credit_card", 6], + ["🪫", "identification_card", 6], + ["💎", "gem", 6], + ["⚖", "balance_scale", 6], + ["🧰", "toolbox", 6], + ["🔧", "wrench", 6], + ["🔨", "hammer", 6], + ["⚒", "hammer_and_pick", 6], + ["🛠", "hammer_and_wrench", 6], + ["⛏", "pick", 6], + ["🪓", "axe", 6], + ["🦯", "probing_cane", 6], + ["🔩", "nut_and_bolt", 6], + ["⚙", "gear", 6], + ["🪃", "boomerang", 6], + ["🪚", "carpentry_saw", 6], + ["🪛", "screwdriver", 6], + ["🪝", "hook", 6], + ["🪜", "ladder", 6], + ["🧱", "brick", 6], + ["⛓", "chains", 6], + ["🧲", "magnet", 6], + ["🔫", "gun", 6], + ["💣", "bomb", 6], + ["🧨", "firecracker", 6], + ["🔪", "hocho", 6], + ["🗡", "dagger", 6], + ["⚔", "crossed_swords", 6], + ["🛡", "shield", 6], + ["🚬", "smoking", 6], + ["☠", "skull_and_crossbones", 6], + ["⚰", "coffin", 6], + ["⚱", "funeral_urn", 6], + ["🏺", "amphora", 6], + ["🔮", "crystal_ball", 6], + ["📿", "prayer_beads", 6], + ["🧿", "nazar_amulet", 6], + ["💈", "barber", 6], + ["⚗", "alembic", 6], + ["🔭", "telescope", 6], + ["🔬", "microscope", 6], + ["🕳", "hole", 6], + ["💊", "pill", 6], + ["💉", "syringe", 6], + ["🩸", "drop_of_blood", 6], + ["🩹", "adhesive_bandage", 6], + ["🩺", "stethoscope", 6], + ["🪒", "razor", 6], + ["🩻", "xray", 6], + ["🩼", "crutch", 6], + ["🧬", "dna", 6], + ["🧫", "petri_dish", 6], + ["🧪", "test_tube", 6], + ["🌡", "thermometer", 6], + ["🧹", "broom", 6], + ["🧺", "basket", 6], + ["🧻", "toilet_paper", 6], + ["🏷", "label", 6], + ["🔖", "bookmark", 6], + ["🚽", "toilet", 6], + ["🚿", "shower", 6], + ["🛁", "bathtub", 6], + ["🧼", "soap", 6], + ["🧽", "sponge", 6], + ["🧴", "lotion_bottle", 6], + ["🔑", "key", 6], + ["🗝", "old_key", 6], + ["🛋", "couch_and_lamp", 6], + ["🪔", "diya_Lamp", 6], + ["🛌", "sleeping_bed", 6], + ["🛏", "bed", 6], + ["🚪", "door", 6], + ["🪑", "chair", 6], + ["🛎", "bellhop_bell", 6], + ["🧸", "teddy_bear", 6], + ["🖼", "framed_picture", 6], + ["🗺", "world_map", 6], + ["🛗", "elevator", 6], + ["🪞", "mirror", 6], + ["🪟", "window", 6], + ["🪠", "plunger", 6], + ["🪤", "mouse_trap", 6], + ["🪣", "bucket", 6], + ["🪥", "toothbrush", 6], + ["🫧", "bubbles", 6], + ["⛱", "parasol_on_ground", 6], + ["🗿", "moyai", 6], + ["🛍", "shopping", 6], + ["🛒", "shopping_cart", 6], + ["🎈", "balloon", 6], + ["🎏", "flags", 6], + ["🎀", "ribbon", 6], + ["🎁", "gift", 6], + ["🎊", "confetti_ball", 6], + ["🎉", "tada", 6], + ["🎎", "dolls", 6], + ["🎐", "wind_chime", 6], + ["🎌", "crossed_flags", 6], + ["🏮", "izakaya_lantern", 6], + ["🧧", "red_envelope", 6], + ["✉️", "email", 6], + ["📩", "envelope_with_arrow", 6], + ["📨", "incoming_envelope", 6], + ["📧", "e-mail", 6], + ["💌", "love_letter", 6], + ["📮", "postbox", 6], + ["📪", "mailbox_closed", 6], + ["📫", "mailbox", 6], + ["📬", "mailbox_with_mail", 6], + ["📭", "mailbox_with_no_mail", 6], + ["📦", "package", 6], + ["📯", "postal_horn", 6], + ["📥", "inbox_tray", 6], + ["📤", "outbox_tray", 6], + ["📜", "scroll", 6], + ["📃", "page_with_curl", 6], + ["📑", "bookmark_tabs", 6], + ["🧾", "receipt", 6], + ["📊", "bar_chart", 6], + ["📈", "chart_with_upwards_trend", 6], + ["📉", "chart_with_downwards_trend", 6], + ["📄", "page_facing_up", 6], + ["📅", "date", 6], + ["📆", "calendar", 6], + ["🗓", "spiral_calendar", 6], + ["📇", "card_index", 6], + ["🗃", "card_file_box", 6], + ["🗳", "ballot_box", 6], + ["🗄", "file_cabinet", 6], + ["📋", "clipboard", 6], + ["🗒", "spiral_notepad", 6], + ["📁", "file_folder", 6], + ["📂", "open_file_folder", 6], + ["🗂", "card_index_dividers", 6], + ["🗞", "newspaper_roll", 6], + ["📰", "newspaper", 6], + ["📓", "notebook", 6], + ["📕", "closed_book", 6], + ["📗", "green_book", 6], + ["📘", "blue_book", 6], + ["📙", "orange_book", 6], + ["📔", "notebook_with_decorative_cover", 6], + ["📒", "ledger", 6], + ["📚", "books", 6], + ["📖", "open_book", 6], + ["🧷", "safety_pin", 6], + ["🔗", "link", 6], + ["📎", "paperclip", 6], + ["🖇", "paperclips", 6], + ["✂️", "scissors", 6], + ["📐", "triangular_ruler", 6], + ["📏", "straight_ruler", 6], + ["🧮", "abacus", 6], + ["📌", "pushpin", 6], + ["📍", "round_pushpin", 6], + ["🚩", "triangular_flag_on_post", 6], + ["🏳", "white_flag", 6], + ["🏴", "black_flag", 6], + ["🏳️🌈", "rainbow_flag", 6], + ["🏳️⚧️", "transgender_flag", 6], + ["🔐", "closed_lock_with_key", 6], + ["🔒", "lock", 6], + ["🔓", "unlock", 6], + ["🔏", "lock_with_ink_pen", 6], + ["🖊", "pen", 6], + ["🖋", "fountain_pen", 6], + ["✒️", "black_nib", 6], + ["📝", "memo", 6], + ["✏️", "pencil2", 6], + ["🖍", "crayon", 6], + ["🖌", "paintbrush", 6], + ["🔍", "mag", 6], + ["🔎", "mag_right", 6], + ["🪦", "headstone", 6], + ["🪧", "placard", 6], + ["💯", "100", 7], + ["🔢", "1234", 7], + ["❤️", "heart", 7], + ["🧡", "orange_heart", 7], + ["💛", "yellow_heart", 7], + ["💚", "green_heart", 7], + ["💙", "blue_heart", 7], + ["💜", "purple_heart", 7], + ["🤎", "brown_heart", 7], + ["🖤", "black_heart", 7], + ["🤍", "white_heart", 7], + ["💔", "broken_heart", 7], + ["❣", "heavy_heart_exclamation", 7], + ["💕", "two_hearts", 7], + ["💞", "revolving_hearts", 7], + ["💓", "heartbeat", 7], + ["💗", "heartpulse", 7], + ["💖", "sparkling_heart", 7], + ["💘", "cupid", 7], + ["💝", "gift_heart", 7], + ["💟", "heart_decoration", 7], + ["❤️🔥", "heart_on_fire", 7], + ["❤️🩹", "mending_heart", 7], + ["☮", "peace_symbol", 7], + ["✝", "latin_cross", 7], + ["☪", "star_and_crescent", 7], + ["🕉", "om", 7], + ["☸", "wheel_of_dharma", 7], + ["✡", "star_of_david", 7], + ["🔯", "six_pointed_star", 7], + ["🕎", "menorah", 7], + ["☯", "yin_yang", 7], + ["☦", "orthodox_cross", 7], + ["🛐", "place_of_worship", 7], + ["⛎", "ophiuchus", 7], + ["♈", "aries", 7], + ["♉", "taurus", 7], + ["♊", "gemini", 7], + ["♋", "cancer", 7], + ["♌", "leo", 7], + ["♍", "virgo", 7], + ["♎", "libra", 7], + ["♏", "scorpius", 7], + ["♐", "sagittarius", 7], + ["♑", "capricorn", 7], + ["♒", "aquarius", 7], + ["♓", "pisces", 7], + ["🆔", "id", 7], + ["⚛", "atom_symbol", 7], + ["⚧️", "transgender_symbol", 7], + ["🈳", "u7a7a", 7], + ["🈹", "u5272", 7], + ["☢", "radioactive", 7], + ["☣", "biohazard", 7], + ["📴", "mobile_phone_off", 7], + ["📳", "vibration_mode", 7], + ["🈶", "u6709", 7], + ["🈚", "u7121", 7], + ["🈸", "u7533", 7], + ["🈺", "u55b6", 7], + ["🈷️", "u6708", 7], + ["✴️", "eight_pointed_black_star", 7], + ["🆚", "vs", 7], + ["🉑", "accept", 7], + ["💮", "white_flower", 7], + ["🉐", "ideograph_advantage", 7], + ["㊙️", "secret", 7], + ["㊗️", "congratulations", 7], + ["🈴", "u5408", 7], + ["🈵", "u6e80", 7], + ["🈲", "u7981", 7], + ["🅰️", "a", 7], + ["🅱️", "b", 7], + ["🆎", "ab", 7], + ["🆑", "cl", 7], + ["🅾️", "o2", 7], + ["🆘", "sos", 7], + ["⛔", "no_entry", 7], + ["📛", "name_badge", 7], + ["🚫", "no_entry_sign", 7], + ["❌", "x", 7], + ["⭕", "o", 7], + ["🛑", "stop_sign", 7], + ["💢", "anger", 7], + ["♨️", "hotsprings", 7], + ["🚷", "no_pedestrians", 7], + ["🚯", "do_not_litter", 7], + ["🚳", "no_bicycles", 7], + ["🚱", "non-potable_water", 7], + ["🔞", "underage", 7], + ["📵", "no_mobile_phones", 7], + ["❗", "exclamation", 7], + ["❕", "grey_exclamation", 7], + ["❓", "question", 7], + ["❔", "grey_question", 7], + ["‼️", "bangbang", 7], + ["⁉️", "interrobang", 7], + ["🔅", "low_brightness", 7], + ["🔆", "high_brightness", 7], + ["🔱", "trident", 7], + ["⚜", "fleur_de_lis", 7], + ["〽️", "part_alternation_mark", 7], + ["⚠️", "warning", 7], + ["🚸", "children_crossing", 7], + ["🔰", "beginner", 7], + ["♻️", "recycle", 7], + ["🈯", "u6307", 7], + ["💹", "chart", 7], + ["❇️", "sparkle", 7], + ["✳️", "eight_spoked_asterisk", 7], + ["❎", "negative_squared_cross_mark", 7], + ["✅", "white_check_mark", 7], + ["💠", "diamond_shape_with_a_dot_inside", 7], + ["🌀", "cyclone", 7], + ["➿", "loop", 7], + ["🌐", "globe_with_meridians", 7], + ["Ⓜ️", "m", 7], + ["🏧", "atm", 7], + ["🈂️", "sa", 7], + ["🛂", "passport_control", 7], + ["🛃", "customs", 7], + ["🛄", "baggage_claim", 7], + ["🛅", "left_luggage", 7], + ["♿", "wheelchair", 7], + ["🚭", "no_smoking", 7], + ["🚾", "wc", 7], + ["🅿️", "parking", 7], + ["🚰", "potable_water", 7], + ["🚹", "mens", 7], + ["🚺", "womens", 7], + ["🚼", "baby_symbol", 7], + ["🚻", "restroom", 7], + ["🚮", "put_litter_in_its_place", 7], + ["🎦", "cinema", 7], + ["📶", "signal_strength", 7], + ["🈁", "koko", 7], + ["🆖", "ng", 7], + ["🆗", "ok", 7], + ["🆙", "up", 7], + ["🆒", "cool", 7], + ["🆕", "new", 7], + ["🆓", "free", 7], + ["0️⃣", "zero", 7], + ["1️⃣", "one", 7], + ["2️⃣", "two", 7], + ["3️⃣", "three", 7], + ["4️⃣", "four", 7], + ["5️⃣", "five", 7], + ["6️⃣", "six", 7], + ["7️⃣", "seven", 7], + ["8️⃣", "eight", 7], + ["9️⃣", "nine", 7], + ["🔟", "keycap_ten", 7], + ["*⃣", "asterisk", 7], + ["⏏️", "eject_button", 7], + ["▶️", "arrow_forward", 7], + ["⏸", "pause_button", 7], + ["⏭", "next_track_button", 7], + ["⏹", "stop_button", 7], + ["⏺", "record_button", 7], + ["⏯", "play_or_pause_button", 7], + ["⏮", "previous_track_button", 7], + ["⏩", "fast_forward", 7], + ["⏪", "rewind", 7], + ["🔀", "twisted_rightwards_arrows", 7], + ["🔁", "repeat", 7], + ["🔂", "repeat_one", 7], + ["◀️", "arrow_backward", 7], + ["🔼", "arrow_up_small", 7], + ["🔽", "arrow_down_small", 7], + ["⏫", "arrow_double_up", 7], + ["⏬", "arrow_double_down", 7], + ["➡️", "arrow_right", 7], + ["⬅️", "arrow_left", 7], + ["⬆️", "arrow_up", 7], + ["⬇️", "arrow_down", 7], + ["↗️", "arrow_upper_right", 7], + ["↘️", "arrow_lower_right", 7], + ["↙️", "arrow_lower_left", 7], + ["↖️", "arrow_upper_left", 7], + ["↕️", "arrow_up_down", 7], + ["↔️", "left_right_arrow", 7], + ["🔄", "arrows_counterclockwise", 7], + ["↪️", "arrow_right_hook", 7], + ["↩️", "leftwards_arrow_with_hook", 7], + ["⤴️", "arrow_heading_up", 7], + ["⤵️", "arrow_heading_down", 7], + ["#️⃣", "hash", 7], + ["ℹ️", "information_source", 7], + ["🔤", "abc", 7], + ["🔡", "abcd", 7], + ["🔠", "capital_abcd", 7], + ["🔣", "symbols", 7], + ["🎵", "musical_note", 7], + ["🎶", "notes", 7], + ["〰️", "wavy_dash", 7], + ["➰", "curly_loop", 7], + ["✔️", "heavy_check_mark", 7], + ["🔃", "arrows_clockwise", 7], + ["➕", "heavy_plus_sign", 7], + ["➖", "heavy_minus_sign", 7], + ["➗", "heavy_division_sign", 7], + ["✖️", "heavy_multiplication_x", 7], + ["🟰", "heavy_equals_sign", 7], + ["♾", "infinity", 7], + ["💲", "heavy_dollar_sign", 7], + ["💱", "currency_exchange", 7], + ["©️", "copyright", 7], + ["®️", "registered", 7], + ["™️", "tm", 7], + ["🔚", "end", 7], + ["🔙", "back", 7], + ["🔛", "on", 7], + ["🔝", "top", 7], + ["🔜", "soon", 7], + ["☑️", "ballot_box_with_check", 7], + ["🔘", "radio_button", 7], + ["⚫", "black_circle", 7], + ["⚪", "white_circle", 7], + ["🔴", "red_circle", 7], + ["🟠", "orange_circle", 7], + ["🟡", "yellow_circle", 7], + ["🟢", "green_circle", 7], + ["🔵", "large_blue_circle", 7], + ["🟣", "purple_circle", 7], + ["🟤", "brown_circle", 7], + ["🔸", "small_orange_diamond", 7], + ["🔹", "small_blue_diamond", 7], + ["🔶", "large_orange_diamond", 7], + ["🔷", "large_blue_diamond", 7], + ["🔺", "small_red_triangle", 7], + ["▪️", "black_small_square", 7], + ["▫️", "white_small_square", 7], + ["⬛", "black_large_square", 7], + ["⬜", "white_large_square", 7], + ["🟥", "red_square", 7], + ["🟧", "orange_square", 7], + ["🟨", "yellow_square", 7], + ["🟩", "green_square", 7], + ["🟦", "blue_square", 7], + ["🟪", "purple_square", 7], + ["🟫", "brown_square", 7], + ["🔻", "small_red_triangle_down", 7], + ["◼️", "black_medium_square", 7], + ["◻️", "white_medium_square", 7], + ["◾", "black_medium_small_square", 7], + ["◽", "white_medium_small_square", 7], + ["🔲", "black_square_button", 7], + ["🔳", "white_square_button", 7], + ["🔈", "speaker", 7], + ["🔉", "sound", 7], + ["🔊", "loud_sound", 7], + ["🔇", "mute", 7], + ["📣", "mega", 7], + ["📢", "loudspeaker", 7], + ["🔔", "bell", 7], + ["🔕", "no_bell", 7], + ["🃏", "black_joker", 7], + ["🀄", "mahjong", 7], + ["♠️", "spades", 7], + ["♣️", "clubs", 7], + ["♥️", "hearts", 7], + ["♦️", "diamonds", 7], + ["🎴", "flower_playing_cards", 7], + ["💭", "thought_balloon", 7], + ["🗯", "right_anger_bubble", 7], + ["💬", "speech_balloon", 7], + ["🗨", "left_speech_bubble", 7], + ["🕐", "clock1", 7], + ["🕑", "clock2", 7], + ["🕒", "clock3", 7], + ["🕓", "clock4", 7], + ["🕔", "clock5", 7], + ["🕕", "clock6", 7], + ["🕖", "clock7", 7], + ["🕗", "clock8", 7], + ["🕘", "clock9", 7], + ["🕙", "clock10", 7], + ["🕚", "clock11", 7], + ["🕛", "clock12", 7], + ["🕜", "clock130", 7], + ["🕝", "clock230", 7], + ["🕞", "clock330", 7], + ["🕟", "clock430", 7], + ["🕠", "clock530", 7], + ["🕡", "clock630", 7], + ["🕢", "clock730", 7], + ["🕣", "clock830", 7], + ["🕤", "clock930", 7], + ["🕥", "clock1030", 7], + ["🕦", "clock1130", 7], + ["🕧", "clock1230", 7], + ["🇦🇫", "afghanistan", 8], + ["🇦🇽", "aland_islands", 8], + ["🇦🇱", "albania", 8], + ["🇩🇿", "algeria", 8], + ["🇦🇸", "american_samoa", 8], + ["🇦🇩", "andorra", 8], + ["🇦🇴", "angola", 8], + ["🇦🇮", "anguilla", 8], + ["🇦🇶", "antarctica", 8], + ["🇦🇬", "antigua_barbuda", 8], + ["🇦🇷", "argentina", 8], + ["🇦🇲", "armenia", 8], + ["🇦🇼", "aruba", 8], + ["🇦🇨", "ascension_island", 8], + ["🇦🇺", "australia", 8], + ["🇦🇹", "austria", 8], + ["🇦🇿", "azerbaijan", 8], + ["🇧🇸", "bahamas", 8], + ["🇧🇭", "bahrain", 8], + ["🇧🇩", "bangladesh", 8], + ["🇧🇧", "barbados", 8], + ["🇧🇾", "belarus", 8], + ["🇧🇪", "belgium", 8], + ["🇧🇿", "belize", 8], + ["🇧🇯", "benin", 8], + ["🇧🇲", "bermuda", 8], + ["🇧🇹", "bhutan", 8], + ["🇧🇴", "bolivia", 8], + ["🇧🇶", "caribbean_netherlands", 8], + ["🇧🇦", "bosnia_herzegovina", 8], + ["🇧🇼", "botswana", 8], + ["🇧🇷", "brazil", 8], + ["🇮🇴", "british_indian_ocean_territory", 8], + ["🇻🇬", "british_virgin_islands", 8], + ["🇧🇳", "brunei", 8], + ["🇧🇬", "bulgaria", 8], + ["🇧🇫", "burkina_faso", 8], + ["🇧🇮", "burundi", 8], + ["🇨🇻", "cape_verde", 8], + ["🇰🇭", "cambodia", 8], + ["🇨🇲", "cameroon", 8], + ["🇨🇦", "canada", 8], + ["🇮🇨", "canary_islands", 8], + ["🇰🇾", "cayman_islands", 8], + ["🇨🇫", "central_african_republic", 8], + ["🇹🇩", "chad", 8], + ["🇨🇱", "chile", 8], + ["🇨🇳", "cn", 8], + ["🇨🇽", "christmas_island", 8], + ["🇨🇨", "cocos_islands", 8], + ["🇨🇴", "colombia", 8], + ["🇰🇲", "comoros", 8], + ["🇨🇬", "congo_brazzaville", 8], + ["🇨🇩", "congo_kinshasa", 8], + ["🇨🇰", "cook_islands", 8], + ["🇨🇷", "costa_rica", 8], + ["🇭🇷", "croatia", 8], + ["🇨🇺", "cuba", 8], + ["🇨🇼", "curacao", 8], + ["🇨🇾", "cyprus", 8], + ["🇨🇿", "czech_republic", 8], + ["🇩🇰", "denmark", 8], + ["🇩🇯", "djibouti", 8], + ["🇩🇲", "dominica", 8], + ["🇩🇴", "dominican_republic", 8], + ["🇪🇨", "ecuador", 8], + ["🇪🇬", "egypt", 8], + ["🇸🇻", "el_salvador", 8], + ["🇬🇶", "equatorial_guinea", 8], + ["🇪🇷", "eritrea", 8], + ["🇪🇪", "estonia", 8], + ["🇪🇹", "ethiopia", 8], + ["🇪🇺", "eu", 8], + ["🇫🇰", "falkland_islands", 8], + ["🇫🇴", "faroe_islands", 8], + ["🇫🇯", "fiji", 8], + ["🇫🇮", "finland", 8], + ["🇫🇷", "fr", 8], + ["🇬🇫", "french_guiana", 8], + ["🇵🇫", "french_polynesia", 8], + ["🇹🇫", "french_southern_territories", 8], + ["🇬🇦", "gabon", 8], + ["🇬🇲", "gambia", 8], + ["🇬🇪", "georgia", 8], + ["🇩🇪", "de", 8], + ["🇬🇭", "ghana", 8], + ["🇬🇮", "gibraltar", 8], + ["🇬🇷", "greece", 8], + ["🇬🇱", "greenland", 8], + ["🇬🇩", "grenada", 8], + ["🇬🇵", "guadeloupe", 8], + ["🇬🇺", "guam", 8], + ["🇬🇹", "guatemala", 8], + ["🇬🇬", "guernsey", 8], + ["🇬🇳", "guinea", 8], + ["🇬🇼", "guinea_bissau", 8], + ["🇬🇾", "guyana", 8], + ["🇭🇹", "haiti", 8], + ["🇭🇳", "honduras", 8], + ["🇭🇰", "hong_kong", 8], + ["🇭🇺", "hungary", 8], + ["🇮🇸", "iceland", 8], + ["🇮🇳", "india", 8], + ["🇮🇩", "indonesia", 8], + ["🇮🇷", "iran", 8], + ["🇮🇶", "iraq", 8], + ["🇮🇪", "ireland", 8], + ["🇮🇲", "isle_of_man", 8], + ["🇮🇱", "israel", 8], + ["🇮🇹", "it", 8], + ["🇨🇮", "cote_divoire", 8], + ["🇯🇲", "jamaica", 8], + ["🇯🇵", "jp", 8], + ["🇯🇪", "jersey", 8], + ["🇯🇴", "jordan", 8], + ["🇰🇿", "kazakhstan", 8], + ["🇰🇪", "kenya", 8], + ["🇰🇮", "kiribati", 8], + ["🇽🇰", "kosovo", 8], + ["🇰🇼", "kuwait", 8], + ["🇰🇬", "kyrgyzstan", 8], + ["🇱🇦", "laos", 8], + ["🇱🇻", "latvia", 8], + ["🇱🇧", "lebanon", 8], + ["🇱🇸", "lesotho", 8], + ["🇱🇷", "liberia", 8], + ["🇱🇾", "libya", 8], + ["🇱🇮", "liechtenstein", 8], + ["🇱🇹", "lithuania", 8], + ["🇱🇺", "luxembourg", 8], + ["🇲🇴", "macau", 8], + ["🇲🇰", "macedonia", 8], + ["🇲🇬", "madagascar", 8], + ["🇲🇼", "malawi", 8], + ["🇲🇾", "malaysia", 8], + ["🇲🇻", "maldives", 8], + ["🇲🇱", "mali", 8], + ["🇲🇹", "malta", 8], + ["🇲🇭", "marshall_islands", 8], + ["🇲🇶", "martinique", 8], + ["🇲🇷", "mauritania", 8], + ["🇲🇺", "mauritius", 8], + ["🇾🇹", "mayotte", 8], + ["🇲🇽", "mexico", 8], + ["🇫🇲", "micronesia", 8], + ["🇲🇩", "moldova", 8], + ["🇲🇨", "monaco", 8], + ["🇲🇳", "mongolia", 8], + ["🇲🇪", "montenegro", 8], + ["🇲🇸", "montserrat", 8], + ["🇲🇦", "morocco", 8], + ["🇲🇿", "mozambique", 8], + ["🇲🇲", "myanmar", 8], + ["🇳🇦", "namibia", 8], + ["🇳🇷", "nauru", 8], + ["🇳🇵", "nepal", 8], + ["🇳🇱", "netherlands", 8], + ["🇳🇨", "new_caledonia", 8], + ["🇳🇿", "new_zealand", 8], + ["🇳🇮", "nicaragua", 8], + ["🇳🇪", "niger", 8], + ["🇳🇬", "nigeria", 8], + ["🇳🇺", "niue", 8], + ["🇳🇫", "norfolk_island", 8], + ["🇲🇵", "northern_mariana_islands", 8], + ["🇰🇵", "north_korea", 8], + ["🇳🇴", "norway", 8], + ["🇴🇲", "oman", 8], + ["🇵🇰", "pakistan", 8], + ["🇵🇼", "palau", 8], + ["🇵🇸", "palestinian_territories", 8], + ["🇵🇦", "panama", 8], + ["🇵🇬", "papua_new_guinea", 8], + ["🇵🇾", "paraguay", 8], + ["🇵🇪", "peru", 8], + ["🇵🇭", "philippines", 8], + ["🇵🇳", "pitcairn_islands", 8], + ["🇵🇱", "poland", 8], + ["🇵🇹", "portugal", 8], + ["🇵🇷", "puerto_rico", 8], + ["🇶🇦", "qatar", 8], + ["🇷🇪", "reunion", 8], + ["🇷🇴", "romania", 8], + ["🇷🇺", "ru", 8], + ["🇷🇼", "rwanda", 8], + ["🇧🇱", "st_barthelemy", 8], + ["🇸🇭", "st_helena", 8], + ["🇰🇳", "st_kitts_nevis", 8], + ["🇱🇨", "st_lucia", 8], + ["🇵🇲", "st_pierre_miquelon", 8], + ["🇻🇨", "st_vincent_grenadines", 8], + ["🇼🇸", "samoa", 8], + ["🇸🇲", "san_marino", 8], + ["🇸🇹", "sao_tome_principe", 8], + ["🇸🇦", "saudi_arabia", 8], + ["🇸🇳", "senegal", 8], + ["🇷🇸", "serbia", 8], + ["🇸🇨", "seychelles", 8], + ["🇸🇱", "sierra_leone", 8], + ["🇸🇬", "singapore", 8], + ["🇸🇽", "sint_maarten", 8], + ["🇸🇰", "slovakia", 8], + ["🇸🇮", "slovenia", 8], + ["🇸🇧", "solomon_islands", 8], + ["🇸🇴", "somalia", 8], + ["🇿🇦", "south_africa", 8], + ["🇬🇸", "south_georgia_south_sandwich_islands", 8], + ["🇰🇷", "kr", 8], + ["🇸🇸", "south_sudan", 8], + ["🇪🇸", "es", 8], + ["🇱🇰", "sri_lanka", 8], + ["🇸🇩", "sudan", 8], + ["🇸🇷", "suriname", 8], + ["🇸🇿", "swaziland", 8], + ["🇸🇪", "sweden", 8], + ["🇨🇭", "switzerland", 8], + ["🇸🇾", "syria", 8], + ["🇹🇼", "taiwan", 8], + ["🇹🇯", "tajikistan", 8], + ["🇹🇿", "tanzania", 8], + ["🇹🇭", "thailand", 8], + ["🇹🇱", "timor_leste", 8], + ["🇹🇬", "togo", 8], + ["🇹🇰", "tokelau", 8], + ["🇹🇴", "tonga", 8], + ["🇹🇹", "trinidad_tobago", 8], + ["🇹🇦", "tristan_da_cunha", 8], + ["🇹🇳", "tunisia", 8], + ["🇹🇷", "tr", 8], + ["🇹🇲", "turkmenistan", 8], + ["🇹🇨", "turks_caicos_islands", 8], + ["🇹🇻", "tuvalu", 8], + ["🇺🇬", "uganda", 8], + ["🇺🇦", "ukraine", 8], + ["🇦🇪", "united_arab_emirates", 8], + ["🇬🇧", "uk", 8], + ["🏴", "england", 8], + ["🏴", "scotland", 8], + ["🏴", "wales", 8], + ["🇺🇸", "us", 8], + ["🇻🇮", "us_virgin_islands", 8], + ["🇺🇾", "uruguay", 8], + ["🇺🇿", "uzbekistan", 8], + ["🇻🇺", "vanuatu", 8], + ["🇻🇦", "vatican_city", 8], + ["🇻🇪", "venezuela", 8], + ["🇻🇳", "vietnam", 8], + ["🇼🇫", "wallis_futuna", 8], + ["🇪🇭", "western_sahara", 8], + ["🇾🇪", "yemen", 8], + ["🇿🇲", "zambia", 8], + ["🇿🇼", "zimbabwe", 8], + ["🇺🇳", "united_nations", 8], + ["🏴☠️", "pirate_flag", 8] ] - diff --git a/packages/frontend/src/scripts/emojilist.ts b/packages/frontend/src/scripts/emojilist.ts index 2e853b58b5..3f63e6b214 100644 --- a/packages/frontend/src/scripts/emojilist.ts +++ b/packages/frontend/src/scripts/emojilist.ts @@ -2,7 +2,6 @@ export const unicodeEmojiCategories = ['face', 'people', 'animals_and_nature', ' export type UnicodeEmojiDef = { name: string; - keywords: string[]; char: string; category: typeof unicodeEmojiCategories[number]; } @@ -10,11 +9,16 @@ export type UnicodeEmojiDef = { // initial converted from https://github.com/muan/emojilib/commit/242fe68be86ed6536843b83f7e32f376468b38fb import _emojilist from '../emojilist.json'; -export const emojilist = _emojilist as UnicodeEmojiDef[]; +export const emojilist: UnicodeEmojiDef[] = _emojilist.map(x => ({ + name: x[1] as string, + char: x[0] as string, + category: unicodeEmojiCategories[x[2]], +})); const _indexByChar = new Map<string, number>(); const _charGroupByCategory = new Map<string, string[]>(); -emojilist.forEach((emo, i) => { +for (let i = 0; i < emojilist.length; i++) { + const emo = emojilist[i]; _indexByChar.set(emo.char, i); if (_charGroupByCategory.has(emo.category)) { @@ -22,7 +26,7 @@ emojilist.forEach((emo, i) => { } else { _charGroupByCategory.set(emo.category, [emo.char]); } -}); +} export const emojiCharByCategory = _charGroupByCategory; From 8b33a70fc488219495fb899e2b4e9ff562047e24 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 11:32:29 +0900 Subject: [PATCH 123/213] =?UTF-8?q?vue-plyr=E3=82=84=E3=82=81=E3=82=8B?= =?UTF-8?q?=E3=81=AA=E3=81=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 問題点が多い - バンドルサイズ削減 --- packages/frontend/package.json | 1 - .../frontend/src/components/MkMediaBanner.vue | 95 ++++++--------- .../frontend/src/components/MkMediaVideo.vue | 115 ++++++++---------- pnpm-lock.yaml | 78 +++--------- 4 files changed, 109 insertions(+), 180 deletions(-) diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 1175ce2e1e..84f3d9ce63 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -72,7 +72,6 @@ "vanilla-tilt": "1.8.0", "vite": "4.3.9", "vue": "3.3.4", - "vue-plyr": "7.0.0", "vue-prism-editor": "2.0.0-alpha.2", "vuedraggable": "next" }, diff --git a/packages/frontend/src/components/MkMediaBanner.vue b/packages/frontend/src/components/MkMediaBanner.vue index 5ca4c50518..5902d6fd25 100644 --- a/packages/frontend/src/components/MkMediaBanner.vue +++ b/packages/frontend/src/components/MkMediaBanner.vue @@ -1,27 +1,27 @@ <template> -<div class="mk-media-banner"> - <div v-if="media.isSensitive && hide" class="sensitive" @click="hide = false"> - <span class="icon"><i class="ti ti-alert-triangle"></i></span> +<div :class="$style.root"> + <div v-if="media.isSensitive && hide" :class="$style.sensitive" @click="hide = false"> + <span style="font-size: 1.6em;"><i class="ti ti-alert-triangle"></i></span> <b>{{ i18n.ts.sensitive }}</b> <span>{{ i18n.ts.clickToShow }}</span> </div> - <div v-else-if="media.type.startsWith('audio') && media.type !== 'audio/midi'" class="audio"> - <VuePlyr :options="{ volume: 0.5 }"> - <audio controls preload="metadata"> - <source - :src="media.url" - :type="media.type" - /> - </audio> - </VuePlyr> + <div v-else-if="media.type.startsWith('audio') && media.type !== 'audio/midi'" :class="$style.audio"> + <audio + ref="audioEl" + :src="media.url" + :title="media.name" + controls + preload="metadata" + @volumechange="volumechange" + /> </div> <a - v-else class="download" + v-else :class="$style.download" :href="media.url" :title="media.name" :download="media.name" > - <span class="icon"><i class="ti ti-download"></i></span> + <span style="font-size: 1.6em;"><i class="ti ti-download"></i></span> <b>{{ media.name }}</b> </a> </div> @@ -30,9 +30,7 @@ <script lang="ts" setup> import { onMounted } from 'vue'; import * as misskey from 'misskey-js'; -import VuePlyr from 'vue-plyr'; import { soundConfigStore } from '@/scripts/sound'; -import 'vue-plyr/dist/vue-plyr.css'; import { i18n } from '@/i18n'; const props = withDefaults(defineProps<{ @@ -52,55 +50,34 @@ onMounted(() => { }); </script> -<style lang="scss" scoped> -.mk-media-banner { +<style lang="scss" module> +.root { width: 100%; border-radius: 4px; margin-top: 4px; - // overflow: clip; + overflow: clip; +} - --plyr-color-main: var(--accent); - --plyr-audio-controls-background: var(--bg); - --plyr-audio-controls-color: var(--accentLighten); +.download, +.sensitive { + display: flex; + align-items: center; + font-size: 12px; + padding: 8px 12px; + white-space: nowrap; +} - > .download, - > .sensitive { - display: flex; - align-items: center; - font-size: 12px; - padding: 8px 12px; - white-space: nowrap; +.download { + background: var(--noteAttachedFile); +} - > * { - display: block; - } +.sensitive { + background: #111; + color: #fff; +} - > b { - overflow: hidden; - text-overflow: ellipsis; - } - - > *:not(:last-child) { - margin-right: .2em; - } - - > .icon { - font-size: 1.6em; - } - } - - > .download { - background: var(--noteAttachedFile); - } - - > .sensitive { - background: #111; - color: #fff; - } - - > .audio { - border-radius: 8px; - // overflow: clip; - } +.audio { + border-radius: 8px; + overflow: clip; } </style> diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index e2c1bed785..40bae90b5e 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -1,36 +1,36 @@ <template> -<div v-if="hide" class="icozogqfvdetwohsdglrbswgrejoxbdj" @click="hide = false"> +<div v-if="hide" :class="$style.hidden" @click="hide = false"> <!-- 【注意】dataSaverMode が有効になっている際には、hide が false になるまでサムネイルや動画を読み込まないようにすること --> - <div> - <b v-if="video.isSensitive"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.enableDataSaverMode ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b> - <b v-else><i class="ti ti-movie"></i> {{ defaultStore.state.enableDataSaverMode && video.size ? bytes(video.size) : i18n.ts.video }}</b> + <div :class="$style.sensitive"> + <b v-if="video.isSensitive" style="display: block;"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.enableDataSaverMode ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b> + <b v-else style="display: block;"><i class="ti ti-movie"></i> {{ defaultStore.state.enableDataSaverMode && video.size ? bytes(video.size) : i18n.ts.video }}</b> <span>{{ i18n.ts.clickToShow }}</span> </div> </div> -<div v-else class="kkjnbbplepmiyuadieoenjgutgcmtsvu"> - <VuePlyr :options="{ volume: 0.5 }"> - <video - controls - :data-poster="video.thumbnailUrl" +<div v-else :class="$style.visible"> + <video + :class="$style.video" + :poster="video.thumbnailUrl" + :title="video.comment" + :alt="video.comment" + preload="none" + controls + @contextmenu.stop + > + <source + :src="video.url" + :type="video.type" > - <source - size="720" - :src="video.url" - :type="video.type" - /> - </video> - </VuePlyr> - <i class="ti ti-eye-off" @click="hide = true"></i> + </video> + <i class="ti ti-eye-off" :class="$style.hide" @click="hide = true"></i> </div> </template> <script lang="ts" setup> import { ref } from 'vue'; import * as misskey from 'misskey-js'; -import VuePlyr from 'vue-plyr'; import bytes from '@/filters/bytes'; import { defaultStore } from '@/store'; -import 'vue-plyr/dist/vue-plyr.css'; import { i18n } from '@/i18n'; const props = defineProps<{ @@ -40,56 +40,49 @@ const props = defineProps<{ const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.enableDataSaverMode) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore')); </script> -<style lang="scss" scoped> -.kkjnbbplepmiyuadieoenjgutgcmtsvu { +<style lang="scss" module> +.visible { position: relative; - - --plyr-color-main: var(--accent); - - > i { - display: block; - position: absolute; - border-radius: 6px; - background-color: var(--fg); - color: var(--accentLighten); - font-size: 14px; - opacity: .5; - padding: 3px 6px; - text-align: center; - cursor: pointer; - top: 12px; - right: 12px; - } - - > video { - display: flex; - justify-content: center; - align-items: center; - - font-size: 3.5em; - overflow: hidden; - background-position: center; - background-size: cover; - width: 100%; - height: 100%; - } } -.icozogqfvdetwohsdglrbswgrejoxbdj { +.hide { + display: block; + position: absolute; + border-radius: 6px; + background-color: var(--fg); + color: var(--accentLighten); + font-size: 14px; + opacity: .5; + padding: 3px 6px; + text-align: center; + cursor: pointer; + top: 12px; + right: 12px; +} + +.video { + display: flex; + justify-content: center; + align-items: center; + font-size: 3.5em; + overflow: hidden; + background-position: center; + background-size: cover; + width: 100%; + height: 100%; +} + +.hidden { display: flex; justify-content: center; align-items: center; background: #111; color: #fff; +} - > div { - display: table-cell; - text-align: center; - font-size: 12px; - - > b { - display: block; - } - } +.sensitive { + display: table-cell; + text-align: center; + font-size: 12px; } </style> diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd565cd33b..4a1219a74b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -805,9 +805,6 @@ importers: vue: specifier: 3.3.4 version: 3.3.4 - vue-plyr: - specifier: 7.0.0 - version: 7.0.0 vue-prism-editor: specifier: 2.0.0-alpha.2 version: 2.0.0-alpha.2(vue@3.3.4) @@ -5538,7 +5535,7 @@ packages: ts-dedent: 2.2.0 util-deprecate: 1.0.2 watchpack: 2.4.0 - ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) + ws: 8.13.0 transitivePeerDependencies: - bufferutil - encoding @@ -7448,14 +7445,6 @@ packages: '@vue/compiler-core': 3.3.4 '@vue/shared': 3.3.4 - /@vue/compiler-sfc@2.7.14: - resolution: {integrity: sha512-aNmNHyLPsw+sVvlQFQ2/8sjNuLtK54TC6cuKnVzAY93ks4ZBrvwQSnkkIh7bsbNhum5hJBS00wSDipQ937f5DA==} - dependencies: - '@babel/parser': 7.21.9 - postcss: 8.4.23 - source-map: 0.6.1 - dev: false - /@vue/compiler-sfc@3.3.4: resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} dependencies: @@ -8713,6 +8702,7 @@ packages: requiresBuild: true dependencies: node-gyp-build: 4.6.0 + dev: false /bullmq@3.14.1: resolution: {integrity: sha512-Fom78UKljYsnJmwbROVPx3eFLuVfQjQbw9KCnVupLzT31RQHhFHV2xd/4J4oWl4u34bZ1JmEUfNnqNBz+IOJuA==} @@ -9753,10 +9743,6 @@ packages: /csstype@3.1.1: resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} - /custom-event-polyfill@1.0.7: - resolution: {integrity: sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==} - dev: false - /cwise-compiler@1.1.3: resolution: {integrity: sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ==} dependencies: @@ -10352,10 +10338,6 @@ packages: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} dev: false - /entities@4.4.0: - resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} - engines: {node: '>=0.12'} - /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -14288,10 +14270,6 @@ packages: strip-bom: 2.0.0 dev: false - /loadjs@4.2.0: - resolution: {integrity: sha512-AgQGZisAlTPbTEzrHPb6q+NYBMD+DP9uvGSIjSUM5uG+0jG15cb8axWpxuOIqrmQjn6scaaH8JwloiP27b2KXA==} - dev: false - /local-pkg@0.4.3: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} @@ -15281,6 +15259,7 @@ packages: /node-gyp-build@4.6.0: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} hasBin: true + dev: false /node-gyp@9.3.1: resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} @@ -15903,7 +15882,7 @@ packages: /parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} dependencies: - entities: 4.4.0 + entities: 4.5.0 /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} @@ -17001,10 +16980,6 @@ packages: resolution: {integrity: sha512-9CRCUX/w4+fNMzlYgA8GeJz7BZwBPwaGm3FhAm9Hi50k8wNy2CyiJQa8awygWJay87uVVCV0/FwbLcD6+/A9KQ==} dev: false - /rangetouch@2.0.1: - resolution: {integrity: sha512-sln+pNSc8NGaHoLzwNBssFSf/rSYkqeBXzX1AtJlkJiUaVSJSbRAWJk+4omsXkN+EJalzkZhWQ3th1m0FpR5xA==} - dev: false - /ratelimiter@3.4.1: resolution: {integrity: sha512-5FJbRW/Jkkdk29ksedAfWFkQkhbUrMx3QJGwMKAypeIiQf4yrLW+gtPKZiaWt4zPrtw1uGufOjGO7UGM6VllsQ==} dev: false @@ -19676,10 +19651,6 @@ packages: requires-port: 1.0.0 dev: false - /url-polyfill@1.1.12: - resolution: {integrity: sha512-mYFmBHCapZjtcNHW0MDq9967t+z4Dmg5CJ0KqysK3+ZbyoNOWQHksGCTWwDhxGXllkWlOc10Xfko6v4a3ucM6A==} - dev: false - /urlsafe-base64@1.0.0: resolution: {integrity: sha512-RtuPeMy7c1UrHwproMZN9gN6kiZ0SvJwRaEzwZY0j9MypEkFqyBaKv176jvlPtg58Zh36bOkS0NFABXMHvvGCA==} dev: false @@ -19705,6 +19676,7 @@ packages: requiresBuild: true dependencies: node-gyp-build: 4.6.0 + dev: false /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -20031,13 +20003,6 @@ packages: vue: 3.3.4 dev: true - /vue-plyr@7.0.0: - resolution: {integrity: sha512-NvbO/ZzV1IxlBQQbQlon5Sk8hKuGAj3k4k0XVdi7gM4oSqu8mZMhJ3WM3FfAtNfV790jbLnb8P3dHYqaBqIv6g==} - dependencies: - plyr: github.com/sampotts/plyr/d434c9af16e641400aaee93188594208d88f2658 - vue: 2.7.14 - dev: false - /vue-prism-editor@2.0.0-alpha.2(vue@3.3.4): resolution: {integrity: sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==} engines: {node: '>=10'} @@ -20066,13 +20031,6 @@ packages: typescript: 5.0.4 dev: true - /vue@2.7.14: - resolution: {integrity: sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==} - dependencies: - '@vue/compiler-sfc': 2.7.14 - csstype: 3.1.1 - dev: false - /vue@3.3.4: resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} dependencies: @@ -20368,6 +20326,19 @@ packages: async-limiter: 1.0.1 dev: true + /ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + /ws@8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3): resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} engines: {node: '>=10.0.0'} @@ -20382,6 +20353,7 @@ packages: dependencies: bufferutil: 4.0.7 utf-8-validate: 6.0.3 + dev: false /xev@3.0.2: resolution: {integrity: sha512-8kxuH95iMXzHZj+fwqfA4UrPcYOy6bGIgfWzo9Ji23JoEc30ge/Z++Ubkiuy8c0+M64nXmmxrmJ7C8wnuBhluw==} @@ -20646,15 +20618,3 @@ packages: jschardet: 3.0.0 private-ip: 2.3.3 trace-redirect: 1.0.6 - - github.com/sampotts/plyr/d434c9af16e641400aaee93188594208d88f2658: - resolution: {tarball: https://codeload.github.com/sampotts/plyr/tar.gz/d434c9af16e641400aaee93188594208d88f2658} - name: plyr - version: 3.7.0 - dependencies: - core-js: 3.29.1 - custom-event-polyfill: 1.0.7 - loadjs: 4.2.0 - rangetouch: 2.0.1 - url-polyfill: 1.1.12 - dev: false From 8f14b42e81ba891744cad19e4c6aa0d2d30f5e53 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 11:51:29 +0900 Subject: [PATCH 124/213] =?UTF-8?q?perf:=20=E3=82=A4=E3=83=B3=E3=82=B9?= =?UTF-8?q?=E3=82=BF=E3=83=B3=E3=82=B9=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB?= =?UTF-8?q?=E3=83=88=E3=83=86=E3=83=BC=E3=83=9E=E3=82=92=E4=BA=88=E3=82=81?= =?UTF-8?q?json5=20->=20json=E3=81=AB=E5=A4=89=E6=8F=9B=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=81=8A=E3=81=8F=E3=81=93=E3=81=A8=E3=81=A7json5=E3=82=92?= =?UTF-8?q?=E5=88=9D=E6=9C=9F=E3=83=90=E3=83=B3=E3=83=89=E3=83=AB=E3=81=AB?= =?UTF-8?q?=E5=90=AB=E3=82=81=E3=81=9A=E3=81=AB=E6=B8=88=E3=82=80=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/src/server/api/endpoints/meta.ts | 6 ++++-- packages/frontend/src/boot/common.ts | 5 ++--- pnpm-lock.yaml | 19 +------------------ 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 584ea07c3b..53d724a9dd 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,5 +1,6 @@ import { IsNull, LessThanOrEqual, MoreThan } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; +import * as JSON5 from 'json5'; import type { AdsRepository, UsersRepository } from '@/models/index.js'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; @@ -292,8 +293,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { backgroundImageUrl: instance.backgroundImageUrl, logoImageUrl: instance.logoImageUrl, maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, - defaultLightTheme: instance.defaultLightTheme, - defaultDarkTheme: instance.defaultDarkTheme, + // クライアントの手間を減らすためあらかじめJSONに変換しておく + defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null, + defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null, ads: ads.map(ad => ({ id: ad.id, url: ad.url, diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index e9d6586f85..e1b12fe7d6 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -1,6 +1,5 @@ import { computed, createApp, watch, markRaw, version as vueVersion, defineAsyncComponent, App } from 'vue'; import { compareVersions } from 'compare-versions'; -import JSON5 from 'json5'; import widgets from '@/widgets'; import directives from '@/directives'; import components from '@/components'; @@ -180,8 +179,8 @@ export async function common(createVue: () => App<Element>) { fetchInstanceMetaPromise.then(() => { if (defaultStore.state.themeInitial) { - if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON5.parse(instance.defaultLightTheme)); - if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON5.parse(instance.defaultDarkTheme)); + if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON.parse(instance.defaultLightTheme)); + if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON.parse(instance.defaultDarkTheme)); defaultStore.set('themeInitial', false); } }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a1219a74b..711e0dc0ab 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5535,7 +5535,7 @@ packages: ts-dedent: 2.2.0 util-deprecate: 1.0.2 watchpack: 2.4.0 - ws: 8.13.0 + ws: 8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) transitivePeerDependencies: - bufferutil - encoding @@ -8702,7 +8702,6 @@ packages: requiresBuild: true dependencies: node-gyp-build: 4.6.0 - dev: false /bullmq@3.14.1: resolution: {integrity: sha512-Fom78UKljYsnJmwbROVPx3eFLuVfQjQbw9KCnVupLzT31RQHhFHV2xd/4J4oWl4u34bZ1JmEUfNnqNBz+IOJuA==} @@ -15259,7 +15258,6 @@ packages: /node-gyp-build@4.6.0: resolution: {integrity: sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==} hasBin: true - dev: false /node-gyp@9.3.1: resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} @@ -19676,7 +19674,6 @@ packages: requiresBuild: true dependencies: node-gyp-build: 4.6.0 - dev: false /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -20326,19 +20323,6 @@ packages: async-limiter: 1.0.1 dev: true - /ws@8.13.0: - resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true - /ws@8.13.0(bufferutil@4.0.7)(utf-8-validate@6.0.3): resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} engines: {node: '>=10.0.0'} @@ -20353,7 +20337,6 @@ packages: dependencies: bufferutil: 4.0.7 utf-8-validate: 6.0.3 - dev: false /xev@3.0.2: resolution: {integrity: sha512-8kxuH95iMXzHZj+fwqfA4UrPcYOy6bGIgfWzo9Ji23JoEc30ge/Z++Ubkiuy8c0+M64nXmmxrmJ7C8wnuBhluw==} From f09100788251892e1ac2f9fcde47c8e159251e84 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 12:16:39 +0900 Subject: [PATCH 125/213] refactor --- packages/frontend/src/components/MkPostForm.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 668f023e51..731d171178 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -22,16 +22,16 @@ <span v-if="visibility === 'specified'"><i class="ti ti-mail"></i></span> <span :class="$style.headerRightButtonText">{{ i18n.ts._visibility[visibility] }}</span> </button> - <button v-else :class="['_button', $style.headerRightItem, $style.visibility]" disabled> + <button v-else class="_button" :class="[$style.headerRightItem, $style.visibility]" disabled> <span><i class="ti ti-device-tv"></i></span> <span :class="$style.headerRightButtonText">{{ channel.name }}</span> </button> </template> - <button v-click-anime v-tooltip="i18n.ts._visibility.disableFederation" :class="['_button', $style.headerRightItem, $style.localOnly, { [$style.danger]: localOnly }]" :disabled="channel != null || visibility === 'specified'" @click="toggleLocalOnly"> + <button v-click-anime v-tooltip="i18n.ts._visibility.disableFederation" class="_button" :class="[$style.headerRightItem, $style.localOnly, { [$style.danger]: localOnly }]" :disabled="channel != null || visibility === 'specified'" @click="toggleLocalOnly"> <span v-if="!localOnly"><i class="ti ti-rocket"></i></span> <span v-else><i class="ti ti-rocket-off"></i></span> </button> - <button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" :class="['_button', $style.headerRightItem, $style.reactionAcceptance, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance"> + <button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" class="_button" :class="[$style.headerRightItem, $style.reactionAcceptance, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance"> <span v-if="reactionAcceptance === 'likeOnly'"><i class="ti ti-heart"></i></span> <span v-else-if="reactionAcceptance === 'likeOnlyForRemote'"><i class="ti ti-heart-plus"></i></span> <span v-else><i class="ti ti-icons"></i></span> From a3a47b8d35d1f563cfadf87ce077a24cf3bf7cb1 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 14:34:55 +0900 Subject: [PATCH 126/213] :art: --- .../frontend/src/components/MkMediaImage.vue | 40 +++++++------------ .../src/components/MkPostFormAttaches.vue | 2 +- .../src/scripts/get-drive-file-menu.ts | 2 +- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index c1f8ab3a67..b21776eb49 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -32,7 +32,6 @@ <div v-if="image.comment" :class="$style.indicator">ALT</div> <div v-if="image.isSensitive" :class="$style.indicator" style="color: var(--warn);">NSFW</div> </div> - <button v-tooltip="i18n.ts.hide" :class="$style.hide" class="_button" @click.stop.prevent="hide = true"><i class="ti ti-eye-off"></i></button> <button :class="$style.menu" class="_button" @click.stop="showMenu"><i class="ti ti-dots"></i></button> </template> </div> @@ -79,9 +78,15 @@ watch(() => props.image, () => { }); function showMenu(ev: MouseEvent) { - os.popupMenu([...(iAmModerator ? [{ - text: i18n.ts.markAsSensitive, + os.popupMenu([{ + text: i18n.ts.hide, icon: 'ti ti-eye-off', + action: () => { + hide = true; + }, + }, ...(iAmModerator ? [{ + text: i18n.ts.markAsSensitive, + icon: 'ti ti-eye-exclamation', action: () => { os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true }); }, @@ -122,21 +127,6 @@ function showMenu(ev: MouseEvent) { background-size: 16px 16px; } -.hide { - display: block; - position: absolute; - border-radius: 6px; - background-color: var(--accentedBg); - -webkit-backdrop-filter: var(--blur, blur(15px)); - backdrop-filter: var(--blur, blur(15px)); - color: var(--accent); - font-size: 0.8em; - padding: 6px 8px; - text-align: center; - top: 12px; - right: 12px; -} - .menu { display: block; position: absolute; @@ -148,8 +138,8 @@ function showMenu(ev: MouseEvent) { font-size: 0.8em; padding: 6px 8px; text-align: center; - bottom: 12px; - right: 12px; + bottom: 10px; + right: 10px; } .imageContainer { @@ -166,12 +156,10 @@ function showMenu(ev: MouseEvent) { .indicators { display: inline-flex; position: absolute; - top: 12px; - left: 12px; - text-align: center; + top: 10px; + left: 10px; pointer-events: none; opacity: .5; - font-size: 14px; gap: 6px; } @@ -182,7 +170,7 @@ function showMenu(ev: MouseEvent) { color: var(--accentLighten); display: inline-block; font-weight: bold; - font-size: 12px; - padding: 2px 6px; + font-size: 0.8em; + padding: 2px 5px; } </style> diff --git a/packages/frontend/src/components/MkPostFormAttaches.vue b/packages/frontend/src/components/MkPostFormAttaches.vue index ee4d439cc3..18fa142ebc 100644 --- a/packages/frontend/src/components/MkPostFormAttaches.vue +++ b/packages/frontend/src/components/MkPostFormAttaches.vue @@ -93,7 +93,7 @@ function showFileMenu(file, ev: MouseEvent) { action: () => { rename(file); }, }, { text: file.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive, - icon: file.isSensitive ? 'ti ti-eye-off' : 'ti ti-eye', + icon: file.isSensitive ? 'ti ti-eye-exclamation' : 'ti ti-eye', action: () => { toggleSensitive(file); }, }, { text: i18n.ts.describeFile, diff --git a/packages/frontend/src/scripts/get-drive-file-menu.ts b/packages/frontend/src/scripts/get-drive-file-menu.ts index ed01b49054..060c8a1a11 100644 --- a/packages/frontend/src/scripts/get-drive-file-menu.ts +++ b/packages/frontend/src/scripts/get-drive-file-menu.ts @@ -73,7 +73,7 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile) { action: () => rename(file), }, { text: file.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive, - icon: file.isSensitive ? 'ti ti-eye' : 'ti ti-eye-off', + icon: file.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation', action: () => toggleSensitive(file), }, { text: i18n.ts.describeFile, From de71845b35c62c43f002e92848468cfd7fc38bcc Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 14:38:13 +0900 Subject: [PATCH 127/213] :art: --- packages/frontend/src/pages/settings/drive.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/src/pages/settings/drive.vue b/packages/frontend/src/pages/settings/drive.vue index 6fa3871205..8d7b30dc6e 100644 --- a/packages/frontend/src/pages/settings/drive.vue +++ b/packages/frontend/src/pages/settings/drive.vue @@ -141,6 +141,7 @@ definePageMetadata({ <style lang="scss" module> .meter { + height: 10px; background: rgba(0, 0, 0, 0.1); border-radius: 999px; overflow: clip; From 8e8e3dbe4e7716e807985838a7374736a4918680 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 15:18:08 +0900 Subject: [PATCH 128/213] refactor --- packages/frontend/src/ui/universal.vue | 40 +++++++------------ .../frontend/src/ui/universal.widgets.vue | 23 +---------- 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index d3fd0403d2..18735ead5f 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -1,5 +1,5 @@ <template> -<div :class="[$style.root, { [$style.withWallpaper]: wallpaper }]"> +<div :class="$style.root"> <XSidebar v-if="!isMobile" :class="$style.sidebar"/> <MkStickyContainer :class="$style.contents"> @@ -12,8 +12,8 @@ </main> </MkStickyContainer> - <div v-if="isDesktop" ref="widgetsEl" :class="$style.widgets"> - <XWidgets :marginTop="'var(--margin)'" @mounted="attachSticky"/> + <div v-if="isDesktop" :class="$style.widgets"> + <XWidgets :marginTop="'var(--margin)'"/> </div> <button v-if="!isDesktop && !isMobile" :class="$style.widgetButton" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button> @@ -87,7 +87,6 @@ import { defineAsyncComponent, provide, onMounted, computed, ref, ComputedRef, watch, inject, Ref } from 'vue'; import XCommon from './_common_/common.vue'; import { instanceName } from '@/config'; -import { StickySidebar } from '@/scripts/sticky-sidebar'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; import * as os from '@/os'; import { defaultStore } from '@/store'; @@ -114,7 +113,6 @@ window.addEventListener('resize', () => { }); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); -const widgetsEl = $shallowRef<HTMLElement>(); const widgetsShowing = $ref(false); const navFooter = $shallowRef<HTMLElement>(); @@ -140,8 +138,6 @@ mainRouter.on('change', () => { drawerMenuShowing.value = false; }); -document.documentElement.style.overflowY = 'scroll'; - if (window.innerWidth > 1024) { const tempUI = miLocalStorage.getItem('ui_temp'); if (tempUI) { @@ -197,19 +193,10 @@ const onContextmenu = (ev) => { }], ev); }; -const attachSticky = (el) => { - const sticky = new StickySidebar(widgetsEl); - window.addEventListener('scroll', () => { - sticky.calc(window.scrollY); - }, { passive: true }); -}; - function top() { - window.scroll({ top: 0, behavior: 'smooth' }); + // TODO } -const wallpaper = miLocalStorage.getItem('wallpaper') != null; - let navFooterHeight = $ref(0); provide<Ref<number>>(CURRENT_STICKY_BOTTOM, $$(navFooterHeight)); @@ -275,28 +262,31 @@ $widgets-hide-threshold: 1090px; } .root { - min-height: 100dvh; + height: 100dvh; + overflow: clip; box-sizing: border-box; display: flex; } -.withWallpaper { - background: var(--wallpaperOverlay); - //backdrop-filter: var(--blur, blur(4px)); -} - .sidebar { border-right: solid 0.5px var(--divider); } .contents { - width: 100%; + flex: 1; + height: 100%; min-width: 0; + overflow: auto; + overflow-y: scroll; background: var(--bg); } .widgets { - padding: 0 var(--margin) calc(var(--margin) + env(safe-area-inset-bottom, 0px)); + width: 350px; + height: 100%; + box-sizing: border-box; + overflow: auto; + padding: var(--margin) var(--margin) calc(var(--margin) + env(safe-area-inset-bottom, 0px)); border-left: solid 0.5px var(--divider); background: var(--bg); diff --git a/packages/frontend/src/ui/universal.widgets.vue b/packages/frontend/src/ui/universal.widgets.vue index a3e34ed181..1ee95bf06e 100644 --- a/packages/frontend/src/ui/universal.widgets.vue +++ b/packages/frontend/src/ui/universal.widgets.vue @@ -1,5 +1,5 @@ <template> -<div :class="$style.root" :style="{ paddingTop: marginTop }"> +<div :class="$style.root"> <XWidgets :class="$style.widgets" :edit="editMode" :widgets="widgets" @addWidget="addWidget" @removeWidget="removeWidget" @updateWidget="updateWidget" @updateWidgets="updateWidgets" @exit="editMode = false"/> <button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button> @@ -11,7 +11,7 @@ let editMode = $ref(false); </script> <script lang="ts" setup> -import { onMounted } from 'vue'; +import { } from 'vue'; import XWidgets from '@/components/MkWidgets.vue'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; @@ -21,28 +21,16 @@ const props = withDefaults(defineProps<{ // left = place: leftだけを表示 // right = rightとnullを表示 place?: 'left' | null | 'right'; - marginTop?: string; }>(), { place: null, - marginTop: '0', }); -const emit = defineEmits<{ - (ev: 'mounted', el?: Element): void; -}>(); - -let rootEl = $shallowRef<HTMLDivElement>(); - const widgets = $computed(() => { if (props.place === null) return defaultStore.reactiveState.widgets.value; if (props.place === 'left') return defaultStore.reactiveState.widgets.value.filter(w => w.place === 'left'); return defaultStore.reactiveState.widgets.value.filter(w => w.place !== 'left'); }); -onMounted(() => { - emit('mounted', rootEl); -}); - function addWidget(widget) { defaultStore.set('widgets', [{ ...widget, @@ -83,13 +71,6 @@ function updateWidgets(thisWidgets) { <style lang="scss" module> .root { - position: sticky; - height: min-content; - box-sizing: border-box; -} - -.widgets { - width: 300px; } .edit { From a4a171781b336f85c841846fe78b10715ce97f29 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 15:23:21 +0900 Subject: [PATCH 129/213] clean up --- packages/frontend/src/ui/universal.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 18735ead5f..0f7b5ad90a 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -13,7 +13,7 @@ </MkStickyContainer> <div v-if="isDesktop" :class="$style.widgets"> - <XWidgets :marginTop="'var(--margin)'"/> + <XWidgets/> </div> <button v-if="!isDesktop && !isMobile" :class="$style.widgetButton" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button> From a6cd97ca9a4684e8621766e61d4171f0a1a2c3d8 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 17:27:47 +0900 Subject: [PATCH 130/213] =?UTF-8?q?fix(backend):=20=E3=80=8C=E3=82=A2?= =?UTF-8?q?=E3=82=AF=E3=82=BB=E3=82=B9=E3=83=88=E3=83=BC=E3=82=AF=E3=83=B3?= =?UTF-8?q?=E3=81=AE=E7=AE=A1=E7=90=86=E3=80=8D=E7=94=BB=E9=9D=A2=E3=81=A7?= =?UTF-8?q?=E3=82=A2=E3=83=97=E3=83=AA=E3=81=AE=E6=83=85=E5=A0=B1=E3=81=8C?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E5=95=8F?= =?UTF-8?q?=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #10920 --- CHANGELOG.md | 5 +++-- packages/backend/src/server/api/endpoints/auth/accept.ts | 3 --- packages/backend/src/server/api/endpoints/i/apps.ts | 5 +++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36bc63b0af..a61051e32b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,8 +34,9 @@ - アカウントの初期設定ウィザードにあとでボタンを追加 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 - Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正 -- fix:ロールタイムラインが無効でも投稿が流れてしまう問題の修正 -- fix:ロールタイムラインにて全ての投稿が流れてしまう問題の修正 +- Fix: ロールタイムラインが無効でも投稿が流れてしまう問題の修正 +- Fix: ロールタイムラインにて全ての投稿が流れてしまう問題の修正 +- Fix: 「アクセストークンの管理」画面でアプリの情報が表示されない問題の修正 ### Server - bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 diff --git a/packages/backend/src/server/api/endpoints/auth/accept.ts b/packages/backend/src/server/api/endpoints/auth/accept.ts index cb2e661bfb..05842460cf 100644 --- a/packages/backend/src/server/api/endpoints/auth/accept.ts +++ b/packages/backend/src/server/api/endpoints/auth/accept.ts @@ -55,7 +55,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { throw new ApiError(meta.errors.noSuchSession); } - // Generate access token const accessToken = secureRndstr(32, true); // Fetch exist access token @@ -65,7 +64,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { }); if (exist == null) { - // Lookup app const app = await this.appsRepository.findOneByOrFail({ id: session.appId }); // Generate Hash @@ -75,7 +73,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { const now = new Date(); - // Insert access token doc await this.accessTokensRepository.insert({ id: this.idService.genId(), createdAt: now, diff --git a/packages/backend/src/server/api/endpoints/i/apps.ts b/packages/backend/src/server/api/endpoints/i/apps.ts index 3361e5a4d3..48fb03a8af 100644 --- a/packages/backend/src/server/api/endpoints/i/apps.ts +++ b/packages/backend/src/server/api/endpoints/i/apps.ts @@ -26,7 +26,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { ) { super(meta, paramDef, async (ps, me) => { const query = this.accessTokensRepository.createQueryBuilder('token') - .where('token.userId = :userId', { userId: me.id }); + .where('token.userId = :userId', { userId: me.id }) + .leftJoinAndSelect('token.app', 'app'); switch (ps.sort) { case '+createdAt': query.orderBy('token.createdAt', 'DESC'); break; @@ -40,7 +41,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { return await Promise.all(tokens.map(token => ({ id: token.id, - name: token.name, + name: token.name ?? token.app?.name, createdAt: token.createdAt, lastUsedAt: token.lastUsedAt, permission: token.permission, From f2d9e3105db3215da77881162b6627032456a46f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 17:37:38 +0900 Subject: [PATCH 131/213] =?UTF-8?q?fix(frontend):=20Pages=E3=81=AE?= =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=83=86=E3=83=B3=E3=83=84=E3=81=8C=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E3=83=BB=E4=BD=9C?= =?UTF-8?q?=E6=88=90=E3=82=84=E7=B7=A8=E9=9B=86=E3=81=8C=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #10908 --- packages/frontend/src/components/page/page.block.vue | 12 +++++++++++- packages/frontend/src/components/page/page.vue | 2 +- .../src/pages/page-editor/page-editor.blocks.vue | 12 +++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/page/page.block.vue b/packages/frontend/src/components/page/page.block.vue index dddb9d76bc..2bf3d12daa 100644 --- a/packages/frontend/src/components/page/page.block.vue +++ b/packages/frontend/src/components/page/page.block.vue @@ -1,5 +1,5 @@ <template> -<component :is="'x-' + block.type" :key="block.id" :page="page" :block="block" :h="h"/> +<component :is="getComponent(block.type)" :key="block.id" :page="page" :block="block" :h="h"/> </template> <script lang="ts" setup> @@ -11,6 +11,16 @@ import XImage from './page.image.vue'; import XNote from './page.note.vue'; import { Block } from './block.type'; +function getComponent(type: string) { + switch (type) { + case 'text': return XText; + case 'section': return XSection; + case 'image': return XImage; + case 'note': return XNote; + default: return null; + } +} + defineProps<{ block: Block, h: number, diff --git a/packages/frontend/src/components/page/page.vue b/packages/frontend/src/components/page/page.vue index a6d3ff6359..c2c2693224 100644 --- a/packages/frontend/src/components/page/page.vue +++ b/packages/frontend/src/components/page/page.vue @@ -1,6 +1,6 @@ <template> <div :class="{ [$style.center]: page.alignCenter, [$style.serif]: page.font === 'serif' }"> - <XBlock v-for="child in page.content" :key="child.id" :block="child" :h="2"/> + <XBlock v-for="child in page.content" :key="child.id" :page="page" :block="child" :h="2"/> </div> </template> diff --git a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue index 24b9cb4065..fc945b3d63 100644 --- a/packages/frontend/src/pages/page-editor/page-editor.blocks.vue +++ b/packages/frontend/src/pages/page-editor/page-editor.blocks.vue @@ -3,7 +3,7 @@ <template #item="{element}"> <div :class="$style.item"> <!-- divが無いとエラーになる https://github.com/SortableJS/vue.draggable.next/issues/189 --> - <component :is="'x-' + element.type" :modelValue="element" @update:modelValue="updateItem" @remove="() => removeItem(element)"/> + <component :is="getComponent(element.type)" :modelValue="element" @update:modelValue="updateItem" @remove="() => removeItem(element)"/> </div> </template> </Sortable> @@ -16,6 +16,16 @@ import XText from './els/page-editor.el.text.vue'; import XImage from './els/page-editor.el.image.vue'; import XNote from './els/page-editor.el.note.vue'; +function getComponent(type: string) { + switch (type) { + case 'section': return XSection; + case 'text': return XText; + case 'image': return XImage; + case 'note': return XNote; + default: return null; + } +} + const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default)); const props = defineProps<{ From 4256e20a7f1a6d80f863dfc9c3372f02d9d11be1 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 17:39:37 +0900 Subject: [PATCH 132/213] 13.13.0-beta.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 81522f1e5c..d2cfcafd1a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0-beta.4", + "version": "13.13.0-beta.5", "codename": "nasubi", "repository": { "type": "git", From d7efdd7123a95731bd7dd4413cbe3d5b22751aef Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 30 May 2023 18:55:22 +0900 Subject: [PATCH 133/213] perf(frontend): minify file names Resolve #10924 --- packages/frontend/vite.config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 7c9b31c150..482c98fe88 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -129,6 +129,8 @@ export function getConfig(): UserConfig { vue: ['vue'], photoswipe: ['photoswipe', 'photoswipe/lightbox', 'photoswipe/style.css'], }, + chunkFileNames: process.env.NODE_ENV === 'production' ? '[hash:8].js' : '[name]-[hash:8].js', + assetFileNames: process.env.NODE_ENV === 'production' ? '[hash:8][extname]' : '[name]-[hash:8][extname]', }, }, cssCodeSplit: true, From f8f330416448cc8df0a458ef9eed6918eae5e140 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Tue, 30 May 2023 16:24:45 +0000 Subject: [PATCH 134/213] fix(frontend/MkNoteDetailed): fix css module --- packages/frontend/src/components/MkNoteDetailed.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 3ce516b267..19aa73127b 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -4,7 +4,7 @@ v-show="!isDeleted" ref="el" v-hotkey="keymap" - :class="[$style.root, { [$style.renote]: isRenote }]" + :class="$style.root" > <MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/> <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/> From 8e5d31eb5cc4fa474ae89e75dc4acba4da95246e Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 31 May 2023 09:06:29 +0900 Subject: [PATCH 135/213] New Crowdin updates (#10918) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Japanese, Kansai) * New translations ja-JP.yml (Japanese, Kansai) * New translations ja-JP.yml (Norwegian) * New translations ja-JP.yml (Chinese Traditional) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Norwegian) * New translations ja-JP.yml (Norwegian) * New translations ja-JP.yml (Norwegian) --- locales/ja-KS.yml | 10 +++- locales/ko-KR.yml | 28 ++++++++-- locales/no-NO.yml | 134 ++++++++++++++++++++++++++++++++-------------- locales/zh-TW.yml | 6 +++ 4 files changed, 132 insertions(+), 46 deletions(-) diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 69ea0d172a..652814ca98 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -47,11 +47,13 @@ copyContent: "内容をコピー" copyLink: "リンクをコピー" delete: "ほかす" deleteAndEdit: "ほかして直す" -deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Renote、返信も全部消えるんやけどそれでもええん?" +deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、Renote、返信も全部消えるんやけどそれでもええん?" addToList: "リストに入れたる" sendMessage: "メッセージを送る" copyRSS: "RSSをコピー" copyUsername: "ユーザー名をコピー" +copyUserId: "ユーザーIDをコピー" +copyNoteId: "ノートIDをコピー" searchUser: "ユーザーを検索" reply: "返事" loadMore: "まだまだあるで!" @@ -1043,6 +1045,10 @@ preventAiLearning: "生成AIの学習に使わんといて" preventAiLearningDescription: "他の文章生成AIとか画像生成AIに、投稿したノートとか画像なんかを勝手に使わんように頼むで。具体的にはnoaiフラグをHTMLレスポンスに含めるんやけど、これ聞いてくれるんはAIの気分次第やから、使われる可能性もちょっとはあるな。" options: "オプション" specifyUser: "ユーザー指定" +rolesThatCanBeUsedThisEmojiAsReaction: "ツッコミとして使えるロール" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールが一個も指定されてへんかったら、誰でもツッコミとして使えるで。" +cancelReactionConfirm: "ツッコむんをやっぱやめるか?" +changeReactionConfirm: "ツッコミを別のに変えるか?" _initialAccountSetting: accountCreated: "アカウント作り終わったで。" letsStartAccountSetup: "アカウントの初期設定をしよか。" @@ -1614,7 +1620,7 @@ _timelineTutorial: step2_2: "最初のノートは、自己紹介とか「{name}始めてみたんや」とかがええと思うで。" step3_1: "投稿できた?" step3_2: "あんたのノートがタイムラインに出てきたら成功や。" - step4_1: "ノートには、「リアクション」を付けれるで。" + step4_1: "ノートには、「ツッコミ」を付けれるで。" step4_2: "ツッコむんやったら、ノートの「+」マークを押して、好きな絵文字を選ぶで。" _2fa: alreadyRegistered: "もう設定終わっとるわ。" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 11ab762aa4..1f0e7294fd 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -52,6 +52,8 @@ addToList: "리스트에 추가" sendMessage: "메시지 보내기" copyRSS: "RSS 복사" copyUsername: "유저명 복사" +copyUserId: "유저 ID 복사" +copyNoteId: "노트 ID 복사" searchUser: "사용자 검색" reply: "답글" loadMore: "더 보기" @@ -505,7 +507,7 @@ objectStoragePrefixDesc: "이 Prefix 의 디렉토리 아래에 파일이 저장 objectStorageEndpoint: "Endpoint" objectStorageEndpointDesc: "AWS S3의 경우 공란, 다른 서비스의 경우 각 서비스의 가이드에 맞게 endpoint를 설정해주세요. '<host>' 혹은 '<host>:<port>' 와 같이 지정합니다." objectStorageRegion: "Region" -objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해주세요. 사용하는 서비스에 region 개념이 없는 경우 'us-east-1'으로 설정해 주세요. AWS 설정 파일 또는 환경 변수를 참조할 경우에는 비워주세요." +objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해 주세요. 사용하는 서비스에 region 개념이 없는 경우 'us-east-1'으로 설정해 주세요. AWS 설정 파일 또는 환경 변수를 참조할 경우에는 비워주세요." objectStorageUseSSL: "SSL 사용" objectStorageUseSSLDesc: "API 호출시 HTTPS 를 사용하지 않는 경우 OFF 로 설정해 주세요" objectStorageUseProxy: "연결에 프록시를 사용" @@ -790,6 +792,7 @@ noMaintainerInformationWarning: "관리자 정보가 설정되어 있지 않습 noBotProtectionWarning: "Bot 방어가 설정되어 있지 않습니다." configure: "설정하기" postToGallery: "갤러리에 업로드" +postToHashtag: "이 해시태그에 게시" gallery: "갤러리" recentPosts: "최근 포스트" popularPosts: "인기 포스트" @@ -823,6 +826,7 @@ translatedFrom: "{x}에서 번역" accountDeletionInProgress: "계정 삭제 작업을 진행하고 있습니다" usernameInfo: "서버상에서 계정을 식별하기 위한 이름. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있습니다. 사용자명은 나중에 변경할 수 없습니다." aiChanMode: "아이 모드" +devMode: "개발자 모드" keepCw: "CW 유지하기" pubSub: "Pub/Sub 계정" lastCommunication: "마지막 통신" @@ -830,8 +834,10 @@ resolved: "해결됨" unresolved: "해결되지 않음" breakFollow: "팔로워 해제" breakFollowConfirm: "팔로우를 해제하시겠습니까?" -itsOn: "켜짐" -itsOff: "꺼짐" +itsOn: "켜져 있습니다" +itsOff: "꺼져 있습니다" +on: "켜짐" +off: "꺼짐" emailRequiredForSignup: "가입할 때 이메일 주소 입력을 필수로 하기" unread: "읽지 않음" filter: "필터" @@ -986,6 +992,8 @@ cannotBeChangedLater: "나중에 변경할 수 없습니다." reactionAcceptance: "리액션 수신" likeOnly: "좋아요만 받기" likeOnlyForRemote: "리모트에서는 좋아요만 받기" +nonSensitiveOnly: "열람 주의로 설정되지 않았을 때만 받기" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "열람 주의로 설정되지 않았을 때만 받기 (리모트에서는 좋아요만 받기)" rolesAssignedToMe: "나에게 할당된 역할" resetPasswordConfirm: "비밀번호를 재설정하시겠습니까?" sensitiveWords: "민감한 단어" @@ -1043,20 +1051,30 @@ preventAiLearning: "기계학습(생성형 AI)으로의 사용을 거부" preventAiLearningDescription: "외부의 문장 생성 AI나 이미지 생성 AI에 대해 제출한 노트나 이미지 등의 콘텐츠를 학습의 대상으로 사용하지 않도록 요구합니다. 다만, 이 요구사항을 지킬 의무는 없기 때문에 학습을 완전히 방지하는 것은 아닙니다." options: "옵션" specifyUser: "사용자 지정" +failedToPreviewUrl: "미리 볼 수 없음" +update: "업데이트" +rolesThatCanBeUsedThisEmojiAsReaction: "이 이모지를 리액션으로 사용할 수 있는 역할" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "역할을 지정하지 않으면, 누구나 이 이모지를 리액션으로 사용할 수 있습니다." +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "역할은 공개로 설정되어 있어야 합니다." +cancelReactionConfirm: "리액션을 취소하시겠습니까?" +changeReactionConfirm: "리액션을 변경하시겠습니까?" +later: "나중에" +goToMisskey: "Misskey로" _initialAccountSetting: accountCreated: "계정 생성이 완료되었습니다!" letsStartAccountSetup: "계정의 초기 설정을 진행합니다." letsFillYourProfile: "우선 나의 프로필을 설정해 보아요." profileSetting: "프로필 설정" - privacySetting: "\n프라이버시설정" + privacySetting: "\n프라이버시 설정" theseSettingsCanEditLater: "이 설정들은 나중에도 변경할 수 있습니다." - youCanEditMoreSettingsInSettingsPageLater: "이 외에도 '설정' 페이지에서 다양한 설정을 나의 입맛에 맛게 조절할 수 있습니다. 꼭 확인해 보세요!" + youCanEditMoreSettingsInSettingsPageLater: "이 외에도 '설정' 페이지에서 다양한 설정을 나의 입맛에 맞게 조절할 수 있습니다. 꼭 확인해 보세요!" followUsers: "관심사가 맞는 유저를 팔로우하여 타임라인을 가꾸어 봅시다." pushNotificationDescription: "푸시 알림을 활성화하면 {name}의 알림을 나의 기기에서 받아볼 수 있게 됩니다." initialAccountSettingCompleted: "초기 설정을 모두 마쳤습니다!" haveFun: "{name}와 함께 즐거운 시간 보내세요!" ifYouNeedLearnMore: "{name}(Misskey)의 사용 방법에 대해 자세히 알아보려면 {link}를 참고해 주세요." skipAreYouSure: "초기 설정을 넘기시겠습니까?" + laterAreYouSure: "초기 설정을 나중에 다시 진행하시겠습니까?" _serverRules: description: "회원 가입 이전에 간단하게 표시할 서버 규칙입니다. 이용 약관의 요약으로 구성하는 것을 추천합니다." _accountMigration: diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 585fb95b3d..7bc647fc1d 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -1,5 +1,7 @@ --- _lang_: "Norsk Bokmål" +headlineMisskey: "Et nettverk forbundet med notes" +introMisskey: "Velkommen! Misskey er en desentralisert mikrobloggtjeneste med åpen kildekode.\nOpprett \"notes\" for å dele tankene dine med alle rundt deg. 📡\nMed \"reaksjoner\" kan du også raskt gi uttrykk for hva du synes om alles notes. 👍\nLa oss utforske en ny verden! 🚀" monthAndDay: "{day}-{month}" search: "Søk" notifications: "Varsler" @@ -10,8 +12,10 @@ fetchingAsApObject: "Henter fra Fediverse..." ok: "OK" gotIt: "Skjønner" cancel: "Avbryt" -noThankYou: "Avbryt" +noThankYou: "Ikke nå" enterUsername: "Skriv inn brukernavn" +renotedBy: "Renotes av {user}" +noNotes: "Ingen notes" noNotifications: "Ingen varsler" instance: "Server" settings: "Innstillinger" @@ -30,20 +34,21 @@ uploading: "Laster opp" save: "Lagre" users: "Brukere" addUser: "Legg til bruker" -favorite: "Favoritt" +favorite: "Legg til i favoritter" favorites: "Favoritter" -unfavorite: "Fjern favoritt" +unfavorite: "Fjern fra favoritter" favorited: "Lagt til i favoritter." alreadyFavorited: "Allerede lagt til i favoritter." cantFavorite: "Kunne ikke legge til i favoritter." -pin: "Fest" -unpin: "Opphev festing" +pin: "Fest til profil" +unpin: "Fjern fra profil" copyContent: "Kopier innhold" copyLink: "Kopier lenke" delete: "Slett" deleteAndEdit: "Slett og rediger" +deleteAndEditConfirm: "Er du sikker på at du vil slette denne noten og redigere den? Du vil miste alle reaksjoner, renotes og svar på den." addToList: "Legg til i liste" -sendMessage: "Send melding" +sendMessage: "Send en melding" copyRSS: "Kopier RSS" copyUsername: "Kopier brukernavn" searchUser: "Søk brukere" @@ -63,7 +68,9 @@ unfollowConfirm: "Er du sikker på at du vil slutte å følge {name}?" importRequested: "Du har bedt om import. Dette kan ta en stund." lists: "Lister" noLists: "Ingen lister" -following: "Følg" +note: "Note" +notes: "Notes" +following: "Følger" followers: "Følgere" followsYou: "Følger deg" createList: "Opprett liste" @@ -80,8 +87,13 @@ followRequests: "Følgeforespørsel" unfollow: "Avfølg" followRequestPending: "Venter på godkjenning" enterEmoji: "Skriv inn en emoji" +renote: "Renote" +renoted: "Renotet." +cantRenote: "Dette innlegget kan ikke renotes." +cantReRenote: "En renote kan ikke renotes." quote: "Sitat" -pinned: "Fest" +pinnedNote: "Festet note" +pinned: "Fest til profil" you: "Du" clickToShow: "Klikk for å vise" add: "Legg til" @@ -89,18 +101,21 @@ reaction: "Reaksjon" reactions: "Reaksjoner" reactionSetting: "Reaksjoner som vises i reaksjonsvelgeren" reactionSettingDescription2: "Dra for å endre rekkefølgen, klikk for å slette, trykk \"+\" for å legge til." +rememberNoteVisibility: "Husk innstillingene for synlighet av notes" attachCancel: "Fjern vedlegg" enterFileName: "Skriv inn filnavn" mute: "Skjul" unmute: "Vis" +renoteMute: "Skjul renotes" +renoteUnmute: "Vis renotes" block: "Blokker" unblock: "Opphev blokkering" suspend: "Suspender" -blockConfirm: "Blokker?" +blockConfirm: "Er du sikker på at du vil blokke denne kontoen?" unblockConfirm: "Er du sikker på at du vil oppheve blokkeringen av denne kontoen?" suspendConfirm: "Er du sikker på at du vil suspendere denne kontoen?" -selectList: "Velg liste" -selectChannel: "Velg kanal" +selectList: "Velg en liste" +selectChannel: "Velg en kanal" selectAntenna: "Velg en antenne" selectWidget: "Velg en widget" editWidgets: "Rediger widgeter" @@ -113,6 +128,7 @@ flagAsBot: "Merk denne kontoen som en bot" flagAsBotDescription: "Aktiver dette alternativet hvis denne kontoen styres av et program. Hvis det er aktivert, vil det fungere som et flagg for andre utviklere for å forhindre endeløse interaksjonskjeder med andre roboter og justere Misskeys interne systemer til å behandle denne kontoen som en bot." flagAsCat: "Merk denne kontoen som en katt" flagAsCatDescription: "Aktiver dette alternativet for å merke denne kontoen som en katt." +flagShowTimelineReplies: "Vis svar i tidslinje" addAccount: "Legg til konto" reloadAccountsList: "Last inn kontoliste på nytt" loginFailed: "Kunne ikke logge inn" @@ -120,12 +136,15 @@ general: "Generelt" searchWith: "Søk: {q}" youHaveNoLists: "Du har ingen lister" followConfirm: "Er du sikker på at du vil følge {name}?" -selectUser: "Velg bruker" +host: "Vert" +selectUser: "Velg en bruker" recipient: "Mottaker" annotation: "Kommentarer" federation: "Føderasjon" -instances: "Server" +instances: "Servere" registeredAt: "Registrerte seg" +latestRequestReceivedAt: "Siste forespørsel mottatt" +latestStatus: "Siste status" perHour: "Per time" perDay: "Per dag" stopActivityDelivery: "Slutt å sende aktiviteter" @@ -136,7 +155,7 @@ withNFiles: "{n} fil(er)" network: "Nettverk" statistics: "Statistikk" clearQueue: "Tøm kø" -clearQueueConfirmTitle: "Vil du tømme kø?" +clearQueueConfirmTitle: "Er du sikker på at du vil tømme køen?" blockedInstances: "Blokkerte severe" blockedInstancesDescription: "Skriv opp vertsnavnene til serverne du vil blokkere, atskilt med linjeskift. Serverne i listen vil ikke lenger kunne kommunisere med denne serveren." muteAndBlock: "Skjul og blokker" @@ -144,9 +163,11 @@ mutedUsers: "Skjulte brukere" blockedUsers: "Blokkerte brukere" noUsers: "Det er ingen brukere" editProfile: "Rediger profil" +noteDeleteConfirm: "Er du sikker på at du vil slette denne noten?" pinLimitExceeded: "Du kan ikke feste flere." +intro: "Installasjonen av Misskey er ferdig! Vennligst opprett en administratorkonto." done: "Ferdig" -noCustomEmojis: "Ingen emoji" +noCustomEmojis: "Det er ingen emoji" noJobs: "Det er ingen jobber" blocked: "Blokkert" suspended: "Suspendert" @@ -160,11 +181,13 @@ attachFile: "Legg ved filer" more: "Mer!" announcements: "Kunngjøringer" remove: "Slett" -removed: "Slettet" +removed: "Vellykket slettet" removeAreYouSure: "Er du sikker på at du vil fjerne \"{x}\"?" deleteAreYouSure: "Er du sikker på at du vil slette \"{x}\"?" saved: "Lagret" upload: "Laste opp" +keepOriginalUploading: "Behold originalbildet" +fromUrl: "Fra URL" explore: "Utforsk" messageRead: "Lest" agree: "Jeg godtar" @@ -178,16 +201,16 @@ yearsOld: "{age} år gammel" light: "Lys" dark: "Mørk" fileName: "Filnavn" -selectFile: "Velg fil" -selectFiles: "Velg fil" -selectFolder: "Velg mappe" -selectFolders: "Velg mappe" +selectFile: "Velg en fil" +selectFiles: "Velg filer" +selectFolder: "Velg en mappe" +selectFolders: "Velg mapper" renameFile: "Endre filnavn" folderName: "Mappenavn" -createFolder: "Opprett mappe" +createFolder: "Opprett en mappe" renameFolder: "Endre mappenavn" -deleteFolder: "Slett mappe" -addFile: "Legg til fil" +deleteFolder: "Slett denne mappen" +addFile: "Legg til en fil" emptyFolder: "Denne mappen er tom" unableToDelete: "Kan ikke slette" circularReferenceFolder: "Målmappen er en undermappe til mappen du ønsker å flytte." @@ -196,14 +219,14 @@ copyUrl: "Kopier URL" rename: "Endre navn" avatar: "Avatar" banner: "Banner" -doNothing: "Gjør ingenting" +doNothing: "Ignorer" accept: "Tillatt" reject: "Avslå" instanceName: "Servernavn" instanceDescription: "Serverbeskrivelse" -thisYear: "I år" +thisYear: "År" thisMonth: "Måned" -today: "I dag" +today: "Dag" dayX: "{day}" monthX: "{month}" yearX: "{year}" @@ -216,9 +239,10 @@ registration: "Registrer" enableRegistration: "Aktiver registrering av nye brukere" invite: "Inviter" basicInfo: "Grunnleggende informasjon" -pinnedUsers: "Festete brukrere" +pinnedUsers: "Festede brukrere" pinnedUsersDescription: "Liste over brukernavn atskilt med linjeskift som skal festes i \"Utforsk\" fanen." -pinnedPages: "Festete sider" +pinnedPages: "Festede sider" +pinnedNotes: "Festet note" hcaptcha: "hCaptcha" enableHcaptcha: "Aktiver hCaptcha" recaptcha: "reCAPTCHA" @@ -245,25 +269,37 @@ available: "Tilgjengelig" unavailable: "Utilgjengelig" tooShort: "For kort" tooLong: "For langt" +weakPassword: "Svakt passord" +normalPassword: "Gjennomsnittlig passord" +strongPassword: "Sterkt passord" +signinWith: "Logg inn med {x}" +signinFailed: "Kunne ikke logge inn. Det oppgitte brukernavnet eller passordet er feil." or: "eller" language: "Språk" aboutX: "Om {x}" -category: "Kategorier" +category: "Kategori" createAccount: "Opprett konto" +openImageInNewTab: "Åpne bilder i ny fane" +clientSettings: "Klientinnstillinger" +accountSettings: "Kontoinnstillinger" objectStorageRegion: "Region" objectStorageUseSSL: "Bruk SSL" objectStorageUseProxy: "Bruk Proxy" deleteAll: "Slett alt" +newNoteRecived: "Det er nye notes" listen: "Lytt" none: "Ingen" +volume: "Volum" chooseEmoji: "Velg emoji" recentUsed: "Sist brukte" install: "Installer" +uninstall: "Avinstaller" nothing: "Ingenting" deleteAllFiles: "Slett alle filer" -deleteAllFilesConfirm: "Vil du slette alle filer?" +deleteAllFilesConfirm: "Er du sikker på at du vil slette alle filer?" +userSuspended: "Denne brukeren har blitt suspendert." accountDeleted: "Kontoen blir slettet" -accountDeletedDescription: "Denne kontoen blir slettet" +accountDeletedDescription: "Denne kontoen har blitt slettet." menu: "Meny" poll: "Avstemning" description: "Beskrivelse" @@ -274,6 +310,7 @@ small: "Liten" notificationType: "Varseltype" edit: "Rediger" email: "E-post" +smtpHost: "Vert" smtpUser: "Brukernavn" smtpPass: "Passord" userSaysSomething: "{name} sa noe" @@ -289,16 +326,24 @@ reportAbuse: "Rappoter" send: "Send" openInNewTab: "Åpne i ny fane" waitingFor: "Venter på {x}" +random: "Tilfeldig" system: "System" +desktop: "Skrivebord" +i18nInfo: "Misskey oversettes til flere språk av frivillige. Du kan hjelpe til på {link}." followingCount: "Følger" followersCount: "Følgere" yes: "Ja" no: "Nei" +contact: "Kontakt" +developer: "Utvikler" +makeExplorable: "Gjør konto synlig i \"Utforsk\"" +makeExplorableDescription: "Hvis du slår av dette, vises ikke kontoen din i \"Utforsk\" delen." left: "Venstre" saveAs: "Lagre som" value: "Verdi" deleteConfirm: "Vil du slette?" invalidValue: "Verdien er ugyldig." +closeAccount: "Avslutt konto" emailNotification: "E-postvarsler" inChannelSearch: "Søk i kanal" clear: "Tøm" @@ -312,17 +357,23 @@ accounts: "Kontoer" switch: "Bytt" gallery: "Galleri" ads: "Annonser" +memo: "Notat" high: "Høy" low: "Lav" -sent: "Send" +sent: "Sendt" +received: "Mottatt" learnMore: "Les mer" +misskeyUpdated: "Misskey har blitt oppdatert!" translate: "Oversett" +translatedFrom: "Oversatt fra {x}" unread: "Ulest" manageAccounts: "Administrer konto" classic: "Klassisk" muteThread: "Skjul denne tråden" unmuteThread: "Vis denne tråden" +continueThread: "Vis fortsettelse av tråden" hide: "Skjul" +smartphone: "Smarttelefon" tablet: "Nettbrett" auto: "Automatisk" size: "Størrelse" @@ -338,10 +389,10 @@ check: "Sjekk" deleteAccount: "Slett konto" document: "Dokumenter" logoutConfirm: "Vil du logge ut?" -pleaseSelect: "Vennligst velg" +pleaseSelect: "Velg et alternativ" type: "Type" beta: "Beta" -account: "Kontoer" +account: "Konto" move: "Flytt" pushNotification: "Push-varsler" tools: "Verktøy" @@ -357,6 +408,7 @@ role: "Rolle" color: "Farge" youCannotCreateAnymore: "Du kan ikke opprette flere." cannotPerformTemporary: "Midlertidig utilgjengelig" +achievements: "Prestasjoner" thisPostMayBeAnnoyingCancel: "Avbryt" exploreOtherServers: "Utforsk andre severe" letsLookAtTimeline: "La oss se på tidslinje" @@ -400,7 +452,7 @@ _achievements: _justPlainLucky: title: "Rett og slett heldig" _setNameToSyuilo: - description: "Du har satt navnet ditt til \"syuilo\"" + description: "Du satte navnet ditt til \"syuilo\"" _passedSinceAccountCreated1: title: "Ett års jubileum" description: "Det har gått ett år siden kontoen din ble opprettet" @@ -468,15 +520,17 @@ _theme: key: "Nøkkel" keys: link: "Lenke" + renote: "Renote" _sfx: + note: "Notes" notification: "Varsler" _ago: future: "Fremitid" justNow: "Akkurat nå" - secondsAgo: "{n} sekunder siden" - minutesAgo: "{n} minutter siden" - hoursAgo: "{n} timer siden" - daysAgo: "{n} dager siden" + secondsAgo: "{n}s siden" + minutesAgo: "{n}m siden" + hoursAgo: "{n}t siden" + daysAgo: "{n}d siden" weeksAgo: "{n} uker siden" monthsAgo: "{n} måneder siden" yearsAgo: "{n} år siden" @@ -579,10 +633,12 @@ _notification: _types: follow: "Følg" reply: "Svar" + renote: "Renote" quote: "Sitat" reaction: "Reaksjon" _actions: reply: "Svar" + renote: "Renote" _deck: swapLeft: "Flytt til venstre" swapRight: "Flytt til høyre" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 6044a6532f..04c14b2c65 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1055,6 +1055,11 @@ failedToPreviewUrl: "無法預覽" update: "更新" rolesThatCanBeUsedThisEmojiAsReaction: "可以當成反應使用的角色" rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "如果是未指定角色的情況,則任何人都可以被當成反應來使用。" +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "角色必須是公開的角色。" +cancelReactionConfirm: "要取消做出的反應嗎?" +changeReactionConfirm: "要變更做出的反應嗎?" +later: "稍後再說" +goToMisskey: "往Misskey" _initialAccountSetting: accountCreated: "帳戶已建立完成!" letsStartAccountSetup: "來進行帳戶的初始設定吧。" @@ -1069,6 +1074,7 @@ _initialAccountSetting: haveFun: "盡情享受{name}吧!" ifYouNeedLearnMore: "關於如何使用{name}(Misskey)的詳細資訊,請見{link}。" skipAreYouSure: "要略過初始設定嗎?" + laterAreYouSure: "稍後再重新進行初始設定嗎?" _serverRules: description: "設定伺服器的簡要規則,在新的註冊之前顯示。建議的內容是使用條款的摘要。" _accountMigration: From 14da0a65f70b21eb2e9dec10dab9683e271358d5 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 31 May 2023 12:24:00 +0900 Subject: [PATCH 136/213] tweak ui --- packages/frontend/src/ui/_common_/navbar.vue | 1 + packages/frontend/src/ui/deck.vue | 1 + packages/frontend/src/ui/deck/column.vue | 3 +-- packages/frontend/src/ui/universal.vue | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index 2daff868a9..b9bce4d74d 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -118,6 +118,7 @@ function more(ev: MouseEvent) { box-sizing: border-box; overflow: auto; overflow-x: clip; + overscroll-behavior: contain; background: var(--navBg); contain: strict; display: flex; diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 51cb803397..c828731773 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -306,6 +306,7 @@ async function deleteProfile() { display: flex; overflow-x: auto; overflow-y: clip; + overscroll-behavior: contain; background: var(--deckBg); &.center { diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 2c75577ba4..d95f826f20 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -387,9 +387,8 @@ function onDrop(ev) { .body { height: calc(100% - var(--deckColumnHeaderHeight)); overflow-y: auto; - overflow-x: hidden; // Safari does not supports clip overflow-x: clip; - -webkit-overflow-scrolling: touch; + overscroll-behavior-y: contain; box-sizing: border-box; container-type: size; background-color: var(--bg); diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 0f7b5ad90a..3e06522b69 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -278,6 +278,7 @@ $widgets-hide-threshold: 1090px; min-width: 0; overflow: auto; overflow-y: scroll; + overscroll-behavior: contain; background: var(--bg); } From 821bb1c4767bee84fd9e1196cfee0dabf92c431a Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 31 May 2023 12:42:24 +0900 Subject: [PATCH 137/213] =?UTF-8?q?perf(frontend):=20=E3=82=B5=E3=83=BC?= =?UTF-8?q?=E3=83=90=E3=83=BC=E3=81=AB=E3=82=AB=E3=82=B9=E3=82=BF=E3=83=A0?= =?UTF-8?q?=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=AE=E7=A8=AE=E9=A1=9E=E3=81=8C?= =?UTF-8?q?=E5=A4=9A=E3=81=84=E5=A0=B4=E5=90=88=E3=81=AE=E3=83=91=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=BC=E3=83=9E=E3=83=B3=E3=82=B9=E3=81=AE=E6=94=B9?= =?UTF-8?q?=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve #10925 --- CHANGELOG.md | 1 + packages/frontend/src/components/MkEmojiPicker.vue | 4 ++-- .../frontend/src/components/global/MkCustomEmoji.vue | 4 ++-- packages/frontend/src/custom-emojis.ts | 10 +++++++++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a61051e32b..0e61e7f35c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - ハッシュタグのノート一覧ページから、そのハッシュタグで投稿するボタンを追加 - アカウント初期設定ウィザードに戻るボタンを追加 - アカウントの初期設定ウィザードにあとでボタンを追加 +- サーバーにカスタム絵文字の種類が多い場合のパフォーマンスの改善 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正 - Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正 - Fix: ロールタイムラインが無効でも投稿が流れてしまう問題の修正 diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index d489b3e9b9..b632baaa2b 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -101,7 +101,7 @@ import { isTouchUsing } from '@/scripts/touch'; import { deviceKind } from '@/scripts/device-kind'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; -import { customEmojiCategories, customEmojis } from '@/custom-emojis'; +import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis'; import { $i } from '@/account'; const props = withDefaults(defineProps<{ @@ -337,7 +337,7 @@ function done(query?: string): boolean | void { if (query == null || typeof query !== 'string') return; const q2 = query.replace(/:/g, ''); - const exactMatchCustom = customEmojis.value.find(emoji => emoji.name === q2); + const exactMatchCustom = customEmojisMap.get(q2); if (exactMatchCustom) { chosen(exactMatchCustom); return true; diff --git a/packages/frontend/src/components/global/MkCustomEmoji.vue b/packages/frontend/src/components/global/MkCustomEmoji.vue index 0cb31ffcba..e8a7f17cc6 100644 --- a/packages/frontend/src/components/global/MkCustomEmoji.vue +++ b/packages/frontend/src/components/global/MkCustomEmoji.vue @@ -7,7 +7,7 @@ import { computed } from 'vue'; import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy'; import { defaultStore } from '@/store'; -import { customEmojis } from '@/custom-emojis'; +import { customEmojisMap } from '@/custom-emojis'; const props = defineProps<{ name: string; @@ -26,7 +26,7 @@ const rawUrl = computed(() => { return props.url; } if (isLocal.value) { - return customEmojis.value.find(x => x.name === customEmojiName.value)?.url ?? null; + return customEmojisMap.get(customEmojiName.value)?.url ?? null; } return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`; }); diff --git a/packages/frontend/src/custom-emojis.ts b/packages/frontend/src/custom-emojis.ts index de1b5b8a63..9b738b2fd4 100644 --- a/packages/frontend/src/custom-emojis.ts +++ b/packages/frontend/src/custom-emojis.ts @@ -1,4 +1,4 @@ -import { shallowRef, computed, markRaw } from 'vue'; +import { shallowRef, computed, markRaw, watch } from 'vue'; import * as Misskey from 'misskey-js'; import { api, apiGet } from './os'; import { useStream } from '@/stream'; @@ -16,6 +16,14 @@ export const customEmojiCategories = computed<[ ...string[], null ]>(() => { return markRaw([...Array.from(categories), null]); }); +export const customEmojisMap = new Map<string, Misskey.entities.CustomEmoji>(); +watch(customEmojis, emojis => { + customEmojisMap.clear(); + for (const emoji of emojis) { + customEmojisMap.set(emoji.name, emoji); + } +}, { immediate: true }); + // TODO: ここら辺副作用なのでいい感じにする const stream = useStream(); From aba0755880d6797f49d34c8b7fe2c602d153e367 Mon Sep 17 00:00:00 2001 From: kabo2468 <28654659+kabo2468@users.noreply.github.com> Date: Wed, 31 May 2023 12:57:40 +0900 Subject: [PATCH 138/213] =?UTF-8?q?enhance(client):=20MFM=E3=81=AEx2,=20sc?= =?UTF-8?q?ale,=20position=E3=81=8C=E5=90=AB=E3=81=BE=E3=82=8C=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=81=9F=E3=82=89=E3=83=8E=E3=83=BC=E3=83=88=E3=82=92?= =?UTF-8?q?=E3=81=9F=E3=81=9F=E3=82=80=E3=82=88=E3=81=86=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=9F=20(#10165)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(client): MFMのx2, scale, positionが含まれていたらノートをたたむようにした * Update CHANGELOG.md --------- Co-authored-by: tamaina <tamaina@hotmail.co.jp> --- CHANGELOG.md | 1 + packages/frontend/src/components/MkNote.vue | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e61e7f35c..dd7882c344 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -367,6 +367,7 @@ Meilisearchの設定に`index`が必要になりました。値はMisskeyサー - アンテナでCWも検索対象にするように - ノートの操作部をホバー時のみ表示するオプションを追加 - サウンドを追加 +- enhance(client): MFMのx2, scale, positionが含まれていたらノートをたたむように - サーバーのパフォーマンスを改善 ### Bugfixes diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index e0f2ab61c5..30ec9123bb 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -205,8 +205,11 @@ const isMyRenote = $i && ($i.id === note.userId); const showContent = ref(false); const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null; const isLong = (appearNote.cw == null && appearNote.text != null && ( + (appearNote.text.includes('$[x2')) || (appearNote.text.includes('$[x3')) || (appearNote.text.includes('$[x4')) || + (appearNote.text.includes('$[scale')) || + (appearNote.text.includes('$[position')) || (appearNote.text.split('\n').length > 9) || (appearNote.text.length > 500) || (appearNote.files.length >= 5) || @@ -274,7 +277,7 @@ function renote(viaKeyboard = false) { const y = rect.top + (el.offsetHeight / 2); os.popup(MkRippleEffect, { x, y }, {}, 'end'); } - + os.api('notes/create', { renoteId: appearNote.id, channelId: appearNote.channelId, @@ -305,7 +308,7 @@ function renote(viaKeyboard = false) { const y = rect.top + (el.offsetHeight / 2); os.popup(MkRippleEffect, { x, y }, {}, 'end'); } - + os.api('notes/create', { renoteId: appearNote.id, }).then(() => { From e11f82c300e17049c03f1de510ebc59bb51d0b00 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 31 May 2023 13:27:59 +0900 Subject: [PATCH 139/213] refactor --- packages/frontend/src/ui/_common_/navbar.vue | 740 +++++++++---------- 1 file changed, 370 insertions(+), 370 deletions(-) diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index b9bce4d74d..e9f0624a2e 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -1,51 +1,50 @@ <template> -<div class="mvcprjjd" :class="{ iconOnly }"> - <div class="body"> - <div class="top"> - <div class="banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> - <button v-click-anime v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="item _button instance" @click="openInstanceMenu"> - <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/> +<div :class="[$style.root, { [$style.iconOnly]: iconOnly }]"> + <div :class="$style.body"> + <div :class="$style.top"> + <div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> + <button v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu"> + <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/> </button> </div> - <div class="middle"> - <MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.timeline" class="item index" activeClass="active" to="/" exact> - <i class="icon ti ti-home ti-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> + <div :class="$style.middle"> + <MkA v-tooltip.noDelay.right="i18n.ts.timeline" :class="$style.item" :activeClass="$style.active" to="/" exact> + <i :class="$style.itemIcon" class="ti ti-home ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.timeline }}</span> </MkA> <template v-for="item in menu"> - <div v-if="item === '-'" class="divider"></div> + <div v-if="item === '-'" :class="$style.divider"></div> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" - v-click-anime v-tooltip.noDelay.right="navbarItemDef[item].title" - class="item _button" - :class="[item, { active: navbarItemDef[item].active }]" - activeClass="active" + class="_button" + :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" + :activeClass="$style.active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}" > - <i class="icon ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span> - <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon _indicatorCircle"></i></span> + <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span> + <span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> </component> </template> - <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.noDelay.right="i18n.ts.controlPanel" class="item" activeClass="active" to="/admin"> - <i class="icon ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> + <div :class="$style.divider"></div> + <MkA v-if="$i.isAdmin || $i.isModerator" v-tooltip.noDelay.right="i18n.ts.controlPanel" :class="$style.item" :activeClass="$style.active" to="/admin"> + <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span> </MkA> - <button v-click-anime class="item _button" @click="more"> - <i class="icon ti ti-grid-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> - <span v-if="otherMenuItemIndicated" class="indicator"><i class="icon _indicatorCircle"></i></span> + <button class="_button" :class="$style.item" @click="more"> + <i :class="$style.itemIcon" class="ti ti-grid-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span> + <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> </button> - <MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.settings" class="item" activeClass="active" to="/settings"> - <i class="icon ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> + <MkA v-tooltip.noDelay.right="i18n.ts.settings" :class="$style.item" :activeClass="$style.active" to="/settings"> + <i :class="$style.itemIcon" class="ti ti-settings ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.settings }}</span> </MkA> </div> - <div class="bottom"> - <button v-tooltip.noDelay.right="i18n.ts.note" class="item _button post" data-cy-open-post-form @click="os.post"> - <i class="icon ti ti-pencil ti-fw"></i><span class="text">{{ i18n.ts.note }}</span> + <div :class="$style.bottom"> + <button v-tooltip.noDelay.right="i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post"> + <i class="ti ti-pencil ti-fw" :class="$style.postIcon"></i><span :class="$style.postText">{{ i18n.ts.note }}</span> </button> - <button v-click-anime v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="item _button account" @click="openAccountMenu"> - <MkAvatar :user="$i" class="avatar"/><MkAcct class="text _nowrap" :user="$i"/> + <button v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openAccountMenu"> + <MkAvatar :user="$i" :class="$style.avatar"/><MkAcct class="_nowrap" :class="$style.acct" :user="$i"/> </button> </div> </div> @@ -99,375 +98,376 @@ function more(ev: MouseEvent) { } </script> -<style lang="scss" scoped> -.mvcprjjd { - $nav-width: 250px; - $nav-icon-only-width: 80px; +<style lang="scss" module> +.root { + --nav-width: 250px; + --nav-icon-only-width: 80px; - flex: 0 0 $nav-width; - width: $nav-width; + flex: 0 0 var(--nav-width); + width: var(--nav-width); box-sizing: border-box; +} - > .body { - position: fixed; +.body { + position: fixed; + top: 0; + left: 0; + z-index: 1001; + width: var(--nav-icon-only-width); + height: 100dvh; + box-sizing: border-box; + overflow: auto; + overflow-x: clip; + overscroll-behavior: contain; + background: var(--navBg); + contain: strict; + display: flex; + flex-direction: column; +} + +.root:not(.iconOnly) { + .body { + width: var(--nav-width); + } + + .top { + position: sticky; + top: 0; + z-index: 1; + padding: 20px 0; + background: var(--X14); + -webkit-backdrop-filter: var(--blur, blur(8px)); + backdrop-filter: var(--blur, blur(8px)); + } + + .banner { + position: absolute; top: 0; left: 0; - z-index: 1001; - width: $nav-icon-only-width; - height: 100dvh; - box-sizing: border-box; - overflow: auto; - overflow-x: clip; - overscroll-behavior: contain; - background: var(--navBg); - contain: strict; + width: 100%; + height: 100%; + background-size: cover; + background-position: center center; + -webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); + mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); + } + + .instance { + position: relative; + display: block; + text-align: center; + width: 100%; + } + + .instanceIcon { + display: inline-block; + width: 38px; + aspect-ratio: 1; + } + + .bottom { + position: sticky; + bottom: 0; + padding: 20px 0; + background: var(--X14); + -webkit-backdrop-filter: var(--blur, blur(8px)); + backdrop-filter: var(--blur, blur(8px)); + } + + .post { + position: relative; + display: block; + width: 100%; + height: 40px; + color: var(--fgOnAccent); + font-weight: bold; + text-align: left; + + &:before { + content: ""; + display: block; + width: calc(100% - 38px); + height: 100%; + margin: auto; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 999px; + background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); + } + + &:hover, &.active { + &:before { + background: var(--accentLighten); + } + } + } + + .postIcon { + position: relative; + margin-left: 30px; + margin-right: 8px; + width: 32px; + } + + .postText { + position: relative; + } + + .account { + position: relative; display: flex; - flex-direction: column; + align-items: center; + padding-left: 30px; + width: 100%; + text-align: left; + box-sizing: border-box; + margin-top: 16px; } - &:not(.iconOnly) { - > .body { - width: $nav-width; + .avatar { + display: block; + flex-shrink: 0; + position: relative; + width: 32px; + aspect-ratio: 1; + margin-right: 8px; + } - > .top { - position: sticky; + .acct { + display: block; + flex-shrink: 1; + padding-right: 8px; + } + + .middle { + flex: 1; + } + + .divider { + margin: 16px 16px; + border-top: solid 0.5px var(--divider); + } + + .item { + position: relative; + display: block; + padding-left: 30px; + line-height: 2.85rem; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + width: 100%; + text-align: left; + box-sizing: border-box; + color: var(--navFg); + + &:hover { + text-decoration: none; + color: var(--navHoverFg); + } + + &.active { + color: var(--navActive); + } + + &:hover, &.active { + color: var(--accent); + + &:before { + content: ""; + display: block; + width: calc(100% - 34px); + height: 100%; + margin: auto; + position: absolute; top: 0; - z-index: 1; - padding: 20px 0; - background: var(--X14); - -webkit-backdrop-filter: var(--blur, blur(8px)); - backdrop-filter: var(--blur, blur(8px)); - - > .banner { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-size: cover; - background-position: center center; - -webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); - mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); - } - - > .instance { - position: relative; - display: block; - text-align: center; - width: 100%; - - > .icon { - display: inline-block; - width: 38px; - aspect-ratio: 1; - } - } - } - - > .bottom { - position: sticky; + left: 0; + right: 0; bottom: 0; - padding: 20px 0; - background: var(--X14); - -webkit-backdrop-filter: var(--blur, blur(8px)); - backdrop-filter: var(--blur, blur(8px)); - - > .post { - position: relative; - display: block; - width: 100%; - height: 40px; - color: var(--fgOnAccent); - font-weight: bold; - text-align: left; - - &:before { - content: ""; - display: block; - width: calc(100% - 38px); - height: 100%; - margin: auto; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 999px; - background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); - } - - &:hover, &.active { - &:before { - background: var(--accentLighten); - } - } - - > .icon { - position: relative; - margin-left: 30px; - margin-right: 8px; - width: 32px; - } - - > .text { - position: relative; - } - } - - > .account { - position: relative; - display: flex; - align-items: center; - padding-left: 30px; - width: 100%; - text-align: left; - box-sizing: border-box; - margin-top: 16px; - - > .avatar { - display: block; - flex-shrink: 0; - position: relative; - width: 32px; - aspect-ratio: 1; - margin-right: 8px; - } - - > .text { - display: block; - flex-shrink: 1; - padding-right: 8px; - } - } - } - - > .middle { - flex: 1; - - > .divider { - margin: 16px 16px; - border-top: solid 0.5px var(--divider); - } - - > .item { - position: relative; - display: block; - padding-left: 30px; - line-height: 2.85rem; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - width: 100%; - text-align: left; - box-sizing: border-box; - color: var(--navFg); - - > .icon { - position: relative; - width: 32px; - margin-right: 8px; - } - - > .indicator { - position: absolute; - top: 0; - left: 20px; - color: var(--navIndicator); - font-size: 8px; - animation: blink 1s infinite; - } - - > .text { - position: relative; - font-size: 0.9em; - } - - &:hover { - text-decoration: none; - color: var(--navHoverFg); - } - - &.active { - color: var(--navActive); - } - - &:hover, &.active { - color: var(--accent); - - &:before { - content: ""; - display: block; - width: calc(100% - 34px); - height: 100%; - margin: auto; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 999px; - background: var(--accentedBg); - } - } - } + border-radius: 999px; + background: var(--accentedBg); } } } - &.iconOnly { - flex: 0 0 $nav-icon-only-width; - width: $nav-icon-only-width; + .itemIcon { + position: relative; + width: 32px; + margin-right: 8px; + } - > .body { - width: $nav-icon-only-width; + .itemIndicator { + position: absolute; + top: 0; + left: 20px; + color: var(--navIndicator); + font-size: 8px; + animation: blink 1s infinite; + } - > .top { - position: sticky; - top: 0; - z-index: 1; - padding: 20px 0; - background: var(--X14); - -webkit-backdrop-filter: var(--blur, blur(8px)); - backdrop-filter: var(--blur, blur(8px)); + .itemText { + position: relative; + font-size: 0.9em; + } +} - > .instance { - display: block; - text-align: center; - width: 100%; +.root.iconOnly { + flex: 0 0 var(--nav-icon-only-width); + width: var(--nav-icon-only-width); - > .icon { - display: inline-block; - width: 30px; - aspect-ratio: 1; - } - } - } + .body { + width: var(--nav-icon-only-width); + } - > .bottom { - position: sticky; - bottom: 0; - padding: 20px 0; - background: var(--X14); - -webkit-backdrop-filter: var(--blur, blur(8px)); - backdrop-filter: var(--blur, blur(8px)); + .top { + position: sticky; + top: 0; + z-index: 1; + padding: 20px 0; + background: var(--X14); + -webkit-backdrop-filter: var(--blur, blur(8px)); + backdrop-filter: var(--blur, blur(8px)); + } - > .post { - display: block; - position: relative; - width: 100%; - height: 52px; - margin-bottom: 16px; - text-align: center; + .instance { + display: block; + text-align: center; + width: 100%; + } - &:before { - content: ""; - display: block; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: auto; - width: 52px; - aspect-ratio: 1/1; - border-radius: 100%; - background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); - } + .instanceIcon { + display: inline-block; + width: 30px; + aspect-ratio: 1; + } - &:hover, &.active { - &:before { - background: var(--accentLighten); - } - } + .bottom { + position: sticky; + bottom: 0; + padding: 20px 0; + background: var(--X14); + -webkit-backdrop-filter: var(--blur, blur(8px)); + backdrop-filter: var(--blur, blur(8px)); + } - > .icon { - position: relative; - color: var(--fgOnAccent); - } + .post { + display: block; + position: relative; + width: 100%; + height: 52px; + margin-bottom: 16px; + text-align: center; - > .text { - display: none; - } - } + &:before { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + width: 52px; + aspect-ratio: 1/1; + border-radius: 100%; + background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); + } - > .account { - display: block; - text-align: center; - width: 100%; - - > .avatar { - display: inline-block; - width: 38px; - aspect-ratio: 1; - } - - > .text { - display: none; - } - } - } - - > .middle { - flex: 1; - - > .divider { - margin: 8px auto; - width: calc(100% - 32px); - border-top: solid 0.5px var(--divider); - } - - > .item { - display: block; - position: relative; - padding: 18px 0; - width: 100%; - text-align: center; - - > .icon { - display: block; - margin: 0 auto; - opacity: 0.7; - } - - > .text { - display: none; - } - - > .indicator { - position: absolute; - top: 6px; - left: 24px; - color: var(--navIndicator); - font-size: 8px; - animation: blink 1s infinite; - } - - &:hover, &.active { - text-decoration: none; - color: var(--accent); - - &:before { - content: ""; - display: block; - height: 100%; - aspect-ratio: 1; - margin: auto; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 999px; - background: var(--accentedBg); - } - - > .icon, > .text { - opacity: 1; - } - } - } + &:hover, &.active { + &:before { + background: var(--accentLighten); } } } + + .postIcon { + position: relative; + color: var(--fgOnAccent); + } + + .postText { + display: none; + } + + .account { + display: block; + text-align: center; + width: 100%; + } + + .avatar { + display: inline-block; + width: 38px; + aspect-ratio: 1; + } + + .acct { + display: none; + } + + .middle { + flex: 1; + } + + .divider { + margin: 8px auto; + width: calc(100% - 32px); + border-top: solid 0.5px var(--divider); + } + + .item { + display: block; + position: relative; + padding: 18px 0; + width: 100%; + text-align: center; + + &:hover, &.active { + text-decoration: none; + color: var(--accent); + + &:before { + content: ""; + display: block; + height: 100%; + aspect-ratio: 1; + margin: auto; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 999px; + background: var(--accentedBg); + } + + > .icon, + > .text { + opacity: 1; + } + } + } + + .itemIcon { + display: block; + margin: 0 auto; + opacity: 0.7; + } + + .itemText { + display: none; + } + + .itemIndicator { + position: absolute; + top: 6px; + left: 24px; + color: var(--navIndicator); + font-size: 8px; + animation: blink 1s infinite; + } } </style> From 9521519cb82ef8e1b95b2a1fcb544912a25175a7 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 31 May 2023 13:41:38 +0900 Subject: [PATCH 140/213] reafactor --- .../src/ui/_common_/navbar-for-mobile.vue | 424 +++++++++--------- 1 file changed, 208 insertions(+), 216 deletions(-) diff --git a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue index 6aacdd0150..365486a0ae 100644 --- a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue +++ b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue @@ -1,43 +1,41 @@ <template> -<div class="kmwsukvl"> - <div class="body"> - <div class="top"> - <div class="banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> - <button v-click-anime class="item _button instance" @click="openInstanceMenu"> - <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/> - </button> - </div> - <div class="middle"> - <MkA v-click-anime class="item index" activeClass="active" to="/" exact> - <i class="icon ti ti-home ti-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> - </MkA> - <template v-for="item in menu"> - <div v-if="item === '-'" class="divider"></div> - <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: navbarItemDef[item].active }]" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> - <i class="icon ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span> - <span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon _indicatorCircle"></i></span> - </component> - </template> - <div class="divider"></div> - <MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" activeClass="active" to="/admin"> - <i class="icon ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> - </MkA> - <button v-click-anime class="item _button" @click="more"> - <i class="icon ti ti-grid-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> - <span v-if="otherMenuItemIndicated" class="indicator"><i class="icon _indicatorCircle"></i></span> - </button> - <MkA v-click-anime class="item" activeClass="active" to="/settings"> - <i class="icon ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> - </MkA> - </div> - <div class="bottom"> - <button class="item _button post" data-cy-open-post-form @click="os.post"> - <i class="icon ti ti-pencil ti-fw"></i><span class="text">{{ i18n.ts.note }}</span> - </button> - <button v-click-anime class="item _button account" @click="openAccountMenu"> - <MkAvatar :user="$i" class="avatar"/><MkAcct class="text _nowrap" :user="$i"/> - </button> - </div> +<div :class="$style.root"> + <div :class="$style.top"> + <div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> + <button class="_button" :class="$style.instance" @click="openInstanceMenu"> + <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/> + </button> + </div> + <div :class="$style.middle"> + <MkA :class="$style.item" :activeClass="$style.active" to="/" exact> + <i :class="$style.itemIcon" class="ti ti-home ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.timeline }}</span> + </MkA> + <template v-for="item in menu"> + <div v-if="item === '-'" :class="$style.divider"></div> + <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" class="_button" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :activeClass="$style.active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> + <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span> + <span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> + </component> + </template> + <div :class="$style.divider"></div> + <MkA v-if="$i.isAdmin || $i.isModerator" :class="$style.item" :activeClass="$style.active" to="/admin"> + <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span> + </MkA> + <button :class="$style.item" class="_button" @click="more"> + <i :class="$style.itemIcon" class="ti ti-grid-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span> + <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span> + </button> + <MkA :class="$style.item" :activeClass="$style.active" to="/settings"> + <i :class="$style.itemIcon" class="ti ti-settings ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.settings }}</span> + </MkA> + </div> + <div :class="$style.bottom"> + <button class="_button" :class="$style.post" data-cy-open-post-form @click="os.post"> + <i :class="$style.postIcon" class="ti ti-pencil ti-fw"></i><span style="position: relative;">{{ i18n.ts.note }}</span> + </button> + <button class="_button" :class="$style.account" @click="openAccountMenu"> + <MkAvatar :user="$i" :class="$style.avatar"/><MkAcct :class="$style.acct" class="_nowrap" :user="$i"/> + </button> </div> </div> </template> @@ -73,192 +71,186 @@ function more() { } </script> -<style lang="scss" scoped> -.kmwsukvl { - > .body { - display: flex; - flex-direction: column; +<style lang="scss" module> +.root { + display: flex; + flex-direction: column; +} - > .top { - position: sticky; - top: 0; - z-index: 1; - padding: 20px 0; - background: var(--X14); - -webkit-backdrop-filter: var(--blur, blur(8px)); - backdrop-filter: var(--blur, blur(8px)); +.top { + position: sticky; + top: 0; + z-index: 1; + padding: 20px 0; + background: var(--X14); + -webkit-backdrop-filter: var(--blur, blur(8px)); + backdrop-filter: var(--blur, blur(8px)); +} - > .banner { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-size: cover; - background-position: center center; - -webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); - mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); - } +.banner { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-size: cover; + background-position: center center; + -webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); + mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); +} - > .instance { - position: relative; - display: block; - text-align: center; - width: 100%; +.instance { + position: relative; + display: block; + text-align: center; + width: 100%; +} - > .icon { - display: inline-block; - width: 38px; - aspect-ratio: 1; - } - } - } +.instanceIcon { + display: inline-block; + width: 38px; + aspect-ratio: 1; +} - > .bottom { - position: sticky; - bottom: 0; - padding: 20px 0; - background: var(--X14); - -webkit-backdrop-filter: var(--blur, blur(8px)); - backdrop-filter: var(--blur, blur(8px)); +.bottom { + position: sticky; + bottom: 0; + padding: 20px 0; + background: var(--X14); + -webkit-backdrop-filter: var(--blur, blur(8px)); + backdrop-filter: var(--blur, blur(8px)); +} - > .post { - position: relative; - display: block; - width: 100%; - height: 40px; - color: var(--fgOnAccent); - font-weight: bold; - text-align: left; +.post { + position: relative; + display: block; + width: 100%; + height: 40px; + color: var(--fgOnAccent); + font-weight: bold; + text-align: left; - &:before { - content: ""; - display: block; - width: calc(100% - 38px); - height: 100%; - margin: auto; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 999px; - background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); - } + &:before { + content: ""; + display: block; + width: calc(100% - 38px); + height: 100%; + margin: auto; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 999px; + background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); + } - &:hover, &.active { - &:before { - background: var(--accentLighten); - } - } - - > .icon { - position: relative; - margin-left: 30px; - margin-right: 8px; - width: 32px; - } - - > .text { - position: relative; - } - } - - > .account { - position: relative; - display: flex; - align-items: center; - padding-left: 30px; - width: 100%; - text-align: left; - box-sizing: border-box; - margin-top: 16px; - - > .avatar { - display: block; - flex-shrink: 0; - position: relative; - width: 32px; - aspect-ratio: 1; - margin-right: 8px; - } - - > .text { - display: block; - flex-shrink: 1; - padding-right: 8px; - } - } - } - - > .middle { - flex: 1; - - > .divider { - margin: 16px 16px; - border-top: solid 0.5px var(--divider); - } - - > .item { - position: relative; - display: block; - padding-left: 24px; - line-height: 2.85rem; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - width: 100%; - text-align: left; - box-sizing: border-box; - color: var(--navFg); - - > .icon { - position: relative; - width: 32px; - margin-right: 8px; - } - - > .indicator { - position: absolute; - top: 0; - left: 20px; - color: var(--navIndicator); - font-size: 8px; - animation: blink 1s infinite; - } - - > .text { - position: relative; - font-size: 0.9em; - } - - &:hover { - text-decoration: none; - color: var(--navHoverFg); - } - - &.active { - color: var(--navActive); - } - - &:hover, &.active { - &:before { - content: ""; - display: block; - width: calc(100% - 24px); - height: 100%; - margin: auto; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 999px; - background: var(--accentedBg); - } - } - } + &:hover, &.active { + &:before { + background: var(--accentLighten); } } } + +.postIcon { + position: relative; + margin-left: 30px; + margin-right: 8px; + width: 32px; +} + +.account { + position: relative; + display: flex; + align-items: center; + padding-left: 30px; + width: 100%; + text-align: left; + box-sizing: border-box; + margin-top: 16px; +} + +.avatar { + display: block; + flex-shrink: 0; + position: relative; + width: 32px; + aspect-ratio: 1; + margin-right: 8px; +} + +.acct { + display: block; + flex-shrink: 1; + padding-right: 8px; +} + +.middle { + flex: 1; +} + +.divider { + margin: 16px 16px; + border-top: solid 0.5px var(--divider); +} + +.item { + position: relative; + display: block; + padding-left: 24px; + line-height: 2.85rem; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + width: 100%; + text-align: left; + box-sizing: border-box; + color: var(--navFg); + + &:hover { + text-decoration: none; + color: var(--navHoverFg); + } + + &.active { + color: var(--navActive); + } + + &:hover, &.active { + &:before { + content: ""; + display: block; + width: calc(100% - 24px); + height: 100%; + margin: auto; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 999px; + background: var(--accentedBg); + } + } +} + +.itemIcon { + position: relative; + width: 32px; + margin-right: 8px; +} + +.itemIndicator { + position: absolute; + top: 0; + left: 20px; + color: var(--navIndicator); + font-size: 8px; + animation: blink 1s infinite; +} + +.itemText { + position: relative; + font-size: 0.9em; +} </style> From a535142e82400b1972f25cbbdbdf3ec295be905b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 31 May 2023 13:43:36 +0900 Subject: [PATCH 141/213] 13.13.0-beta.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d2cfcafd1a..089df44db1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0-beta.5", + "version": "13.13.0-beta.6", "codename": "nasubi", "repository": { "type": "git", From 6dd219b6c7d13d6852a5e4173fb8cd7430bd41ff Mon Sep 17 00:00:00 2001 From: mappi <mappi@mizuiromoon.com> Date: Wed, 31 May 2023 14:03:54 +0900 Subject: [PATCH 142/213] =?UTF-8?q?fix:=20Firefox=E3=81=AB=E3=81=8A?= =?UTF-8?q?=E3=81=91=E3=82=8B=E7=B5=B5=E6=96=87=E5=AD=97=E3=83=94=E3=83=83?= =?UTF-8?q?=E3=82=AB=E3=83=BC=E3=81=AETab=E3=82=AD=E3=83=BC=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=BC=E3=82=AB=E3=82=B9=E5=95=8F=E9=A1=8C=E3=81=AE?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#10926)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix 10744 * fix 10744 * Update CHANGELOG.md * add comment --- CHANGELOG.md | 1 + packages/frontend/src/components/MkEmojiPicker.vue | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd7882c344..a53d506ef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ - Fix: ロールタイムラインが無効でも投稿が流れてしまう問題の修正 - Fix: ロールタイムラインにて全ての投稿が流れてしまう問題の修正 - Fix: 「アクセストークンの管理」画面でアプリの情報が表示されない問題の修正 +- Fix: Firefoxにおける絵文字ピッカーのTabキーフォーカス問題の修正 ### Server - bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index b632baaa2b..aab00e17d6 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -1,7 +1,8 @@ <template> <div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"> <input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keydown.stop.prevent.enter="onEnter"> - <div ref="emojisEl" class="emojis"> + <!-- FirefoxのTabフォーカスが想定外の挙動となるためtabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 --> + <div ref="emojisEl" class="emojis" tabindex="-1"> <section class="result"> <div v-if="searchResultCustom.length > 0" class="body"> <button From 6addf9002cbdcd09e2deb66f0278946db990f014 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Wed, 31 May 2023 18:03:43 +0900 Subject: [PATCH 143/213] tweak ui --- .../components/global/MkStickyContainer.vue | 9 +++++---- packages/frontend/src/ui/universal.vue | 20 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/frontend/src/components/global/MkStickyContainer.vue b/packages/frontend/src/components/global/MkStickyContainer.vue index 44c02088da..e5dba54b4e 100644 --- a/packages/frontend/src/components/global/MkStickyContainer.vue +++ b/packages/frontend/src/components/global/MkStickyContainer.vue @@ -14,6 +14,7 @@ <script lang="ts" setup> import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue'; +import { $$ } from 'vue/macros'; import { CURRENT_STICKY_BOTTOM, CURRENT_STICKY_TOP } from '@/const'; const rootEl = $shallowRef<HTMLElement>(); @@ -83,8 +84,8 @@ onMounted(() => { onUnmounted(() => { observer.disconnect(); }); + +defineExpose({ + rootEl: $$(rootEl), +}); </script> - -<style lang="scss" module> - -</style> diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 3e06522b69..20bf08ad7e 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -2,14 +2,10 @@ <div :class="$style.root"> <XSidebar v-if="!isMobile" :class="$style.sidebar"/> - <MkStickyContainer :class="$style.contents"> + <MkStickyContainer ref="contents" :class="$style.contents" style="container-type: inline-size;" @contextmenu.stop="onContextmenu"> <template #header><XStatusBars :class="$style.statusbars"/></template> - <main style="min-width: 0;" @contextmenu.stop="onContextmenu"> - <div :class="$style.content" style="container-type: inline-size;"> - <RouterView/> - </div> - <div :class="$style.spacer"></div> - </main> + <RouterView/> + <div :class="$style.spacer"></div> </MkStickyContainer> <div v-if="isDesktop" :class="$style.widgets"> @@ -84,8 +80,9 @@ </template> <script lang="ts" setup> -import { defineAsyncComponent, provide, onMounted, computed, ref, ComputedRef, watch, inject, Ref } from 'vue'; +import { defineAsyncComponent, provide, onMounted, computed, ref, ComputedRef, watch, shallowRef, Ref } from 'vue'; import XCommon from './_common_/common.vue'; +import type MkStickyContainer from '@/components/global/MkStickyContainer.vue'; import { instanceName } from '@/config'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; import * as os from '@/os'; @@ -98,6 +95,7 @@ import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata'; import { deviceKind } from '@/scripts/device-kind'; import { miLocalStorage } from '@/local-storage'; import { CURRENT_STICKY_BOTTOM } from '@/const'; + const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); @@ -115,6 +113,7 @@ window.addEventListener('resize', () => { let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); const widgetsShowing = $ref(false); const navFooter = $shallowRef<HTMLElement>(); +const contents = shallowRef<InstanceType<typeof MkStickyContainer>>(); provide('router', mainRouter); provideMetadataReceiver((info) => { @@ -194,7 +193,10 @@ const onContextmenu = (ev) => { }; function top() { - // TODO + contents.value.rootEl.scrollTo({ + top: 0, + behavior: 'smooth', + }); } let navFooterHeight = $ref(0); From 1cc616b86cfd2293f20393e85429e31596ea2049 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Wed, 31 May 2023 16:00:55 +0000 Subject: [PATCH 144/213] fix(frontend): disconnect ResizeObserver --- .../frontend/src/components/MkContainer.vue | 20 +++++++++++----- packages/frontend/src/components/MkModal.vue | 16 +++++++++---- packages/frontend/src/components/MkOmit.vue | 24 ++++++++++++------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/frontend/src/components/MkContainer.vue b/packages/frontend/src/components/MkContainer.vue index d2d0fa3e4b..f7cc697d67 100644 --- a/packages/frontend/src/components/MkContainer.vue +++ b/packages/frontend/src/components/MkContainer.vue @@ -34,7 +34,7 @@ </template> <script lang="ts" setup> -import { onMounted, ref, shallowRef, watch } from 'vue'; +import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'; import { defaultStore } from '@/store'; import { i18n } from '@/i18n'; @@ -83,13 +83,19 @@ function afterLeave(el) { const calcOmit = () => { if (omitted.value || ignoreOmit.value || props.maxHeight == null) return; + if (!contentEl.value) return; const height = contentEl.value.offsetHeight; omitted.value = height > props.maxHeight; }; +const omitObserver = new ResizeObserver((entries, observer) => { + calcOmit(); +}); + onMounted(() => { watch(showBody, v => { - const headerHeight = props.showHeader ? headerEl.value.offsetHeight : 0; + if (!rootEl.value) return; + const headerHeight = props.showHeader ? headerEl.value?.offsetHeight ?? 0 : 0; rootEl.value.style.minHeight = `${headerHeight}px`; if (v) { rootEl.value.style.flexBasis = 'auto'; @@ -100,13 +106,15 @@ onMounted(() => { immediate: true, }); - rootEl.value.style.setProperty('--maxHeight', props.maxHeight + 'px'); + if (rootEl.value) rootEl.value.style.setProperty('--maxHeight', props.maxHeight + 'px'); calcOmit(); - new ResizeObserver((entries, observer) => { - calcOmit(); - }).observe(contentEl.value); + if (contentEl.value) omitObserver.observe(contentEl.value); +}); + +onUnmounted(() => { + omitObserver.disconnect(); }); </script> diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue index a33bb2d0e2..b9ce6de697 100644 --- a/packages/frontend/src/components/MkModal.vue +++ b/packages/frontend/src/components/MkModal.vue @@ -17,7 +17,7 @@ </template> <script lang="ts" setup> -import { nextTick, onMounted, watch, provide } from 'vue'; +import { nextTick, onMounted, watch, provide, onUnmounted } from 'vue'; import * as os from '@/os'; import { isTouchUsing } from '@/scripts/touch'; import { defaultStore } from '@/store'; @@ -38,7 +38,7 @@ type ModalTypes = 'popup' | 'dialog' | 'drawer'; const props = withDefaults(defineProps<{ manualShowing?: boolean | null; anchor?: { x: string; y: string; }; - src?: HTMLElement; + src?: HTMLElement | null; preferType?: ModalTypes | 'auto'; zPriority?: 'low' | 'middle' | 'high'; noOverlap?: boolean; @@ -264,6 +264,10 @@ const onOpened = () => { }, { passive: true }); }; +const alignObserver = new ResizeObserver((entries, observer) => { + align(); +}); + onMounted(() => { watch(() => props.src, async () => { if (props.src) { @@ -278,12 +282,14 @@ onMounted(() => { }, { immediate: true }); nextTick(() => { - new ResizeObserver((entries, observer) => { - align(); - }).observe(content!); + alignObserver.observe(content!); }); }); +onUnmounted(() => { + alignObserver.disconnect(); +}); + defineExpose({ close, }); diff --git a/packages/frontend/src/components/MkOmit.vue b/packages/frontend/src/components/MkOmit.vue index e2d68d12c3..668f9ff5af 100644 --- a/packages/frontend/src/components/MkOmit.vue +++ b/packages/frontend/src/components/MkOmit.vue @@ -8,7 +8,7 @@ </template> <script lang="ts" setup> -import { onMounted } from 'vue'; +import { onMounted, onUnmounted } from 'vue'; import { i18n } from '@/i18n'; const props = withDefaults(defineProps<{ @@ -21,16 +21,22 @@ let content = $shallowRef<HTMLElement>(); let omitted = $ref(false); let ignoreOmit = $ref(false); -onMounted(() => { - const calcOmit = () => { - if (omitted || ignoreOmit) return; - omitted = content.offsetHeight > props.maxHeight; - }; +const calcOmit = () => { + if (omitted || ignoreOmit) return; + omitted = content.offsetHeight > props.maxHeight; +}; +const omitObserver = new ResizeObserver((entries, observer) => { calcOmit(); - new ResizeObserver((entries, observer) => { - calcOmit(); - }).observe(content); +}); + +onMounted(() => { + calcOmit(); + omitObserver.observe(content); +}); + +onUnmounted(() => { + omitObserver.disconnect(); }); </script> From ff94b64c91d93aa01bf727ab72ba6937a2028897 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 07:51:02 +0900 Subject: [PATCH 145/213] :art: --- packages/frontend/src/components/MkMediaImage.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index b21776eb49..b921a066f7 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -87,6 +87,7 @@ function showMenu(ev: MouseEvent) { }, ...(iAmModerator ? [{ text: i18n.ts.markAsSensitive, icon: 'ti ti-eye-exclamation', + danger: true, action: () => { os.apiWithDialog('drive/files/update', { fileId: props.image.id, isSensitive: true }); }, From d8a564c6a0686ce814e39df80aa70b05191a3466 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 08:54:37 +0900 Subject: [PATCH 146/213] :art: --- packages/frontend/src/ui/universal.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 20bf08ad7e..c9a4945762 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -321,6 +321,7 @@ $widgets-hide-threshold: 1090px; top: 0; right: 0; z-index: 1001; + width: 310px; height: 100dvh; padding: var(--margin) var(--margin) calc(var(--margin) + env(safe-area-inset-bottom, 0px)) !important; box-sizing: border-box; From a2c77a0944a6b2fe0d958c01e6c449b5b57a3223 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 09:20:37 +0900 Subject: [PATCH 147/213] Update style.scss --- packages/frontend/src/style.scss | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 689cb6ed82..70d48d2da0 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -22,11 +22,7 @@ } html { - touch-action: manipulation; background-color: var(--bg); - background-attachment: fixed; - background-size: cover; - background-position: center; color: var(--fg); accent-color: var(--accent); overflow: auto; @@ -87,6 +83,7 @@ html._themeChanging_ { } html, body { + touch-action: manipulation; margin: 0; padding: 0; scroll-behavior: smooth; From 8cc6c2c864b0cd93e0e270a774386d4fb0f139b6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 09:29:29 +0900 Subject: [PATCH 148/213] New Crowdin updates (#10929) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Chinese Simplified) * New translations ja-JP.yml (Chinese Simplified) * New translations ja-JP.yml (Norwegian) --- locales/ko-KR.yml | 6 +++--- locales/no-NO.yml | 51 ++++++++++++++++++++++++++++++++++------------- locales/zh-CN.yml | 18 +++++++++++++++++ 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 1f0e7294fd..5903bf577d 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1065,7 +1065,7 @@ _initialAccountSetting: letsStartAccountSetup: "계정의 초기 설정을 진행합니다." letsFillYourProfile: "우선 나의 프로필을 설정해 보아요." profileSetting: "프로필 설정" - privacySetting: "\n프라이버시 설정" + privacySetting: "프라이버시 설정" theseSettingsCanEditLater: "이 설정들은 나중에도 변경할 수 있습니다." youCanEditMoreSettingsInSettingsPageLater: "이 외에도 '설정' 페이지에서 다양한 설정을 나의 입맛에 맞게 조절할 수 있습니다. 꼭 확인해 보세요!" followUsers: "관심사가 맞는 유저를 팔로우하여 타임라인을 가꾸어 봅시다." @@ -1073,8 +1073,8 @@ _initialAccountSetting: initialAccountSettingCompleted: "초기 설정을 모두 마쳤습니다!" haveFun: "{name}와 함께 즐거운 시간 보내세요!" ifYouNeedLearnMore: "{name}(Misskey)의 사용 방법에 대해 자세히 알아보려면 {link}를 참고해 주세요." - skipAreYouSure: "초기 설정을 넘기시겠습니까?" - laterAreYouSure: "초기 설정을 나중에 다시 진행하시겠습니까?" + skipAreYouSure: "초기 설정을 중단하시겠습니까?" + laterAreYouSure: "초기 설정을 나중에 진행하시겠습니까?" _serverRules: description: "회원 가입 이전에 간단하게 표시할 서버 규칙입니다. 이용 약관의 요약으로 구성하는 것을 추천합니다." _accountMigration: diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 7bc647fc1d..9d6c5fc501 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -1,7 +1,7 @@ --- _lang_: "Norsk Bokmål" -headlineMisskey: "Et nettverk forbundet med notes" -introMisskey: "Velkommen! Misskey er en desentralisert mikrobloggtjeneste med åpen kildekode.\nOpprett \"notes\" for å dele tankene dine med alle rundt deg. 📡\nMed \"reaksjoner\" kan du også raskt gi uttrykk for hva du synes om alles notes. 👍\nLa oss utforske en ny verden! 🚀" +headlineMisskey: "Et nettverk forbundet med Notes" +introMisskey: "Velkommen! Misskey er en desentralisert mikrobloggtjeneste med åpen kildekode.\nOpprett \"Notes\" for å dele tankene dine med alle rundt deg. 📡\nMed \"reaksjoner\" kan du også raskt gi uttrykk for hva du synes om alles Notes. 👍\nLa oss utforske en ny verden! 🚀" monthAndDay: "{day}-{month}" search: "Søk" notifications: "Varsler" @@ -15,7 +15,7 @@ cancel: "Avbryt" noThankYou: "Ikke nå" enterUsername: "Skriv inn brukernavn" renotedBy: "Renotes av {user}" -noNotes: "Ingen notes" +noNotes: "Ingen Notes" noNotifications: "Ingen varsler" instance: "Server" settings: "Innstillinger" @@ -46,7 +46,7 @@ copyContent: "Kopier innhold" copyLink: "Kopier lenke" delete: "Slett" deleteAndEdit: "Slett og rediger" -deleteAndEditConfirm: "Er du sikker på at du vil slette denne noten og redigere den? Du vil miste alle reaksjoner, renotes og svar på den." +deleteAndEditConfirm: "Er du sikker på at du vil slette denne Noten og redigere den? Du vil miste alle reaksjoner, Renotes og svar på den." addToList: "Legg til i liste" sendMessage: "Send en melding" copyRSS: "Kopier RSS" @@ -90,9 +90,9 @@ enterEmoji: "Skriv inn en emoji" renote: "Renote" renoted: "Renotet." cantRenote: "Dette innlegget kan ikke renotes." -cantReRenote: "En renote kan ikke renotes." +cantReRenote: "En Renote kan ikke renotes." quote: "Sitat" -pinnedNote: "Festet note" +pinnedNote: "Festet Note" pinned: "Fest til profil" you: "Du" clickToShow: "Klikk for å vise" @@ -101,13 +101,13 @@ reaction: "Reaksjon" reactions: "Reaksjoner" reactionSetting: "Reaksjoner som vises i reaksjonsvelgeren" reactionSettingDescription2: "Dra for å endre rekkefølgen, klikk for å slette, trykk \"+\" for å legge til." -rememberNoteVisibility: "Husk innstillingene for synlighet av notes" +rememberNoteVisibility: "Husk innstillingene for synlighet av Notes" attachCancel: "Fjern vedlegg" enterFileName: "Skriv inn filnavn" mute: "Skjul" unmute: "Vis" -renoteMute: "Skjul renotes" -renoteUnmute: "Vis renotes" +renoteMute: "Skjul Renotes" +renoteUnmute: "Vis Renotes" block: "Blokker" unblock: "Opphev blokkering" suspend: "Suspender" @@ -163,7 +163,7 @@ mutedUsers: "Skjulte brukere" blockedUsers: "Blokkerte brukere" noUsers: "Det er ingen brukere" editProfile: "Rediger profil" -noteDeleteConfirm: "Er du sikker på at du vil slette denne noten?" +noteDeleteConfirm: "Er du sikker på at du vil slette denne Noten?" pinLimitExceeded: "Du kan ikke feste flere." intro: "Installasjonen av Misskey er ferdig! Vennligst opprett en administratorkonto." done: "Ferdig" @@ -195,7 +195,7 @@ termsOfService: "Vilkår for bruk" home: "Hjem" activity: "Aktivitet" images: "Bilder" -image: "Bilder" +image: "Bilde" birthday: "Bursdag" yearsOld: "{age} år gammel" light: "Lys" @@ -226,7 +226,7 @@ instanceName: "Servernavn" instanceDescription: "Serverbeskrivelse" thisYear: "År" thisMonth: "Måned" -today: "Dag" +today: "I dag" dayX: "{day}" monthX: "{month}" yearX: "{year}" @@ -242,13 +242,14 @@ basicInfo: "Grunnleggende informasjon" pinnedUsers: "Festede brukrere" pinnedUsersDescription: "Liste over brukernavn atskilt med linjeskift som skal festes i \"Utforsk\" fanen." pinnedPages: "Festede sider" -pinnedNotes: "Festet note" +pinnedNotes: "Festet Note" hcaptcha: "hCaptcha" enableHcaptcha: "Aktiver hCaptcha" recaptcha: "reCAPTCHA" enableRecaptcha: "Aktiver reCAPTCHA" turnstile: "Turnstile" enableTurnstile: "Aktiver Turnstile" +antennas: "Antenner" name: "Navn" popularUsers: "Populære brukere" exploreUsersCount: "Det finnes {count} brukere" @@ -286,7 +287,7 @@ objectStorageRegion: "Region" objectStorageUseSSL: "Bruk SSL" objectStorageUseProxy: "Bruk Proxy" deleteAll: "Slett alt" -newNoteRecived: "Det er nye notes" +newNoteRecived: "Det er nye Notes" listen: "Lytt" none: "Ingen" volume: "Volum" @@ -339,6 +340,7 @@ developer: "Utvikler" makeExplorable: "Gjør konto synlig i \"Utforsk\"" makeExplorableDescription: "Hvis du slår av dette, vises ikke kontoen din i \"Utforsk\" delen." left: "Venstre" +nNotes: "{n} Notes" saveAs: "Lagre som" value: "Verdi" deleteConfirm: "Vil du slette?" @@ -424,6 +426,26 @@ _initialAccountSetting: theseSettingsCanEditLater: "Du kan endre disse innstillingene senere." _achievements: _types: + _notes10: + title: "Noen Notes" + _notes100: + title: "Mange Notes" + _notes500: + title: "Dekket i Notes" + _notes1000: + title: "Et fjell av Notes" + _notes5000: + title: "Overfylte Notes" + _notes10000: + title: "Super Notes" + _notes20000: + title: "Trenger... mer... Notes..." + _notes30000: + title: "Notes Notes Notes!" + _notes40000: + title: "Note fabrikk" + _notes50000: + title: "Planet av Notes" _notes100000: flavor: "Du har jammen mye å si." _noteFavorited1: @@ -650,6 +672,7 @@ _deck: _columns: notifications: "Varsler" tl: "Tidslinje" + antenna: "Antenner" list: "Lister" channel: "Kanaler" direct: "Direkte" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index f7d5ab0e6c..a9ef92e7d3 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -52,6 +52,8 @@ addToList: "添加至列表" sendMessage: "发送" copyRSS: "复制RSS" copyUsername: "复制用户名" +copyUserId: "复制用户ID" +copyNoteId: "复制帖子ID" searchUser: "搜索用户" reply: "回复" loadMore: "查看更多" @@ -790,6 +792,7 @@ noMaintainerInformationWarning: "管理人员信息未设置。" noBotProtectionWarning: "Bot保护未设置。" configure: "设置" postToGallery: "发送到图库" +postToHashtag: "投稿到这个标签" gallery: "图库" recentPosts: "最新发布" popularPosts: "热门投稿" @@ -823,6 +826,7 @@ translatedFrom: "从 {x} 翻译" accountDeletionInProgress: "正在删除账户" usernameInfo: "在服务器上唯一标识您的帐户的名称。您可以使用字母 (a ~ z, A ~ Z)、数字 (0 ~ 9) 和下划线 (_)。用户名以后不能更改。" aiChanMode: "小蓝模式" +devMode: "开发者模式" keepCw: "回复时维持隐藏内容" pubSub: "Pub/Sub账户" lastCommunication: "最近通信" @@ -832,6 +836,8 @@ breakFollow: "移除关注者" breakFollowConfirm: "你想取消关注吗?" itsOn: "已开启" itsOff: "已关闭" +on: "开启" +off: "关闭" emailRequiredForSignup: "注册账户需要电子邮件地址" unread: "未读" filter: "筛选" @@ -986,6 +992,8 @@ cannotBeChangedLater: "之后不能再更改。" reactionAcceptance: "接受表情回应" likeOnly: "仅点赞" likeOnlyForRemote: "远程仅点赞" +nonSensitiveOnly: "仅限非敏感内容" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "仅限非敏感内容(远程仅点赞)" rolesAssignedToMe: "指派给自己的角色" resetPasswordConfirm: "确定重置密码?" sensitiveWords: "敏感词" @@ -1043,6 +1051,15 @@ preventAiLearning: "拒绝接受生成式AI的学习" preventAiLearningDescription: "要求文章生成AI或图像生成AI不能够以发布的帖子和图像等内容作为学习对象。这是通过在HTML响应中包含noai标志来实现的,这不能完全阻止AI学习你的发布内容,并不是所有AI都会遵守这类请求。" options: "选项" specifyUser: "用户指定" +failedToPreviewUrl: "无法预览" +update: "更新" +rolesThatCanBeUsedThisEmojiAsReaction: "可以使用表情作为回应的角色" +rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "在没有指定角色的情况下,任何人都可以使用表情作为回应。" +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "角色必须是公开的。" +cancelReactionConfirm: "要取消回应吗?" +changeReactionConfirm: "要更改回应吗?" +later: "一会再说" +goToMisskey: "去往Misskey" _initialAccountSetting: accountCreated: "账户创建完成了!" letsStartAccountSetup: "来进行帐户的初始设置吧。" @@ -1057,6 +1074,7 @@ _initialAccountSetting: haveFun: "希望{name}在这里玩得开心!" ifYouNeedLearnMore: "关于{name}(Misskey)的使用方法,详见{link}。" skipAreYouSure: "要跳过初始设置吗?" + laterAreYouSure: "要稍后再进行初始设定吗?" _serverRules: description: "在新用户注册前显示服务器的简单规则。推荐显示服务条款的主要内容。" _accountMigration: From 31a8129cb932816228a5137f44cd6095d3ec40ed Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 13:20:43 +0900 Subject: [PATCH 149/213] New translations ja-JP.yml (Korean) (#10933) --- locales/ko-KR.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 5903bf577d..b4a9507b04 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1080,12 +1080,12 @@ _serverRules: _accountMigration: moveFrom: "다른 계정에서 이 계정으로 이사" moveFromSub: "다른 계정에 대한 별칭을 생성" - moveFromLabel: "기존 계정:" + moveFromLabel: "기존 계정 #{n}" moveFromDescription: "다른 계정에서 이 계정으로 팔로워를 가져오려면, 우선 여기에서 별칭을 지정해야 합니다. 반드시 이사하기 전에 지정해야 합니다! 기존 계정을 다음과 같은 형식으로 입력해 주십시오: @person@instance.com" moveTo: "이 계정에서 다른 계정으로 이사" moveToLabel: "이사할 계정:" moveCannotBeUndone: "한 번 이사하면, 두 번 다시 되돌릴 수 없습니다." - moveAccountDescription: "이 작업은 취소할 수 없습니다. 먼저 이사할 계정에서 이 계정에 대한 별칭을 지정하였는지 다시 한 번 확인해 주십시오. 별칭을 지정한 다음, 이사할 계정을 다음과 같은 형식으로 입력해 주십시오: @person@instance.com" + moveAccountDescription: "새 계정으로 이전합니다.\n ・팔로워가 새 계정을 자동으로 팔로우 합니다\n ・이 계정에서 팔로우는 모두 해제됩니다\n ・이 계정으로는 노트 작성 등을 할 수 없게 됩니다\n\n팔로워의 이전은 자동이지만, 팔로우는 수동으로 진행해야 합니다. 이전하기 전에 이 계정에서 팔로우를 내보내고, 이전 후에는 즉시 이전한 계정에서 가져오기를 진행하십시오.\n리스트・뮤트・차단에 대해서도 마찬가지이므로 수동으로 이전해야 합니다.\n\n(이 설명은 이 서버(Misskey v13.12.0 이후)의 사양입니다. Mastodon 등의 다른 ActivityPub 소프트웨어에서는 작동이 다를 수 있습니다.)" moveAccountHowTo: "계정을 이사하려면 우선 이사갈 계정에서 이 계정에 대한 별칭을 지정해야 합니다.\n별칭을 작성한 다음, 이사갈 계정을 다음과 같이 입력하십시오:\n@username@server.example.com" startMigration: "이사하기" migrationConfirm: "정말로 이 계정을 {account} 으로 이전하시겠습니까? 한 번 이전한 다음에는 취소할 수 없으며, 두 번 다시 원래 상태로 복구할 수 없습니다.\n이사할 계정에서 계정 별칭을 지정하였는지 다시 한 번 확인하십시오." From ec2f05d4f79d8f9b1a866527d906db6a2a2b5ba7 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 13:28:43 +0900 Subject: [PATCH 150/213] =?UTF-8?q?fix(backend):=20i/notifications?= =?UTF-8?q?=E3=81=AEsinceId=E3=81=8C=E6=A9=9F=E8=83=BD=E3=81=97=E3=81=AA?= =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #10902 --- CHANGELOG.md | 1 + .../backend/src/server/api/endpoints/i/notifications.ts | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a53d506ef5..5b2b4784af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ - bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 - ストリーミングのパフォーマンスを改善 - Fix: お知らせの画像URLを空にできない問題を修正 +- Fix: i/notificationsのsinceIdが機能しない問題を修正 ## 13.12.2 diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts index e141be764a..f5662f4a0e 100644 --- a/packages/backend/src/server/api/endpoints/i/notifications.ts +++ b/packages/backend/src/server/api/endpoints/i/notifications.ts @@ -91,18 +91,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { const includeTypes = ps.includeTypes && ps.includeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][]; const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][]; - const limit = ps.limit + (ps.untilId ? 1 : 0); // untilIdに指定したものも含まれるため+1 + const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1 const notificationsRes = await this.redisClient.xrevrange( `notificationTimeline:${me.id}`, ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : '+', - '-', + ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : '-', 'COUNT', limit); if (notificationsRes.length === 0) { return []; } - let notifications = notificationsRes.map(x => JSON.parse(x[1][1])).filter(x => x.id !== ps.untilId) as Notification[]; + let notifications = notificationsRes.map(x => JSON.parse(x[1][1])).filter(x => x.id !== ps.untilId && x !== ps.sinceId) as Notification[]; if (includeTypes && includeTypes.length > 0) { notifications = notifications.filter(notification => includeTypes.includes(notification.type)); From 3089a86c8e111e2ddef0b359999b5b720fc1033a Mon Sep 17 00:00:00 2001 From: SASAGAWA Kiyoshi <sasagawa@kent-and-co.com> Date: Thu, 1 Jun 2023 13:29:44 +0900 Subject: [PATCH 151/213] =?UTF-8?q?fix:=20=E3=83=86=E3=83=BC=E3=83=9E?= =?UTF-8?q?=E3=81=AB=E3=83=97=E3=83=AD=E3=83=91=E3=83=86=E3=82=A3=20'fgOnW?= =?UTF-8?q?hite'=20=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=97=E3=81=A6=E3=83=95?= =?UTF-8?q?=E3=82=A9=E3=83=AD=E3=83=BC=E3=83=9C=E3=82=BF=E3=83=B3=E3=81=AE?= =?UTF-8?q?=E3=82=B9=E3=82=BF=E3=82=A4=E3=83=AB=E3=82=92=E8=AA=BF=E6=95=B4?= =?UTF-8?q?=20(#10931)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add theme property 'fgOnWhite' and fix styles of follow button. * fix: add theme property 'fgOnWhite' and fix styles of follow button. --- CHANGELOG.md | 2 ++ packages/frontend/src/components/MkFollowButton.vue | 3 +-- packages/frontend/src/themes/_dark.json5 | 1 + packages/frontend/src/themes/_light.json5 | 1 + packages/frontend/src/themes/d-astro.json5 | 1 + packages/frontend/src/themes/d-botanical.json5 | 1 + packages/frontend/src/themes/d-cherry.json5 | 1 + packages/frontend/src/themes/d-dark.json5 | 1 + packages/frontend/src/themes/d-future.json5 | 1 + packages/frontend/src/themes/d-green-lime.json5 | 1 + packages/frontend/src/themes/d-green-orange.json5 | 1 + packages/frontend/src/themes/d-ice.json5 | 1 + packages/frontend/src/themes/d-persimmon.json5 | 1 + packages/frontend/src/themes/d-u0.json5 | 1 + packages/frontend/src/themes/l-apricot.json5 | 1 + packages/frontend/src/themes/l-botanical.json5 | 1 + packages/frontend/src/themes/l-cherry.json5 | 1 + packages/frontend/src/themes/l-coffee.json5 | 1 + packages/frontend/src/themes/l-light.json5 | 1 + packages/frontend/src/themes/l-rainy.json5 | 1 + packages/frontend/src/themes/l-sushi.json5 | 1 + packages/frontend/src/themes/l-u0.json5 | 1 + packages/frontend/src/themes/l-vivid.json5 | 1 + 23 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b2b4784af..a17c9c231b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,8 @@ - Fix: ロールタイムラインにて全ての投稿が流れてしまう問題の修正 - Fix: 「アクセストークンの管理」画面でアプリの情報が表示されない問題の修正 - Fix: Firefoxにおける絵文字ピッカーのTabキーフォーカス問題の修正 +- Fix: フォローボタンがテーマのカラースキームによって視認性が悪くなる問題を修正 + - 新しいプロパティ `fgOnWhite` が追加されました ### Server - bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index c4e13441e0..b732fbb2b9 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -131,8 +131,7 @@ onBeforeUnmount(() => { position: relative; display: inline-block; font-weight: bold; - color: var(--accent); - background: transparent; + color: var(--fgOnWhite); border: solid 1px var(--accent); padding: 0; height: 31px; diff --git a/packages/frontend/src/themes/_dark.json5 b/packages/frontend/src/themes/_dark.json5 index b8820bcf86..5ef6adb085 100644 --- a/packages/frontend/src/themes/_dark.json5 +++ b/packages/frontend/src/themes/_dark.json5 @@ -21,6 +21,7 @@ fgTransparent: ':alpha<0.5<@fg', fgHighlighted: ':lighten<3<@fg', fgOnAccent: '#fff', + fgOnWhite: '#333', divider: 'rgba(255, 255, 255, 0.1)', indicator: '@accent', panel: ':lighten<3<@bg', diff --git a/packages/frontend/src/themes/_light.json5 b/packages/frontend/src/themes/_light.json5 index da3c770555..32f3c74909 100644 --- a/packages/frontend/src/themes/_light.json5 +++ b/packages/frontend/src/themes/_light.json5 @@ -21,6 +21,7 @@ fgTransparent: ':alpha<0.5<@fg', fgHighlighted: ':darken<3<@fg', fgOnAccent: '#fff', + fgOnWhite: '#333', divider: 'rgba(0, 0, 0, 0.1)', indicator: '@accent', panel: ':lighten<3<@bg', diff --git a/packages/frontend/src/themes/d-astro.json5 b/packages/frontend/src/themes/d-astro.json5 index c6a927ec3a..09a9ead1a2 100644 --- a/packages/frontend/src/themes/d-astro.json5 +++ b/packages/frontend/src/themes/d-astro.json5 @@ -53,6 +53,7 @@ panelHeaderBg: ':lighten<3<@panel', panelHeaderFg: '@fg', htmlThemeColor: '@bg', + fgOnWhite: '@accent', panelHighlight: ':lighten<3<@panel', listItemHoverBg: 'rgba(255, 255, 255, 0.03)', scrollbarHandle: 'rgba(255, 255, 255, 0.2)', diff --git a/packages/frontend/src/themes/d-botanical.json5 b/packages/frontend/src/themes/d-botanical.json5 index 33cf7aa817..62208d2378 100644 --- a/packages/frontend/src/themes/d-botanical.json5 +++ b/packages/frontend/src/themes/d-botanical.json5 @@ -11,6 +11,7 @@ bg: 'rgb(37, 38, 36)', fg: 'rgb(216, 212, 199)', fgHighlighted: '#fff', + fgOnWhite: '@accent', divider: 'rgba(255, 255, 255, 0.14)', panel: 'rgb(47, 47, 44)', panelHeaderDivider: 'rgba(0, 0, 0, 0)', diff --git a/packages/frontend/src/themes/d-cherry.json5 b/packages/frontend/src/themes/d-cherry.json5 index a7e1ad1c80..f9638124c2 100644 --- a/packages/frontend/src/themes/d-cherry.json5 +++ b/packages/frontend/src/themes/d-cherry.json5 @@ -10,6 +10,7 @@ accent: 'rgb(255, 89, 117)', bg: 'rgb(28, 28, 37)', fg: 'rgb(236, 239, 244)', + fgOnWhite: '@accent', panel: 'rgb(35, 35, 47)', renote: '@accent', link: '@accent', diff --git a/packages/frontend/src/themes/d-dark.json5 b/packages/frontend/src/themes/d-dark.json5 index 63144e88ea..ae4f7d53f5 100644 --- a/packages/frontend/src/themes/d-dark.json5 +++ b/packages/frontend/src/themes/d-dark.json5 @@ -11,6 +11,7 @@ bg: '#232323', fg: 'rgb(199, 209, 216)', fgHighlighted: '#fff', + fgOnWhite: '@accent', divider: 'rgba(255, 255, 255, 0.14)', panel: '#2d2d2d', panelHeaderDivider: 'rgba(0, 0, 0, 0)', diff --git a/packages/frontend/src/themes/d-future.json5 b/packages/frontend/src/themes/d-future.json5 index 0962a12411..f2c1f3eb86 100644 --- a/packages/frontend/src/themes/d-future.json5 +++ b/packages/frontend/src/themes/d-future.json5 @@ -12,6 +12,7 @@ fg: '#D5D5D6', fgHighlighted: '#fff', fgOnAccent: '#000', + fgOnWhite: '@accent', divider: 'rgba(255, 255, 255, 0.1)', panel: '#18181c', panelHeaderDivider: 'rgba(0, 0, 0, 0)', diff --git a/packages/frontend/src/themes/d-green-lime.json5 b/packages/frontend/src/themes/d-green-lime.json5 index 9522f534a4..ca4e688fdb 100644 --- a/packages/frontend/src/themes/d-green-lime.json5 +++ b/packages/frontend/src/themes/d-green-lime.json5 @@ -12,6 +12,7 @@ fg: '#dee7e4', fgHighlighted: '#fff', fgOnAccent: '#192320', + fgOnWhite: '@accent', divider: '#e7fffb24', panel: '#192320', panelHeaderDivider: 'rgba(0, 0, 0, 0)', diff --git a/packages/frontend/src/themes/d-green-orange.json5 b/packages/frontend/src/themes/d-green-orange.json5 index e542782c66..c2539816e2 100644 --- a/packages/frontend/src/themes/d-green-orange.json5 +++ b/packages/frontend/src/themes/d-green-orange.json5 @@ -12,6 +12,7 @@ fg: '#dee7e4', fgHighlighted: '#fff', fgOnAccent: '#192320', + fgOnWhite: '@accent', divider: '#e7fffb24', panel: '#192320', panelHeaderDivider: 'rgba(0, 0, 0, 0)', diff --git a/packages/frontend/src/themes/d-ice.json5 b/packages/frontend/src/themes/d-ice.json5 index 179b060dcf..b4abc0cacb 100644 --- a/packages/frontend/src/themes/d-ice.json5 +++ b/packages/frontend/src/themes/d-ice.json5 @@ -8,6 +8,7 @@ props: { accent: '#47BFE8', + fgOnWhite: '@accent', bg: '#212526', }, } diff --git a/packages/frontend/src/themes/d-persimmon.json5 b/packages/frontend/src/themes/d-persimmon.json5 index e36265ff10..0ab6523dd7 100644 --- a/packages/frontend/src/themes/d-persimmon.json5 +++ b/packages/frontend/src/themes/d-persimmon.json5 @@ -11,6 +11,7 @@ bg: 'rgb(31, 33, 31)', fg: '#cdd8c7', fgHighlighted: '#fff', + fgOnWhite: '@accent', divider: 'rgba(255, 255, 255, 0.14)', panel: 'rgb(41, 43, 41)', infoFg: '@fg', diff --git a/packages/frontend/src/themes/d-u0.json5 b/packages/frontend/src/themes/d-u0.json5 index 3fce93b2fe..ed776746a8 100644 --- a/packages/frontend/src/themes/d-u0.json5 +++ b/packages/frontend/src/themes/d-u0.json5 @@ -55,6 +55,7 @@ codeNumber: '#cfff9e', codeString: '#ffb675', fgOnAccent: '#fff', + fgOnWhite: '@accent', infoWarnBg: '#42321c', infoWarnFg: '#ffbd3e', navHoverFg: ':lighten<17<@fg', diff --git a/packages/frontend/src/themes/l-apricot.json5 b/packages/frontend/src/themes/l-apricot.json5 index 1ed5525575..fe1f9f8927 100644 --- a/packages/frontend/src/themes/l-apricot.json5 +++ b/packages/frontend/src/themes/l-apricot.json5 @@ -10,6 +10,7 @@ accent: 'rgb(234, 154, 82)', bg: '#e6e5e2', fg: 'rgb(149, 143, 139)', + fgOnWhite: '@accent', panel: '#EEECE8', renote: '@accent', link: '@accent', diff --git a/packages/frontend/src/themes/l-botanical.json5 b/packages/frontend/src/themes/l-botanical.json5 index 2ea9a7d6c9..5c98927896 100644 --- a/packages/frontend/src/themes/l-botanical.json5 +++ b/packages/frontend/src/themes/l-botanical.json5 @@ -11,6 +11,7 @@ bg: 'e2deda', fg: '#3d3d3d', fgHighlighted: '#6bc9a0', + fgOnWhite: '@accent', divider: '#cfcfcf', panel: '@X14', panelHeaderBg: '@panel', diff --git a/packages/frontend/src/themes/l-cherry.json5 b/packages/frontend/src/themes/l-cherry.json5 index 5ad240241e..1189a28fe6 100644 --- a/packages/frontend/src/themes/l-cherry.json5 +++ b/packages/frontend/src/themes/l-cherry.json5 @@ -10,6 +10,7 @@ accent: 'rgb(219, 96, 114)', bg: 'rgb(254, 248, 249)', fg: 'rgb(152, 13, 26)', + fgOnWhite: '@accent', panel: 'rgb(255, 255, 255)', renote: '@accent', link: 'rgb(156, 187, 5)', diff --git a/packages/frontend/src/themes/l-coffee.json5 b/packages/frontend/src/themes/l-coffee.json5 index fbcd4fa9ef..b64cc73583 100644 --- a/packages/frontend/src/themes/l-coffee.json5 +++ b/packages/frontend/src/themes/l-coffee.json5 @@ -10,6 +10,7 @@ accent: '#9f8989', bg: '#f5f3f3', fg: '#7f6666', + fgOnWhite: '@accent', panel: '#fff', divider: 'rgba(87, 68, 68, 0.1)', renote: 'rgb(160, 172, 125)', diff --git a/packages/frontend/src/themes/l-light.json5 b/packages/frontend/src/themes/l-light.json5 index 248355c945..63c2e6d278 100644 --- a/packages/frontend/src/themes/l-light.json5 +++ b/packages/frontend/src/themes/l-light.json5 @@ -10,6 +10,7 @@ props: { bg: '#f9f9f9', fg: '#676767', + fgOnWhite: '@accent', divider: '#e8e8e8', header: ':alpha<0.7<@panel', navBg: '#fff', diff --git a/packages/frontend/src/themes/l-rainy.json5 b/packages/frontend/src/themes/l-rainy.json5 index 283dd74c6c..e7d1d5af00 100644 --- a/packages/frontend/src/themes/l-rainy.json5 +++ b/packages/frontend/src/themes/l-rainy.json5 @@ -10,6 +10,7 @@ accent: '#5db0da', bg: 'rgb(246 248 249)', fg: '#636b71', + fgOnWhite: '@accent', panel: '#fff', divider: 'rgb(230 233 234)', panelHeaderDivider: '@divider', diff --git a/packages/frontend/src/themes/l-sushi.json5 b/packages/frontend/src/themes/l-sushi.json5 index 5846927d65..e787d63734 100644 --- a/packages/frontend/src/themes/l-sushi.json5 +++ b/packages/frontend/src/themes/l-sushi.json5 @@ -10,6 +10,7 @@ accent: '#e36749', bg: '#f0eee9', fg: '#5f5f5f', + fgOnWhite: '@accent', renote: '@accent', link: '@accent', mention: '@accent', diff --git a/packages/frontend/src/themes/l-u0.json5 b/packages/frontend/src/themes/l-u0.json5 index 03b114ba39..b77b15e3f0 100644 --- a/packages/frontend/src/themes/l-u0.json5 +++ b/packages/frontend/src/themes/l-u0.json5 @@ -55,6 +55,7 @@ codeNumber: '#cfff9e', codeString: '#ffb675', fgOnAccent: '#fff', + fgOnWhite: '@accent', infoWarnBg: '#42321c', infoWarnFg: '#ffbd3e', navHoverFg: ':lighten<17<@fg', diff --git a/packages/frontend/src/themes/l-vivid.json5 b/packages/frontend/src/themes/l-vivid.json5 index b3c08f38ae..822ef948dd 100644 --- a/packages/frontend/src/themes/l-vivid.json5 +++ b/packages/frontend/src/themes/l-vivid.json5 @@ -52,6 +52,7 @@ driveFolderBg: ':alpha<0.3<@accent', fgHighlighted: ':darken<3<@fg', fgTransparent: ':alpha<0.5<@fg', + fgOnWhite: '@accent', panelHeaderBg: ':lighten<3<@panel', panelHeaderFg: '@fg', htmlThemeColor: '@bg', From 6c09361ec6ea50d816fc37cb2b5bbd00dc94ebbf Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 13:50:13 +0900 Subject: [PATCH 152/213] :art: --- packages/frontend/src/ui/_common_/navbar.vue | 2 +- packages/frontend/src/ui/universal.vue | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index e9f0624a2e..a184f1d2f0 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -101,7 +101,7 @@ function more(ev: MouseEvent) { <style lang="scss" module> .root { --nav-width: 250px; - --nav-icon-only-width: 80px; + --nav-icon-only-width: 72px; flex: 0 0 var(--nav-width); width: var(--nav-width); diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index c9a4945762..c0da59a57d 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -266,6 +266,7 @@ $widgets-hide-threshold: 1090px; .root { height: 100dvh; overflow: clip; + contain: strict; box-sizing: border-box; display: flex; } From 2c0b10b0ee77e27bd1498bd457248686c30a45e4 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 16:28:24 +0900 Subject: [PATCH 153/213] refactor --- packages/frontend/src/scripts/emojilist.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/scripts/emojilist.ts b/packages/frontend/src/scripts/emojilist.ts index 3f63e6b214..79661b7ce9 100644 --- a/packages/frontend/src/scripts/emojilist.ts +++ b/packages/frontend/src/scripts/emojilist.ts @@ -30,10 +30,10 @@ for (let i = 0; i < emojilist.length; i++) { export const emojiCharByCategory = _charGroupByCategory; -export function getEmojiName(char: string): string | undefined { +export function getEmojiName(char: string): string | null { const idx = _indexByChar.get(char); - if (typeof idx === 'undefined') { - return undefined; + if (idx == null) { + return null; } else { return emojilist[idx].name; } From cd827488891ff538d480fa2f9821908bed9a6756 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 17:10:53 +0900 Subject: [PATCH 154/213] =?UTF-8?q?enhance(frontend):=20=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E3=81=AE=E7=B5=B5=E6=96=87=E5=AD=97=E7=94=A8=E8=BE=9E=E6=9B=B8?= =?UTF-8?q?=E3=82=92=E3=83=80=E3=82=A6=E3=83=B3=E3=83=AD=E3=83=BC=E3=83=89?= =?UTF-8?q?=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve #10921 --- locales/ja-JP.yml | 1 + .../src/components/MkAutocomplete.vue | 15 +- .../frontend/src/components/MkEmojiPicker.vue | 30 +- .../frontend/src/pages/settings/general.vue | 22 + packages/frontend/src/store.ts | 4 + .../src/unicode-emoji-indexes/en-US.json | 1784 +++++++++++++++++ 6 files changed, 1849 insertions(+), 7 deletions(-) create mode 100644 packages/frontend/src/unicode-emoji-indexes/en-US.json diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 0ca37caa58..40fad285ca 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1060,6 +1060,7 @@ cancelReactionConfirm: "リアクションを取り消しますか?" changeReactionConfirm: "リアクションを変更しますか?" later: "あとで" goToMisskey: "Misskeyへ" +additionalEmojiDictionary: "絵文字の追加辞書" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 4338a8f8e6..1af998dedd 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -42,7 +42,7 @@ import { acct } from '@/filters/user'; import * as os from '@/os'; import { MFM_TAGS } from '@/scripts/mfm-tags'; import { defaultStore } from '@/store'; -import { emojilist } from '@/scripts/emojilist'; +import { emojilist, getEmojiName } from '@/scripts/emojilist'; import { i18n } from '@/i18n'; import { miLocalStorage } from '@/local-storage'; import { customEmojis } from '@/custom-emojis'; @@ -71,6 +71,19 @@ const emojiDb = computed(() => { url: char2path(x.char), })); + for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { + for (const [emoji, keywords] of Object.entries(index)) { + for (const k of keywords) { + unicodeEmojiDB.push({ + emoji: emoji, + name: k, + aliasOf: getEmojiName(emoji)!, + url: char2path(emoji), + }); + } + } + } + unicodeEmojiDB.sort((a, b) => a.name.length - b.name.length); //#endregion diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index aab00e17d6..cf856fd31f 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -224,7 +224,6 @@ watch(q, () => { if (newQ.includes(' ')) { // AND検索 const keywords = newQ.split(' '); - // 名前にキーワードが含まれている for (const emoji of emojis) { if (keywords.every(keyword => emoji.name.includes(keyword))) { matches.add(emoji); @@ -233,11 +232,12 @@ watch(q, () => { } if (matches.size >= max) return matches; - // 名前にキーワードが含まれている - for (const emoji of emojis) { - if (keywords.every(keyword => emoji.name.includes(keyword))) { - matches.add(emoji); - if (matches.size >= max) break; + for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { + for (const emoji of emojis) { + if (keywords.every(keyword => index[emoji.char].some(k => k.includes(keyword)))) { + matches.add(emoji); + if (matches.size >= max) break; + } } } } else { @@ -249,6 +249,15 @@ watch(q, () => { } if (matches.size >= max) return matches; + for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { + for (const emoji of emojis) { + if (index[emoji.char].some(k => k.startsWith(newQ))) { + matches.add(emoji); + if (matches.size >= max) break; + } + } + } + for (const emoji of emojis) { if (emoji.name.includes(newQ)) { matches.add(emoji); @@ -256,6 +265,15 @@ watch(q, () => { } } if (matches.size >= max) return matches; + + for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { + for (const emoji of emojis) { + if (index[emoji.char].some(k => k.includes(newQ))) { + matches.add(emoji); + if (matches.size >= max) break; + } + } + } } return matches; diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 9d06d35e60..4ac077a5e3 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -147,6 +147,10 @@ <template #label>{{ i18n.ts.other }}</template> <div class="_gaps"> + <MkFolder> + <template #label>{{ i18n.ts.additionalEmojiDictionary }}</template> + <MkButton @click="downloadEmojiIndex('en-US')"><i class="ti ti-download"></i> en-US</MkButton> + </MkFolder> <MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> <FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink> <FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink> @@ -161,6 +165,8 @@ import MkSwitch from '@/components/MkSwitch.vue'; import MkSelect from '@/components/MkSelect.vue'; import MkRadios from '@/components/MkRadios.vue'; import MkRange from '@/components/MkRange.vue'; +import MkFolder from '@/components/MkFolder.vue'; +import MkButton from '@/components/MkButton.vue'; import FormSection from '@/components/form/section.vue'; import FormLink from '@/components/form/link.vue'; import MkLink from '@/components/MkLink.vue'; @@ -253,6 +259,22 @@ watch([ await reloadAsk(); }); +async function downloadEmojiIndex(lang: string) { + async function main() { + const currentIndexes = defaultStore.state.additionalUnicodeEmojiIndexes; + function download() { + switch (lang) { + case 'en-US': return import('../../unicode-emoji-indexes/en-US.json').then(x => x.default); + default: throw new Error('unrecognized lang: ' + lang); + } + } + currentIndexes[lang] = await download(); + defaultStore.set('additionalUnicodeEmojiIndexes', currentIndexes); + } + + os.promiseDialog(main()); +} + const headerActions = $computed(() => []); const headerTabs = $computed(() => []); diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index aa4b98c05c..4e43c8e745 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -338,6 +338,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: true, }, + additionalUnicodeEmojiIndexes: { + where: 'device', + default: {} as Record<string, Record<string, string[]>>, + }, })); // TODO: 他のタブと永続化されたstateを同期 diff --git a/packages/frontend/src/unicode-emoji-indexes/en-US.json b/packages/frontend/src/unicode-emoji-indexes/en-US.json new file mode 100644 index 0000000000..c5544418db --- /dev/null +++ b/packages/frontend/src/unicode-emoji-indexes/en-US.json @@ -0,0 +1,1784 @@ +{ + "😀": ["face", "smile", "happy", "joy", ": D", "grin"], + "😬": ["face", "grimace", "teeth"], + "😁": ["face", "happy", "smile", "joy", "kawaii"], + "😂": ["face", "cry", "tears", "weep", "happy", "happytears", "haha"], + "🤣": ["face", "rolling", "floor", "laughing", "lol", "haha"], + "🥳": ["face", "celebration", "woohoo"], + "😃": ["face", "happy", "joy", "haha", ": D", ": )", "smile", "funny"], + "😄": ["face", "happy", "joy", "funny", "haha", "laugh", "like", ": D", ": )"], + "😅": ["face", "hot", "happy", "laugh", "sweat", "smile", "relief"], + "🥲": ["face"], + "😆": ["happy", "joy", "lol", "satisfied", "haha", "face", "glad", "XD", "laugh"], + "😇": ["face", "angel", "heaven", "halo"], + "😉": ["face", "happy", "mischievous", "secret", ";)", "smile", "eye"], + "😊": ["face", "smile", "happy", "flushed", "crush", "embarrassed", "shy", "joy"], + "🙂": ["face", "smile"], + "🙃": ["face", "flipped", "silly", "smile"], + "☺️": ["face", "blush", "massage", "happiness"], + "😋": ["happy", "joy", "tongue", "smile", "face", "silly", "yummy", "nom", "delicious", "savouring"], + "😌": ["face", "relaxed", "phew", "massage", "happiness"], + "😍": ["face", "love", "like", "affection", "valentines", "infatuation", "crush", "heart"], + "🥰": ["face", "love", "like", "affection", "valentines", "infatuation", "crush", "hearts", "adore"], + "😘": ["face", "love", "like", "affection", "valentines", "infatuation", "kiss"], + "😗": ["love", "like", "face", "3", "valentines", "infatuation", "kiss"], + "😙": ["face", "affection", "valentines", "infatuation", "kiss"], + "😚": ["face", "love", "like", "affection", "valentines", "infatuation", "kiss"], + "😜": ["face", "prank", "childish", "playful", "mischievous", "smile", "wink", "tongue"], + "🤪": ["face", "goofy", "crazy"], + "🤨": ["face", "distrust", "scepticism", "disapproval", "disbelief", "surprise"], + "🧐": ["face", "stuffy", "wealthy"], + "😝": ["face", "prank", "playful", "mischievous", "smile", "tongue"], + "😛": ["face", "prank", "childish", "playful", "mischievous", "smile", "tongue"], + "🤑": ["face", "rich", "dollar", "money"], + "🤓": ["face", "nerdy", "geek", "dork"], + "🥸": ["face", "nose", "glasses", "incognito"], + "😎": ["face", "cool", "smile", "summer", "beach", "sunglass"], + "🤩": ["face", "smile", "starry", "eyes", "grinning"], + "🤡": ["face"], + "🤠": ["face", "cowgirl", "hat"], + "🤗": ["face", "smile", "hug"], + "😏": ["face", "smile", "mean", "prank", "smug", "sarcasm"], + "😶": ["face", "hellokitty"], + "😐": ["indifference", "meh", ": |", "neutral"], + "😑": ["face", "indifferent", "-_-", "meh", "deadpan"], + "😒": ["indifference", "bored", "straight face", "serious", "sarcasm", "unimpressed", "skeptical", "dubious", "side_eye"], + "🙄": ["face", "eyeroll", "frustrated"], + "🤔": ["face", "hmmm", "think", "consider"], + "🤥": ["face", "lie", "pinocchio"], + "🤭": ["face", "whoops", "shock", "surprise"], + "🤫": ["face", "quiet", "shhh"], + "🤬": ["face", "swearing", "cursing", "cussing", "profanity", "expletive"], + "🤯": ["face", "shocked", "mind", "blown"], + "😳": ["face", "blush", "shy", "flattered"], + "😞": ["face", "sad", "upset", "depressed", ": ("], + "😟": ["face", "concern", "nervous", ": ("], + "😠": ["mad", "face", "annoyed", "frustrated"], + "😡": ["angry", "mad", "hate", "despise"], + "😔": ["face", "sad", "depressed", "upset"], + "😕": ["face", "indifference", "huh", "weird", "hmmm", ": /"], + "🙁": ["face", "frowning", "disappointed", "sad", "upset"], + "☹": ["face", "sad", "upset", "frown"], + "😣": ["face", "sick", "no", "upset", "oops"], + "😖": ["face", "confused", "sick", "unwell", "oops", ": S"], + "😫": ["sick", "whine", "upset", "frustrated"], + "😩": ["face", "tired", "sleepy", "sad", "frustrated", "upset"], + "🥺": ["face", "begging", "mercy"], + "😤": ["face", "gas", "phew", "proud", "pride"], + "😮": ["face", "surprise", "impressed", "wow", "whoa", ": O"], + "😱": ["face", "munch", "scared", "omg"], + "😨": ["face", "scared", "terrified", "nervous", "oops", "huh"], + "😰": ["face", "nervous", "sweat"], + "😯": ["face", "woo", "shh"], + "😦": ["face", "aw", "what"], + "😧": ["face", "stunned", "nervous"], + "😢": ["face", "tears", "sad", "depressed", "upset", ": '("], + "😥": ["face", "phew", "sweat", "nervous"], + "🤤": ["face"], + "😪": ["face", "tired", "rest", "nap"], + "😓": ["face", "hot", "sad", "tired", "exercise"], + "🥵": ["face", "feverish", "heat", "red", "sweating"], + "🥶": ["face", "blue", "freezing", "frozen", "frostbite", "icicles"], + "😭": ["face", "cry", "tears", "sad", "upset", "depressed"], + "😵": ["spent", "unconscious", "xox", "dizzy"], + "😲": ["face", "xox", "surprised", "poisoned"], + "🤐": ["face", "sealed", "zipper", "secret"], + "🤢": ["face", "vomit", "gross", "green", "sick", "throw up", "ill"], + "🤧": ["face", "gesundheit", "sneeze", "sick", "allergy"], + "🤮": ["face", "sick"], + "😷": ["face", "sick", "ill", "disease"], + "🤒": ["sick", "temperature", "thermometer", "cold", "fever"], + "🤕": ["injured", "clumsy", "bandage", "hurt"], + "🥴": ["face", "dizzy", "intoxicated", "tipsy", "wavy"], + "🥱": ["face", "tired", "yawning"], + "😴": ["face", "tired", "sleepy", "night", "zzz"], + "💤": ["sleepy", "tired", "dream"], + "😶🌫️": [], + "😮💨": [], + "😵💫": [], + "🫠": ["disappear", "dissolve", "liquid", "melt", "toketa"], + "🫢": ["amazement", "awe", "disbelief", "embarrass", "scared", "surprise", "ohoho"], + "🫣": ["captivated", "peep", "stare", "chunibyo"], + "🫡": ["ok", "salute", "sunny", "troops", "yes", "raja"], + "🫥": ["depressed", "disappear", "hide", "introvert", "invisible", "tensen"], + "🫤": ["disappointed", "meh", "skeptical", "unsure"], + "🥹": ["angry", "cry", "proud", "resist", "sad"], + "💩": ["hankey", "shitface", "fail", "turd", "shit"], + "😈": ["devil", "horns"], + "👿": ["devil", "angry", "horns"], + "👹": ["monster", "red", "mask", "halloween", "scary", "creepy", "devil", "demon", "japanese", "ogre"], + "👺": ["red", "evil", "mask", "monster", "scary", "creepy", "japanese", "goblin"], + "💀": ["dead", "skeleton", "creepy", "death"], + "👻": ["halloween", "spooky", "scary"], + "👽": ["UFO", "paul", "weird", "outer_space"], + "🤖": ["computer", "machine", "bot"], + "😺": ["animal", "cats", "happy", "smile"], + "😸": ["animal", "cats", "smile"], + "😹": ["animal", "cats", "haha", "happy", "tears"], + "😻": ["animal", "love", "like", "affection", "cats", "valentines", "heart"], + "😼": ["animal", "cats", "smirk"], + "😽": ["animal", "cats", "kiss"], + "🙀": ["animal", "cats", "munch", "scared", "scream"], + "😿": ["animal", "tears", "weep", "sad", "cats", "upset", "cry"], + "😾": ["animal", "cats"], + "🤲": ["hands", "gesture", "cupped", "prayer"], + "🙌": ["gesture", "hooray", "yea", "celebration", "hands"], + "👏": ["hands", "praise", "applause", "congrats", "yay"], + "👋": ["hands", "gesture", "goodbye", "solong", "farewell", "hello", "hi", "palm"], + "🤙": ["hands", "gesture"], + "👍": ["thumbsup", "yes", "awesome", "good", "agree", "accept", "cool", "hand", "like"], + "👎": ["thumbsdown", "no", "dislike", "hand"], + "👊": ["angry", "violence", "fist", "hit", "attack", "hand"], + "✊": ["fingers", "hand", "grasp"], + "🤛": ["hand", "fistbump"], + "🤜": ["hand", "fistbump"], + "✌": ["fingers", "ohyeah", "hand", "peace", "victory", "two"], + "👌": ["fingers", "limbs", "perfect", "ok", "okay"], + "✋": ["fingers", "stop", "highfive", "palm", "ban"], + "🤚": ["fingers", "raised", "backhand"], + "👐": ["fingers", "butterfly", "hands", "open"], + "💪": ["arm", "flex", "hand", "summer", "strong", "biceps"], + "🦾": ["flex", "hand", "strong", "biceps"], + "🙏": ["please", "hope", "wish", "namaste", "highfive"], + "🦶": ["kick", "stomp"], + "🦵": ["kick", "limb"], + "🦿": ["kick", "limb"], + "🤝": ["agreement", "shake"], + "☝": ["hand", "fingers", "direction", "up"], + "👆": ["fingers", "hand", "direction", "up"], + "👇": ["fingers", "hand", "direction", "down"], + "👈": ["direction", "fingers", "hand", "left"], + "👉": ["fingers", "hand", "direction", "right"], + "🖕": ["hand", "fingers", "rude", "middle", "flipping"], + "🖐": ["hand", "fingers", "palm"], + "🤟": ["hand", "fingers", "gesture"], + "🤘": ["hand", "fingers", "evil_eye", "sign_of_horns", "rock_on"], + "🤞": ["good", "lucky"], + "🖖": ["hand", "fingers", "spock", "star trek"], + "✍": ["lower_left_ballpoint_pen", "stationery", "write", "compose"], + "🫰": [], + "🫱": [], + "🫲": [], + "🫳": [], + "🫴": [], + "🫵": [], + "🫶": ["moemoekyun"], + "🤏": ["hand", "fingers"], + "🤌": ["hand", "fingers"], + "🤳": ["camera", "phone"], + "💅": ["beauty", "manicure", "finger", "fashion", "nail"], + "👄": ["mouth", "kiss"], + "🫦": [], + "🦷": ["teeth", "dentist"], + "👅": ["mouth", "playful"], + "👂": ["face", "hear", "sound", "listen"], + "🦻": ["face", "hear", "sound", "listen"], + "👃": ["smell", "sniff"], + "👁": ["face", "look", "see", "watch", "stare"], + "👀": ["look", "watch", "stalk", "peek", "see"], + "🧠": ["smart", "intelligent"], + "🫀": [], + "🫁": [], + "👤": ["user", "person", "human"], + "👥": ["user", "person", "human", "group", "team"], + "🗣": ["user", "person", "human", "sing", "say", "talk"], + "👶": ["child", "boy", "girl", "toddler"], + "🧒": ["gender-neutral", "young"], + "👦": ["man", "male", "guy", "teenager"], + "👧": ["female", "woman", "teenager"], + "🧑": ["gender-neutral", "person"], + "👨": ["mustache", "father", "dad", "guy", "classy", "sir", "moustache"], + "👩": ["female", "girls", "lady"], + "🧑🦱": ["curly", "afro", "braids", "ringlets"], + "👩🦱": ["woman", "female", "girl", "curly", "afro", "braids", "ringlets"], + "👨🦱": ["man", "male", "boy", "guy", "curly", "afro", "braids", "ringlets"], + "🧑🦰": ["redhead"], + "👩🦰": ["woman", "female", "girl", "ginger", "redhead"], + "👨🦰": ["man", "male", "boy", "guy", "ginger", "redhead"], + "👱♀️": ["woman", "female", "girl", "blonde", "person"], + "👱": ["man", "male", "boy", "blonde", "guy", "person"], + "🧑🦳": ["gray", "old", "white"], + "👩🦳": ["woman", "female", "girl", "gray", "old", "white"], + "👨🦳": ["man", "male", "boy", "guy", "gray", "old", "white"], + "🧑🦲": ["bald", "chemotherapy", "hairless", "shaven"], + "👩🦲": ["woman", "female", "girl", "bald", "chemotherapy", "hairless", "shaven"], + "👨🦲": ["man", "male", "boy", "guy", "bald", "chemotherapy", "hairless", "shaven"], + "🧔": ["person", "bewhiskered"], + "🧓": ["human", "elder", "senior", "gender-neutral"], + "👴": ["human", "male", "men", "old", "elder", "senior"], + "👵": ["human", "female", "women", "lady", "old", "elder", "senior"], + "👲": ["male", "boy", "chinese"], + "🧕": ["female", "hijab", "mantilla", "tichel"], + "👳♀️": ["female", "indian", "hinduism", "arabs", "woman"], + "👳": ["male", "indian", "hinduism", "arabs"], + "👮♀️": ["woman", "police", "law", "legal", "enforcement", "arrest", "911", "female"], + "👮": ["man", "police", "law", "legal", "enforcement", "arrest", "911"], + "👷♀️": ["female", "human", "wip", "build", "construction", "worker", "labor", "woman"], + "👷": ["male", "human", "wip", "guy", "build", "construction", "worker", "labor"], + "💂♀️": ["uk", "gb", "british", "female", "royal", "woman"], + "💂": ["uk", "gb", "british", "male", "guy", "royal"], + "🕵️♀️": ["human", "spy", "detective", "female", "woman"], + "🕵": ["human", "spy", "detective"], + "🧑⚕️": ["doctor", "nurse", "therapist", "healthcare", "human"], + "👩⚕️": ["doctor", "nurse", "therapist", "healthcare", "woman", "human"], + "👨⚕️": ["doctor", "nurse", "therapist", "healthcare", "man", "human"], + "🧑🌾": ["rancher", "gardener", "human"], + "👩🌾": ["rancher", "gardener", "woman", "human"], + "👨🌾": ["rancher", "gardener", "man", "human"], + "🧑🍳": ["chef", "human"], + "👩🍳": ["chef", "woman", "human"], + "👨🍳": ["chef", "man", "human"], + "🧑🎓": ["graduate", "human"], + "👩🎓": ["graduate", "woman", "human"], + "👨🎓": ["graduate", "man", "human"], + "🧑🎤": ["rockstar", "entertainer", "human"], + "👩🎤": ["rockstar", "entertainer", "woman", "human"], + "👨🎤": ["rockstar", "entertainer", "man", "human"], + "🧑🏫": ["instructor", "professor", "human"], + "👩🏫": ["instructor", "professor", "woman", "human"], + "👨🏫": ["instructor", "professor", "man", "human"], + "🧑🏭": ["assembly", "industrial", "human"], + "👩🏭": ["assembly", "industrial", "woman", "human"], + "👨🏭": ["assembly", "industrial", "man", "human"], + "🧑💻": ["coder", "developer", "engineer", "programmer", "software", "human", "laptop", "computer"], + "👩💻": ["coder", "developer", "engineer", "programmer", "software", "woman", "human", "laptop", "computer"], + "👨💻": ["coder", "developer", "engineer", "programmer", "software", "man", "human", "laptop", "computer"], + "🧑💼": ["business", "manager", "human"], + "👩💼": ["business", "manager", "woman", "human"], + "👨💼": ["business", "manager", "man", "human"], + "🧑🔧": ["plumber", "human", "wrench"], + "👩🔧": ["plumber", "woman", "human", "wrench"], + "👨🔧": ["plumber", "man", "human", "wrench"], + "🧑🔬": ["biologist", "chemist", "engineer", "physicist", "human"], + "👩🔬": ["biologist", "chemist", "engineer", "physicist", "woman", "human"], + "👨🔬": ["biologist", "chemist", "engineer", "physicist", "man", "human"], + "🧑🎨": ["painter", "human"], + "👩🎨": ["painter", "woman", "human"], + "👨🎨": ["painter", "man", "human"], + "🧑🚒": ["fireman", "human"], + "👩🚒": ["fireman", "woman", "human"], + "👨🚒": ["fireman", "man", "human"], + "🧑✈️": ["aviator", "plane", "human"], + "👩✈️": ["aviator", "plane", "woman", "human"], + "👨✈️": ["aviator", "plane", "man", "human"], + "🧑🚀": ["space", "rocket", "human"], + "👩🚀": ["space", "rocket", "woman", "human"], + "👨🚀": ["space", "rocket", "man", "human"], + "🧑⚖️": ["justice", "court", "human"], + "👩⚖️": ["justice", "court", "woman", "human"], + "👨⚖️": ["justice", "court", "man", "human"], + "🦸♀️": ["woman", "female", "good", "heroine", "superpowers"], + "🦸♂️": ["man", "male", "good", "hero", "superpowers"], + "🦹♀️": ["woman", "female", "evil", "bad", "criminal", "heroine", "superpowers"], + "🦹♂️": ["man", "male", "evil", "bad", "criminal", "hero", "superpowers"], + "🤶": ["woman", "female", "xmas", "mother christmas"], + "🧑🎄": ["xmas", "christmas"], + "🎅": ["festival", "man", "male", "xmas", "father christmas"], + "🥷": [], + "🧙♀️": ["woman", "female", "mage", "witch"], + "🧙♂️": ["man", "male", "mage", "sorcerer"], + "🧝♀️": ["woman", "female"], + "🧝♂️": ["man", "male"], + "🧛♀️": ["woman", "female"], + "🧛♂️": ["man", "male", "dracula"], + "🧟♀️": ["woman", "female", "undead", "walking dead"], + "🧟♂️": ["man", "male", "dracula", "undead", "walking dead"], + "🧞♀️": ["woman", "female"], + "🧞♂️": ["man", "male"], + "🧜♀️": ["woman", "female", "merwoman", "ariel"], + "🧜♂️": ["man", "male", "triton"], + "🧚♀️": ["woman", "female"], + "🧚♂️": ["man", "male"], + "👼": ["heaven", "wings", "halo"], + "🧌": [], + "🤰": ["baby"], + "🫃": [], + "🫄": [], + "🫅": [], + "🤱": ["nursing", "baby"], + "👩🍼": [], + "👨🍼": [], + "🧑🍼": [], + "👸": ["girl", "woman", "female", "blond", "crown", "royal", "queen"], + "🤴": ["boy", "man", "male", "crown", "royal", "king"], + "👰": ["couple", "marriage", "wedding", "woman", "bride"], + "👰": ["couple", "marriage", "wedding", "woman", "bride"], + "🤵": ["couple", "marriage", "wedding", "groom"], + "🤵": ["couple", "marriage", "wedding", "groom"], + "🏃♀️": ["woman", "walking", "exercise", "race", "running", "female"], + "🏃": ["man", "walking", "exercise", "race", "running"], + "🚶♀️": ["human", "feet", "steps", "woman", "female"], + "🚶": ["human", "feet", "steps"], + "💃": ["female", "girl", "woman", "fun"], + "🕺": ["male", "boy", "fun", "dancer"], + "👯": ["female", "bunny", "women", "girls"], + "👯♂️": ["male", "bunny", "men", "boys"], + "👫": ["pair", "people", "human", "love", "date", "dating", "like", "affection", "valentines", "marriage"], + "🧑🤝🧑": ["pair", "couple", "love", "like", "bromance", "friendship", "people", "human"], + "👬": ["pair", "couple", "love", "like", "bromance", "friendship", "people", "man", "human"], + "👭": ["pair", "couple", "love", "like", "bromance", "friendship", "people", "female", "human"], + "🫂": [], + "🙇♀️": ["woman", "female", "girl"], + "🙇": ["man", "male", "boy"], + "🤦♂️": ["man", "male", "boy", "disbelief"], + "🤦♀️": ["woman", "female", "girl", "disbelief"], + "🤷": ["woman", "female", "girl", "confused", "indifferent", "doubt"], + "🤷♂️": ["man", "male", "boy", "confused", "indifferent", "doubt"], + "💁": ["female", "girl", "woman", "human", "information"], + "💁♂️": ["male", "boy", "man", "human", "information"], + "🙅": ["female", "girl", "woman", "nope"], + "🙅♂️": ["male", "boy", "man", "nope"], + "🙆": ["women", "girl", "female", "pink", "human", "woman"], + "🙆♂️": ["men", "boy", "male", "blue", "human", "man"], + "🙋": ["female", "girl", "woman"], + "🙋♂️": ["male", "boy", "man"], + "🙎": ["female", "girl", "woman"], + "🙎♂️": ["male", "boy", "man"], + "🙍": ["female", "girl", "woman", "sad", "depressed", "discouraged", "unhappy"], + "🙍♂️": ["male", "boy", "man", "sad", "depressed", "discouraged", "unhappy"], + "💇": ["female", "girl", "woman"], + "💇♂️": ["male", "boy", "man"], + "💆": ["female", "girl", "woman", "head"], + "💆♂️": ["male", "boy", "man", "head"], + "🧖♀️": ["female", "woman", "spa", "steamroom", "sauna"], + "🧖♂️": ["male", "man", "spa", "steamroom", "sauna"], + "🧏♀️": ["woman", "female"], + "🧏♂️": ["man", "male"], + "🧍♀️": ["woman", "female"], + "🧍♂️": ["man", "male"], + "🧎♀️": ["woman", "female"], + "🧎♂️": ["man", "male"], + "🧑🦯": ["accessibility", "blind"], + "👩🦯": ["woman", "female", "accessibility", "blind"], + "👨🦯": ["man", "male", "accessibility", "blind"], + "🧑🦼": ["accessibility"], + "👩🦼": ["woman", "female", "accessibility"], + "👨🦼": ["man", "male", "accessibility"], + "🧑🦽": ["accessibility"], + "👩🦽": ["woman", "female", "accessibility"], + "👨🦽": ["man", "male", "accessibility"], + "💑": ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], + "👩❤️👩": ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], + "👨❤️👨": ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], + "💏": ["pair", "valentines", "love", "like", "dating", "marriage"], + "👩❤️💋👩": ["pair", "valentines", "love", "like", "dating", "marriage"], + "👨❤️💋👨": ["pair", "valentines", "love", "like", "dating", "marriage"], + "👪": ["home", "parents", "child", "mom", "dad", "father", "mother", "people", "human"], + "👨👩👧": ["home", "parents", "people", "human", "child"], + "👨👩👧👦": ["home", "parents", "people", "human", "children"], + "👨👩👦👦": ["home", "parents", "people", "human", "children"], + "👨👩👧👧": ["home", "parents", "people", "human", "children"], + "👩👩👦": ["home", "parents", "people", "human", "children"], + "👩👩👧": ["home", "parents", "people", "human", "children"], + "👩👩👧👦": ["home", "parents", "people", "human", "children"], + "👩👩👦👦": ["home", "parents", "people", "human", "children"], + "👩👩👧👧": ["home", "parents", "people", "human", "children"], + "👨👨👦": ["home", "parents", "people", "human", "children"], + "👨👨👧": ["home", "parents", "people", "human", "children"], + "👨👨👧👦": ["home", "parents", "people", "human", "children"], + "👨👨👦👦": ["home", "parents", "people", "human", "children"], + "👨👨👧👧": ["home", "parents", "people", "human", "children"], + "👩👦": ["home", "parent", "people", "human", "child"], + "👩👧": ["home", "parent", "people", "human", "child"], + "👩👧👦": ["home", "parent", "people", "human", "children"], + "👩👦👦": ["home", "parent", "people", "human", "children"], + "👩👧👧": ["home", "parent", "people", "human", "children"], + "👨👦": ["home", "parent", "people", "human", "child"], + "👨👧": ["home", "parent", "people", "human", "child"], + "👨👧👦": ["home", "parent", "people", "human", "children"], + "👨👦👦": ["home", "parent", "people", "human", "children"], + "👨👧👧": ["home", "parent", "people", "human", "children"], + "🧶": ["ball", "crochet", "knit"], + "🧵": ["needle", "sewing", "spool", "string"], + "🧥": ["jacket"], + "🥼": ["doctor", "experiment", "scientist", "chemist"], + "👚": ["fashion", "shopping_bags", "female"], + "👕": ["fashion", "cloth", "casual", "shirt", "tee"], + "👖": ["fashion", "shopping"], + "👔": ["shirt", "suitup", "formal", "fashion", "cloth", "business"], + "👗": ["clothes", "fashion", "shopping"], + "👙": ["swimming", "female", "woman", "girl", "fashion", "beach", "summer"], + "🩱": ["swimming", "female", "woman", "girl", "fashion", "beach", "summer"], + "👘": ["dress", "fashion", "women", "female", "japanese"], + "🥻": ["dress", "fashion", "women", "female"], + "🩲": ["dress", "fashion"], + "🩳": ["dress", "fashion"], + "💄": ["female", "girl", "fashion", "woman"], + "💋": ["face", "lips", "love", "like", "affection", "valentines"], + "👣": ["feet", "tracking", "walking", "beach"], + "🥿": ["ballet", "slip-on", "slipper"], + "👠": ["fashion", "shoes", "female", "pumps", "stiletto"], + "👡": ["shoes", "fashion", "flip flops"], + "👢": ["shoes", "fashion"], + "👞": ["fashion", "male"], + "👟": ["shoes", "sports", "sneakers"], + "🩴": [], + "🩰": ["shoes", "sports"], + "🧦": ["stockings", "clothes"], + "🧤": ["hands", "winter", "clothes"], + "🧣": ["neck", "winter", "clothes"], + "👒": ["fashion", "accessories", "female", "lady", "spring"], + "🎩": ["magic", "gentleman", "classy", "circus"], + "🧢": ["cap", "baseball"], + "⛑": ["construction", "build"], + "🪖": [], + "🎓": ["school", "college", "degree", "university", "graduation", "cap", "hat", "legal", "learn", "education"], + "👑": ["king", "kod", "leader", "royalty", "lord"], + "🎒": ["student", "education", "bag", "backpack"], + "🧳": ["packing", "travel"], + "👝": ["bag", "accessories", "shopping"], + "👛": ["fashion", "accessories", "money", "sales", "shopping"], + "👜": ["fashion", "accessory", "accessories", "shopping"], + "💼": ["business", "documents", "work", "law", "legal", "job", "career"], + "👓": ["fashion", "accessories", "eyesight", "nerdy", "dork", "geek"], + "🕶": ["face", "cool", "accessories"], + "🥽": ["eyes", "protection", "safety"], + "💍": ["wedding", "propose", "marriage", "valentines", "diamond", "fashion", "jewelry", "gem", "engagement"], + "🌂": ["weather", "rain", "drizzle"], + "🐶": ["animal", "friend", "nature", "woof", "puppy", "pet", "faithful"], + "🐱": ["animal", "meow", "nature", "pet", "kitten"], + "🐈⬛": ["animal", "meow", "nature", "pet", "kitten"], + "🐭": ["animal", "nature", "cheese_wedge", "rodent"], + "🐹": ["animal", "nature"], + "🐰": ["animal", "nature", "pet", "spring", "magic", "bunny"], + "🦊": ["animal", "nature", "face"], + "🐻": ["animal", "nature", "wild"], + "🐼": ["animal", "nature", "panda"], + "🐨": ["animal", "nature"], + "🐯": ["animal", "cat", "danger", "wild", "nature", "roar"], + "🦁": ["animal", "nature"], + "🐮": ["beef", "ox", "animal", "nature", "moo", "milk"], + "🐷": ["animal", "oink", "nature"], + "🐽": ["animal", "oink"], + "🐸": ["animal", "nature", "croak", "toad"], + "🦑": ["animal", "nature", "ocean", "sea"], + "🐙": ["animal", "creature", "ocean", "sea", "nature", "beach"], + "🦐": ["animal", "ocean", "nature", "seafood"], + "🐵": ["animal", "nature", "circus"], + "🦍": ["animal", "nature", "circus"], + "🙈": ["monkey", "animal", "nature", "haha"], + "🙉": ["animal", "monkey", "nature"], + "🙊": ["monkey", "animal", "nature", "omg"], + "🐒": ["animal", "nature", "banana", "circus"], + "🐔": ["animal", "cluck", "nature", "bird"], + "🐧": ["animal", "nature"], + "🐦": ["animal", "nature", "fly", "tweet", "spring"], + "🐤": ["animal", "chicken", "bird"], + "🐣": ["animal", "chicken", "egg", "born", "baby", "bird"], + "🐥": ["animal", "chicken", "baby", "bird"], + "🦆": ["animal", "nature", "bird", "mallard"], + "🦅": ["animal", "nature", "bird"], + "🦉": ["animal", "nature", "bird", "hoot"], + "🦇": ["animal", "nature", "blind", "vampire"], + "🐺": ["animal", "nature", "wild"], + "🐗": ["animal", "nature"], + "🐴": ["animal", "brown", "nature"], + "🦄": ["animal", "nature", "mystical"], + "🐝": ["animal", "insect", "nature", "bug", "spring", "honey"], + "🐛": ["animal", "insect", "nature", "worm"], + "🦋": ["animal", "insect", "nature", "caterpillar"], + "🐌": ["slow", "animal", "shell"], + "🐞": ["animal", "insect", "nature", "ladybug"], + "🐜": ["animal", "insect", "nature", "bug"], + "🦗": ["animal", "cricket", "chirp"], + "🕷": ["animal", "arachnid"], + "🪲": ["animal"], + "🪳": ["animal"], + "🪰": ["animal"], + "🪱": ["animal"], + "🦂": ["animal", "arachnid"], + "🦀": ["animal", "crustacean"], + "🐍": ["animal", "evil", "nature", "hiss", "python"], + "🦎": ["animal", "nature", "reptile"], + "🦖": ["animal", "nature", "dinosaur", "tyrannosaurus", "extinct"], + "🦕": ["animal", "nature", "dinosaur", "brachiosaurus", "brontosaurus", "diplodocus", "extinct"], + "🐢": ["animal", "slow", "nature", "tortoise"], + "🐠": ["animal", "swim", "ocean", "beach", "nemo"], + "🐟": ["animal", "food", "nature"], + "🐡": ["animal", "nature", "food", "sea", "ocean"], + "🐬": ["animal", "nature", "fish", "sea", "ocean", "flipper", "fins", "beach"], + "🦈": ["animal", "nature", "fish", "sea", "ocean", "jaws", "fins", "beach"], + "🐳": ["animal", "nature", "sea", "ocean"], + "🐋": ["animal", "nature", "sea", "ocean"], + "🐊": ["animal", "nature", "reptile", "lizard", "alligator"], + "🐆": ["animal", "nature"], + "🦓": ["animal", "nature", "stripes", "safari"], + "🐅": ["animal", "nature", "roar"], + "🐃": ["animal", "nature", "ox", "cow"], + "🐂": ["animal", "cow", "beef"], + "🐄": ["beef", "ox", "animal", "nature", "moo", "milk"], + "🦌": ["animal", "nature", "horns", "venison"], + "🐪": ["animal", "hot", "desert", "hump"], + "🐫": ["animal", "nature", "hot", "desert", "hump"], + "🦒": ["animal", "nature", "spots", "safari"], + "🐘": ["animal", "nature", "nose", "th", "circus"], + "🦏": ["animal", "nature", "horn"], + "🐐": ["animal", "nature"], + "🐏": ["animal", "sheep", "nature"], + "🐑": ["animal", "nature", "wool", "shipit"], + "🐎": ["animal", "gamble", "luck"], + "🐖": ["animal", "nature"], + "🐀": ["animal", "mouse", "rodent"], + "🐁": ["animal", "nature", "rodent"], + "🐓": ["animal", "nature", "chicken"], + "🦃": ["animal", "bird"], + "🕊": ["animal", "bird"], + "🐕": ["animal", "nature", "friend", "doge", "pet", "faithful"], + "🐩": ["dog", "animal", "101", "nature", "pet"], + "🐈": ["animal", "meow", "pet", "cats"], + "🐇": ["animal", "nature", "pet", "magic", "spring"], + "🐿": ["animal", "nature", "rodent", "squirrel"], + "🦔": ["animal", "nature", "spiny"], + "🦝": ["animal", "nature"], + "🦙": ["animal", "nature", "alpaca"], + "🦛": ["animal", "nature"], + "🦘": ["animal", "nature", "australia", "joey", "hop", "marsupial"], + "🦡": ["animal", "nature", "honey"], + "🦢": ["animal", "nature", "bird"], + "🦚": ["animal", "nature", "peahen", "bird"], + "🦜": ["animal", "nature", "bird", "pirate", "talk"], + "🦞": ["animal", "nature", "bisque", "claws", "seafood"], + "🦠": ["amoeba", "bacteria", "germs"], + "🦟": ["animal", "nature", "insect", "malaria"], + "🦬": ["animal", "nature"], + "🦣": ["animal", "nature"], + "🦫": ["animal", "nature"], + "🐻❄️": ["animal", "nature"], + "🦤": ["animal", "nature"], + "🪶": ["animal", "nature"], + "🦭": ["animal", "nature"], + "🐾": ["animal", "tracking", "footprints", "dog", "cat", "pet", "feet"], + "🐉": ["animal", "myth", "nature", "chinese", "green"], + "🐲": ["animal", "myth", "nature", "chinese", "green"], + "🦧": ["animal", "nature"], + "🦮": ["animal", "nature"], + "🐕🦺": ["animal", "nature"], + "🦥": ["animal", "nature"], + "🦦": ["animal", "nature"], + "🦨": ["animal", "nature"], + "🦩": ["animal", "nature"], + "🌵": ["vegetable", "plant", "nature"], + "🎄": ["festival", "vacation", "december", "xmas", "celebration"], + "🌲": ["plant", "nature"], + "🌳": ["plant", "nature"], + "🌴": ["plant", "vegetable", "nature", "summer", "beach", "mojito", "tropical"], + "🌱": ["plant", "nature", "grass", "lawn", "spring"], + "🌿": ["vegetable", "plant", "medicine", "weed", "grass", "lawn"], + "☘": ["vegetable", "plant", "nature", "irish", "clover"], + "🍀": ["vegetable", "plant", "nature", "lucky", "irish"], + "🎍": ["plant", "nature", "vegetable", "panda", "pine_decoration"], + "🎋": ["plant", "nature", "branch", "summer"], + "🍃": ["nature", "plant", "tree", "vegetable", "grass", "lawn", "spring"], + "🍂": ["nature", "plant", "vegetable", "leaves"], + "🍁": ["nature", "plant", "vegetable", "ca", "fall"], + "🌾": ["nature", "plant"], + "🌺": ["plant", "vegetable", "flowers", "beach"], + "🌻": ["nature", "plant", "fall"], + "🌹": ["flowers", "valentines", "love", "spring"], + "🥀": ["plant", "nature", "flower"], + "🌷": ["flowers", "plant", "nature", "summer", "spring"], + "🌼": ["nature", "flowers", "yellow"], + "🌸": ["nature", "plant", "spring", "flower"], + "💐": ["flowers", "nature", "spring"], + "🍄": ["plant", "vegetable"], + "🪴": ["plant"], + "🌰": ["food", "squirrel"], + "🎃": ["halloween", "light", "pumpkin", "creepy", "fall"], + "🐚": ["nature", "sea", "beach"], + "🕸": ["animal", "insect", "arachnid", "silk"], + "🌎": ["globe", "world", "USA", "international"], + "🌍": ["globe", "world", "international"], + "🌏": ["globe", "world", "east", "international"], + "🪐": ["saturn"], + "🌕": ["nature", "yellow", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌖": ["nature", "twilight", "planet", "space", "night", "evening", "sleep", "waxing_gibbous_moon"], + "🌗": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌘": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌑": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌒": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌓": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌔": ["nature", "night", "sky", "gray", "twilight", "planet", "space", "evening", "sleep"], + "🌚": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌝": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌛": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌜": ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], + "🌞": ["nature", "morning", "sky"], + "🌙": ["night", "sleep", "sky", "evening", "magic"], + "⭐": ["night", "yellow"], + "🌟": ["night", "sparkle", "awesome", "good", "magic"], + "💫": ["star", "sparkle", "shoot", "magic"], + "✨": ["stars", "shine", "shiny", "cool", "awesome", "good", "magic"], + "☄": ["space"], + "☀️": ["weather", "nature", "brightness", "summer", "beach", "spring"], + "🌤": ["weather"], + "⛅": ["weather", "nature", "cloudy", "morning", "fall", "spring"], + "🌥": ["weather"], + "🌦": ["weather"], + "☁️": ["weather", "sky"], + "🌧": ["weather"], + "⛈": ["weather", "lightning"], + "🌩": ["weather", "thunder"], + "⚡": ["thunder", "weather", "lightning bolt", "fast"], + "🔥": ["hot", "cook", "flame"], + "💥": ["bomb", "explode", "explosion", "collision", "blown"], + "❄️": ["winter", "season", "cold", "weather", "christmas", "xmas"], + "🌨": ["weather"], + "⛄": ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen", "without_snow"], + "☃": ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen"], + "🌬": ["gust", "air"], + "💨": ["wind", "air", "fast", "shoo", "fart", "smoke", "puff"], + "🌪": ["weather", "cyclone", "twister"], + "🌫": ["weather"], + "☂": ["weather", "spring"], + "☔": ["rainy", "weather", "spring"], + "💧": ["water", "drip", "faucet", "spring"], + "💦": ["water", "drip", "oops"], + "🌊": ["sea", "water", "wave", "nature", "tsunami", "disaster"], + "🪷": [], + "🪸": [], + "🪹": [], + "🪺": [], + "🍏": ["fruit", "nature"], + "🍎": ["fruit", "mac", "school"], + "🍐": ["fruit", "nature", "food"], + "🍊": ["food", "fruit", "nature", "orange"], + "🍋": ["fruit", "nature"], + "🍌": ["fruit", "food", "monkey"], + "🍉": ["fruit", "food", "picnic", "summer"], + "🍇": ["fruit", "food", "wine"], + "🍓": ["fruit", "food", "nature"], + "🍈": ["fruit", "nature", "food"], + "🍒": ["food", "fruit"], + "🍑": ["fruit", "nature", "food"], + "🍍": ["fruit", "nature", "food"], + "🥥": ["fruit", "nature", "food", "palm"], + "🥝": ["fruit", "food"], + "🥭": ["fruit", "food", "tropical"], + "🥑": ["fruit", "food"], + "🥦": ["fruit", "food", "vegetable"], + "🍅": ["fruit", "vegetable", "nature", "food"], + "🍆": ["vegetable", "nature", "food", "aubergine"], + "🥒": ["fruit", "food", "pickle"], + "🫐": ["fruit", "food"], + "🫒": ["fruit", "food"], + "🫑": ["fruit", "food"], + "🥕": ["vegetable", "food", "orange"], + "🌶": ["food", "spicy", "chilli", "chili"], + "🥔": ["food", "tuber", "vegatable", "starch"], + "🌽": ["food", "vegetable", "plant"], + "🥬": ["food", "vegetable", "plant", "bok choy", "cabbage", "kale", "lettuce"], + "🍠": ["food", "nature"], + "🥜": ["food", "nut"], + "🧄": ["food"], + "🧅": ["food"], + "🍯": ["bees", "sweet", "kitchen"], + "🥐": ["food", "bread", "french"], + "🍞": ["food", "wheat", "breakfast", "toast"], + "🥖": ["food", "bread", "french"], + "🥯": ["food", "bread", "bakery", "schmear"], + "🥨": ["food", "bread", "twisted"], + "🧀": ["food", "chadder"], + "🥚": ["food", "chicken", "breakfast"], + "🥓": ["food", "breakfast", "pork", "pig", "meat"], + "🥩": ["food", "cow", "meat", "cut", "chop", "lambchop", "porkchop"], + "🥞": ["food", "breakfast", "flapjacks", "hotcakes"], + "🍗": ["food", "meat", "drumstick", "bird", "chicken", "turkey"], + "🍖": ["good", "food", "drumstick"], + "🦴": ["skeleton"], + "🍤": ["food", "animal", "appetizer", "summer"], + "🍳": ["food", "breakfast", "kitchen", "egg"], + "🍔": ["meat", "fast food", "beef", "cheeseburger", "mcdonalds", "burger king"], + "🍟": ["chips", "snack", "fast food"], + "🥙": ["food", "flatbread", "stuffed", "gyro"], + "🌭": ["food", "frankfurter"], + "🍕": ["food", "party"], + "🥪": ["food", "lunch", "bread"], + "🥫": ["food", "soup"], + "🍝": ["food", "italian", "noodle"], + "🌮": ["food", "mexican"], + "🌯": ["food", "mexican"], + "🥗": ["food", "healthy", "lettuce"], + "🥘": ["food", "cooking", "casserole", "paella"], + "🍜": ["food", "japanese", "noodle", "chopsticks"], + "🍲": ["food", "meat", "soup"], + "🍥": ["food", "japan", "sea", "beach", "narutomaki", "pink", "swirl", "kamaboko", "surimi", "ramen"], + "🥠": ["food", "prophecy"], + "🍣": ["food", "fish", "japanese", "rice"], + "🍱": ["food", "japanese", "box"], + "🍛": ["food", "spicy", "hot", "indian"], + "🍙": ["food", "japanese"], + "🍚": ["food", "china", "asian"], + "🍘": ["food", "japanese"], + "🍢": ["food", "japanese"], + "🍡": ["food", "dessert", "sweet", "japanese", "barbecue", "meat"], + "🍧": ["hot", "dessert", "summer"], + "🍨": ["food", "hot", "dessert"], + "🍦": ["food", "hot", "dessert", "summer"], + "🥧": ["food", "dessert", "pastry"], + "🍰": ["food", "dessert"], + "🧁": ["food", "dessert", "bakery", "sweet"], + "🥮": ["food", "autumn"], + "🎂": ["food", "dessert", "cake"], + "🍮": ["dessert", "food"], + "🍬": ["snack", "dessert", "sweet", "lolly"], + "🍭": ["food", "snack", "candy", "sweet"], + "🍫": ["food", "snack", "dessert", "sweet"], + "🍿": ["food", "movie theater", "films", "snack"], + "🥟": ["food", "empanada", "pierogi", "potsticker"], + "🍩": ["food", "dessert", "snack", "sweet", "donut"], + "🍪": ["food", "snack", "oreo", "chocolate", "sweet", "dessert"], + "🧇": ["food"], + "🧆": ["food"], + "🧈": ["food"], + "🦪": ["food"], + "🫓": ["food"], + "🫔": ["food"], + "🫕": ["food"], + "🥛": ["beverage", "drink", "cow"], + "🍺": ["relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"], + "🍻": ["relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"], + "🥂": ["beverage", "drink", "party", "alcohol", "celebrate", "cheers", "wine", "champagne", "toast"], + "🍷": ["drink", "beverage", "drunk", "alcohol", "booze"], + "🥃": ["drink", "beverage", "drunk", "alcohol", "liquor", "booze", "bourbon", "scotch", "whisky", "glass", "shot"], + "🍸": ["drink", "drunk", "alcohol", "beverage", "booze", "mojito"], + "🍹": ["beverage", "cocktail", "summer", "beach", "alcohol", "booze", "mojito"], + "🍾": ["drink", "wine", "bottle", "celebration"], + "🍶": ["wine", "drink", "drunk", "beverage", "japanese", "alcohol", "booze"], + "🍵": ["drink", "bowl", "breakfast", "green", "british"], + "🥤": ["drink", "soda"], + "☕": ["beverage", "caffeine", "latte", "espresso"], + "🫖": [], + "🧋": ["tapioca"], + "🍼": ["food", "container", "milk"], + "🧃": ["food", "drink"], + "🧉": ["food", "drink"], + "🧊": ["food"], + "🧂": ["condiment", "shaker"], + "🥄": ["cutlery", "kitchen", "tableware"], + "🍴": ["cutlery", "kitchen"], + "🍽": ["food", "eat", "meal", "lunch", "dinner", "restaurant"], + "🥣": ["food", "breakfast", "cereal", "oatmeal", "porridge"], + "🥡": ["food", "leftovers"], + "🥢": ["food"], + "🫗": [], + "🫘": [], + "🫙": [], + "⚽": ["sports", "football"], + "🏀": ["sports", "balls", "NBA"], + "🏈": ["sports", "balls", "NFL"], + "⚾": ["sports", "balls"], + "🥎": ["sports", "balls"], + "🎾": ["sports", "balls", "green"], + "🏐": ["sports", "balls"], + "🏉": ["sports", "team"], + "🥏": ["sports", "frisbee", "ultimate"], + "🎱": ["pool", "hobby", "game", "luck", "magic"], + "⛳": ["sports", "business", "flag", "hole", "summer"], + "🏌️♀️": ["sports", "business", "woman", "female"], + "🏌": ["sports", "business"], + "🏓": ["sports", "pingpong"], + "🏸": ["sports"], + "🥅": ["sports"], + "🏒": ["sports"], + "🏑": ["sports"], + "🥍": ["sports", "ball", "stick"], + "🏏": ["sports"], + "🎿": ["sports", "winter", "cold", "snow"], + "⛷": ["sports", "winter", "snow"], + "🏂": ["sports", "winter"], + "🤺": ["sports", "fencing", "sword"], + "🤼♀️": ["sports", "wrestlers"], + "🤼♂️": ["sports", "wrestlers"], + "🤸♀️": ["gymnastics"], + "🤸♂️": ["gymnastics"], + "🤾♀️": ["sports"], + "🤾♂️": ["sports"], + "⛸": ["sports"], + "🥌": ["sports"], + "🛹": ["board"], + "🛷": ["sleigh", "luge", "toboggan"], + "🏹": ["sports"], + "🎣": ["food", "hobby", "summer"], + "🥊": ["sports", "fighting"], + "🥋": ["judo", "karate", "taekwondo"], + "🚣♀️": ["sports", "hobby", "water", "ship", "woman", "female"], + "🚣": ["sports", "hobby", "water", "ship"], + "🧗♀️": ["sports", "hobby", "woman", "female", "rock"], + "🧗♂️": ["sports", "hobby", "man", "male", "rock"], + "🏊♀️": ["sports", "exercise", "human", "athlete", "water", "summer", "woman", "female"], + "🏊": ["sports", "exercise", "human", "athlete", "water", "summer"], + "🤽♀️": ["sports", "pool"], + "🤽♂️": ["sports", "pool"], + "🧘♀️": ["woman", "female", "meditation", "yoga", "serenity", "zen", "mindfulness"], + "🧘♂️": ["man", "male", "meditation", "yoga", "serenity", "zen", "mindfulness"], + "🏄♀️": ["sports", "ocean", "sea", "summer", "beach", "woman", "female"], + "🏄": ["sports", "ocean", "sea", "summer", "beach"], + "🛀": ["clean", "shower", "bathroom"], + "⛹️♀️": ["sports", "human", "woman", "female"], + "⛹": ["sports", "human"], + "🏋️♀️": ["sports", "training", "exercise", "woman", "female"], + "🏋": ["sports", "training", "exercise"], + "🚴♀️": ["sports", "bike", "exercise", "hipster", "woman", "female"], + "🚴": ["sports", "bike", "exercise", "hipster"], + "🚵♀️": ["transportation", "sports", "human", "race", "bike", "woman", "female"], + "🚵": ["transportation", "sports", "human", "race", "bike"], + "🏇": ["animal", "betting", "competition", "gambling", "luck"], + "🤿": ["sports"], + "🪀": ["sports"], + "🪁": ["sports"], + "🦺": ["sports"], + "🪡": [], + "🪢": [], + "🕴": ["suit", "business", "levitate", "hover", "jump"], + "🏆": ["win", "award", "contest", "place", "ftw", "ceremony"], + "🎽": ["play", "pageant"], + "🏅": ["award", "winning"], + "🎖": ["award", "winning", "army"], + "🥇": ["award", "winning", "first"], + "🥈": ["award", "second"], + "🥉": ["award", "third"], + "🎗": ["sports", "cause", "support", "awareness"], + "🏵": ["flower", "decoration", "military"], + "🎫": ["event", "concert", "pass"], + "🎟": ["sports", "concert", "entrance"], + "🎭": ["acting", "theater", "drama"], + "🎨": ["design", "paint", "draw", "colors"], + "🎪": ["festival", "carnival", "party"], + "🤹♀️": ["juggle", "balance", "skill", "multitask"], + "🤹♂️": ["juggle", "balance", "skill", "multitask"], + "🎤": ["sound", "music", "PA", "sing", "talkshow"], + "🎧": ["music", "score", "gadgets"], + "🎼": ["treble", "clef", "compose"], + "🎹": ["piano", "instrument", "compose"], + "🥁": ["music", "instrument", "drumsticks", "snare"], + "🎷": ["music", "instrument", "jazz", "blues"], + "🎺": ["music", "brass"], + "🎸": ["music", "instrument"], + "🎻": ["music", "instrument", "orchestra", "symphony"], + "🪕": ["music", "instrument"], + "🪗": ["music", "instrument"], + "🪘": ["music", "instrument"], + "🎬": ["movie", "film", "record"], + "🎮": ["play", "console", "PS4", "controller"], + "👾": ["game", "arcade", "play"], + "🎯": ["game", "play", "bar", "target", "bullseye"], + "🎲": ["dice", "random", "tabletop", "play", "luck"], + "♟️": ["expendable"], + "🎰": ["bet", "gamble", "vegas", "fruit machine", "luck", "casino"], + "🧩": ["interlocking", "puzzle", "piece"], + "🎳": ["sports", "fun", "play"], + "🪄": [], + "🪅": [], + "🪆": [], + "🪬": [], + "🪩": [], + "🚗": ["red", "transportation", "vehicle"], + "🚕": ["uber", "vehicle", "cars", "transportation"], + "🚙": ["transportation", "vehicle"], + "🚌": ["car", "vehicle", "transportation"], + "🚎": ["bart", "transportation", "vehicle"], + "🏎": ["sports", "race", "fast", "formula", "f1"], + "🚓": ["vehicle", "cars", "transportation", "law", "legal", "enforcement"], + "🚑": ["health", "911", "hospital"], + "🚒": ["transportation", "cars", "vehicle"], + "🚐": ["vehicle", "car", "transportation"], + "🚚": ["cars", "transportation"], + "🚛": ["vehicle", "cars", "transportation", "express"], + "🚜": ["vehicle", "car", "farming", "agriculture"], + "🛴": ["vehicle", "kick", "razor"], + "🏍": ["race", "sports", "fast"], + "🚲": ["sports", "bicycle", "exercise", "hipster"], + "🛵": ["vehicle", "vespa", "sasha"], + "🦽": ["vehicle"], + "🦼": ["vehicle"], + "🛺": ["vehicle"], + "🪂": ["vehicle"], + "🚨": ["police", "ambulance", "911", "emergency", "alert", "error", "pinged", "law", "legal"], + "🚔": ["vehicle", "law", "legal", "enforcement", "911"], + "🚍": ["vehicle", "transportation"], + "🚘": ["car", "vehicle", "transportation"], + "🚖": ["vehicle", "cars", "uber"], + "🚡": ["transportation", "vehicle", "ski"], + "🚠": ["transportation", "vehicle", "ski"], + "🚟": ["vehicle", "transportation"], + "🚃": ["transportation", "vehicle", "train"], + "🚋": ["transportation", "vehicle", "carriage", "public", "travel"], + "🚝": ["transportation", "vehicle"], + "🚄": ["transportation", "vehicle"], + "🚅": ["transportation", "vehicle", "speed", "fast", "public", "travel"], + "🚈": ["transportation", "vehicle"], + "🚞": ["transportation", "vehicle"], + "🚂": ["transportation", "vehicle", "train"], + "🚆": ["transportation", "vehicle"], + "🚇": ["transportation", "blue-square", "mrt", "underground", "tube"], + "🚊": ["transportation", "vehicle"], + "🚉": ["transportation", "vehicle", "public"], + "🛸": ["transportation", "vehicle", "ufo"], + "🚁": ["transportation", "vehicle", "fly"], + "🛩": ["flight", "transportation", "fly", "vehicle"], + "✈️": ["vehicle", "transportation", "flight", "fly"], + "🛫": ["airport", "flight", "landing"], + "🛬": ["airport", "flight", "boarding"], + "⛵": ["ship", "summer", "transportation", "water", "sailing"], + "🛥": ["ship"], + "🚤": ["ship", "transportation", "vehicle", "summer"], + "⛴": ["boat", "ship", "yacht"], + "🛳": ["yacht", "cruise", "ferry"], + "🚀": ["launch", "ship", "staffmode", "NASA", "outer space", "outer_space", "fly"], + "🛰": ["communication", "gps", "orbit", "spaceflight", "NASA", "ISS"], + "🛻": ["car"], + "🛼": [], + "💺": ["sit", "airplane", "transport", "bus", "flight", "fly"], + "🛶": ["boat", "paddle", "water", "ship"], + "⚓": ["ship", "ferry", "sea", "boat"], + "🚧": ["wip", "progress", "caution", "warning"], + "⛽": ["gas station", "petroleum"], + "🚏": ["transportation", "wait"], + "🚦": ["transportation", "driving"], + "🚥": ["transportation", "signal"], + "🏁": ["contest", "finishline", "race", "gokart"], + "🚢": ["transportation", "titanic", "deploy"], + "🎡": ["photo", "carnival", "londoneye"], + "🎢": ["carnival", "playground", "photo", "fun"], + "🎠": ["photo", "carnival"], + "🏗": ["wip", "working", "progress"], + "🌁": ["photo", "mountain"], + "🏭": ["building", "industry", "pollution", "smoke"], + "⛲": ["photo", "summer", "water", "fresh"], + "🎑": ["photo", "japan", "asia", "tsukimi"], + "⛰": ["photo", "nature", "environment"], + "🏔": ["photo", "nature", "environment", "winter", "cold"], + "🗻": ["photo", "mountain", "nature", "japanese"], + "🌋": ["photo", "nature", "disaster"], + "🗾": ["nation", "country", "japanese", "asia"], + "🏕": ["photo", "outdoors", "tent"], + "⛺": ["photo", "camping", "outdoors"], + "🏞": ["photo", "environment", "nature"], + "🛣": ["road", "cupertino", "interstate", "highway"], + "🛤": ["train", "transportation"], + "🌅": ["morning", "view", "vacation", "photo"], + "🌄": ["view", "vacation", "photo"], + "🏜": ["photo", "warm", "saharah"], + "🏖": ["weather", "summer", "sunny", "sand", "mojito"], + "🏝": ["photo", "tropical", "mojito"], + "🌇": ["photo", "good morning", "dawn"], + "🌆": ["photo", "evening", "sky", "buildings"], + "🏙": ["photo", "night life", "urban"], + "🌃": ["evening", "city", "downtown"], + "🌉": ["photo", "sanfrancisco"], + "🌌": ["photo", "space", "stars"], + "🌠": ["night", "photo"], + "🎇": ["stars", "night", "shine"], + "🎆": ["photo", "festival", "carnival", "congratulations"], + "🌈": ["nature", "happy", "unicorn_face", "photo", "sky", "spring"], + "🏘": ["buildings", "photo"], + "🏰": ["building", "royalty", "history"], + "🏯": ["photo", "building"], + "🗼": ["photo", "japanese"], + "": ["photo", "japanese"], + "🏟": ["photo", "place", "sports", "concert", "venue"], + "🗽": ["american", "newyork"], + "🏠": ["building", "home"], + "🏡": ["home", "plant", "nature"], + "🏚": ["abandon", "evict", "broken", "building"], + "🏢": ["building", "bureau", "work"], + "🏬": ["building", "shopping", "mall"], + "🏣": ["building", "envelope", "communication"], + "🏤": ["building", "email"], + "🏥": ["building", "health", "surgery", "doctor"], + "🏦": ["building", "money", "sales", "cash", "business", "enterprise"], + "🏨": ["building", "accomodation", "checkin"], + "🏪": ["building", "shopping", "groceries"], + "🏫": ["building", "student", "education", "learn", "teach"], + "🏩": ["like", "affection", "dating"], + "💒": ["love", "like", "affection", "couple", "marriage", "bride", "groom"], + "🏛": ["art", "culture", "history"], + "⛪": ["building", "religion", "christ"], + "🕌": ["islam", "worship", "minaret"], + "🕍": ["judaism", "worship", "temple", "jewish"], + "🕋": ["mecca", "mosque", "islam"], + "⛩": ["temple", "japan", "kyoto"], + "🛕": ["temple"], + "🪨": [], + "🪵": [], + "🛖": [], + "🛝": [], + "🛞": [], + "🛟": [], + "⌚": ["time", "accessories"], + "📱": ["technology", "apple", "gadgets", "dial"], + "📲": ["iphone", "incoming"], + "💻": ["technology", "laptop", "screen", "display", "monitor"], + "⌨": ["technology", "computer", "type", "input", "text"], + "🖥": ["technology", "computing", "screen"], + "🖨": ["paper", "ink"], + "🖱": ["click"], + "🖲": ["technology", "trackpad"], + "🕹": ["game", "play"], + "🗜": ["tool"], + "💽": ["technology", "record", "data", "disk", "90s"], + "💾": ["oldschool", "technology", "save", "90s", "80s"], + "💿": ["technology", "dvd", "disk", "disc", "90s"], + "📀": ["cd", "disk", "disc"], + "📼": ["record", "video", "oldschool", "90s", "80s"], + "📷": ["gadgets", "photography"], + "📸": ["photography", "gadgets"], + "📹": ["film", "record"], + "🎥": ["film", "record"], + "📽": ["video", "tape", "record", "movie"], + "🎞": ["movie"], + "📞": ["technology", "communication", "dial"], + "☎️": ["technology", "communication", "dial", "telephone"], + "📟": ["bbcall", "oldschool", "90s"], + "📠": ["communication", "technology"], + "📺": ["technology", "program", "oldschool", "show", "television"], + "📻": ["communication", "music", "podcast", "program"], + "🎙": ["sing", "recording", "artist", "talkshow"], + "🎚": ["scale"], + "🎛": ["dial"], + "🧭": ["magnetic", "navigation", "orienteering"], + "⏱": ["time", "deadline"], + "⏲": ["alarm"], + "⏰": ["time", "wake"], + "🕰": ["time"], + "⏳": ["oldschool", "time", "countdown"], + "⌛": ["time", "clock", "oldschool", "limit", "exam", "quiz", "test"], + "📡": ["communication", "future", "radio", "space"], + "🔋": ["power", "energy", "sustain"], + "🪫": [], + "🔌": ["charger", "power"], + "💡": ["light", "electricity", "idea"], + "🔦": ["dark", "camping", "sight", "night"], + "🕯": ["fire", "wax"], + "🧯": ["quench"], + "🗑": ["bin", "trash", "rubbish", "garbage", "toss"], + "🛢": ["barrell"], + "💸": ["dollar", "bills", "payment", "sale"], + "💵": ["money", "sales", "bill", "currency"], + "💴": ["money", "sales", "japanese", "dollar", "currency"], + "💶": ["money", "sales", "dollar", "currency"], + "💷": ["british", "sterling", "money", "sales", "bills", "uk", "england", "currency"], + "💰": ["dollar", "payment", "coins", "sale"], + "🪙": ["dollar", "payment", "coins", "sale"], + "💳": ["money", "sales", "dollar", "bill", "payment", "shopping"], + "🪫": [], + "💎": ["blue", "ruby", "diamond", "jewelry"], + "⚖": ["law", "fairness", "weight"], + "🧰": ["tools", "diy", "fix", "maintainer", "mechanic"], + "🔧": ["tools", "diy", "ikea", "fix", "maintainer"], + "🔨": ["tools", "build", "create"], + "⚒": ["tools", "build", "create"], + "🛠": ["tools", "build", "create"], + "⛏": ["tools", "dig"], + "🪓": ["tools"], + "🦯": ["tools"], + "🔩": ["handy", "tools", "fix"], + "⚙": ["cog"], + "🪃": ["tool"], + "🪚": ["tool"], + "🪛": ["tool"], + "🪝": ["tool"], + "🪜": ["tool"], + "🧱": ["bricks"], + "⛓": ["lock", "arrest"], + "🧲": ["attraction", "magnetic"], + "🔫": ["violence", "weapon", "pistol", "revolver"], + "💣": ["boom", "explode", "explosion", "terrorism"], + "🧨": ["dynamite", "boom", "explode", "explosion", "explosive"], + "🔪": ["knife", "blade", "cutlery", "kitchen", "weapon"], + "🗡": ["weapon"], + "⚔": ["weapon"], + "🛡": ["protection", "security"], + "🚬": ["kills", "tobacco", "cigarette", "joint", "smoke"], + "☠": ["poison", "danger", "deadly", "scary", "death", "pirate", "evil"], + "⚰": ["vampire", "dead", "die", "death", "rip", "graveyard", "cemetery", "casket", "funeral", "box"], + "⚱": ["dead", "die", "death", "rip", "ashes"], + "🏺": ["vase", "jar"], + "🔮": ["disco", "party", "magic", "circus", "fortune_teller"], + "📿": ["dhikr", "religious"], + "🧿": ["bead", "charm"], + "💈": ["hair", "salon", "style"], + "⚗": ["distilling", "science", "experiment", "chemistry"], + "🔭": ["stars", "space", "zoom", "science", "astronomy"], + "🔬": ["laboratory", "experiment", "zoomin", "science", "study"], + "🕳": ["embarrassing"], + "💊": ["health", "medicine", "doctor", "pharmacy", "drug"], + "💉": ["health", "hospital", "drugs", "blood", "medicine", "needle", "doctor", "nurse"], + "🩸": ["health", "hospital", "medicine", "needle", "doctor", "nurse"], + "🩹": ["health", "hospital", "medicine", "needle", "doctor", "nurse"], + "🩺": ["health", "hospital", "medicine", "needle", "doctor", "nurse"], + "🪒": ["health"], + "🩻": [], + "🩼": [], + "🧬": ["biologist", "genetics", "life"], + "🧫": ["bacteria", "biology", "culture", "lab"], + "🧪": ["chemistry", "experiment", "lab", "science"], + "🌡": ["weather", "temperature", "hot", "cold"], + "🧹": ["cleaning", "sweeping", "witch"], + "🧺": ["laundry"], + "🧻": ["roll"], + "🏷": ["sale", "tag"], + "🔖": ["favorite", "label", "save"], + "🚽": ["restroom", "wc", "washroom", "bathroom", "potty"], + "🚿": ["clean", "water", "bathroom"], + "🛁": ["clean", "shower", "bathroom"], + "🧼": ["bar", "bathing", "cleaning", "lather"], + "🧽": ["absorbing", "cleaning", "porous"], + "🧴": ["moisturizer", "sunscreen"], + "🔑": ["lock", "door", "password"], + "🗝": ["lock", "door", "password"], + "🛋": ["read", "chill"], + "🪔": ["light", "oil"], + "🛌": ["bed", "rest"], + "🛏": ["sleep", "rest"], + "🚪": ["house", "entry", "exit"], + "🪑": ["house", "desk"], + "🛎": ["service"], + "🧸": ["plush", "stuffed"], + "🖼": ["photography"], + "🗺": ["location", "direction"], + "🛗": ["household"], + "🪞": ["household"], + "🪟": ["household"], + "🪠": ["household"], + "🪤": ["household"], + "🪣": ["household"], + "🪥": ["household"], + "🫧": [], + "⛱": ["weather", "summer"], + "🗿": ["rock", "easter island", "moai"], + "🛍": ["mall", "buy", "purchase"], + "🛒": ["trolley"], + "🎈": ["party", "celebration", "birthday", "circus"], + "🎏": ["fish", "japanese", "koinobori", "carp", "banner"], + "🎀": ["decoration", "pink", "girl", "bowtie"], + "🎁": ["present", "birthday", "christmas", "xmas"], + "🎊": ["festival", "party", "birthday", "circus"], + "🎉": ["party", "congratulations", "birthday", "magic", "circus", "celebration"], + "🎎": ["japanese", "toy", "kimono"], + "🎐": ["nature", "ding", "spring", "bell"], + "🎌": ["japanese", "nation", "country", "border"], + "🏮": ["light", "paper", "halloween", "spooky"], + "🧧": ["gift"], + "✉️": ["letter", "postal", "inbox", "communication"], + "📩": ["email", "communication"], + "📨": ["email", "inbox"], + "📧": ["communication", "inbox"], + "💌": ["email", "like", "affection", "envelope", "valentines"], + "📮": ["email", "letter", "envelope"], + "📪": ["email", "communication", "inbox"], + "📫": ["email", "inbox", "communication"], + "📬": ["email", "inbox", "communication"], + "📭": ["email", "inbox"], + "📦": ["mail", "gift", "cardboard", "box", "moving"], + "📯": ["instrument", "music"], + "📥": ["email", "documents"], + "📤": ["inbox", "email"], + "📜": ["documents", "ancient", "history", "paper"], + "📃": ["documents", "office", "paper"], + "📑": ["favorite", "save", "order", "tidy"], + "🧾": ["accounting", "expenses"], + "📊": ["graph", "presentation", "stats"], + "📈": ["graph", "presentation", "stats", "recovery", "business", "economics", "money", "sales", "good", "success"], + "📉": ["graph", "presentation", "stats", "recession", "business", "economics", "money", "sales", "bad", "failure"], + "📄": ["documents", "office", "paper", "information"], + "📅": ["calendar", "schedule"], + "📆": ["schedule", "date", "planning"], + "🗓": ["date", "schedule", "planning"], + "📇": ["business", "stationery"], + "🗃": ["business", "stationery"], + "🗳": ["election", "vote"], + "🗄": ["filing", "organizing"], + "📋": ["stationery", "documents"], + "🗒": ["memo", "stationery"], + "📁": ["documents", "business", "office"], + "📂": ["documents", "load"], + "🗂": ["organizing", "business", "stationery"], + "🗞": ["press", "headline"], + "📰": ["press", "headline"], + "📓": ["stationery", "record", "notes", "paper", "study"], + "📕": ["read", "library", "knowledge", "textbook", "learn"], + "📗": ["read", "library", "knowledge", "study"], + "📘": ["read", "library", "knowledge", "learn", "study"], + "📙": ["read", "library", "knowledge", "textbook", "study"], + "📔": ["classroom", "notes", "record", "paper", "study"], + "📒": ["notes", "paper"], + "📚": ["literature", "library", "study"], + "📖": ["book", "read", "library", "knowledge", "literature", "learn", "study"], + "🧷": ["diaper"], + "🔗": ["rings", "url"], + "📎": ["documents", "stationery"], + "🖇": ["documents", "stationery"], + "✂️": ["stationery", "cut"], + "📐": ["stationery", "math", "architect", "sketch"], + "📏": ["stationery", "calculate", "length", "math", "school", "drawing", "architect", "sketch"], + "🧮": ["calculation"], + "📌": ["stationery", "mark", "here"], + "📍": ["stationery", "location", "map", "here"], + "🚩": ["mark", "milestone", "place"], + "🏳": ["losing", "loser", "lost", "surrender", "give up", "fail"], + "🏴": ["pirate"], + "🏳️🌈": ["flag", "rainbow", "pride", "gay", "lgbt", "glbt", "queer", "homosexual", "lesbian", "bisexual", "transgender"], + "🏳️⚧️": ["flag", "transgender"], + "🔐": ["security", "privacy"], + "🔒": ["security", "password", "padlock"], + "🔓": ["privacy", "security"], + "🔏": ["security", "secret"], + "🖊": ["stationery", "writing", "write"], + "🖋": ["stationery", "writing", "write"], + "✒️": ["pen", "stationery", "writing", "write"], + "📝": ["write", "documents", "stationery", "pencil", "paper", "writing", "legal", "exam", "quiz", "test", "study", "compose"], + "✏️": ["stationery", "write", "paper", "writing", "school", "study"], + "🖍": ["drawing", "creativity"], + "🖌": ["drawing", "creativity", "art"], + "🔍": ["search", "zoom", "find", "detective"], + "🔎": ["search", "zoom", "find", "detective"], + "🪦": [], + "🪧": [], + "💯": ["score", "perfect", "numbers", "century", "exam", "quiz", "test", "pass", "hundred"], + "🔢": ["numbers", "blue-square"], + "❤️": ["love", "like", "affection", "valentines"], + "🧡": ["love", "like", "affection", "valentines"], + "💛": ["love", "like", "affection", "valentines"], + "💚": ["love", "like", "affection", "valentines"], + "💙": ["love", "like", "affection", "valentines"], + "💜": ["love", "like", "affection", "valentines"], + "🤎": ["love", "like", "affection", "valentines"], + "🖤": ["love", "like", "affection", "valentines"], + "🤍": ["love", "like", "affection", "valentines"], + "💔": ["sad", "sorry", "break", "heart", "heartbreak"], + "❣": ["decoration", "love"], + "💕": ["love", "like", "affection", "valentines", "heart"], + "💞": ["love", "like", "affection", "valentines"], + "💓": ["love", "like", "affection", "valentines", "pink", "heart"], + "💗": ["like", "love", "affection", "valentines", "pink"], + "💖": ["love", "like", "affection", "valentines"], + "💘": ["love", "like", "heart", "affection", "valentines"], + "💝": ["love", "valentines"], + "💟": ["purple-square", "love", "like"], + "❤️🔥": [], + "❤️🩹": [], + "☮": ["hippie"], + "✝": ["christianity"], + "☪": ["islam"], + "🕉": ["hinduism", "buddhism", "sikhism", "jainism"], + "☸": ["hinduism", "buddhism", "sikhism", "jainism"], + "✡": ["judaism"], + "🔯": ["purple-square", "religion", "jewish", "hexagram"], + "🕎": ["hanukkah", "candles", "jewish"], + "☯": ["balance"], + "☦": ["suppedaneum", "religion"], + "🛐": ["religion", "church", "temple", "prayer"], + "⛎": ["sign", "purple-square", "constellation", "astrology"], + "♈": ["sign", "purple-square", "zodiac", "astrology"], + "♉": ["purple-square", "sign", "zodiac", "astrology"], + "♊": ["sign", "zodiac", "purple-square", "astrology"], + "♋": ["sign", "zodiac", "purple-square", "astrology"], + "♌": ["sign", "purple-square", "zodiac", "astrology"], + "♍": ["sign", "zodiac", "purple-square", "astrology"], + "♎": ["sign", "purple-square", "zodiac", "astrology"], + "♏": ["sign", "zodiac", "purple-square", "astrology", "scorpio"], + "♐": ["sign", "zodiac", "purple-square", "astrology"], + "♑": ["sign", "zodiac", "purple-square", "astrology"], + "♒": ["sign", "purple-square", "zodiac", "astrology"], + "♓": ["purple-square", "sign", "zodiac", "astrology"], + "🆔": ["purple-square", "words"], + "⚛": ["science", "physics", "chemistry"], + "⚧️": ["purple-square", "woman", "female", "toilet", "loo", "restroom", "gender"], + "🈳": ["kanji", "japanese", "chinese", "empty", "sky", "blue-square", "aki"], + "🈹": ["cut", "divide", "chinese", "kanji", "pink-square", "waribiki"], + "☢": ["nuclear", "danger"], + "☣": ["danger"], + "📴": ["mute", "orange-square", "silence", "quiet"], + "📳": ["orange-square", "phone"], + "🈶": ["orange-square", "chinese", "have", "kanji", "ari"], + "🈚": ["nothing", "chinese", "kanji", "japanese", "orange-square", "nashi"], + "🈸": ["chinese", "japanese", "kanji", "orange-square", "moushikomi"], + "🈺": ["japanese", "opening hours", "orange-square", "eigyo"], + "🈷️": ["chinese", "month", "moon", "japanese", "orange-square", "kanji", "tsuki", "tsukigime", "getsugaku"], + "✴️": ["orange-square", "shape", "polygon"], + "🆚": ["words", "orange-square"], + "🉑": ["ok", "good", "chinese", "kanji", "agree", "yes", "orange-circle"], + "💮": ["japanese", "spring"], + "🉐": ["chinese", "kanji", "obtain", "get", "circle"], + "㊙️": ["privacy", "chinese", "sshh", "kanji", "red-circle"], + "㊗️": ["chinese", "kanji", "japanese", "red-circle"], + "🈴": ["japanese", "chinese", "join", "kanji", "red-square", "goukaku", "pass"], + "🈵": ["full", "chinese", "japanese", "red-square", "kanji", "man"], + "🈲": ["kanji", "japanese", "chinese", "forbidden", "limit", "restricted", "red-square", "kinshi"], + "🅰️": ["red-square", "alphabet", "letter"], + "🅱️": ["red-square", "alphabet", "letter"], + "🆎": ["red-square", "alphabet"], + "🆑": ["alphabet", "words", "red-square"], + "🅾️": ["alphabet", "red-square", "letter"], + "🆘": ["help", "red-square", "words", "emergency", "911"], + "⛔": ["limit", "security", "privacy", "bad", "denied", "stop", "circle"], + "📛": ["fire", "forbid"], + "🚫": ["forbid", "stop", "limit", "denied", "disallow", "circle"], + "❌": ["no", "delete", "remove", "cancel", "red"], + "⭕": ["circle", "round"], + "🛑": ["stop"], + "💢": ["angry", "mad"], + "♨️": ["bath", "warm", "relax"], + "🚷": ["rules", "crossing", "walking", "circle"], + "🚯": ["trash", "bin", "garbage", "circle"], + "🚳": ["cyclist", "prohibited", "circle"], + "🚱": ["drink", "faucet", "tap", "circle"], + "🔞": ["18", "drink", "pub", "night", "minor", "circle"], + "📵": ["iphone", "mute", "circle"], + "❗": ["heavy_exclamation_mark", "danger", "surprise", "punctuation", "wow", "warning"], + "❕": ["surprise", "punctuation", "gray", "wow", "warning"], + "❓": ["doubt", "confused"], + "❔": ["doubts", "gray", "huh", "confused"], + "‼️": ["exclamation", "surprise"], + "⁉️": ["wat", "punctuation", "surprise"], + "🔅": ["sun", "afternoon", "warm", "summer"], + "🔆": ["sun", "light"], + "🔱": ["weapon", "spear"], + "⚜": ["decorative", "scout"], + "〽️": ["graph", "presentation", "stats", "business", "economics", "bad"], + "⚠️": ["exclamation", "wip", "alert", "error", "problem", "issue"], + "🚸": ["school", "warning", "danger", "sign", "driving", "yellow-diamond"], + "🔰": ["badge", "shield"], + "♻️": ["arrow", "environment", "garbage", "trash"], + "🈯": ["chinese", "point", "green-square", "kanji", "reserved", "shiteiseki"], + "💹": ["green-square", "graph", "presentation", "stats"], + "❇️": ["stars", "green-square", "awesome", "good", "fireworks"], + "✳️": ["star", "sparkle", "green-square"], + "❎": ["x", "green-square", "no", "deny"], + "✅": ["green-square", "ok", "agree", "vote", "election", "answer", "tick"], + "💠": ["jewel", "blue", "gem", "crystal", "fancy"], + "🌀": ["weather", "swirl", "blue", "cloud", "vortex", "spiral", "whirlpool", "spin", "tornado", "hurricane", "typhoon"], + "➿": ["tape", "cassette"], + "🌐": ["earth", "international", "world", "internet", "interweb", "i18n"], + "Ⓜ️": ["alphabet", "blue-circle", "letter"], + "🏧": ["money", "sales", "cash", "blue-square", "payment", "bank"], + "🈂️": ["japanese", "blue-square", "katakana"], + "🛂": ["custom", "blue-square"], + "🛃": ["passport", "border", "blue-square"], + "🛄": ["blue-square", "airport", "transport"], + "🛅": ["blue-square", "travel"], + "♿": ["blue-square", "disabled", "a11y", "accessibility"], + "🚭": ["cigarette", "blue-square", "smell", "smoke"], + "🚾": ["toilet", "restroom", "blue-square"], + "🅿️": ["cars", "blue-square", "alphabet", "letter"], + "🚰": ["blue-square", "liquid", "restroom", "cleaning", "faucet"], + "🚹": ["toilet", "restroom", "wc", "blue-square", "gender", "male"], + "🚺": ["purple-square", "woman", "female", "toilet", "loo", "restroom", "gender"], + "🚼": ["orange-square", "child"], + "🚻": ["blue-square", "toilet", "refresh", "wc", "gender"], + "🚮": ["blue-square", "sign", "human", "info"], + "🎦": ["blue-square", "record", "film", "movie", "curtain", "stage", "theater"], + "📶": ["blue-square", "reception", "phone", "internet", "connection", "wifi", "bluetooth", "bars"], + "🈁": ["blue-square", "here", "katakana", "japanese", "destination"], + "🆖": ["blue-square", "words", "shape", "icon"], + "🆗": ["good", "agree", "yes", "blue-square"], + "🆙": ["blue-square", "above", "high"], + "🆒": ["words", "blue-square"], + "🆕": ["blue-square", "words", "start"], + "🆓": ["blue-square", "words"], + "0️⃣": ["0", "numbers", "blue-square", "null"], + "1️⃣": ["blue-square", "numbers", "1"], + "2️⃣": ["numbers", "2", "prime", "blue-square"], + "3️⃣": ["3", "numbers", "prime", "blue-square"], + "4️⃣": ["4", "numbers", "blue-square"], + "5️⃣": ["5", "numbers", "blue-square", "prime"], + "6️⃣": ["6", "numbers", "blue-square"], + "7️⃣": ["7", "numbers", "blue-square", "prime"], + "8️⃣": ["8", "blue-square", "numbers"], + "9️⃣": ["blue-square", "numbers", "9"], + "🔟": ["numbers", "10", "blue-square"], + "*⃣": ["star", "keycap"], + "⏏️": ["blue-square"], + "▶️": ["blue-square", "right", "direction", "play"], + "⏸": ["pause", "blue-square"], + "⏭": ["forward", "next", "blue-square"], + "⏹": ["blue-square"], + "⏺": ["blue-square"], + "⏯": ["blue-square", "play", "pause"], + "⏮": ["backward"], + "⏩": ["blue-square", "play", "speed", "continue"], + "⏪": ["play", "blue-square"], + "🔀": ["blue-square", "shuffle", "music", "random"], + "🔁": ["loop", "record"], + "🔂": ["blue-square", "loop"], + "◀️": ["blue-square", "left", "direction"], + "🔼": ["blue-square", "triangle", "direction", "point", "forward", "top"], + "🔽": ["blue-square", "direction", "bottom"], + "⏫": ["blue-square", "direction", "top"], + "⏬": ["blue-square", "direction", "bottom"], + "➡️": ["blue-square", "next"], + "⬅️": ["blue-square", "previous", "back"], + "⬆️": ["blue-square", "continue", "top", "direction"], + "⬇️": ["blue-square", "direction", "bottom"], + "↗️": ["blue-square", "point", "direction", "diagonal", "northeast"], + "↘️": ["blue-square", "direction", "diagonal", "southeast"], + "↙️": ["blue-square", "direction", "diagonal", "southwest"], + "↖️": ["blue-square", "point", "direction", "diagonal", "northwest"], + "↕️": ["blue-square", "direction", "way", "vertical"], + "↔️": ["shape", "direction", "horizontal", "sideways"], + "🔄": ["blue-square", "sync", "cycle"], + "↪️": ["blue-square", "return", "rotate", "direction"], + "↩️": ["back", "return", "blue-square", "undo", "enter"], + "⤴️": ["blue-square", "direction", "top"], + "⤵️": ["blue-square", "direction", "bottom"], + "#️⃣": ["symbol", "blue-square", "twitter"], + "ℹ️": ["blue-square", "alphabet", "letter"], + "🔤": ["blue-square", "alphabet"], + "🔡": ["blue-square", "alphabet"], + "🔠": ["alphabet", "words", "blue-square"], + "🔣": ["blue-square", "music", "note", "ampersand", "percent", "glyphs", "characters"], + "🎵": ["score", "tone", "sound"], + "🎶": ["music", "score"], + "〰️": ["draw", "line", "moustache", "mustache", "squiggle", "scribble"], + "➰": ["scribble", "draw", "shape", "squiggle"], + "✔️": ["ok", "nike", "answer", "yes", "tick"], + "🔃": ["sync", "cycle", "round", "repeat"], + "➕": ["math", "calculation", "addition", "more", "increase"], + "➖": ["math", "calculation", "subtract", "less"], + "➗": ["divide", "math", "calculation"], + "✖️": ["math", "calculation"], + "🟰": [], + "♾": ["forever"], + "💲": ["money", "sales", "payment", "currency", "buck"], + "💱": ["money", "sales", "dollar", "travel"], + "©️": ["ip", "license", "circle", "law", "legal"], + "®️": ["alphabet", "circle"], + "™️": ["trademark", "brand", "law", "legal"], + "🔚": ["words", "arrow"], + "🔙": ["arrow", "words", "return"], + "🔛": ["arrow", "words"], + "🔝": ["words", "blue-square"], + "🔜": ["arrow", "words"], + "☑️": ["ok", "agree", "confirm", "black-square", "vote", "election", "yes", "tick"], + "🔘": ["input", "old", "music", "circle"], + "⚫": ["shape", "button", "round"], + "⚪": ["shape", "round"], + "🔴": ["shape", "error", "danger"], + "🟠": ["shape"], + "🟡": ["shape"], + "🟢": ["shape"], + "🔵": ["shape", "icon", "button"], + "🟣": ["shape"], + "🟤": ["shape"], + "🔸": ["shape", "jewel", "gem"], + "🔹": ["shape", "jewel", "gem"], + "🔶": ["shape", "jewel", "gem"], + "🔷": ["shape", "jewel", "gem"], + "🔺": ["shape", "direction", "up", "top"], + "▪️": ["shape", "icon"], + "▫️": ["shape", "icon"], + "⬛": ["shape", "icon", "button"], + "⬜": ["shape", "icon", "stone", "button"], + "🟥": ["shape"], + "🟧": ["shape"], + "🟨": ["shape"], + "🟩": ["shape"], + "🟦": ["shape"], + "🟪": ["shape"], + "🟫": ["shape"], + "🔻": ["shape", "direction", "bottom"], + "◼️": ["shape", "button", "icon"], + "◻️": ["shape", "stone", "icon"], + "◾": ["icon", "shape", "button"], + "◽": ["shape", "stone", "icon", "button"], + "🔲": ["shape", "input", "frame"], + "🔳": ["shape", "input"], + "🔈": ["sound", "volume", "silence", "broadcast"], + "🔉": ["volume", "speaker", "broadcast"], + "🔊": ["volume", "noise", "noisy", "speaker", "broadcast"], + "🔇": ["sound", "volume", "silence", "quiet"], + "📣": ["sound", "speaker", "volume"], + "📢": ["volume", "sound"], + "🔔": ["sound", "notification", "christmas", "xmas", "chime"], + "🔕": ["sound", "volume", "mute", "quiet", "silent"], + "🃏": ["poker", "cards", "game", "play", "magic"], + "🀄": ["game", "play", "chinese", "kanji"], + "♠️": ["poker", "cards", "suits", "magic"], + "♣️": ["poker", "cards", "magic", "suits"], + "♥️": ["poker", "cards", "magic", "suits"], + "♦️": ["poker", "cards", "magic", "suits"], + "🎴": ["game", "sunset", "red"], + "💭": ["bubble", "cloud", "speech", "thinking", "dream"], + "🗯": ["caption", "speech", "thinking", "mad"], + "💬": ["bubble", "words", "message", "talk", "chatting"], + "🗨": ["words", "message", "talk", "chatting"], + "🕐": ["time", "late", "early", "schedule"], + "🕑": ["time", "late", "early", "schedule"], + "🕒": ["time", "late", "early", "schedule"], + "🕓": ["time", "late", "early", "schedule"], + "🕔": ["time", "late", "early", "schedule"], + "🕕": ["time", "late", "early", "schedule", "dawn", "dusk"], + "🕖": ["time", "late", "early", "schedule"], + "🕗": ["time", "late", "early", "schedule"], + "🕘": ["time", "late", "early", "schedule"], + "🕙": ["time", "late", "early", "schedule"], + "🕚": ["time", "late", "early", "schedule"], + "🕛": ["time", "noon", "midnight", "midday", "late", "early", "schedule"], + "🕜": ["time", "late", "early", "schedule"], + "🕝": ["time", "late", "early", "schedule"], + "🕞": ["time", "late", "early", "schedule"], + "🕟": ["time", "late", "early", "schedule"], + "🕠": ["time", "late", "early", "schedule"], + "🕡": ["time", "late", "early", "schedule"], + "🕢": ["time", "late", "early", "schedule"], + "🕣": ["time", "late", "early", "schedule"], + "🕤": ["time", "late", "early", "schedule"], + "🕥": ["time", "late", "early", "schedule"], + "🕦": ["time", "late", "early", "schedule"], + "🕧": ["time", "late", "early", "schedule"], + "🇦🇫": ["af", "flag", "nation", "country", "banner"], + "🇦🇽": ["Åland", "islands", "flag", "nation", "country", "banner"], + "🇦🇱": ["al", "flag", "nation", "country", "banner"], + "🇩🇿": ["dz", "flag", "nation", "country", "banner"], + "🇦🇸": ["american", "ws", "flag", "nation", "country", "banner"], + "🇦🇩": ["ad", "flag", "nation", "country", "banner"], + "🇦🇴": ["ao", "flag", "nation", "country", "banner"], + "🇦🇮": ["ai", "flag", "nation", "country", "banner"], + "🇦🇶": ["aq", "flag", "nation", "country", "banner"], + "🇦🇬": ["antigua", "barbuda", "flag", "nation", "country", "banner"], + "🇦🇷": ["ar", "flag", "nation", "country", "banner"], + "🇦🇲": ["am", "flag", "nation", "country", "banner"], + "🇦🇼": ["aw", "flag", "nation", "country", "banner"], + "🇦🇨": ["flag", "nation", "country", "banner"], + "🇦🇺": ["au", "flag", "nation", "country", "banner"], + "🇦🇹": ["at", "flag", "nation", "country", "banner"], + "🇦🇿": ["az", "flag", "nation", "country", "banner"], + "🇧🇸": ["bs", "flag", "nation", "country", "banner"], + "🇧🇭": ["bh", "flag", "nation", "country", "banner"], + "🇧🇩": ["bd", "flag", "nation", "country", "banner"], + "🇧🇧": ["bb", "flag", "nation", "country", "banner"], + "🇧🇾": ["by", "flag", "nation", "country", "banner"], + "🇧🇪": ["be", "flag", "nation", "country", "banner"], + "🇧🇿": ["bz", "flag", "nation", "country", "banner"], + "🇧🇯": ["bj", "flag", "nation", "country", "banner"], + "🇧🇲": ["bm", "flag", "nation", "country", "banner"], + "🇧🇹": ["bt", "flag", "nation", "country", "banner"], + "🇧🇴": ["bo", "flag", "nation", "country", "banner"], + "🇧🇶": ["bonaire", "flag", "nation", "country", "banner"], + "🇧🇦": ["bosnia", "herzegovina", "flag", "nation", "country", "banner"], + "🇧🇼": ["bw", "flag", "nation", "country", "banner"], + "🇧🇷": ["br", "flag", "nation", "country", "banner"], + "🇮🇴": ["british", "indian", "ocean", "territory", "flag", "nation", "country", "banner"], + "🇻🇬": ["british", "virgin", "islands", "bvi", "flag", "nation", "country", "banner"], + "🇧🇳": ["bn", "darussalam", "flag", "nation", "country", "banner"], + "🇧🇬": ["bg", "flag", "nation", "country", "banner"], + "🇧🇫": ["burkina", "faso", "flag", "nation", "country", "banner"], + "🇧🇮": ["bi", "flag", "nation", "country", "banner"], + "🇨🇻": ["cabo", "verde", "flag", "nation", "country", "banner"], + "🇰🇭": ["kh", "flag", "nation", "country", "banner"], + "🇨🇲": ["cm", "flag", "nation", "country", "banner"], + "🇨🇦": ["ca", "flag", "nation", "country", "banner"], + "🇮🇨": ["canary", "islands", "flag", "nation", "country", "banner"], + "🇰🇾": ["cayman", "islands", "flag", "nation", "country", "banner"], + "🇨🇫": ["central", "african", "republic", "flag", "nation", "country", "banner"], + "🇹🇩": ["td", "flag", "nation", "country", "banner"], + "🇨🇱": ["flag", "nation", "country", "banner"], + "🇨🇳": ["china", "chinese", "prc", "flag", "country", "nation", "banner"], + "🇨🇽": ["christmas", "island", "flag", "nation", "country", "banner"], + "🇨🇨": ["cocos", "keeling", "islands", "flag", "nation", "country", "banner"], + "🇨🇴": ["co", "flag", "nation", "country", "banner"], + "🇰🇲": ["km", "flag", "nation", "country", "banner"], + "🇨🇬": ["congo", "flag", "nation", "country", "banner"], + "🇨🇩": ["congo", "democratic", "republic", "flag", "nation", "country", "banner"], + "🇨🇰": ["cook", "islands", "flag", "nation", "country", "banner"], + "🇨🇷": ["costa", "rica", "flag", "nation", "country", "banner"], + "🇭🇷": ["hr", "flag", "nation", "country", "banner"], + "🇨🇺": ["cu", "flag", "nation", "country", "banner"], + "🇨🇼": ["curaçao", "flag", "nation", "country", "banner"], + "🇨🇾": ["cy", "flag", "nation", "country", "banner"], + "🇨🇿": ["cz", "flag", "nation", "country", "banner"], + "🇩🇰": ["dk", "flag", "nation", "country", "banner"], + "🇩🇯": ["dj", "flag", "nation", "country", "banner"], + "🇩🇲": ["dm", "flag", "nation", "country", "banner"], + "🇩🇴": ["dominican", "republic", "flag", "nation", "country", "banner"], + "🇪🇨": ["ec", "flag", "nation", "country", "banner"], + "🇪🇬": ["eg", "flag", "nation", "country", "banner"], + "🇸🇻": ["el", "salvador", "flag", "nation", "country", "banner"], + "🇬🇶": ["equatorial", "gn", "flag", "nation", "country", "banner"], + "🇪🇷": ["er", "flag", "nation", "country", "banner"], + "🇪🇪": ["ee", "flag", "nation", "country", "banner"], + "🇪🇹": ["et", "flag", "nation", "country", "banner"], + "🇪🇺": ["european", "union", "flag", "banner"], + "🇫🇰": ["falkland", "islands", "malvinas", "flag", "nation", "country", "banner"], + "🇫🇴": ["faroe", "islands", "flag", "nation", "country", "banner"], + "🇫🇯": ["fj", "flag", "nation", "country", "banner"], + "🇫🇮": ["fi", "flag", "nation", "country", "banner"], + "🇫🇷": ["banner", "flag", "nation", "france", "french", "country"], + "🇬🇫": ["french", "guiana", "flag", "nation", "country", "banner"], + "🇵🇫": ["french", "polynesia", "flag", "nation", "country", "banner"], + "🇹🇫": ["french", "southern", "territories", "flag", "nation", "country", "banner"], + "🇬🇦": ["ga", "flag", "nation", "country", "banner"], + "🇬🇲": ["gm", "flag", "nation", "country", "banner"], + "🇬🇪": ["ge", "flag", "nation", "country", "banner"], + "🇩🇪": ["german", "nation", "flag", "country", "banner"], + "🇬🇭": ["gh", "flag", "nation", "country", "banner"], + "🇬🇮": ["gi", "flag", "nation", "country", "banner"], + "🇬🇷": ["gr", "flag", "nation", "country", "banner"], + "🇬🇱": ["gl", "flag", "nation", "country", "banner"], + "🇬🇩": ["gd", "flag", "nation", "country", "banner"], + "🇬🇵": ["gp", "flag", "nation", "country", "banner"], + "🇬🇺": ["gu", "flag", "nation", "country", "banner"], + "🇬🇹": ["gt", "flag", "nation", "country", "banner"], + "🇬🇬": ["gg", "flag", "nation", "country", "banner"], + "🇬🇳": ["gn", "flag", "nation", "country", "banner"], + "🇬🇼": ["gw", "bissau", "flag", "nation", "country", "banner"], + "🇬🇾": ["gy", "flag", "nation", "country", "banner"], + "🇭🇹": ["ht", "flag", "nation", "country", "banner"], + "🇭🇳": ["hn", "flag", "nation", "country", "banner"], + "🇭🇰": ["hong", "kong", "flag", "nation", "country", "banner"], + "🇭🇺": ["hu", "flag", "nation", "country", "banner"], + "🇮🇸": ["is", "flag", "nation", "country", "banner"], + "🇮🇳": ["in", "flag", "nation", "country", "banner"], + "🇮🇩": ["flag", "nation", "country", "banner"], + "🇮🇷": ["iran, ", "islamic", "republic", "flag", "nation", "country", "banner"], + "🇮🇶": ["iq", "flag", "nation", "country", "banner"], + "🇮🇪": ["ie", "flag", "nation", "country", "banner"], + "🇮🇲": ["isle", "man", "flag", "nation", "country", "banner"], + "🇮🇱": ["il", "flag", "nation", "country", "banner"], + "🇮🇹": ["italy", "flag", "nation", "country", "banner"], + "🇨🇮": ["ivory", "coast", "flag", "nation", "country", "banner"], + "🇯🇲": ["jm", "flag", "nation", "country", "banner"], + "🇯🇵": ["japanese", "nation", "flag", "country", "banner"], + "🇯🇪": ["je", "flag", "nation", "country", "banner"], + "🇯🇴": ["jo", "flag", "nation", "country", "banner"], + "🇰🇿": ["kz", "flag", "nation", "country", "banner"], + "🇰🇪": ["ke", "flag", "nation", "country", "banner"], + "🇰🇮": ["ki", "flag", "nation", "country", "banner"], + "🇽🇰": ["xk", "flag", "nation", "country", "banner"], + "🇰🇼": ["kw", "flag", "nation", "country", "banner"], + "🇰🇬": ["kg", "flag", "nation", "country", "banner"], + "🇱🇦": ["lao", "democratic", "republic", "flag", "nation", "country", "banner"], + "🇱🇻": ["lv", "flag", "nation", "country", "banner"], + "🇱🇧": ["lb", "flag", "nation", "country", "banner"], + "🇱🇸": ["ls", "flag", "nation", "country", "banner"], + "🇱🇷": ["lr", "flag", "nation", "country", "banner"], + "🇱🇾": ["ly", "flag", "nation", "country", "banner"], + "🇱🇮": ["li", "flag", "nation", "country", "banner"], + "🇱🇹": ["lt", "flag", "nation", "country", "banner"], + "🇱🇺": ["lu", "flag", "nation", "country", "banner"], + "🇲🇴": ["macao", "flag", "nation", "country", "banner"], + "🇲🇰": ["macedonia, ", "flag", "nation", "country", "banner"], + "🇲🇬": ["mg", "flag", "nation", "country", "banner"], + "🇲🇼": ["mw", "flag", "nation", "country", "banner"], + "🇲🇾": ["my", "flag", "nation", "country", "banner"], + "🇲🇻": ["mv", "flag", "nation", "country", "banner"], + "🇲🇱": ["ml", "flag", "nation", "country", "banner"], + "🇲🇹": ["mt", "flag", "nation", "country", "banner"], + "🇲🇭": ["marshall", "islands", "flag", "nation", "country", "banner"], + "🇲🇶": ["mq", "flag", "nation", "country", "banner"], + "🇲🇷": ["mr", "flag", "nation", "country", "banner"], + "🇲🇺": ["mu", "flag", "nation", "country", "banner"], + "🇾🇹": ["yt", "flag", "nation", "country", "banner"], + "🇲🇽": ["mx", "flag", "nation", "country", "banner"], + "🇫🇲": ["micronesia, ", "federated", "states", "flag", "nation", "country", "banner"], + "🇲🇩": ["moldova, ", "republic", "flag", "nation", "country", "banner"], + "🇲🇨": ["mc", "flag", "nation", "country", "banner"], + "🇲🇳": ["mn", "flag", "nation", "country", "banner"], + "🇲🇪": ["me", "flag", "nation", "country", "banner"], + "🇲🇸": ["ms", "flag", "nation", "country", "banner"], + "🇲🇦": ["ma", "flag", "nation", "country", "banner"], + "🇲🇿": ["mz", "flag", "nation", "country", "banner"], + "🇲🇲": ["mm", "flag", "nation", "country", "banner"], + "🇳🇦": ["na", "flag", "nation", "country", "banner"], + "🇳🇷": ["nr", "flag", "nation", "country", "banner"], + "🇳🇵": ["np", "flag", "nation", "country", "banner"], + "🇳🇱": ["nl", "flag", "nation", "country", "banner"], + "🇳🇨": ["new", "caledonia", "flag", "nation", "country", "banner"], + "🇳🇿": ["new", "zealand", "flag", "nation", "country", "banner"], + "🇳🇮": ["ni", "flag", "nation", "country", "banner"], + "🇳🇪": ["ne", "flag", "nation", "country", "banner"], + "🇳🇬": ["flag", "nation", "country", "banner"], + "🇳🇺": ["nu", "flag", "nation", "country", "banner"], + "🇳🇫": ["norfolk", "island", "flag", "nation", "country", "banner"], + "🇲🇵": ["northern", "mariana", "islands", "flag", "nation", "country", "banner"], + "🇰🇵": ["north", "korea", "nation", "flag", "country", "banner"], + "🇳🇴": ["no", "flag", "nation", "country", "banner"], + "🇴🇲": ["om_symbol", "flag", "nation", "country", "banner"], + "🇵🇰": ["pk", "flag", "nation", "country", "banner"], + "🇵🇼": ["pw", "flag", "nation", "country", "banner"], + "🇵🇸": ["palestine", "palestinian", "territories", "flag", "nation", "country", "banner"], + "🇵🇦": ["pa", "flag", "nation", "country", "banner"], + "🇵🇬": ["papua", "new", "guinea", "flag", "nation", "country", "banner"], + "🇵🇾": ["py", "flag", "nation", "country", "banner"], + "🇵🇪": ["pe", "flag", "nation", "country", "banner"], + "🇵🇭": ["ph", "flag", "nation", "country", "banner"], + "🇵🇳": ["pitcairn", "flag", "nation", "country", "banner"], + "🇵🇱": ["pl", "flag", "nation", "country", "banner"], + "🇵🇹": ["pt", "flag", "nation", "country", "banner"], + "🇵🇷": ["puerto", "rico", "flag", "nation", "country", "banner"], + "🇶🇦": ["qa", "flag", "nation", "country", "banner"], + "🇷🇪": ["réunion", "flag", "nation", "country", "banner"], + "🇷🇴": ["ro", "flag", "nation", "country", "banner"], + "🇷🇺": ["russian", "federation", "flag", "nation", "country", "banner"], + "🇷🇼": ["rw", "flag", "nation", "country", "banner"], + "🇧🇱": ["saint", "barthélemy", "flag", "nation", "country", "banner"], + "🇸🇭": ["saint", "helena", "ascension", "tristan", "cunha", "flag", "nation", "country", "banner"], + "🇰🇳": ["saint", "kitts", "nevis", "flag", "nation", "country", "banner"], + "🇱🇨": ["saint", "lucia", "flag", "nation", "country", "banner"], + "🇵🇲": ["saint", "pierre", "miquelon", "flag", "nation", "country", "banner"], + "🇻🇨": ["saint", "vincent", "grenadines", "flag", "nation", "country", "banner"], + "🇼🇸": ["ws", "flag", "nation", "country", "banner"], + "🇸🇲": ["san", "marino", "flag", "nation", "country", "banner"], + "🇸🇹": ["sao", "tome", "principe", "flag", "nation", "country", "banner"], + "🇸🇦": ["flag", "nation", "country", "banner"], + "🇸🇳": ["sn", "flag", "nation", "country", "banner"], + "🇷🇸": ["rs", "flag", "nation", "country", "banner"], + "🇸🇨": ["sc", "flag", "nation", "country", "banner"], + "🇸🇱": ["sierra", "leone", "flag", "nation", "country", "banner"], + "🇸🇬": ["sg", "flag", "nation", "country", "banner"], + "🇸🇽": ["sint", "maarten", "dutch", "flag", "nation", "country", "banner"], + "🇸🇰": ["sk", "flag", "nation", "country", "banner"], + "🇸🇮": ["si", "flag", "nation", "country", "banner"], + "🇸🇧": ["solomon", "islands", "flag", "nation", "country", "banner"], + "🇸🇴": ["so", "flag", "nation", "country", "banner"], + "🇿🇦": ["south", "africa", "flag", "nation", "country", "banner"], + "🇬🇸": ["south", "georgia", "sandwich", "islands", "flag", "nation", "country", "banner"], + "🇰🇷": ["south", "korea", "nation", "flag", "country", "banner"], + "🇸🇸": ["south", "sd", "flag", "nation", "country", "banner"], + "🇪🇸": ["spain", "flag", "nation", "country", "banner"], + "🇱🇰": ["sri", "lanka", "flag", "nation", "country", "banner"], + "🇸🇩": ["sd", "flag", "nation", "country", "banner"], + "🇸🇷": ["sr", "flag", "nation", "country", "banner"], + "🇸🇿": ["sz", "flag", "nation", "country", "banner"], + "🇸🇪": ["se", "flag", "nation", "country", "banner"], + "🇨🇭": ["ch", "flag", "nation", "country", "banner"], + "🇸🇾": ["syrian", "arab", "republic", "flag", "nation", "country", "banner"], + "🇹🇼": ["tw", "flag", "nation", "country", "banner"], + "🇹🇯": ["tj", "flag", "nation", "country", "banner"], + "🇹🇿": ["tanzania, ", "united", "republic", "flag", "nation", "country", "banner"], + "🇹🇭": ["th", "flag", "nation", "country", "banner"], + "🇹🇱": ["timor", "leste", "flag", "nation", "country", "banner"], + "🇹🇬": ["tg", "flag", "nation", "country", "banner"], + "🇹🇰": ["tk", "flag", "nation", "country", "banner"], + "🇹🇴": ["to", "flag", "nation", "country", "banner"], + "🇹🇹": ["trinidad", "tobago", "flag", "nation", "country", "banner"], + "🇹🇦": ["flag", "nation", "country", "banner"], + "🇹🇳": ["tn", "flag", "nation", "country", "banner"], + "🇹🇷": ["turkey", "flag", "nation", "country", "banner"], + "🇹🇲": ["flag", "nation", "country", "banner"], + "🇹🇨": ["turks", "caicos", "islands", "flag", "nation", "country", "banner"], + "🇹🇻": ["flag", "nation", "country", "banner"], + "🇺🇬": ["ug", "flag", "nation", "country", "banner"], + "🇺🇦": ["ua", "flag", "nation", "country", "banner"], + "🇦🇪": ["united", "arab", "emirates", "flag", "nation", "country", "banner"], + "🇬🇧": ["united", "kingdom", "great", "britain", "northern", "ireland", "flag", "nation", "country", "banner", "british", "UK", "english", "england", "union jack"], + "🏴": ["flag", "english"], + "🏴": ["flag", "scottish"], + "🏴": ["flag", "welsh"], + "🇺🇸": ["united", "states", "america", "flag", "nation", "country", "banner"], + "🇻🇮": ["virgin", "islands", "us", "flag", "nation", "country", "banner"], + "🇺🇾": ["uy", "flag", "nation", "country", "banner"], + "🇺🇿": ["uz", "flag", "nation", "country", "banner"], + "🇻🇺": ["vu", "flag", "nation", "country", "banner"], + "🇻🇦": ["vatican", "city", "flag", "nation", "country", "banner"], + "🇻🇪": ["ve", "bolivarian", "republic", "flag", "nation", "country", "banner"], + "🇻🇳": ["viet", "nam", "flag", "nation", "country", "banner"], + "🇼🇫": ["wallis", "futuna", "flag", "nation", "country", "banner"], + "🇪🇭": ["western", "sahara", "flag", "nation", "country", "banner"], + "🇾🇪": ["ye", "flag", "nation", "country", "banner"], + "🇿🇲": ["zm", "flag", "nation", "country", "banner"], + "🇿🇼": ["zw", "flag", "nation", "country", "banner"], + "🇺🇳": ["un", "flag", "banner"], + "🏴☠️": ["skull", "crossbones", "flag", "banner"] +} From 146e89edd08ab985cd862d30246ad5d7955d63e0 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 17:19:11 +0900 Subject: [PATCH 155/213] Update index.d.ts --- locales/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/locales/index.d.ts b/locales/index.d.ts index a54268676e..3bdb37b9dc 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1063,6 +1063,7 @@ export interface Locale { "changeReactionConfirm": string; "later": string; "goToMisskey": string; + "additionalEmojiDictionary": string; "_initialAccountSetting": { "accountCreated": string; "letsStartAccountSetup": string; From 337dd97b490fb6bcfc351566a4fd80c35a9cda14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Thu, 1 Jun 2023 17:19:46 +0900 Subject: [PATCH 156/213] =?UTF-8?q?perf(#10923):=20CSS=20Modules=20?= =?UTF-8?q?=E3=81=AE=E3=82=AF=E3=83=A9=E3=82=B9=E5=90=8D=E3=82=92=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E3=83=A9=E3=82=A4=E3=83=B3=E5=8C=96=E3=81=99=E3=82=8B?= =?UTF-8?q?=20(#10930)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf(#10923): unwind css module class name * perf(#10923): support multiple components * refactor: clean up * refactor(#10923): avoid `useCssModule()` * fix(#10923): allow direct literal class name * fix(#10923): avoid computed class name * fix(#10923): allow literal keys * fix(#10923): typo * fix(#10923): invalid class names * chore: test * revert: test This reverts commit 5c7ef366eceebe8ba260efa4d5d675f6c1775c45. * fix(#10923): hidden tale * perf(#10923): also unwind scoped css contained components * perf(#10923): `normalizeClass` AOT compilation --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> --- ...lugin-unwind-css-module-class-name.test.ts | 597 +++++++ ...lup-plugin-unwind-css-module-class-name.ts | 275 ++++ packages/frontend/package.json | 4 +- .../src/components/MkAchievements.vue | 9 +- .../src/components/MkAutocomplete.vue | 2 +- packages/frontend/src/components/MkButton.vue | 10 +- .../frontend/src/components/MkClickerGame.vue | 6 +- .../frontend/src/components/MkContainer.vue | 2 +- .../src/components/MkDateSeparatedList.vue | 2 +- packages/frontend/src/components/MkDialog.vue | 10 +- packages/frontend/src/components/MkFolder.vue | 6 +- .../src/components/MkImgWithBlurhash.vue | 5 +- .../frontend/src/components/MkMediaList.vue | 15 +- .../frontend/src/components/MkMention.vue | 2 +- packages/frontend/src/components/MkMenu.vue | 2 +- packages/frontend/src/components/MkModal.vue | 46 +- packages/frontend/src/components/MkNote.vue | 8 +- .../src/components/MkNoteDetailed.vue | 4 +- .../frontend/src/components/MkNotePreview.vue | 2 +- .../src/components/MkNotification.vue | 19 +- packages/frontend/src/components/MkPoll.vue | 2 +- .../frontend/src/components/MkPostForm.vue | 8 +- .../src/components/MkSubNoteContent.vue | 6 +- .../frontend/src/components/MkTextarea.vue | 2 +- .../frontend/src/components/MkUrlPreview.vue | 11 +- .../src/components/MkUserOnlineIndicator.vue | 10 +- .../src/components/MkUserSelectDialog.vue | 4 +- .../src/components/MkUsersTooltip.vue | 12 +- .../src/components/MkVisitorDashboard.vue | 6 +- .../frontend/src/components/MkWidgets.vue | 30 +- .../frontend/src/components/form/link.vue | 4 +- .../frontend/src/components/form/slot.vue | 2 +- .../frontend/src/components/global/MkAd.vue | 12 +- .../frontend/src/components/global/MkUrl.vue | 2 +- .../src/components/page/page.section.vue | 11 +- .../src/pages/admin/RolesEditorFormula.vue | 12 +- .../frontend/src/pages/admin/queue.chart.vue | 7 +- .../frontend/src/pages/admin/server-rules.vue | 2 +- .../pages/settings/preferences-backups.vue | 4 +- .../frontend/src/pages/settings/profile.vue | 6 +- .../frontend/src/pages/signup-complete.vue | 5 +- packages/frontend/src/pages/welcome.setup.vue | 5 +- .../frontend/src/pages/welcome.timeline.vue | 2 +- packages/frontend/src/ui/_common_/common.vue | 38 +- .../src/ui/_common_/statusbar-federation.vue | 2 +- .../frontend/src/ui/_common_/statusbars.vue | 1 - .../src/ui/_common_/stream-indicator.vue | 7 +- packages/frontend/src/ui/deck/column.vue | 2 +- .../frontend/src/ui/universal.widgets.vue | 7 +- packages/frontend/src/widgets/WidgetClock.vue | 8 +- .../frontend/src/widgets/WidgetRssTicker.vue | 2 +- packages/frontend/vite.config.ts | 2 + pnpm-lock.yaml | 1403 ++++++++++++++--- 53 files changed, 2295 insertions(+), 368 deletions(-) create mode 100644 packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts create mode 100644 packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts new file mode 100644 index 0000000000..3929bf0608 --- /dev/null +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts @@ -0,0 +1,597 @@ +import { parse } from 'acorn'; +import { generate } from 'astring'; +import { describe, expect, it } from 'vitest'; +import { normalizeClass, unwindCssModuleClassName } from './rollup-plugin-unwind-css-module-class-name'; +import type * as estree from 'estree'; + +function parseExpression(code: string): estree.Expression { + const program = parse(code, { ecmaVersion: 'latest', sourceType: 'module' }) as unknown as estree.Program; + const statement = program.body[0] as estree.ExpressionStatement; + return statement.expression; +} + +describe(normalizeClass.name, () => { + it('should normalize string', () => { + expect(normalizeClass(parseExpression('"a b c"'))).toBe('a b c'); + }); + it('should trim redundant spaces', () => { + expect(normalizeClass(parseExpression('" a b c "'))).toBe('a b c'); + }); + it('should ignore undefined', () => { + expect(normalizeClass(parseExpression('undefined'))).toBe(''); + }); + it('should ignore non string literals', () => { + expect(normalizeClass(parseExpression('0'))).toBe(''); + expect(normalizeClass(parseExpression('true'))).toBe(''); + expect(normalizeClass(parseExpression('null'))).toBe(''); + expect(normalizeClass(parseExpression('/I.D/'))).toBe(''); + }); + it('should not normalize identifiers', () => { + expect(normalizeClass(parseExpression('EScape'))).toBeNull(); + }); + it('should normalize recursively array', () => { + expect(normalizeClass(parseExpression('["from", ...["Utopia"]]'))).toBe('from Utopia'); + expect(normalizeClass(parseExpression('["from", ...[Utopia]]'))).toBeNull(); + }); + it('should normalize recursively template literal', () => { + expect(normalizeClass(parseExpression('`name ${"shiho"} code ${33}`'))).toBe('name shiho code'); + expect(normalizeClass(parseExpression('`name ${shiho.name} code ${33}`'))).toBeNull(); + }); + it('should normalize recursively binary expression', () => { + expect(normalizeClass(parseExpression('"mirage" + "mirror"'))).toBe('miragemirror'); + expect(normalizeClass(parseExpression('"mirage" + mirror'))).toBeNull(); + }); + it('should normalize recursively object expression', () => { + expect(normalizeClass(parseExpression('({ a: true, b: "c" })'))).toBe('a b'); + expect(normalizeClass(parseExpression('({ a: false, b: "c" })'))).toBe('b'); + expect(normalizeClass(parseExpression('({ a: true, b: c })'))).toBeNull(); + expect(normalizeClass(parseExpression('({ a: true, b: "c", ...({ d: true }) })'))).toBe('a b d'); + expect(normalizeClass(parseExpression('({ a: true, [b]: "c" })'))).toBeNull(); + expect(normalizeClass(parseExpression('({ a: true, b: false, c: !false, d: !!0 })'))).toBe('a c'); + }); +}); + +it('Composition API (standard)', () => { + const ast = parse(` +import { c as api, d as defaultStore, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; +import { M as MkContainer } from './MkContainer-!~{03M}~.js'; +import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; +import './photoswipe-!~{003}~.js'; + +const _hoisted_1 = /* @__PURE__ */ createBaseVNode("i", { class: "ti ti-photo" }, null, -1); +const _sfc_main = /* @__PURE__ */ defineComponent({ + __name: "index.photos", + props: { + user: {} + }, + setup(__props) { + const props = __props; + let fetching = ref(true); + let images = ref([]); + function thumbnail(image) { + return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; + } + onMounted(() => { + const image = [ + "image/jpeg", + "image/webp", + "image/avif", + "image/png", + "image/gif", + "image/apng", + "image/vnd.mozilla.apng" + ]; + api("users/notes", { + userId: props.user.id, + fileType: image, + excludeNsfw: defaultStore.state.nsfw !== "ignore", + limit: 10 + }).then((notes) => { + for (const note of notes) { + for (const file of note.files) { + images.value.push({ + note, + file + }); + } + } + fetching.value = false; + }); + }); + return (_ctx, _cache) => { + const _component_MkLoading = resolveComponent("MkLoading"); + const _component_MkA = resolveComponent("MkA"); + return openBlock(), createBlock(MkContainer, { + "max-height": 300, + foldable: true + }, { + icon: withCtx(() => [ + _hoisted_1 + ]), + header: withCtx(() => [ + createTextVNode(toDisplayString(unref(i18n).ts.images), 1) + ]), + default: withCtx(() => [ + createBaseVNode("div", { + class: normalizeClass(_ctx.$style.root) + }, [ + unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { key: 0 })) : createCommentVNode("", true), + !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { + key: 1, + class: normalizeClass(_ctx.$style.stream) + }, [ + (openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), (image) => { + return openBlock(), createBlock(_component_MkA, { + key: image.note.id + image.file.id, + class: normalizeClass(_ctx.$style.img), + to: unref(notePage)(image.note) + }, { + default: withCtx(() => [ + createVNode(ImgWithBlurhash, { + hash: image.file.blurhash, + src: thumbnail(image.file), + title: image.file.name + }, null, 8, ["hash", "src", "title"]) + ]), + _: 2 + }, 1032, ["class", "to"]); + }), 128)) + ], 2)) : createCommentVNode("", true), + !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { + key: 2, + class: normalizeClass(_ctx.$style.empty) + }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true) + ], 2) + ]), + _: 1 + }); + }; + } +}); + +const root = "xenMW"; +const stream = "xaZzf"; +const img = "xtA8t"; +const empty = "xhYKj"; +const style0 = { + root: root, + stream: stream, + img: img, + empty: empty +}; + +const cssModules = { + "$style": style0 +}; +const index_photos = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); + +export { index_photos as default }; +`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); + unwindCssModuleClassName(ast); + expect(generate(ast)).toBe(` +import {c as api, d as defaultStore, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js'; +import {M as MkContainer} from './MkContainer-!~{03M}~.js'; +import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js'; +import './photoswipe-!~{003}~.js'; +const _hoisted_1 = createBaseVNode("i", { + class: "ti ti-photo" +}, null, -1); +const _sfc_main = defineComponent({ + __name: "index.photos", + props: { + user: {} + }, + setup(__props) { + const props = __props; + let fetching = ref(true); + let images = ref([]); + function thumbnail(image) { + return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; + } + onMounted(() => { + const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"]; + api("users/notes", { + userId: props.user.id, + fileType: image, + excludeNsfw: defaultStore.state.nsfw !== "ignore", + limit: 10 + }).then(notes => { + for (const note of notes) { + for (const file of note.files) { + images.value.push({ + note, + file + }); + } + } + fetching.value = false; + }); + }); + return (_ctx, _cache) => { + const _component_MkLoading = resolveComponent("MkLoading"); + const _component_MkA = resolveComponent("MkA"); + return (openBlock(), createBlock(MkContainer, { + "max-height": 300, + foldable: true + }, { + icon: withCtx(() => [_hoisted_1]), + header: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).ts.images), 1)]), + default: withCtx(() => [createBaseVNode("div", { + class: "xenMW" + }, [unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { + key: 0 + })) : createCommentVNode("", true), !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { + key: 1, + class: "xaZzf" + }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), image => { + return (openBlock(), createBlock(_component_MkA, { + key: image.note.id + image.file.id, + class: "xtA8t", + to: unref(notePage)(image.note) + }, { + default: withCtx(() => [createVNode(ImgWithBlurhash, { + hash: image.file.blurhash, + src: thumbnail(image.file), + title: image.file.name + }, null, 8, ["hash", "src", "title"])]), + _: 2 + }, 1032, ["class", "to"])); + }), 128))], 2)) : createCommentVNode("", true), !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { + key: 2, + class: "xhYKj" + }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true)], 2)]), + _: 1 + })); + }; + } +}); +const root = "xenMW"; +const stream = "xaZzf"; +const img = "xtA8t"; +const empty = "xhYKj"; +const style0 = { + root: root, + stream: stream, + img: img, + empty: empty +}; +const cssModules = { + "$style": style0 +}; +const index_photos = _sfc_main; +export {index_photos as default}; +`.slice(1)); +}); + +it('Composition API (with `useCssModule()`)', () => { + const ast = parse(` +import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; +import { d as defaultStore, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; + +function isDebuggerEnabled(id) { + try { + return localStorage.getItem(\`DEBUG_\${id}\`) !== null; + } catch { + return false; + } +} +function stackTraceInstances() { + let instance = getCurrentInstance(); + const stack = []; + while (instance) { + stack.push(instance); + instance = instance.parent; + } + return stack; +} + +const _sfc_main = defineComponent({ + props: { + items: { + type: Array, + required: true + }, + direction: { + type: String, + required: false, + default: "down" + }, + reversed: { + type: Boolean, + required: false, + default: false + }, + noGap: { + type: Boolean, + required: false, + default: false + }, + ad: { + type: Boolean, + required: false, + default: false + } + }, + setup(props, { slots, expose }) { + const $style = useCssModule(); + function getDateText(time) { + const date = new Date(time).getDate(); + const month = new Date(time).getMonth() + 1; + return i18n.t("monthAndDay", { + month: month.toString(), + day: date.toString() + }); + } + if (props.items.length === 0) + return; + const renderChildrenImpl = () => props.items.map((item, i) => { + if (!slots || !slots.default) + return; + const el = slots.default({ + item + })[0]; + if (el.key == null && item.id) + el.key = item.id; + if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { + const separator = h("div", { + class: $style["separator"], + key: item.id + ":separator" + }, h("p", { + class: $style["date"] + }, [ + h("span", { + class: $style["date-1"] + }, [ + h("i", { + class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` + }), + getDateText(item.createdAt) + ]), + h("span", { + class: $style["date-2"] + }, [ + getDateText(props.items[i + 1].createdAt), + h("i", { + class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` + }) + ]) + ])); + return [el, separator]; + } else { + if (props.ad && item._shouldInsertAd_) { + return [h(MkAd, { + key: item.id + ":ad", + prefer: ["horizontal", "horizontal-big"] + }), el]; + } else { + return el; + } + } + }); + const renderChildren = () => { + const children = renderChildrenImpl(); + if (isDebuggerEnabled(6864)) { + const nodes = children.flatMap((node) => node ?? []); + const keys = new Set(nodes.map((node) => node.key)); + if (keys.size !== nodes.length) { + const id = crypto.randomUUID(); + const instances = stackTraceInstances(); + toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); + console.warn({ id, debugId: 6864, stack: instances }); + } + } + return children; + }; + function onBeforeLeave(el) { + el.style.top = \`\${el.offsetTop}px\`; + el.style.left = \`\${el.offsetLeft}px\`; + } + function onLeaveCanceled(el) { + el.style.top = ""; + el.style.left = ""; + } + return () => h( + defaultStore.state.animation ? TransitionGroup : "div", + { + class: { + [$style["date-separated-list"]]: true, + [$style["date-separated-list-nogap"]]: props.noGap, + [$style["reversed"]]: props.reversed, + [$style["direction-down"]]: props.direction === "down", + [$style["direction-up"]]: props.direction === "up" + }, + ...defaultStore.state.animation ? { + name: "list", + tag: "div", + onBeforeLeave, + onLeaveCanceled + } : {} + }, + { default: renderChildren } + ); + } +}); + +const reversed = "xxiZh"; +const separator = "xxeDx"; +const date = "xxawD"; +const style0 = { + "date-separated-list": "xfKPa", + "date-separated-list-nogap": "xf9zr", + "direction-up": "x7AeO", + "direction-down": "xBIqc", + reversed: reversed, + separator: separator, + date: date, + "date-1": "xwtmh", + "date-1-icon": "xsNPa", + "date-2": "x1xvw", + "date-2-icon": "x9ZiG" +}; + +const cssModules = { + "$style": style0 +}; +const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); + +export { MkDateSeparatedList as M }; +`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); + unwindCssModuleClassName(ast); + expect(generate(ast)).toBe(` +import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js'; +import {d as defaultStore, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js'; +function isDebuggerEnabled(id) { + try { + return localStorage.getItem(\`DEBUG_\${id}\`) !== null; + } catch { + return false; + } +} +function stackTraceInstances() { + let instance = getCurrentInstance(); + const stack = []; + while (instance) { + stack.push(instance); + instance = instance.parent; + } + return stack; +} +const _sfc_main = defineComponent({ + props: { + items: { + type: Array, + required: true + }, + direction: { + type: String, + required: false, + default: "down" + }, + reversed: { + type: Boolean, + required: false, + default: false + }, + noGap: { + type: Boolean, + required: false, + default: false + }, + ad: { + type: Boolean, + required: false, + default: false + } + }, + setup(props, {slots, expose}) { + const $style = useCssModule(); + function getDateText(time) { + const date = new Date(time).getDate(); + const month = new Date(time).getMonth() + 1; + return i18n.t("monthAndDay", { + month: month.toString(), + day: date.toString() + }); + } + if (props.items.length === 0) return; + const renderChildrenImpl = () => props.items.map((item, i) => { + if (!slots || !slots.default) return; + const el = slots.default({ + item + })[0]; + if (el.key == null && item.id) el.key = item.id; + if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { + const separator = h("div", { + class: $style["separator"], + key: item.id + ":separator" + }, h("p", { + class: $style["date"] + }, [h("span", { + class: $style["date-1"] + }, [h("i", { + class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` + }), getDateText(item.createdAt)]), h("span", { + class: $style["date-2"] + }, [getDateText(props.items[i + 1].createdAt), h("i", { + class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` + })])])); + return [el, separator]; + } else { + if (props.ad && item._shouldInsertAd_) { + return [h(MkAd, { + key: item.id + ":ad", + prefer: ["horizontal", "horizontal-big"] + }), el]; + } else { + return el; + } + } + }); + const renderChildren = () => { + const children = renderChildrenImpl(); + if (isDebuggerEnabled(6864)) { + const nodes = children.flatMap(node => node ?? []); + const keys = new Set(nodes.map(node => node.key)); + if (keys.size !== nodes.length) { + const id = crypto.randomUUID(); + const instances = stackTraceInstances(); + toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); + console.warn({ + id, + debugId: 6864, + stack: instances + }); + } + } + return children; + }; + function onBeforeLeave(el) { + el.style.top = \`\${el.offsetTop}px\`; + el.style.left = \`\${el.offsetLeft}px\`; + } + function onLeaveCanceled(el) { + el.style.top = ""; + el.style.left = ""; + } + return () => h(defaultStore.state.animation ? TransitionGroup : "div", { + class: { + [$style["date-separated-list"]]: true, + [$style["date-separated-list-nogap"]]: props.noGap, + [$style["reversed"]]: props.reversed, + [$style["direction-down"]]: props.direction === "down", + [$style["direction-up"]]: props.direction === "up" + }, + ...defaultStore.state.animation ? { + name: "list", + tag: "div", + onBeforeLeave, + onLeaveCanceled + } : {} + }, { + default: renderChildren + }); + } +}); +const reversed = "xxiZh"; +const separator = "xxeDx"; +const date = "xxawD"; +const style0 = { + "date-separated-list": "xfKPa", + "date-separated-list-nogap": "xf9zr", + "direction-up": "x7AeO", + "direction-down": "xBIqc", + reversed: reversed, + separator: separator, + date: date, + "date-1": "xwtmh", + "date-1-icon": "xsNPa", + "date-2": "x1xvw", + "date-2-icon": "x9ZiG" +}; +const cssModules = { + "$style": style0 +}; +const MkDateSeparatedList = _export_sfc(_sfc_main, [["__cssModules", cssModules]]); +export {MkDateSeparatedList as M}; +`.slice(1)); +}); diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts new file mode 100644 index 0000000000..a18f0d9049 --- /dev/null +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts @@ -0,0 +1,275 @@ +import { generate } from 'astring'; +import * as estree from 'estree'; +import { walk } from '../node_modules/estree-walker/src/index.js'; +import type * as estreeWalker from 'estree-walker'; +import type { Plugin } from 'vite'; + +function isFalsyIdentifier(identifier: estree.Identifier): boolean { + return identifier.name === 'undefined' || identifier.name === 'NaN'; +} + +function normalizeClassWalker(tree: estree.Node): string | null { + if (tree.type === 'Identifier') return isFalsyIdentifier(tree) ? '' : null; + if (tree.type === 'Literal') return typeof tree.value === 'string' ? tree.value : ''; + if (tree.type === 'BinaryExpression') { + if (tree.operator !== '+') return null; + const left = normalizeClassWalker(tree.left); + const right = normalizeClassWalker(tree.right); + if (left === null || right === null) return null; + return `${left}${right}`; + } + if (tree.type === 'TemplateLiteral') { + if (tree.expressions.some((x) => x.type !== 'Literal' && (x.type !== 'Identifier' || !isFalsyIdentifier(x)))) return null; + return tree.quasis.reduce((a, c, i) => { + const v = i === tree.quasis.length - 1 ? '' : (tree.expressions[i] as Partial<estree.Literal>).value; + return a + c.value.raw + (typeof v === 'string' ? v : ''); + }, ''); + } + if (tree.type === 'ArrayExpression') { + const values = tree.elements.map((treeNode) => { + if (treeNode === null) return ''; + if (treeNode.type === 'SpreadElement') return normalizeClassWalker(treeNode.argument); + return normalizeClassWalker(treeNode); + }); + if (values.some((x) => x === null)) return null; + return values.join(' '); + } + if (tree.type === 'ObjectExpression') { + const values = tree.properties.map((treeNode) => { + if (treeNode.type === 'SpreadElement') return normalizeClassWalker(treeNode.argument); + let x = treeNode.value; + let inveted = false; + while (x.type === 'UnaryExpression' && x.operator === '!') { + x = x.argument; + inveted = !inveted; + } + if (x.type === 'Literal') { + if (inveted === !x.value) { + return treeNode.key.type === 'Identifier' ? treeNode.computed ? null : treeNode.key.name : treeNode.key.type === 'Literal' ? treeNode.key.value : ''; + } else { + return ''; + } + } + if (x.type === 'Identifier') { + if (inveted !== isFalsyIdentifier(x)) { + return ''; + } else { + return null; + } + } + return null; + }); + if (values.some((x) => x === null)) return null; + return values.join(' '); + } + console.error(`Unexpected node type: ${tree.type}`); + return null; +} + +export function normalizeClass(tree: estree.Node): string | null { + const walked = normalizeClassWalker(tree); + return walked && walked.replace(/^\s+|\s+(?=\s)|\s+$/g, ''); +} + +export function unwindCssModuleClassName(ast: estree.Node): void { + (walk as typeof estreeWalker.walk)(ast, { + enter(node, parent): void { + if (parent?.type !== 'Program') return; + if (node.type !== 'VariableDeclaration') return; + if (node.declarations.length !== 1) return; + if (node.declarations[0].id.type !== 'Identifier') return; + const name = node.declarations[0].id.name; + if (node.declarations[0].init?.type !== 'CallExpression') return; + if (node.declarations[0].init.callee.type !== 'Identifier') return; + if (node.declarations[0].init.callee.name !== '_export_sfc') return; + if (node.declarations[0].init.arguments.length !== 2) return; + if (node.declarations[0].init.arguments[0].type !== 'Identifier') return; + const ident = node.declarations[0].init.arguments[0].name; + if (!ident.startsWith('_sfc_main')) return; + if (node.declarations[0].init.arguments[1].type !== 'ArrayExpression') return; + if (node.declarations[0].init.arguments[1].elements.length === 0) return; + const __cssModulesIndex = node.declarations[0].init.arguments[1].elements.findIndex((x) => { + if (x?.type !== 'ArrayExpression') return false; + if (x.elements.length !== 2) return false; + if (x.elements[0]?.type !== 'Literal') return false; + if (x.elements[0].value !== '__cssModules') return false; + if (x.elements[1]?.type !== 'Identifier') return false; + return true; + }); + if (!~__cssModulesIndex) return; + const cssModuleForestName = ((node.declarations[0].init.arguments[1].elements[__cssModulesIndex] as estree.ArrayExpression).elements[1] as estree.Identifier).name; + const cssModuleForestNode = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== cssModuleForestName) return false; + if (x.declarations[0].init?.type !== 'ObjectExpression') return false; + return true; + }) as unknown as estree.VariableDeclaration; + const moduleForest = new Map((cssModuleForestNode.declarations[0].init as estree.ObjectExpression).properties.flatMap((property) => { + if (property.type !== 'Property') return []; + if (property.key.type !== 'Literal') return []; + if (property.value.type !== 'Identifier') return []; + return [[property.key.value as string, property.value.name as string]]; + })); + const sfcMain = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== ident) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (sfcMain.declarations[0].init?.type !== 'CallExpression') return; + if (sfcMain.declarations[0].init.callee.type !== 'Identifier') return; + if (sfcMain.declarations[0].init.callee.name !== 'defineComponent') return; + if (sfcMain.declarations[0].init.arguments.length !== 1) return; + if (sfcMain.declarations[0].init.arguments[0].type !== 'ObjectExpression') return; + const setup = sfcMain.declarations[0].init.arguments[0].properties.find((x) => { + if (x.type !== 'Property') return false; + if (x.key.type !== 'Identifier') return false; + if (x.key.name !== 'setup') return false; + return true; + }) as unknown as estree.Property; + if (setup.value.type !== 'FunctionExpression') return; + const render = setup.value.body.body.find((x) => { + if (x.type !== 'ReturnStatement') return false; + return true; + }) as unknown as estree.ReturnStatement; + if (render.argument?.type !== 'ArrowFunctionExpression') return; + if (render.argument.params.length !== 2) return; + const ctx = render.argument.params[0]; + if (ctx.type !== 'Identifier') return; + if (ctx.name !== '_ctx') return; + if (render.argument.body.type !== 'BlockStatement') return; + for (const [key, value] of moduleForest) { + const cssModuleTreeNode = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== value) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (cssModuleTreeNode.declarations[0].init?.type !== 'ObjectExpression') return; + const moduleTree = new Map(cssModuleTreeNode.declarations[0].init.properties.flatMap((property) => { + if (property.type !== 'Property') return []; + const actualKey = property.key.type === 'Identifier' ? property.key.name : property.key.type === 'Literal' ? property.key.value : null; + if (typeof actualKey !== 'string') return []; + if (property.value.type === 'Literal') return [[actualKey, property.value.value as string]]; + if (property.value.type !== 'Identifier') return []; + const labelledValue = property.value.name; + const actualValue = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== labelledValue) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (actualValue.declarations[0].init?.type !== 'Literal') return []; + return [[actualKey, actualValue.declarations[0].init.value as string]]; + })); + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { + if (childNode.type !== 'MemberExpression') return; + if (childNode.object.type !== 'MemberExpression') return; + if (childNode.object.object.type !== 'Identifier') return; + if (childNode.object.object.name !== ctx.name) return; + if (childNode.object.property.type !== 'Identifier') return; + if (childNode.object.property.name !== key) return; + if (childNode.property.type !== 'Identifier') return; + const actualValue = moduleTree.get(childNode.property.name); + if (actualValue === undefined) return; + this.replace({ + type: 'Literal', + value: actualValue, + }); + }, + }); + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { + if (childNode.type !== 'MemberExpression') return; + if (childNode.object.type !== 'MemberExpression') return; + if (childNode.object.object.type !== 'Identifier') return; + if (childNode.object.object.name !== ctx.name) return; + if (childNode.object.property.type !== 'Identifier') return; + if (childNode.object.property.name !== key) return; + if (childNode.property.type !== 'Identifier') return; + console.error(`Undefined style detected: ${key}.${childNode.property.name} (in ${name})`); + this.replace({ + type: 'Identifier', + name: 'undefined', + }); + }, + }); + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { + if (childNode.type !== 'CallExpression') return; + if (childNode.callee.type !== 'Identifier') return; + if (childNode.callee.name !== 'normalizeClass') return; + if (childNode.arguments.length !== 1) return; + const normalized = normalizeClass(childNode.arguments[0]); + if (normalized === null) return; + this.replace({ + type: 'Literal', + value: normalized, + }); + }, + }); + } + if (node.declarations[0].init.arguments[1].elements.length === 1) { + this.replace({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: node.declarations[0].id.name, + }, + init: { + type: 'Identifier', + name: ident, + }, + }], + kind: 'const', + }); + } else { + this.replace({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: node.declarations[0].id.name, + }, + init: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '_export_sfc', + }, + arguments: [{ + type: 'Identifier', + name: ident, + }, { + type: 'ArrayExpression', + elements: node.declarations[0].init.arguments[1].elements.slice(0, __cssModulesIndex).concat(node.declarations[0].init.arguments[1].elements.slice(__cssModulesIndex + 1)), + }], + }, + }], + kind: 'const', + }); + } + }, + }); +} + +// eslint-disable-next-line import/no-default-export +export default function pluginUnwindCssModuleClassName(): Plugin { + return { + name: 'UnwindCssModuleClassName', + renderChunk(code): { code: string } { + const ast = this.parse(code) as unknown as estree.Node; + unwindCssModuleClassName(ast); + return { code: generate(ast) }; + }, + }; +} diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 84f3d9ce63..6720a5939b 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -24,6 +24,7 @@ "@vitejs/plugin-vue": "4.2.3", "@vue-macros/reactivity-transform": "0.3.8", "@vue/compiler-sfc": "3.3.4", + "astring": "1.8.5", "autosize": "6.0.1", "broadcast-channel": "4.20.2", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", @@ -39,6 +40,7 @@ "cropperjs": "2.0.0-beta.2", "date-fns": "2.30.0", "escape-regexp": "0.0.1", + "estree-walker": "^3.0.3", "eventemitter3": "5.0.1", "gsap": "3.11.5", "idb-keyval": "6.2.1", @@ -116,7 +118,7 @@ "@typescript-eslint/parser": "5.59.5", "@vitest/coverage-c8": "0.31.1", "@vue/runtime-core": "3.3.4", - "astring": "1.8.5", + "acorn": "^8.8.2", "chokidar-cli": "3.0.0", "cross-env": "7.0.3", "cypress": "12.13.0", diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue index d30037dcf9..3fdb261dac 100644 --- a/packages/frontend/src/components/MkAchievements.vue +++ b/packages/frontend/src/components/MkAchievements.vue @@ -3,7 +3,14 @@ <div v-if="achievements" :class="$style.root"> <div v-for="achievement in achievements" :key="achievement" :class="$style.achievement" class="_panel"> <div :class="$style.icon"> - <div :class="[$style.iconFrame, $style['iconFrame_' + ACHIEVEMENT_BADGES[achievement.name].frame]]"> + <div + :class="[$style.iconFrame, { + [$style.iconFrame_bronze]: ACHIEVEMENT_BADGES[achievement.name].frame === 'bronze', + [$style.iconFrame_silver]: ACHIEVEMENT_BADGES[achievement.name].frame === 'silver', + [$style.iconFrame_gold]: ACHIEVEMENT_BADGES[achievement.name].frame === 'gold', + [$style.iconFrame_platinum]: ACHIEVEMENT_BADGES[achievement.name].frame === 'platinum', + }]" + > <div :class="[$style.iconInner]" :style="{ background: ACHIEVEMENT_BADGES[achievement.name].bg }"> <img :class="$style.iconImg" :src="ACHIEVEMENT_BADGES[achievement.name].img"> </div> diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 1af998dedd..fd892d8174 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -10,7 +10,7 @@ </li> <li tabindex="-1" :class="$style.item" @click="chooseUser()" @keydown="onKeydown">{{ i18n.ts.selectUser }}</li> </ol> - <ol v-else-if="hashtags.length > 0" ref="suggests" :class="[$style.list, $style.hashtags]"> + <ol v-else-if="hashtags.length > 0" ref="suggests" :class="$style.list"> <li v-for="hashtag in hashtags" tabindex="-1" :class="$style.item" @click="complete(type, hashtag)" @keydown="onKeydown"> <span class="name">{{ hashtag }}</span> </li> diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 6de6a4cc70..16e44ec618 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -7,7 +7,7 @@ @click="emit('click', $event)" @mousedown="onMousedown" > - <div ref="ripples" :class="$style.ripples"></div> + <div ref="ripples" :class="$style.ripples" :data-children-class="$style.ripple"></div> <div :class="$style.content"> <slot></slot> </div> @@ -18,7 +18,7 @@ :to="to" @mousedown="onMousedown" > - <div ref="ripples" :class="$style.ripples"></div> + <div ref="ripples" :class="$style.ripples" :data-children-class="$style.ripple"></div> <div :class="$style.content"> <slot></slot> </div> @@ -26,9 +26,7 @@ </template> <script lang="ts" setup> -import { nextTick, onMounted, useCssModule } from 'vue'; - -const $style = useCssModule(); +import { nextTick, onMounted } from 'vue'; const props = defineProps<{ type?: 'button' | 'submit' | 'reset'; @@ -81,7 +79,7 @@ function onMousedown(evt: MouseEvent): void { const rect = target.getBoundingClientRect(); const ripple = document.createElement('div'); - ripple.classList.add($style.ripple); + ripple.classList.add(ripples!.dataset.childrenClass!); ripple.style.top = (evt.clientY - rect.top - 1).toString() + 'px'; ripple.style.left = (evt.clientX - rect.left - 1).toString() + 'px'; diff --git a/packages/frontend/src/components/MkClickerGame.vue b/packages/frontend/src/components/MkClickerGame.vue index da6439fd2c..a6ab5aded4 100644 --- a/packages/frontend/src/components/MkClickerGame.vue +++ b/packages/frontend/src/components/MkClickerGame.vue @@ -3,7 +3,7 @@ <div v-if="game.ready" :class="$style.game"> <div :class="$style.cps" class="">{{ number(cps) }}cps</div> <div :class="$style.count" class=""><i class="ti ti-cookie" style="font-size: 70%;"></i> {{ number(cookies) }}</div> - <button v-click-anime class="_button" :class="$style.button" @click="onClick"> + <button v-click-anime class="_button" @click="onClick"> <img src="/client-assets/cookie.png" :class="$style.img"> </button> </div> @@ -84,10 +84,6 @@ onUnmounted(() => { margin-bottom: 6px; } -.button { - -} - .img { max-width: 90px; } diff --git a/packages/frontend/src/components/MkContainer.vue b/packages/frontend/src/components/MkContainer.vue index f7cc697d67..af1c57b349 100644 --- a/packages/frontend/src/components/MkContainer.vue +++ b/packages/frontend/src/components/MkContainer.vue @@ -1,5 +1,5 @@ <template> -<div ref="rootEl" class="_panel" :class="[$style.root, { [$style.naked]: naked, [$style.thin]: thin, [$style.hideHeader]: !showHeader, [$style.scrollable]: scrollable, [$style.closed]: !showBody }]"> +<div ref="rootEl" class="_panel" :class="[$style.root, { [$style.naked]: naked, [$style.thin]: thin, [$style.scrollable]: scrollable }]"> <header v-if="showHeader" ref="headerEl" :class="$style.header"> <div :class="$style.title"> <span :class="$style.titleIcon"><slot name="icon"></slot></span> diff --git a/packages/frontend/src/components/MkDateSeparatedList.vue b/packages/frontend/src/components/MkDateSeparatedList.vue index d6303f9675..6942a0e6c3 100644 --- a/packages/frontend/src/components/MkDateSeparatedList.vue +++ b/packages/frontend/src/components/MkDateSeparatedList.vue @@ -36,7 +36,7 @@ export default defineComponent({ }, setup(props, { slots, expose }) { - const $style = useCssModule(); + const $style = useCssModule(); // カスタムレンダラなので使っても大丈夫 function getDateText(time: string) { const date = new Date(time).getDate(); const month = new Date(time).getMonth() + 1; diff --git a/packages/frontend/src/components/MkDialog.vue b/packages/frontend/src/components/MkDialog.vue index bd4da6c545..4d5df0bba4 100644 --- a/packages/frontend/src/components/MkDialog.vue +++ b/packages/frontend/src/components/MkDialog.vue @@ -4,7 +4,15 @@ <div v-if="icon" :class="$style.icon"> <i :class="icon"></i> </div> - <div v-else-if="!input && !select" :class="[$style.icon, $style['type_' + type]]"> + <div + v-else-if="!input && !select" + :class="[$style.icon, { + [$style.type_success]: type === 'success', + [$style.type_error]: type === 'error', + [$style.type_warning]: type === 'warning', + [$style.type_info]: type === 'info', + }]" + > <i v-if="type === 'success'" :class="$style.iconInner" class="ti ti-check"></i> <i v-else-if="type === 'error'" :class="$style.iconInner" class="ti ti-circle-x"></i> <i v-else-if="type === 'warning'" :class="$style.iconInner" class="ti ti-alert-triangle"></i> diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index 526f5e94ea..70f0cc5cda 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -5,7 +5,7 @@ <div :class="[$style.header, { [$style.opened]: opened }]" class="_button" role="button" data-cy-folder-header @click="toggle"> <div :class="$style.headerIcon"><slot name="icon"></slot></div> <div :class="$style.headerText"> - <div :class="$style.headerTextMain"> + <div> <MkCondensedLine :minScale="2 / 3"><slot name="label"></slot></MkCondensedLine> </div> <div :class="$style.headerTextSub"> @@ -185,10 +185,6 @@ onMounted(() => { padding-right: 12px; } -.headerTextMain { - -} - .headerTextSub { color: var(--fgTransparentWeak); font-size: .85em; diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 38406cc0be..3750dacddc 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -3,7 +3,7 @@ <TransitionGroup :duration="defaultStore.state.animation && props.transition?.duration || undefined" :enterActiveClass="defaultStore.state.animation && props.transition?.enterActiveClass || undefined" - :leaveActiveClass="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style['transition_leaveActive']) || undefined" + :leaveActiveClass="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style.transition_leaveActive) || undefined" :enterFromClass="defaultStore.state.animation && props.transition?.enterFromClass || undefined" :leaveToClass="defaultStore.state.animation && props.transition?.leaveToClass || undefined" :enterToClass="defaultStore.state.animation && props.transition?.enterToClass || undefined" @@ -42,11 +42,10 @@ const workerPromise = new Promise<WorkerMultiDispatch | null>(resolve => { </script> <script lang="ts" setup> -import { computed, nextTick, onMounted, onUnmounted, shallowRef, useCssModule, watch } from 'vue'; +import { computed, nextTick, onMounted, onUnmounted, shallowRef, watch } from 'vue'; import { v4 as uuid } from 'uuid'; import { render } from 'buraha'; import { defaultStore } from '@/store'; -const $style = useCssModule(); const props = withDefaults(defineProps<{ transition?: { diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue index 0f41ef248f..a0a2450054 100644 --- a/packages/frontend/src/components/MkMediaList.vue +++ b/packages/frontend/src/components/MkMediaList.vue @@ -6,8 +6,11 @@ ref="gallery" :class="[ $style.medias, - count <= 4 ? $style['n' + count] : $style.nMany, - $style[`n1${defaultStore.reactiveState.mediaListWithOneImageAppearance.value}`] + count === 1 ? [$style.n1, { + [$style.n116_9]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '16_9', + [$style.n11_1]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '1_1', + [$style.n12_3]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '2_3', + }] : count === 2 ? $style.n2 : count === 3 ? $style.n3 : count === 4 ? $style.n4 : $style.nMany, ]" > <template v-for="media in mediaList.filter(media => previewable(media))"> @@ -20,7 +23,7 @@ </template> <script lang="ts" setup> -import { onMounted, ref, useCssModule, watch, shallowRef } from 'vue'; +import { onMounted, watch, shallowRef } from 'vue'; import * as misskey from 'misskey-js'; import PhotoSwipeLightbox from 'photoswipe/lightbox'; import PhotoSwipe from 'photoswipe'; @@ -37,8 +40,6 @@ const props = defineProps<{ raw?: boolean; }>(); -const $style = useCssModule(); - const gallery = shallowRef<HTMLDivElement>(); const pswpZIndex = os.claimZIndex('middle'); document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString()); @@ -96,7 +97,7 @@ onMounted(() => { return item; }), gallery: gallery.value, - mainClass: $style.pswp, + mainClass: 'pswp', children: '.image', thumbSelector: '.image', loop: false, @@ -268,7 +269,7 @@ const previewable = (file: misskey.entities.DriveFile): boolean => { border-radius: 8px; } -.pswp { +:global(.pswp) { --pswp-root-z-index: var(--mk-pswp-root-z-index, 2000700) !important; --pswp-bg: var(--modalBg) !important; } diff --git a/packages/frontend/src/components/MkMention.vue b/packages/frontend/src/components/MkMention.vue index 481c3710ca..bb256c394b 100644 --- a/packages/frontend/src/components/MkMention.vue +++ b/packages/frontend/src/components/MkMention.vue @@ -2,7 +2,7 @@ <MkA v-user-preview="canonical" :class="[$style.root, { [$style.isMe]: isMe }]" :to="url" :style="{ background: bgCss }"> <img :class="$style.icon" :src="`/avatar/@${username}@${host}`" alt=""> <span> - <span :class="$style.username">@{{ username }}</span> + <span>@{{ username }}</span> <span v-if="(host != localHost) || defaultStore.state.showFullAcct" :class="$style.host">@{{ toUnicode(host) }}</span> </span> </MkA> diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 2697e3e21a..7dd6a8c88f 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -49,7 +49,7 @@ <span>{{ i18n.ts.none }}</span> </span> </div> - <div v-if="childMenu" :class="$style.child"> + <div v-if="childMenu"> <XChild ref="child" :items="childMenu" :targetElement="childTarget" :rootElement="itemsEl" showing @actioned="childActioned"/> </div> </div> diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue index b9ce6de697..bb5c6c7aab 100644 --- a/packages/frontend/src/components/MkModal.vue +++ b/packages/frontend/src/components/MkModal.vue @@ -1,10 +1,30 @@ <template> <Transition :name="transitionName" - :enterActiveClass="$style['transition_' + transitionName + '_enterActive']" - :leaveActiveClass="$style['transition_' + transitionName + '_leaveActive']" - :enterFromClass="$style['transition_' + transitionName + '_enterFrom']" - :leaveToClass="$style['transition_' + transitionName + '_leaveTo']" + :enterActiveClass="normalizeClass({ + [$style.transition_modalDrawer_enterActive]: transitionName === 'modal-drawer', + [$style.transition_modalPopup_enterActive]: transitionName === 'modal-popup', + [$style.transition_modal_enterActive]: transitionName === 'modal', + [$style.transition_send_enterActive]: transitionName === 'send', + })" + :leaveActiveClass="normalizeClass({ + [$style.transition_modalDrawer_leaveActive]: transitionName === 'modal-drawer', + [$style.transition_modalPopup_leaveActive]: transitionName === 'modal-popup', + [$style.transition_modal_leaveActive]: transitionName === 'modal', + [$style.transition_send_leaveActive]: transitionName === 'send', + })" + :enterFromClass="normalizeClass({ + [$style.transition_modalDrawer_enterFrom]: transitionName === 'modal-drawer', + [$style.transition_modalPopup_enterFrom]: transitionName === 'modal-popup', + [$style.transition_modal_enterFrom]: transitionName === 'modal', + [$style.transition_send_enterFrom]: transitionName === 'send', + })" + :leaveToClass="normalizeClass({ + [$style.transition_modalDrawer_leaveTo]: transitionName === 'modal-drawer', + [$style.transition_modalPopup_leaveTo]: transitionName === 'modal-popup', + [$style.transition_modal_leaveTo]: transitionName === 'modal', + [$style.transition_send_leaveTo]: transitionName === 'send', + })" :duration="transitionDuration" appear @afterLeave="emit('closed')" @enter="emit('opening')" @afterEnter="onOpened" > <div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> @@ -17,7 +37,7 @@ </template> <script lang="ts" setup> -import { nextTick, onMounted, watch, provide, onUnmounted } from 'vue'; +import { nextTick, normalizeClass, onMounted, onUnmounted, provide, watch } from 'vue'; import * as os from '@/os'; import { isTouchUsing } from '@/scripts/touch'; import { defaultStore } from '@/store'; @@ -345,8 +365,8 @@ defineExpose({ } } -.transition_modal-popup_enterActive, -.transition_modal-popup_leaveActive { +.transition_modalPopup_enterActive, +.transition_modalPopup_leaveActive { > .bg { transition: opacity 0.1s !important; } @@ -356,8 +376,8 @@ defineExpose({ transition: opacity 0.1s cubic-bezier(0, 0, 0.2, 1), transform 0.1s cubic-bezier(0, 0, 0.2, 1) !important; } } -.transition_modal-popup_enterFrom, -.transition_modal-popup_leaveTo { +.transition_modalPopup_enterFrom, +.transition_modalPopup_leaveTo { > .bg { opacity: 0; } @@ -370,7 +390,7 @@ defineExpose({ } } -.transition_modal-drawer_enterActive { +.transition_modalDrawer_enterActive { > .bg { transition: opacity 0.2s !important; } @@ -379,7 +399,7 @@ defineExpose({ transition: transform 0.2s cubic-bezier(0,.5,0,1) !important; } } -.transition_modal-drawer_leaveActive { +.transition_modalDrawer_leaveActive { > .bg { transition: opacity 0.2s !important; } @@ -388,8 +408,8 @@ defineExpose({ transition: transform 0.2s cubic-bezier(0,.5,0,1) !important; } } -.transition_modal-drawer_enterFrom, -.transition_modal-drawer_leaveTo { +.transition_modalDrawer_enterFrom, +.transition_modalDrawer_leaveTo { > .bg { opacity: 0; } diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 30ec9123bb..2483204d4c 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -44,8 +44,8 @@ <div v-if="appearNote.channel" :class="$style.colorBar" :style="{ background: appearNote.channel.color }"></div> <MkAvatar :class="$style.avatar" :user="appearNote.user" link preview/> <div :class="$style.main"> - <MkNoteHeader :class="$style.header" :note="appearNote" :mini="true"/> - <MkInstanceTicker v-if="showTicker" :class="$style.ticker" :instance="appearNote.user.instance"/> + <MkNoteHeader :note="appearNote" :mini="true"/> + <MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/> <div style="container-type: inline-size;"> <p v-if="appearNote.cw != null" :class="$style.cw"> <Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :i="$i"/> @@ -58,13 +58,13 @@ <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> <div v-if="translating || translation" :class="$style.translation"> <MkLoading v-if="translating" mini/> - <div v-else :class="$style.translated"> + <div v-else> <b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b> <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> </div> </div> </div> - <div v-if="appearNote.files.length > 0" :class="$style.files"> + <div v-if="appearNote.files.length > 0"> <MkMediaList :mediaList="appearNote.files"/> </div> <MkPoll v-if="appearNote.poll" :note="appearNote" :class="$style.poll"/> diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 19aa73127b..a65039277b 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -52,7 +52,7 @@ </div> </div> <div :class="$style.noteHeaderUsername"><MkAcct :user="appearNote.user"/></div> - <MkInstanceTicker v-if="showTicker" :class="$style.ticker" :instance="appearNote.user.instance"/> + <MkInstanceTicker v-if="showTicker" :instance="appearNote.user.instance"/> </div> </header> <div :class="$style.noteContent"> @@ -72,7 +72,7 @@ <Mfm :text="translation.text" :author="appearNote.user" :i="$i" :emojiUrls="appearNote.emojis"/> </div> </div> - <div v-if="appearNote.files.length > 0" :class="$style.files"> + <div v-if="appearNote.files.length > 0"> <MkMediaList :mediaList="appearNote.files"/> </div> <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" :class="$style.poll"/> diff --git a/packages/frontend/src/components/MkNotePreview.vue b/packages/frontend/src/components/MkNotePreview.vue index 6b55c27869..6786f8b256 100644 --- a/packages/frontend/src/components/MkNotePreview.vue +++ b/packages/frontend/src/components/MkNotePreview.vue @@ -6,7 +6,7 @@ <MkUserName :user="$i" :nowrap="true"/> </div> <div> - <div :class="$style.content"> + <div> <Mfm :text="text.trim()" :author="$i" :i="$i"/> </div> </div> diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index b4c424e79e..d25332b10f 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -5,7 +5,19 @@ <MkAvatar v-else-if="notification.type === 'achievementEarned'" :class="$style.icon" :user="$i" link preview/> <MkAvatar v-else-if="notification.user" :class="$style.icon" :user="notification.user" link preview/> <img v-else-if="notification.icon" :class="$style.icon" :src="notification.icon" alt=""/> - <div :class="[$style.subIcon, $style['t_' + notification.type]]"> + <div + :class="[$style.subIcon, { + [$style.t_follow]: notification.type === 'follow', + [$style.t_followRequestAccepted]: notification.type === 'followRequestAccepted', + [$style.t_receiveFollowRequest]: notification.type === 'receiveFollowRequest', + [$style.t_renote]: notification.type === 'renote', + [$style.t_reply]: notification.type === 'reply', + [$style.t_mention]: notification.type === 'mention', + [$style.t_quote]: notification.type === 'quote', + [$style.t_pollEnded]: notification.type === 'pollEnded', + [$style.t_achievementEarned]: notification.type === 'achievementEarned', + }]" + > <i v-if="notification.type === 'follow'" class="ti ti-plus"></i> <i v-else-if="notification.type === 'receiveFollowRequest'" class="ti ti-clock"></i> <i v-else-if="notification.type === 'followRequestAccepted'" class="ti ti-check"></i> @@ -34,7 +46,7 @@ <span v-else>{{ notification.header }}</span> <MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/> </header> - <div :class="$style.content"> + <div> <MkA v-if="notification.type === 'reaction'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)"> <i class="ti ti-quote" :class="$style.quote"></i> <Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/> @@ -243,9 +255,6 @@ useTooltip(reactionRef, (showing) => { font-size: 0.9em; } -.content { -} - .text { display: flex; width: 100%; diff --git a/packages/frontend/src/components/MkPoll.vue b/packages/frontend/src/components/MkPoll.vue index e2ca5603e3..464e340116 100644 --- a/packages/frontend/src/components/MkPoll.vue +++ b/packages/frontend/src/components/MkPoll.vue @@ -1,7 +1,7 @@ <template> <div :class="{ [$style.done]: closed || isVoted }"> <ul :class="$style.choices"> - <li v-for="(choice, i) in note.poll.choices" :key="i" :class="[$style.choice, { [$style.voted]: choice.voted }]" @click="vote(i)"> + <li v-for="(choice, i) in note.poll.choices" :key="i" :class="$style.choice" @click="vote(i)"> <div :class="$style.bg" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div> <span :class="$style.fg"> <template v-if="choice.isVoted"><i class="ti ti-check" style="margin-right: 4px; color: var(--accent);"></i></template> diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 731d171178..5c65569683 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -27,16 +27,16 @@ <span :class="$style.headerRightButtonText">{{ channel.name }}</span> </button> </template> - <button v-click-anime v-tooltip="i18n.ts._visibility.disableFederation" class="_button" :class="[$style.headerRightItem, $style.localOnly, { [$style.danger]: localOnly }]" :disabled="channel != null || visibility === 'specified'" @click="toggleLocalOnly"> + <button v-click-anime v-tooltip="i18n.ts._visibility.disableFederation" class="_button" :class="[$style.headerRightItem, { [$style.danger]: localOnly }]" :disabled="channel != null || visibility === 'specified'" @click="toggleLocalOnly"> <span v-if="!localOnly"><i class="ti ti-rocket"></i></span> <span v-else><i class="ti ti-rocket-off"></i></span> </button> - <button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" class="_button" :class="[$style.headerRightItem, $style.reactionAcceptance, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance"> + <button v-click-anime v-tooltip="i18n.ts.reactionAcceptance" class="_button" :class="[$style.headerRightItem, { [$style.danger]: reactionAcceptance === 'likeOnly' }]" @click="toggleReactionAcceptance"> <span v-if="reactionAcceptance === 'likeOnly'"><i class="ti ti-heart"></i></span> <span v-else-if="reactionAcceptance === 'likeOnlyForRemote'"><i class="ti ti-heart-plus"></i></span> <span v-else><i class="ti ti-icons"></i></span> </button> - <button v-click-anime class="_button" :class="[$style.submit, { [$style.submitPosting]: posting }]" :disabled="!canPost" data-cy-open-post-form-submit @click="post"> + <button v-click-anime class="_button" :class="$style.submit" :disabled="!canPost" data-cy-open-post-form-submit @click="post"> <div :class="$style.submitInner"> <template v-if="posted"></template> <template v-else-if="posting"><MkEllipsis/></template> @@ -66,7 +66,7 @@ <div v-if="maxTextLength - textLength < 100" :class="['_acrylic', $style.textCount, { [$style.textOver]: textLength > maxTextLength }]">{{ maxTextLength - textLength }}</div> </div> <input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" :class="$style.hashtags" :placeholder="i18n.ts.hashtags" list="hashtags"> - <XPostFormAttaches v-model="files" :class="$style.attaches" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/> + <XPostFormAttaches v-model="files" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/> <MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/> <MkNotePreview v-if="showPreview" :class="$style.preview" :text="text"/> <div v-if="showingOptions" style="padding: 8px 16px;"> diff --git a/packages/frontend/src/components/MkSubNoteContent.vue b/packages/frontend/src/components/MkSubNoteContent.vue index 5f32391c7e..3a050889c8 100644 --- a/packages/frontend/src/components/MkSubNoteContent.vue +++ b/packages/frontend/src/components/MkSubNoteContent.vue @@ -1,6 +1,6 @@ <template> <div :class="[$style.root, { [$style.collapsed]: collapsed }]"> - <div :class="$style.body"> + <div> <span v-if="note.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <span v-if="note.deletedAt" style="opacity: 0.5">({{ i18n.ts.deleted }})</span> <MkA v-if="note.replyId" :class="$style.reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> @@ -76,10 +76,6 @@ const collapsed = $ref( } } -.body { - -} - .reply { margin-right: 6px; color: var(--accent); diff --git a/packages/frontend/src/components/MkTextarea.vue b/packages/frontend/src/components/MkTextarea.vue index f5e6c71b75..83b2ed2444 100644 --- a/packages/frontend/src/components/MkTextarea.vue +++ b/packages/frontend/src/components/MkTextarea.vue @@ -6,7 +6,7 @@ ref="inputEl" v-model="v" v-adaptive-border - :class="[$style.textarea, { [$style.code]: code, _monospace: code }]" + :class="[$style.textarea, { _monospace: code }]" :disabled="disabled" :required="required" :readonly="readonly" diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue index 23be814322..fcad5b8064 100644 --- a/packages/frontend/src/components/MkUrlPreview.vue +++ b/packages/frontend/src/components/MkUrlPreview.vue @@ -22,7 +22,7 @@ </div> </template> <template v-else-if="tweetId && tweetExpanded"> - <div ref="twitter" :class="$style.twitter"> + <div ref="twitter"> <iframe ref="tweet" scrolling="no" frameborder="no" :style="{ position: 'relative', width: '100%', height: `${tweetHeight}px` }" :src="`https://platform.twitter.com/embed/index.html?embedId=${embedId}&hideCard=false&hideThread=false&lang=en&theme=${defaultStore.state.darkMode ? 'dark' : 'light'}&id=${tweetId}`"></iframe> </div> <div :class="$style.action"> @@ -31,7 +31,7 @@ </MkButton> </div> </template> -<div v-else :class="$style.urlPreview"> +<div v-else> <component :is="self ? 'MkA' : 'a'" :class="[$style.link, { [$style.compact]: compact }]" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url"> <div v-if="thumbnail" :class="$style.thumbnail" :style="`background-image: url('${thumbnail}')`"> </div> @@ -210,13 +210,6 @@ onUnmounted(() => { width: 100%; } -.twitter { - -} - -.urlPreview { -} - .link { position: relative; display: block; diff --git a/packages/frontend/src/components/MkUserOnlineIndicator.vue b/packages/frontend/src/components/MkUserOnlineIndicator.vue index 251ab5d79a..a2c2b53b08 100644 --- a/packages/frontend/src/components/MkUserOnlineIndicator.vue +++ b/packages/frontend/src/components/MkUserOnlineIndicator.vue @@ -1,5 +1,13 @@ <template> -<div v-tooltip="text" :class="[$style.root, $style['status_' + user.onlineStatus]]"></div> +<div + v-tooltip="text" + :class="[$style.root, { + [$style.status_online]: user.onlineStatus === 'online', + [$style.status_active]: user.onlineStatus === 'active', + [$style.status_offline]: user.onlineStatus === 'offline', + [$style.status_unknown]: user.onlineStatus === 'unknown', + }]" +></div> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue index 9ba5d9fc53..792ff7afd7 100644 --- a/packages/frontend/src/components/MkUserSelectDialog.vue +++ b/packages/frontend/src/components/MkUserSelectDialog.vue @@ -9,7 +9,7 @@ @closed="$emit('closed')" > <template #header>{{ i18n.ts.selectUser }}</template> - <div :class="$style.root"> + <div> <div :class="$style.form"> <FormSplit :minWidth="170"> <MkInput v-model="username" :autofocus="true" @update:modelValue="search"> @@ -126,8 +126,6 @@ onMounted(() => { </script> <style lang="scss" module> -.root { -} .form { padding: 0 var(--root-margin); diff --git a/packages/frontend/src/components/MkUsersTooltip.vue b/packages/frontend/src/components/MkUsersTooltip.vue index bed725cd1d..0b80c2edc7 100644 --- a/packages/frontend/src/components/MkUsersTooltip.vue +++ b/packages/frontend/src/components/MkUsersTooltip.vue @@ -3,9 +3,9 @@ <div :class="$style.root"> <div v-for="u in users" :key="u.id" :class="$style.user"> <MkAvatar :class="$style.avatar" :user="u"/> - <MkUserName :class="$style.name" :user="u" :nowrap="true"/> + <MkUserName :user="u" :nowrap="true"/> </div> - <div v-if="users.length < count" :class="$style.omitted">+{{ count - users.length }}</div> + <div v-if="users.length < count">+{{ count - users.length }}</div> </div> </MkTooltip> </template> @@ -43,14 +43,6 @@ const emit = defineEmits<{ } } -.name { - -} - -.omitted { - -} - .avatar { width: 24px; height: 24px; diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue index 6226768127..9566cc651f 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.vue @@ -39,7 +39,7 @@ <MkTimeline src="local"/> </div> </div> - <div :class="[$style.activeUsersChart, $style.panel]"> + <div :class="$style.panel"> <XActiveUsersChart/> </div> </div> @@ -220,8 +220,4 @@ function exploreOtherServers() { height: 350px; overflow: auto; } - -.activeUsersChart { - -} </style> diff --git a/packages/frontend/src/components/MkWidgets.vue b/packages/frontend/src/components/MkWidgets.vue index 9fd1d61632..30547c7444 100644 --- a/packages/frontend/src/components/MkWidgets.vue +++ b/packages/frontend/src/components/MkWidgets.vue @@ -1,7 +1,7 @@ <template> <div :class="$style.root"> <template v-if="edit"> - <header :class="$style['edit-header']"> + <header :class="$style.editHeader"> <MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--margin)" data-cy-widget-select> <template #label>{{ i18n.ts.selectWidget }}</template> <option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ i18n.t(`_widgets.${widget}`) }}</option> @@ -15,15 +15,15 @@ handle=".handle" :animation="150" :group="{ name: 'SortableMkWidgets' }" - :class="$style['edit-editing']" + :class="$style.editEditing" @update:modelValue="v => emit('updateWidgets', v)" > <template #item="{element}"> - <div :class="[$style.widget, $style['customize-container']]" data-cy-customize-container> - <button :class="$style['customize-container-config']" class="_button" @click.prevent.stop="configWidget(element.id)"><i class="ti ti-settings"></i></button> - <button :class="$style['customize-container-remove']" data-cy-customize-container-remove class="_button" @click.prevent.stop="removeWidget(element)"><i class="ti ti-x"></i></button> + <div :class="[$style.widget, $style.customizeContainer]" data-cy-customize-container> + <button :class="$style.customizeContainerConfig" class="_button" @click.prevent.stop="configWidget(element.id)"><i class="ti ti-settings"></i></button> + <button :class="$style.customizeContainerRemove" data-cy-customize-container-remove class="_button" @click.prevent.stop="removeWidget(element)"><i class="ti ti-x"></i></button> <div class="handle"> - <component :is="`widget-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style['customize-container-handle-widget']" :widget="element" @updateProps="updateWidget(element.id, $event)"/> + <component :is="`widget-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style.customizeContainerHandleWidget" :widget="element" @updateProps="updateWidget(element.id, $event)"/> </div> </div> </template> @@ -130,7 +130,7 @@ function onContextmenu(widget: Widget, ev: MouseEvent) { } .edit { - &-header { + &Header { margin: 16px 0; > * { @@ -139,17 +139,17 @@ function onContextmenu(widget: Widget, ev: MouseEvent) { } } - &-editing { + &Editing { min-height: 100px; } } -.customize-container { +.customizeContainer { position: relative; cursor: move; - &-config, - &-remove { + &Config, + &Remove { position: absolute; z-index: 10000; top: 8px; @@ -160,17 +160,17 @@ function onContextmenu(widget: Widget, ev: MouseEvent) { border-radius: 4px; } - &-config { + &Config { right: 8px + 8px + 32px; } - &-remove { + &Remove { right: 8px; } - &-handle { + &Handle { - &-widget { + &Widget { pointer-events: none; } } diff --git a/packages/frontend/src/components/form/link.vue b/packages/frontend/src/components/form/link.vue index e6da039ac5..22b5edc3c9 100644 --- a/packages/frontend/src/components/form/link.vue +++ b/packages/frontend/src/components/form/link.vue @@ -5,7 +5,7 @@ <span :class="$style.text"><slot></slot></span> <span :class="$style.suffix"> <span :class="$style.suffixText"><slot name="suffix"></slot></span> - <i class="ti ti-external-link" :class="$style.suffixIcon"></i> + <i class="ti ti-external-link"></i> </span> </a> <MkA v-else :class="[$style.main, { [$style.active]: active }]" class="_button" :to="to" :behavior="behavior"> @@ -13,7 +13,7 @@ <span :class="$style.text"><slot></slot></span> <span :class="$style.suffix"> <span :class="$style.suffixText"><slot name="suffix"></slot></span> - <i class="ti ti-chevron-right" :class="$style.suffixIcon"></i> + <i class="ti ti-chevron-right"></i> </span> </MkA> </div> diff --git a/packages/frontend/src/components/form/slot.vue b/packages/frontend/src/components/form/slot.vue index 792f664ea0..809d80620f 100644 --- a/packages/frontend/src/components/form/slot.vue +++ b/packages/frontend/src/components/form/slot.vue @@ -1,7 +1,7 @@ <template> <div> <div :class="$style.label" @click="focus"><slot name="label"></slot></div> - <div :class="$style.content"> + <div> <slot></slot> </div> <div :class="$style.caption"><slot name="caption"></slot></div> diff --git a/packages/frontend/src/components/global/MkAd.vue b/packages/frontend/src/components/global/MkAd.vue index aa975600f0..8b25ab1b6a 100644 --- a/packages/frontend/src/components/global/MkAd.vue +++ b/packages/frontend/src/components/global/MkAd.vue @@ -1,6 +1,14 @@ <template> <div v-if="chosen && !shouldHide" :class="$style.root"> - <div v-if="!showMenu" :class="[$style.main, $style['form_' + chosen.place]]"> + <div + v-if="!showMenu" + :class="[$style.main, { + [$style.form_square]: chosen.place === 'square', + [$style.form_horizontal]: chosen.place === 'horizontal', + [$style.form_horizontalBig]: chosen.place === 'horizontal-big', + [$style.form_vertical]: chosen.place === 'vertical', + }]" + > <a :href="chosen.url" target="_blank" :class="$style.link"> <img :src="chosen.imageUrl" :class="$style.img"> <button class="_button" :class="$style.i" @click.prevent.stop="toggleMenu"><i :class="$style.iIcon" class="ti ti-info-circle"></i></button> @@ -122,7 +130,7 @@ function reduceFrequency(): void { } } - &.form_horizontal-big { + &.form_horizontalBig { padding: 8px; > .link, diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue index 2a92780306..c1efd9a06b 100644 --- a/packages/frontend/src/components/global/MkUrl.vue +++ b/packages/frontend/src/components/global/MkUrl.vue @@ -6,7 +6,7 @@ <template v-if="!self"> <span :class="$style.schema">{{ schema }}//</span> <span :class="$style.hostname">{{ hostname }}</span> - <span v-if="port != ''" :class="$style.port">:{{ port }}</span> + <span v-if="port != ''">:{{ port }}</span> </template> <template v-if="pathname === '/' && self"> <span :class="$style.self">{{ hostname }}</span> diff --git a/packages/frontend/src/components/page/page.section.vue b/packages/frontend/src/components/page/page.section.vue index 9f79ecc833..83a16ae0a5 100644 --- a/packages/frontend/src/components/page/page.section.vue +++ b/packages/frontend/src/components/page/page.section.vue @@ -1,6 +1,15 @@ <template> <section> - <component :is="'h' + h" :class="h < 5 ? $style['h' + h] : null">{{ block.title }}</component> + <component + :is="'h' + h" + :class="{ + 'h2': h === 2, + 'h3': h === 3, + 'h4': h === 4, + }" + > + {{ block.title }} + </component> <div class="_gaps"> <XBlock v-for="child in block.children" :key="child.id" :page="page" :block="child" :h="h + 1"/> diff --git a/packages/frontend/src/pages/admin/RolesEditorFormula.vue b/packages/frontend/src/pages/admin/RolesEditorFormula.vue index 36e3c32391..9530b27bad 100644 --- a/packages/frontend/src/pages/admin/RolesEditorFormula.vue +++ b/packages/frontend/src/pages/admin/RolesEditorFormula.vue @@ -1,5 +1,5 @@ <template> -<div :class="$style.root" class="_gaps"> +<div class="_gaps"> <div :class="$style.header"> <MkSelect v-model="type" :class="$style.typeSelect"> <option value="isLocal">{{ i18n.ts._role._condition.isLocal }}</option> @@ -24,7 +24,7 @@ </button> </div> - <div v-if="type === 'and' || type === 'or'" :class="$style.values" class="_gaps"> + <div v-if="type === 'and' || type === 'or'" class="_gaps"> <Sortable v-model="v.values" tag="div" class="_gaps" itemKey="id" handle=".drag-handle" :group="{ name: 'roleFormula' }" :animation="150" :swapThreshold="0.5"> <template #item="{element}"> <div :class="$style.item"> @@ -118,10 +118,6 @@ function removeSelf() { </script> <style lang="scss" module> -.root { - -} - .header { display: flex; } @@ -148,8 +144,4 @@ function removeSelf() { border-color: var(--accent); } } - -.values { - -} </style> diff --git a/packages/frontend/src/pages/admin/queue.chart.vue b/packages/frontend/src/pages/admin/queue.chart.vue index 3ad8324d63..8e6856fddd 100644 --- a/packages/frontend/src/pages/admin/queue.chart.vue +++ b/packages/frontend/src/pages/admin/queue.chart.vue @@ -28,8 +28,8 @@ <template #icon><i class="ti ti-alert-triangle"></i></template> <template #label>Errored instances</template> <template #suffix>({{ number(jobs.reduce((a, b) => a + b[1], 0)) }} jobs)</template> - - <div :class="$style.jobs"> + + <div> <div v-if="jobs.length > 0"> <div v-for="job in jobs" :key="job[0]"> <MkA :to="`/instance-info/${job[0]}`" behavior="window">{{ job[0] }}</MkA> @@ -150,7 +150,4 @@ onUnmounted(() => { font-size: 80%; opacity: 0.6; } - -.jobs { -} </style> diff --git a/packages/frontend/src/pages/admin/server-rules.vue b/packages/frontend/src/pages/admin/server-rules.vue index 2e4aba5fe4..fdba4f464e 100644 --- a/packages/frontend/src/pages/admin/server-rules.vue +++ b/packages/frontend/src/pages/admin/server-rules.vue @@ -27,7 +27,7 @@ </Sortable> <div :class="$style.commands"> <MkButton rounded @click="serverRules.push('')"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton> - <MkButton primary rounded :class="$style.buttonSave" @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> + <MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> </div> </div> </MkSpacer> diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 86f633c445..e34901cd11 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -32,7 +32,7 @@ </template> <script lang="ts" setup> -import { computed, onMounted, onUnmounted, useCssModule } from 'vue'; +import { computed, onMounted, onUnmounted } from 'vue'; import { v4 as uuid } from 'uuid'; import FormSection from '@/components/form/section.vue'; import MkButton from '@/components/MkButton.vue'; @@ -48,8 +48,6 @@ import { definePageMetadata } from '@/scripts/page-metadata'; import { miLocalStorage } from '@/local-storage'; const { t, ts } = i18n; -useCssModule(); - const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ 'menu', 'visibility', diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 11e891b784..58217d0475 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -3,7 +3,7 @@ <div :class="$style.avatarAndBanner" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }"> <div :class="$style.avatarContainer"> <MkAvatar :class="$style.avatar" :user="$i" @click="changeAvatar"/> - <MkButton primary rounded :class="$style.avatarEdit" @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton> + <MkButton primary rounded @click="changeAvatar">{{ i18n.ts._profile.changeAvatar }}</MkButton> </div> <MkButton primary rounded :class="$style.bannerEdit" @click="changeBanner">{{ i18n.ts._profile.changeBanner }}</MkButton> </div> @@ -271,10 +271,6 @@ definePageMetadata({ margin: 0 auto 16px auto; } -.avatarEdit { - -} - .bannerEdit { position: absolute; top: 16px; diff --git a/packages/frontend/src/pages/signup-complete.vue b/packages/frontend/src/pages/signup-complete.vue index 2700601c44..61d7eb24fd 100644 --- a/packages/frontend/src/pages/signup-complete.vue +++ b/packages/frontend/src/pages/signup-complete.vue @@ -1,5 +1,5 @@ <template> -<div :class="$style.root"> +<div> <MkAnimBg style="position: fixed; top: 0;"/> <div :class="$style.formContainer"> <form :class="$style.form" class="_panel" @submit.prevent="submit()"> @@ -53,9 +53,6 @@ function submit() { </script> <style lang="scss" module> -.root { -} - .formContainer { min-height: 100svh; padding: 32px 32px 64px 32px; diff --git a/packages/frontend/src/pages/welcome.setup.vue b/packages/frontend/src/pages/welcome.setup.vue index 5a68292b1b..2081cb9c93 100644 --- a/packages/frontend/src/pages/welcome.setup.vue +++ b/packages/frontend/src/pages/welcome.setup.vue @@ -1,5 +1,5 @@ <template> -<div :class="$style.root"> +<div> <MkAnimBg style="position: fixed; top: 0;"/> <div :class="$style.formContainer"> <form :class="$style.form" class="_panel" @submit.prevent="submit()"> @@ -64,9 +64,6 @@ function submit() { </script> <style lang="scss" module> -.root { -} - .formContainer { min-height: 100svh; padding: 32px 32px 64px 32px; diff --git a/packages/frontend/src/pages/welcome.timeline.vue b/packages/frontend/src/pages/welcome.timeline.vue index 46a0775579..a93d103d4f 100644 --- a/packages/frontend/src/pages/welcome.timeline.vue +++ b/packages/frontend/src/pages/welcome.timeline.vue @@ -3,7 +3,7 @@ <div ref="scrollEl" :class="[$style.scrollbox, { [$style.scroll]: isScrolling }]"> <div v-for="note in notes" :key="note.id" :class="$style.note"> <div class="_panel" :class="$style.content"> - <div :class="$style.body"> + <div> <MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> <Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i"/> <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue index 4600d2af8e..3b970eefbe 100644 --- a/packages/frontend/src/ui/_common_/common.vue +++ b/packages/frontend/src/ui/_common_/common.vue @@ -10,7 +10,15 @@ <XUpload v-if="uploads.length > 0"/> <TransitionGroup - tag="div" :class="[$style.notifications, $style[`notificationsPosition-${defaultStore.state.notificationPosition}`], $style[`notificationsStackAxis-${defaultStore.state.notificationStackAxis}`]]" + tag="div" + :class="[$style.notifications, { + [$style.notificationsPosition_leftTop]: defaultStore.state.notificationPosition === 'leftTop', + [$style.notificationsPosition_leftBottom]: defaultStore.state.notificationPosition === 'leftBottom', + [$style.notificationsPosition_rightTop]: defaultStore.state.notificationPosition === 'rightTop', + [$style.notificationsPosition_rightBottom]: defaultStore.state.notificationPosition === 'rightBottom', + [$style.notificationsStackAxis_vertical]: defaultStore.state.notificationStackAxis === 'vertical', + [$style.notificationsStackAxis_horizontal]: defaultStore.state.notificationStackAxis === 'horizontal', + }]" :moveClass="defaultStore.state.animation ? $style.transition_notification_move : ''" :enterActiveClass="defaultStore.state.animation ? $style.transition_notification_enterActive : ''" :leaveActiveClass="defaultStore.state.animation ? $style.transition_notification_leaveActive : ''" @@ -103,31 +111,31 @@ if ($i) { pointer-events: none; display: flex; - &.notificationsPosition-leftTop { + &.notificationsPosition_leftTop { top: var(--margin); left: 0; } - &.notificationsPosition-rightTop { + &.notificationsPosition_rightTop { top: var(--margin); right: 0; } - &.notificationsPosition-leftBottom { + &.notificationsPosition_leftBottom { bottom: calc(var(--minBottomSpacing) + var(--margin)); left: 0; } - &.notificationsPosition-rightBottom { + &.notificationsPosition_rightBottom { bottom: calc(var(--minBottomSpacing) + var(--margin)); right: 0; } - &.notificationsStackAxis-vertical { + &.notificationsStackAxis_vertical { width: 250px; - &.notificationsPosition-leftTop, - &.notificationsPosition-rightTop { + &.notificationsPosition_leftTop, + &.notificationsPosition_rightTop { flex-direction: column; .notification { @@ -137,8 +145,8 @@ if ($i) { } } - &.notificationsPosition-leftBottom, - &.notificationsPosition-rightBottom { + &.notificationsPosition_leftBottom, + &.notificationsPosition_rightBottom { flex-direction: column-reverse; .notification { @@ -149,11 +157,11 @@ if ($i) { } } - &.notificationsStackAxis-horizontal { + &.notificationsStackAxis_horizontal { width: 100%; - &.notificationsPosition-leftTop, - &.notificationsPosition-leftBottom { + &.notificationsPosition_leftTop, + &.notificationsPosition_leftBottom { flex-direction: row; .notification { @@ -163,8 +171,8 @@ if ($i) { } } - &.notificationsPosition-rightTop, - &.notificationsPosition-rightBottom { + &.notificationsPosition_rightTop, + &.notificationsPosition_rightBottom { flex-direction: row-reverse; .notification { diff --git a/packages/frontend/src/ui/_common_/statusbar-federation.vue b/packages/frontend/src/ui/_common_/statusbar-federation.vue index 4ea84c82c2..6f2e4bc9a7 100644 --- a/packages/frontend/src/ui/_common_/statusbar-federation.vue +++ b/packages/frontend/src/ui/_common_/statusbar-federation.vue @@ -14,7 +14,7 @@ <MkA :to="`/instance-info/${instance.host}`" :class="$style.host" class="_monospace"> {{ instance.host }} </MkA> - <span :class="$style.divider"></span> + <span></span> </span> </MarqueeText> </Transition> diff --git a/packages/frontend/src/ui/_common_/statusbars.vue b/packages/frontend/src/ui/_common_/statusbars.vue index bb245c7dd8..3533972cdf 100644 --- a/packages/frontend/src/ui/_common_/statusbars.vue +++ b/packages/frontend/src/ui/_common_/statusbars.vue @@ -4,7 +4,6 @@ v-for="x in defaultStore.reactiveState.statusbars.value" :key="x.id" :class="[$style.item, { [$style.black]: x.black, [$style.verySmall]: x.size === 'verySmall', [$style.small]: x.size === 'small', - [$style.medium]: x.size === 'medium', [$style.large]: x.size === 'large', [$style.veryLarge]: x.size === 'veryLarge', }]" diff --git a/packages/frontend/src/ui/_common_/stream-indicator.vue b/packages/frontend/src/ui/_common_/stream-indicator.vue index 3e97df7ee5..74c475fc7d 100644 --- a/packages/frontend/src/ui/_common_/stream-indicator.vue +++ b/packages/frontend/src/ui/_common_/stream-indicator.vue @@ -2,8 +2,8 @@ <div v-if="hasDisconnected && defaultStore.state.serverDisconnectedBehavior === 'quiet'" :class="$style.root" class="_panel _shadow" @click="resetDisconnected"> <div><i class="ti ti-alert-triangle"></i> {{ i18n.ts.disconnectedFromServer }}</div> <div :class="$style.command" class="_buttons"> - <MkButton :class="$style.commandButton" small primary @click="reload">{{ i18n.ts.reload }}</MkButton> - <MkButton :class="$style.commandButton" small>{{ i18n.ts.doNothing }}</MkButton> + <MkButton small primary @click="reload">{{ i18n.ts.reload }}</MkButton> + <MkButton small>{{ i18n.ts.doNothing }}</MkButton> </div> </div> </template> @@ -54,7 +54,4 @@ onUnmounted(() => { .command { margin-top: 8px; } - -.commandButton { -} </style> diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index d95f826f20..8296c46691 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -1,6 +1,6 @@ <template> <div - :class="[$style.root, { [$style.paged]: isMainColumn, [$style.naked]: naked, [$style.active]: active, [$style.isStacked]: isStacked, [$style.draghover]: draghover, [$style.dragging]: dragging, [$style.dropready]: dropready }]" + :class="[$style.root, { [$style.paged]: isMainColumn, [$style.naked]: naked, [$style.active]: active, [$style.draghover]: draghover, [$style.dragging]: dragging, [$style.dropready]: dropready }]" @dragover.prevent.stop="onDragover" @dragleave="onDragleave" @drop.prevent.stop="onDrop" diff --git a/packages/frontend/src/ui/universal.widgets.vue b/packages/frontend/src/ui/universal.widgets.vue index 1ee95bf06e..ec5e8bb03f 100644 --- a/packages/frontend/src/ui/universal.widgets.vue +++ b/packages/frontend/src/ui/universal.widgets.vue @@ -1,6 +1,6 @@ <template> -<div :class="$style.root"> - <XWidgets :class="$style.widgets" :edit="editMode" :widgets="widgets" @addWidget="addWidget" @removeWidget="removeWidget" @updateWidget="updateWidget" @updateWidgets="updateWidgets" @exit="editMode = false"/> +<div> + <XWidgets :edit="editMode" :widgets="widgets" @addWidget="addWidget" @removeWidget="removeWidget" @updateWidget="updateWidget" @updateWidgets="updateWidgets" @exit="editMode = false"/> <button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button> <button v-else class="_textButton" data-cy-widget-edit :class="$style.edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button> @@ -70,9 +70,6 @@ function updateWidgets(thisWidgets) { </script> <style lang="scss" module> -.root { -} - .edit { width: 100%; } diff --git a/packages/frontend/src/widgets/WidgetClock.vue b/packages/frontend/src/widgets/WidgetClock.vue index 707f403603..aee5026db4 100644 --- a/packages/frontend/src/widgets/WidgetClock.vue +++ b/packages/frontend/src/widgets/WidgetClock.vue @@ -1,6 +1,12 @@ <template> <MkContainer :naked="widgetProps.transparent" :showHeader="false" data-cy-mkw-clock> - <div :class="[$style.root, $style[widgetProps.size]]"> + <div + :class="[$style.root, { + [$style.small]: widgetProps.size === 'small', + [$style.medium]: widgetProps.size === 'medium', + [$style.large]: widgetProps.size === 'large', + }]" + > <div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace" :class="[$style.label, $style.a]">{{ tzAbbrev }}</div> <MkAnalogClock :class="$style.clock" diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue index 135ca37026..6b346c0598 100644 --- a/packages/frontend/src/widgets/WidgetRssTicker.vue +++ b/packages/frontend/src/widgets/WidgetRssTicker.vue @@ -12,7 +12,7 @@ <Transition :name="$style.change" mode="default" appear> <MarqueeText :key="key" :duration="widgetProps.duration" :reverse="widgetProps.reverse"> <span v-for="item in items" :key="item.link" :class="$style.item"> - <a :class="$style.link" :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span :class="$style.divider"></span> + <a :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span :class="$style.divider"></span> </span> </MarqueeText> </Transition> diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index 482c98fe88..531dd0b488 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -8,6 +8,7 @@ import ReactivityTransform from '@vue-macros/reactivity-transform/vite'; import locales from '../../locales'; import generateDTS from '../../locales/generateDTS'; import meta from '../../package.json'; +import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name'; import pluginJson5 from './vite.json5'; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue']; @@ -54,6 +55,7 @@ export function getConfig(): UserConfig { reactivityTransform: true, }), ReactivityTransform(), + pluginUnwindCssModuleClassName(), pluginJson5(), ...process.env.NODE_ENV === 'production' ? [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 711e0dc0ab..c4b66a1ff5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -661,6 +661,9 @@ importers: '@vue/compiler-sfc': specifier: 3.3.4 version: 3.3.4 + astring: + specifier: 1.8.5 + version: 1.8.5 autosize: specifier: 6.0.1 version: 6.0.1 @@ -706,6 +709,9 @@ importers: escape-regexp: specifier: 0.0.1 version: 0.0.1 + estree-walker: + specifier: ^3.0.3 + version: 3.0.3 eventemitter3: specifier: 5.0.1 version: 5.0.1 @@ -932,9 +938,9 @@ importers: '@vue/runtime-core': specifier: 3.3.4 version: 3.3.4 - astring: - specifier: 1.8.5 - version: 1.8.5 + acorn: + specifier: ^8.8.2 + version: 8.8.2 chokidar-cli: specifier: 3.0.0 version: 3.0.0 @@ -2081,15 +2087,15 @@ packages: tslib: 2.5.2 dev: false - /@babel/code-frame@7.18.6: - resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} + /@babel/code-frame@7.21.4: + resolution: {integrity: sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data@7.21.4: - resolution: {integrity: sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==} + /@babel/compat-data@7.22.3: + resolution: {integrity: sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==} engines: {node: '>=6.9.0'} dev: true @@ -2098,15 +2104,38 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.1 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.21.3 - '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) - '@babel/helper-module-transforms': 7.21.2 - '@babel/helpers': 7.21.0 - '@babel/parser': 7.21.9 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.3 - '@babel/types': 7.21.5 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.22.3 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.21.3) + '@babel/helper-module-transforms': 7.22.1 + '@babel/helpers': 7.22.3 + '@babel/parser': 7.22.4 + '@babel/template': 7.21.9 + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 + convert-source-map: 1.9.0 + debug: 4.3.4(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/core@7.22.1: + resolution: {integrity: sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.22.3 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) + '@babel/helper-module-transforms': 7.22.1 + '@babel/helpers': 7.22.3 + '@babel/parser': 7.22.4 + '@babel/template': 7.21.9 + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 convert-source-map: 1.9.0 debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 @@ -2120,7 +2149,17 @@ packages: resolution: {integrity: sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 + '@jridgewell/gen-mapping': 0.3.2 + '@jridgewell/trace-mapping': 0.3.17 + jsesc: 2.5.2 + dev: true + + /@babel/generator@7.22.3: + resolution: {integrity: sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.22.4 '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 jsesc: 2.5.2 @@ -2130,7 +2169,7 @@ packages: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: @@ -2138,16 +2177,16 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-explode-assignable-expression': 7.18.6 - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true - /@babel/helper-compilation-targets@7.21.4(@babel/core@7.21.3): - resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} + /@babel/helper-compilation-targets@7.22.1(@babel/core@7.21.3): + resolution: {integrity: sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.21.4 + '@babel/compat-data': 7.22.3 '@babel/core': 7.21.3 '@babel/helper-validator-option': 7.21.0 browserslist: 4.21.5 @@ -2155,6 +2194,20 @@ packages: semver: 6.3.0 dev: true + /@babel/helper-compilation-targets@7.22.1(@babel/core@7.22.1): + resolution: {integrity: sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.22.3 + '@babel/core': 7.22.1 + '@babel/helper-validator-option': 7.21.0 + browserslist: 4.21.5 + lru-cache: 5.1.1 + semver: 6.3.0 + dev: true + /@babel/helper-create-class-features-plugin@7.21.0(@babel/core@7.21.3): resolution: {integrity: sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ==} engines: {node: '>=6.9.0'} @@ -2163,7 +2216,26 @@ packages: dependencies: '@babel/core': 7.21.3 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-environment-visitor': 7.22.1 + '@babel/helper-function-name': 7.21.0 + '@babel/helper-member-expression-to-functions': 7.21.0 + '@babel/helper-optimise-call-expression': 7.18.6 + '@babel/helper-replace-supers': 7.20.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/helper-split-export-declaration': 7.18.6 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-create-class-features-plugin@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-environment-visitor': 7.22.1 '@babel/helper-function-name': 7.21.0 '@babel/helper-member-expression-to-functions': 7.21.0 '@babel/helper-optimise-call-expression': 7.18.6 @@ -2185,13 +2257,24 @@ packages: regexpu-core: 5.3.2 dev: true + /@babel/helper-create-regexp-features-plugin@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-annotate-as-pure': 7.18.6 + regexpu-core: 5.3.2 + dev: true + /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.21.3): resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} peerDependencies: '@babel/core': ^7.4.0-0 dependencies: '@babel/core': 7.21.3 - '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.21.3) '@babel/helper-plugin-utils': 7.20.2 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 @@ -2201,8 +2284,24 @@ packages: - supports-color dev: true - /@babel/helper-environment-visitor@7.18.9: - resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} + /@babel/helper-define-polyfill-provider@0.3.3(@babel/core@7.22.1): + resolution: {integrity: sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==} + peerDependencies: + '@babel/core': ^7.4.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + debug: 4.3.4(supports-color@8.1.1) + lodash.debounce: 4.0.8 + resolve: 1.22.1 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-environment-visitor@7.22.1: + resolution: {integrity: sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==} engines: {node: '>=6.9.0'} dev: true @@ -2210,50 +2309,50 @@ packages: resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@babel/helper-function-name@7.21.0: resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.20.7 - '@babel/types': 7.21.5 + '@babel/template': 7.21.9 + '@babel/types': 7.22.4 dev: true /@babel/helper-hoist-variables@7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@babel/helper-member-expression-to-functions@7.21.0: resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true - /@babel/helper-module-imports@7.18.6: - resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} + /@babel/helper-module-imports@7.21.4: + resolution: {integrity: sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true - /@babel/helper-module-transforms@7.21.2: - resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} + /@babel/helper-module-transforms@7.22.1: + resolution: {integrity: sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.20.2 + '@babel/helper-environment-visitor': 7.22.1 + '@babel/helper-module-imports': 7.21.4 + '@babel/helper-simple-access': 7.21.5 '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.3 - '@babel/types': 7.21.5 + '@babel/template': 7.21.9 + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 transitivePeerDependencies: - supports-color dev: true @@ -2262,7 +2361,7 @@ packages: resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@babel/helper-plugin-utils@7.20.2: @@ -2278,9 +2377,24 @@ packages: dependencies: '@babel/core': 7.21.3 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-environment-visitor': 7.22.1 '@babel/helper-wrap-function': 7.20.5 - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-remap-async-to-generator@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-environment-visitor': 7.22.1 + '@babel/helper-wrap-function': 7.20.5 + '@babel/types': 7.22.4 transitivePeerDependencies: - supports-color dev: true @@ -2289,35 +2403,35 @@ packages: resolution: {integrity: sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-environment-visitor': 7.22.1 '@babel/helper-member-expression-to-functions': 7.21.0 '@babel/helper-optimise-call-expression': 7.18.6 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.3 - '@babel/types': 7.21.5 + '@babel/template': 7.21.9 + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-simple-access@7.20.2: - resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} + /@babel/helper-simple-access@7.21.5: + resolution: {integrity: sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@babel/helper-skip-transparent-expression-wrappers@7.20.0: resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@babel/helper-split-export-declaration@7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@babel/helper-string-parser@7.21.5: @@ -2338,20 +2452,20 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-function-name': 7.21.0 - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.3 - '@babel/types': 7.21.5 + '@babel/template': 7.21.9 + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 transitivePeerDependencies: - supports-color dev: true - /@babel/helpers@7.21.0: - resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==} + /@babel/helpers@7.22.3: + resolution: {integrity: sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.20.7 - '@babel/traverse': 7.21.3 - '@babel/types': 7.21.5 + '@babel/template': 7.21.9 + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 transitivePeerDependencies: - supports-color dev: true @@ -2370,14 +2484,21 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 /@babel/parser@7.21.9: resolution: {integrity: sha512-q5PNg/Bi1OpGgx5jYlvWZwAorZepEudDMCLtj967aeS7WMont7dUZI46M2XwcIQqvUlMxWfdLFu4S/qSxeUu5g==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 + + /@babel/parser@7.22.4: + resolution: {integrity: sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.22.4 /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} @@ -2389,6 +2510,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.21.3): resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==} engines: {node: '>=6.9.0'} @@ -2401,6 +2532,18 @@ packages: '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.3) dev: true + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.21.3): resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} engines: {node: '>=6.9.0'} @@ -2408,7 +2551,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.3 - '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-environment-visitor': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.3) '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.21.3) @@ -2416,6 +2559,21 @@ packages: - supports-color dev: true + /@babel/plugin-proposal-async-generator-functions@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-environment-visitor': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.1) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} @@ -2429,6 +2587,19 @@ packages: - supports-color dev: true + /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.21.3): resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==} engines: {node: '>=6.9.0'} @@ -2443,6 +2614,20 @@ packages: - supports-color dev: true + /@babel/plugin-proposal-class-static-block@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.1) + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} engines: {node: '>=6.9.0'} @@ -2454,6 +2639,17 @@ packages: '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-dynamic-import@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.21.3): resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} engines: {node: '>=6.9.0'} @@ -2465,6 +2661,17 @@ packages: '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} engines: {node: '>=6.9.0'} @@ -2476,6 +2683,17 @@ packages: '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-json-strings@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.21.3): resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} engines: {node: '>=6.9.0'} @@ -2487,6 +2705,17 @@ packages: '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-logical-assignment-operators@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} engines: {node: '>=6.9.0'} @@ -2498,6 +2727,17 @@ packages: '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} engines: {node: '>=6.9.0'} @@ -2509,20 +2749,45 @@ packages: '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-numeric-separator@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.21.3): resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.21.4 + '@babel/compat-data': 7.22.3 '@babel/core': 7.21.3 - '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.21.3) '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.3) '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.22.3 + '@babel/core': 7.22.1 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} engines: {node: '>=6.9.0'} @@ -2534,6 +2799,17 @@ packages: '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-optional-catch-binding@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.21.3): resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} engines: {node: '>=6.9.0'} @@ -2546,6 +2822,18 @@ packages: '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.21.3) dev: true + /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.1) + dev: true + /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} engines: {node: '>=6.9.0'} @@ -2559,6 +2847,19 @@ packages: - supports-color dev: true + /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.21.3): resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} engines: {node: '>=6.9.0'} @@ -2574,6 +2875,21 @@ packages: - supports-color dev: true + /@babel/plugin-proposal-private-property-in-object@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.1) + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} engines: {node: '>=4'} @@ -2585,6 +2901,17 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-proposal-unicode-property-regex@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==} + engines: {node: '>=4'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.21.3): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: @@ -2594,6 +2921,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.22.1): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: @@ -2603,6 +2939,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.21.3): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: @@ -2612,6 +2957,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.1): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.21.3): resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} @@ -2622,6 +2976,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.22.1): + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: @@ -2631,6 +2995,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: @@ -2640,13 +3013,22 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-flow@7.18.6(@babel/core@7.21.3): + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-flow@7.18.6(@babel/core@7.22.1): resolution: {integrity: sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -2660,6 +3042,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-import-assertions@7.20.0(@babel/core@7.22.1): + resolution: {integrity: sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.21.3): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: @@ -2669,6 +3061,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.22.1): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: @@ -2678,13 +3079,22 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.21.3): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.22.1): resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -2697,6 +3107,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.22.1): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: @@ -2706,6 +3125,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.21.3): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: @@ -2715,6 +3143,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.1): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: @@ -2724,6 +3161,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: @@ -2733,6 +3179,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.21.3): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: @@ -2742,6 +3197,15 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.1): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.21.3): resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} @@ -2752,6 +3216,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.22.1): + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.21.3): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} @@ -2762,13 +3236,23 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.21.3): + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.22.1): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-syntax-typescript@7.20.0(@babel/core@7.22.1): resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -2782,6 +3266,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-arrow-functions@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.21.3): resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} engines: {node: '>=6.9.0'} @@ -2789,13 +3283,27 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.3 - '@babel/helper-module-imports': 7.18.6 + '@babel/helper-module-imports': 7.21.4 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.21.3) transitivePeerDependencies: - supports-color dev: true + /@babel/plugin-transform-async-to-generator@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-module-imports': 7.21.4 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-remap-async-to-generator': 7.18.9(@babel/core@7.22.1) + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} engines: {node: '>=6.9.0'} @@ -2806,6 +3314,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-block-scoped-functions@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.21.3): resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==} engines: {node: '>=6.9.0'} @@ -2816,6 +3334,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-block-scoping@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-classes@7.21.0(@babel/core@7.21.3): resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==} engines: {node: '>=6.9.0'} @@ -2824,8 +3352,28 @@ packages: dependencies: '@babel/core': 7.21.3 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) - '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.21.3) + '@babel/helper-environment-visitor': 7.22.1 + '@babel/helper-function-name': 7.21.0 + '@babel/helper-optimise-call-expression': 7.18.6 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-replace-supers': 7.20.7 + '@babel/helper-split-export-declaration': 7.18.6 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-classes@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-annotate-as-pure': 7.18.6 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) + '@babel/helper-environment-visitor': 7.22.1 '@babel/helper-function-name': 7.21.0 '@babel/helper-optimise-call-expression': 7.18.6 '@babel/helper-plugin-utils': 7.20.2 @@ -2844,7 +3392,18 @@ packages: dependencies: '@babel/core': 7.21.3 '@babel/helper-plugin-utils': 7.20.2 - '@babel/template': 7.20.7 + '@babel/template': 7.21.9 + dev: true + + /@babel/plugin-transform-computed-properties@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/template': 7.21.9 dev: true /@babel/plugin-transform-destructuring@7.21.3(@babel/core@7.21.3): @@ -2857,6 +3416,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-destructuring@7.21.3(@babel/core@7.22.1): + resolution: {integrity: sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} engines: {node: '>=6.9.0'} @@ -2868,6 +3437,17 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-dotall-regex@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.21.3): resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} engines: {node: '>=6.9.0'} @@ -2878,6 +3458,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-duplicate-keys@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} engines: {node: '>=6.9.0'} @@ -2889,15 +3479,26 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-flow-strip-types@7.21.0(@babel/core@7.21.3): + /@babel/plugin-transform-exponentiation-operator@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.18.9 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-flow-strip-types@7.21.0(@babel/core@7.22.1): resolution: {integrity: sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-flow': 7.18.6(@babel/core@7.21.3) + '@babel/plugin-syntax-flow': 7.18.6(@babel/core@7.22.1) dev: true /@babel/plugin-transform-for-of@7.21.0(@babel/core@7.21.3): @@ -2910,6 +3511,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-for-of@7.21.0(@babel/core@7.22.1): + resolution: {integrity: sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.21.3): resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} engines: {node: '>=6.9.0'} @@ -2917,7 +3528,19 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.3 - '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.21.3) + '@babel/helper-function-name': 7.21.0 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-function-name@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) '@babel/helper-function-name': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -2932,6 +3555,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-literals@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} engines: {node: '>=6.9.0'} @@ -2942,6 +3575,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-member-expression-literals@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.21.3): resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} engines: {node: '>=6.9.0'} @@ -2949,7 +3592,20 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.3 - '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-module-transforms': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-amd@7.20.11(@babel/core@7.22.1): + resolution: {integrity: sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-module-transforms': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color @@ -2962,9 +3618,23 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.3 - '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-module-transforms': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-simple-access': 7.20.2 + '@babel/helper-simple-access': 7.21.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-commonjs@7.21.2(@babel/core@7.22.1): + resolution: {integrity: sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-module-transforms': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-simple-access': 7.21.5 transitivePeerDependencies: - supports-color dev: true @@ -2977,7 +3647,22 @@ packages: dependencies: '@babel/core': 7.21.3 '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-module-transforms': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-validator-identifier': 7.19.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-systemjs@7.20.11(@babel/core@7.22.1): + resolution: {integrity: sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-module-transforms': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-identifier': 7.19.1 transitivePeerDependencies: @@ -2991,7 +3676,20 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.3 - '@babel/helper-module-transforms': 7.21.2 + '@babel/helper-module-transforms': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/plugin-transform-modules-umd@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-module-transforms': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color @@ -3008,6 +3706,17 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-named-capturing-groups-regex@7.20.5(@babel/core@7.22.1): + resolution: {integrity: sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} engines: {node: '>=6.9.0'} @@ -3018,6 +3727,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-new-target@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} engines: {node: '>=6.9.0'} @@ -3031,6 +3750,19 @@ packages: - supports-color dev: true + /@babel/plugin-transform-object-super@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-replace-supers': 7.20.7 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/plugin-transform-parameters@7.21.3(@babel/core@7.21.3): resolution: {integrity: sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==} engines: {node: '>=6.9.0'} @@ -3041,6 +3773,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-parameters@7.21.3(@babel/core@7.22.1): + resolution: {integrity: sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} engines: {node: '>=6.9.0'} @@ -3051,38 +3793,48 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-react-jsx-self@7.21.0(@babel/core@7.21.3): + /@babel/plugin-transform-property-literals@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-react-jsx-self@7.21.0(@babel/core@7.22.1): resolution: {integrity: sha512-f/Eq+79JEu+KUANFks9UZCcvydOOGMgF7jBrcwjHa5jTZD8JivnhCJYvmlhR/WTXBWonDExPoW0eO/CR4QJirA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-react-jsx-source@7.19.6(@babel/core@7.21.3): + /@babel/plugin-transform-react-jsx-source@7.19.6(@babel/core@7.22.1): resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-react-jsx@7.21.0(@babel/core@7.21.3): + /@babel/plugin-transform-react-jsx@7.21.0(@babel/core@7.22.1): resolution: {integrity: sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-module-imports': 7.18.6 + '@babel/helper-module-imports': 7.21.4 '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.21.3) - '@babel/types': 7.21.5 + '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.22.1) + '@babel/types': 7.22.4 dev: true /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.21.3): @@ -3096,6 +3848,17 @@ packages: regenerator-transform: 0.15.1 dev: true + /@babel/plugin-transform-regenerator@7.20.5(@babel/core@7.22.1): + resolution: {integrity: sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + regenerator-transform: 0.15.1 + dev: true + /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} engines: {node: '>=6.9.0'} @@ -3106,6 +3869,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-reserved-words@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} engines: {node: '>=6.9.0'} @@ -3116,6 +3889,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-shorthand-properties@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-spread@7.20.7(@babel/core@7.21.3): resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} engines: {node: '>=6.9.0'} @@ -3127,6 +3910,17 @@ packages: '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 dev: true + /@babel/plugin-transform-spread@7.20.7(@babel/core@7.22.1): + resolution: {integrity: sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-skip-transparent-expression-wrappers': 7.20.0 + dev: true + /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} engines: {node: '>=6.9.0'} @@ -3137,6 +3931,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-sticky-regex@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.21.3): resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} engines: {node: '>=6.9.0'} @@ -3147,6 +3951,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-template-literals@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.21.3): resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} engines: {node: '>=6.9.0'} @@ -3157,17 +3971,27 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true - /@babel/plugin-transform-typescript@7.21.3(@babel/core@7.21.3): + /@babel/plugin-transform-typeof-symbol@7.18.9(@babel/core@7.22.1): + resolution: {integrity: sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + + /@babel/plugin-transform-typescript@7.21.3(@babel/core@7.22.1): resolution: {integrity: sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.21.3) + '@babel/helper-create-class-features-plugin': 7.21.0(@babel/core@7.22.1) '@babel/helper-plugin-utils': 7.20.2 - '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.21.3) + '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.22.1) transitivePeerDependencies: - supports-color dev: true @@ -3182,6 +4006,16 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-unicode-escapes@7.18.10(@babel/core@7.22.1): + resolution: {integrity: sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.21.3): resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} engines: {node: '>=6.9.0'} @@ -3193,15 +4027,26 @@ packages: '@babel/helper-plugin-utils': 7.20.2 dev: true + /@babel/plugin-transform-unicode-regex@7.18.6(@babel/core@7.22.1): + resolution: {integrity: sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-create-regexp-features-plugin': 7.21.0(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + dev: true + /@babel/preset-env@7.21.4(@babel/core@7.21.3): resolution: {integrity: sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.21.4 + '@babel/compat-data': 7.22.3 '@babel/core': 7.21.3 - '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.3) + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.21.3) '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-option': 7.21.0 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.21.3) @@ -3269,7 +4114,7 @@ packages: '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.21.3) '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.21.3) '@babel/preset-modules': 0.1.5(@babel/core@7.21.3) - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.21.3) babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.21.3) babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.21.3) @@ -3279,16 +4124,102 @@ packages: - supports-color dev: true - /@babel/preset-flow@7.18.6(@babel/core@7.21.3): + /@babel/preset-env@7.21.4(@babel/core@7.22.1): + resolution: {integrity: sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.22.3 + '@babel/core': 7.22.1 + '@babel/helper-compilation-targets': 7.22.1(@babel/core@7.22.1) + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-validator-option': 7.21.0 + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-class-static-block': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-proposal-dynamic-import': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.22.1) + '@babel/plugin-proposal-json-strings': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-logical-assignment-operators': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-numeric-separator': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-proposal-optional-catch-binding': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-private-property-in-object': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.1) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.22.1) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-import-assertions': 7.20.0(@babel/core@7.22.1) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.1) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.1) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.22.1) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.1) + '@babel/plugin-transform-arrow-functions': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-transform-async-to-generator': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-transform-block-scoped-functions': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-block-scoping': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-transform-classes': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-transform-computed-properties': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-transform-destructuring': 7.21.3(@babel/core@7.22.1) + '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-duplicate-keys': 7.18.9(@babel/core@7.22.1) + '@babel/plugin-transform-exponentiation-operator': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-for-of': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-transform-function-name': 7.18.9(@babel/core@7.22.1) + '@babel/plugin-transform-literals': 7.18.9(@babel/core@7.22.1) + '@babel/plugin-transform-member-expression-literals': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-modules-amd': 7.20.11(@babel/core@7.22.1) + '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.22.1) + '@babel/plugin-transform-modules-systemjs': 7.20.11(@babel/core@7.22.1) + '@babel/plugin-transform-modules-umd': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-named-capturing-groups-regex': 7.20.5(@babel/core@7.22.1) + '@babel/plugin-transform-new-target': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-object-super': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-parameters': 7.21.3(@babel/core@7.22.1) + '@babel/plugin-transform-property-literals': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-regenerator': 7.20.5(@babel/core@7.22.1) + '@babel/plugin-transform-reserved-words': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-shorthand-properties': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-spread': 7.20.7(@babel/core@7.22.1) + '@babel/plugin-transform-sticky-regex': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-template-literals': 7.18.9(@babel/core@7.22.1) + '@babel/plugin-transform-typeof-symbol': 7.18.9(@babel/core@7.22.1) + '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.22.1) + '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.22.1) + '@babel/preset-modules': 0.1.5(@babel/core@7.22.1) + '@babel/types': 7.22.4 + babel-plugin-polyfill-corejs2: 0.3.3(@babel/core@7.22.1) + babel-plugin-polyfill-corejs3: 0.6.0(@babel/core@7.22.1) + babel-plugin-polyfill-regenerator: 0.4.1(@babel/core@7.22.1) + core-js-compat: 3.29.1 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/preset-flow@7.18.6(@babel/core@7.22.1): resolution: {integrity: sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-transform-flow-strip-types': 7.21.0(@babel/core@7.21.3) + '@babel/plugin-transform-flow-strip-types': 7.21.0(@babel/core@7.22.1) dev: true /@babel/preset-modules@0.1.5(@babel/core@7.21.3): @@ -3300,31 +4231,44 @@ packages: '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.3) '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.3) - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 esutils: 2.0.3 dev: true - /@babel/preset-typescript@7.21.0(@babel/core@7.21.3): + /@babel/preset-modules@0.1.5(@babel/core@7.22.1): + resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.22.1) + '@babel/types': 7.22.4 + esutils: 2.0.3 + dev: true + + /@babel/preset-typescript@7.21.0(@babel/core@7.22.1): resolution: {integrity: sha512-myc9mpoVA5m1rF8K8DgLEatOYFDpwC+RkMkjZ0Du6uI62YvDe8uxIEYVs/VCdSJ097nlALiU/yBC7//3nI+hNg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-option': 7.21.0 - '@babel/plugin-transform-typescript': 7.21.3(@babel/core@7.21.3) + '@babel/plugin-transform-typescript': 7.21.3(@babel/core@7.22.1) transitivePeerDependencies: - supports-color dev: true - /@babel/register@7.21.0(@babel/core@7.21.3): + /@babel/register@7.21.0(@babel/core@7.22.1): resolution: {integrity: sha512-9nKsPmYDi5DidAqJaQooxIhsLJiNMkGr8ypQ8Uic7cIox7UCDsM7HuUGxdGT7mSDTYbqzIdsOWzfBton/YJrMw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 clone-deep: 4.0.1 find-cache-dir: 2.1.0 make-dir: 2.1.0 @@ -3348,27 +4292,45 @@ packages: dependencies: regenerator-runtime: 0.13.11 - /@babel/template@7.20.7: - resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} + /@babel/template@7.21.9: + resolution: {integrity: sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.21.9 - '@babel/types': 7.21.5 + '@babel/code-frame': 7.21.4 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 dev: true /@babel/traverse@7.21.3: resolution: {integrity: sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.21.3 - '@babel/helper-environment-visitor': 7.18.9 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.22.3 + '@babel/helper-environment-visitor': 7.22.1 '@babel/helper-function-name': 7.21.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.21.9 - '@babel/types': 7.21.5 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 + debug: 4.3.4(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/traverse@7.22.4: + resolution: {integrity: sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.22.3 + '@babel/helper-environment-visitor': 7.22.1 + '@babel/helper-function-name': 7.21.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: @@ -3382,6 +4344,15 @@ packages: '@babel/helper-string-parser': 7.21.5 '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 + dev: true + + /@babel/types@7.22.4: + resolution: {integrity: sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.21.5 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 /@base2/pretty-print-object@1.0.1: resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} @@ -4171,7 +5142,7 @@ packages: resolution: {integrity: sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@jest/types': 29.5.0 '@jridgewell/trace-mapping': 0.3.17 babel-plugin-istanbul: 6.1.1 @@ -4945,8 +5916,8 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@babel/core': 7.21.3 - '@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.21.3) + '@babel/core': 7.22.1 + '@babel/plugin-transform-react-jsx': 7.21.0(@babel/core@7.22.1) '@jest/transform': 29.5.0 '@mdx-js/react': 2.3.0(react@18.2.0) '@storybook/blocks': 7.0.18(react-dom@18.2.0)(react@18.2.0) @@ -5344,8 +6315,8 @@ packages: resolution: {integrity: sha512-9n4J4thiCUsGSXiRc6ZysqYUaCMCrpu0/qgC+5ngfFRuMmZgUV0y5+0fmaOhT2XjsonTTgucizO82i7+ottCVg==} hasBin: true dependencies: - '@babel/core': 7.21.3 - '@babel/preset-env': 7.21.4(@babel/core@7.21.3) + '@babel/core': 7.22.1 + '@babel/preset-env': 7.21.4(@babel/core@7.22.1) '@ndelangen/get-tarball': 3.0.7 '@storybook/codemod': 7.0.18 '@storybook/core-common': 7.0.18 @@ -5581,7 +6552,7 @@ packages: /@storybook/docs-tools@7.0.18: resolution: {integrity: sha512-H95dW2DquGQ75ZVrFjvznPdCxT0eW6esDnemzLJB61KitcYZrWRavfrZzFtUcpzIa84OgY5pllFYt636v11LHQ==} dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 '@storybook/core-common': 7.0.18 '@storybook/preview-api': 7.0.18 '@storybook/types': 7.0.18 @@ -6379,7 +7350,7 @@ packages: resolution: {integrity: sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==} engines: {node: '>=12'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 '@babel/runtime': 7.21.0 '@types/aria-query': 5.0.1 aria-query: 5.1.3 @@ -6393,7 +7364,7 @@ packages: resolution: {integrity: sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==} engines: {node: '>=14'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 '@babel/runtime': 7.21.0 '@types/aria-query': 5.0.1 aria-query: 5.1.3 @@ -6478,30 +7449,30 @@ packages: /@types/babel__core@7.20.0: resolution: {integrity: sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==} dependencies: - '@babel/parser': 7.21.9 - '@babel/types': 7.21.5 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 - '@types/babel__traverse': 7.18.3 + '@types/babel__traverse': 7.20.0 dev: true /@types/babel__generator@7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@types/babel__template@7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: - '@babel/parser': 7.21.9 - '@babel/types': 7.21.5 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 dev: true - /@types/babel__traverse@7.18.3: - resolution: {integrity: sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==} + /@types/babel__traverse@7.20.0: + resolution: {integrity: sha512-TBOjqAGf0hmaqRwpii5LLkJLg7c6OMm4nHLmpsUxwk9bBHtoTC6dAHdVWdGv4TBxj2CZOZY8Xfq8WmfoVi7n4Q==} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 dev: true /@types/bcryptjs@2.4.2: @@ -7278,9 +8249,9 @@ packages: peerDependencies: vite: ^4.1.0-beta.0 dependencies: - '@babel/core': 7.21.3 - '@babel/plugin-transform-react-jsx-self': 7.21.0(@babel/core@7.21.3) - '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.3) + '@babel/core': 7.22.1 + '@babel/plugin-transform-react-jsx-self': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.22.1) magic-string: 0.27.0 react-refresh: 0.14.0 vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) @@ -7404,7 +8375,7 @@ packages: vue: optional: true dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 '@rollup/pluginutils': 5.0.2(rollup@3.23.0) '@vue/compiler-sfc': 3.3.4 local-pkg: 0.4.3 @@ -7434,7 +8405,7 @@ packages: /@vue/compiler-core@3.3.4: resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} dependencies: - '@babel/parser': 7.21.9 + '@babel/parser': 7.22.4 '@vue/shared': 3.3.4 estree-walker: 2.0.2 source-map-js: 1.0.2 @@ -7468,7 +8439,7 @@ packages: /@vue/reactivity-transform@3.3.4: resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} dependencies: - '@babel/parser': 7.21.9 + '@babel/parser': 7.22.4 '@vue/compiler-core': 3.3.4 '@vue/shared': 3.3.4 estree-walker: 2.0.2 @@ -8147,7 +9118,7 @@ packages: /astring@1.8.5: resolution: {integrity: sha512-TuBbdn7jWVzf8dmFGTaRpW8qgANtWLi1qJLnkfGO5uVf6jf9f/F4B1H35tnOI+qVYZo3p3i8WZlbZOuPAE0wEA==} hasBin: true - dev: true + dev: false /async-done@1.3.2: resolution: {integrity: sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==} @@ -8262,12 +9233,12 @@ packages: - debug dev: true - /babel-core@7.0.0-bridge.0(@babel/core@7.21.3): + /babel-core@7.0.0-bridge.0(@babel/core@7.22.1): resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.21.3 + '@babel/core': 7.22.1 dev: true /babel-jest@29.5.0(@babel/core@7.21.3): @@ -8305,10 +9276,10 @@ packages: resolution: {integrity: sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/template': 7.20.7 - '@babel/types': 7.21.5 + '@babel/template': 7.21.9 + '@babel/types': 7.22.4 '@types/babel__core': 7.20.0 - '@types/babel__traverse': 7.18.3 + '@types/babel__traverse': 7.20.0 dev: true /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.21.3): @@ -8316,7 +9287,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.21.4 + '@babel/compat-data': 7.22.3 '@babel/core': 7.21.3 '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.21.3) semver: 6.3.0 @@ -8324,6 +9295,19 @@ packages: - supports-color dev: true + /babel-plugin-polyfill-corejs2@0.3.3(@babel/core@7.22.1): + resolution: {integrity: sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/compat-data': 7.22.3 + '@babel/core': 7.22.1 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.1) + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.21.3): resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} peerDependencies: @@ -8336,6 +9320,18 @@ packages: - supports-color dev: true + /babel-plugin-polyfill-corejs3@0.6.0(@babel/core@7.22.1): + resolution: {integrity: sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.1) + core-js-compat: 3.29.1 + transitivePeerDependencies: + - supports-color + dev: true + /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.21.3): resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} peerDependencies: @@ -8347,6 +9343,17 @@ packages: - supports-color dev: true + /babel-plugin-polyfill-regenerator@0.4.1(@babel/core@7.22.1): + resolution: {integrity: sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.22.1 + '@babel/helper-define-polyfill-provider': 0.3.3(@babel/core@7.22.1) + transitivePeerDependencies: + - supports-color + dev: true + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.21.3): resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: @@ -8367,6 +9374,26 @@ packages: '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.21.3) dev: true + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.22.1): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.22.1 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.22.1) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.22.1) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.22.1) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.22.1) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.22.1) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.1) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.1) + dev: true + /babel-preset-jest@29.5.0(@babel/core@7.21.3): resolution: {integrity: sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8382,7 +9409,7 @@ packages: resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/types': 7.21.5 + '@babel/types': 7.22.4 /bach@1.2.0: resolution: {integrity: sha512-bZOOfCb3gXBXbTFXq3OZtGR88LwGeJvzu6szttaIzymOTS4ZttBNOWSv7aLZja2EMycKtRYV0Oa8SNKH/zkxvg==} @@ -9528,8 +10555,8 @@ packages: /constantinople@4.0.1: resolution: {integrity: sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==} dependencies: - '@babel/parser': 7.21.9 - '@babel/types': 7.21.5 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 /content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} @@ -10783,8 +11810,8 @@ packages: resolution: {integrity: sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==} engines: {node: '>=8.3.0'} dependencies: - '@babel/traverse': 7.21.3 - '@babel/types': 7.21.5 + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 c8: 7.13.0 transitivePeerDependencies: - supports-color @@ -10793,6 +11820,12 @@ packages: /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.1 + dev: false + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -13149,8 +14182,8 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.21.3 - '@babel/parser': 7.21.9 + '@babel/core': 7.22.1 + '@babel/parser': 7.22.4 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -13528,7 +14561,7 @@ packages: resolution: {integrity: sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 '@jest/types': 29.5.0 '@types/stack-utils': 2.0.1 chalk: 4.1.2 @@ -13661,18 +14694,18 @@ packages: resolution: {integrity: sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.21.3 - '@babel/generator': 7.21.3 - '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.21.3) - '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.21.3) - '@babel/traverse': 7.21.3 - '@babel/types': 7.21.5 + '@babel/core': 7.22.1 + '@babel/generator': 7.22.3 + '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.22.1) + '@babel/traverse': 7.22.4 + '@babel/types': 7.22.4 '@jest/expect-utils': 29.5.0 '@jest/transform': 29.5.0 '@jest/types': 29.5.0 - '@types/babel__traverse': 7.18.3 + '@types/babel__traverse': 7.20.0 '@types/prettier': 2.7.2 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.21.3) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.1) chalk: 4.1.2 expect: 29.5.0 graceful-fs: 4.2.11 @@ -13878,17 +14911,17 @@ packages: peerDependencies: '@babel/preset-env': ^7.1.6 dependencies: - '@babel/core': 7.21.3 - '@babel/parser': 7.21.9 - '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.21.3) - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.21.3) - '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.21.3) - '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.21.3) - '@babel/preset-env': 7.21.4(@babel/core@7.21.3) - '@babel/preset-flow': 7.18.6(@babel/core@7.21.3) - '@babel/preset-typescript': 7.21.0(@babel/core@7.21.3) - '@babel/register': 7.21.0(@babel/core@7.21.3) - babel-core: 7.0.0-bridge.0(@babel/core@7.21.3) + '@babel/core': 7.22.1 + '@babel/parser': 7.22.4 + '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.22.1) + '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.22.1) + '@babel/plugin-transform-modules-commonjs': 7.21.2(@babel/core@7.22.1) + '@babel/preset-env': 7.21.4(@babel/core@7.22.1) + '@babel/preset-flow': 7.18.6(@babel/core@7.22.1) + '@babel/preset-typescript': 7.21.0(@babel/core@7.22.1) + '@babel/register': 7.21.0(@babel/core@7.22.1) + babel-core: 7.0.0-bridge.0(@babel/core@7.22.1) chalk: 4.1.2 flow-parser: 0.202.0 graceful-fs: 4.2.11 @@ -15837,7 +16870,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -17043,8 +18076,8 @@ packages: engines: {node: '>=12.0.0'} hasBin: true dependencies: - '@babel/core': 7.21.3 - '@babel/generator': 7.21.3 + '@babel/core': 7.22.1 + '@babel/generator': 7.22.3 ast-types: 0.14.2 commander: 2.20.3 doctrine: 3.0.0 @@ -19959,8 +20992,8 @@ packages: /vue-docgen-api@4.64.1(vue@3.3.4): resolution: {integrity: sha512-jbOf7ByE3Zvtuk+429Jorl+eIeh2aB2Fx1GUo3xJd1aByJWE8KDlSEa6b11PB1ze8f0sRUBraRDinICCk0KY7g==} dependencies: - '@babel/parser': 7.21.9 - '@babel/types': 7.21.5 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 '@vue/compiler-dom': 3.3.4 '@vue/compiler-sfc': 3.3.4 ast-types: 0.14.2 @@ -20244,8 +21277,8 @@ packages: resolution: {integrity: sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==} engines: {node: '>= 10.0.0'} dependencies: - '@babel/parser': 7.21.9 - '@babel/types': 7.21.5 + '@babel/parser': 7.22.4 + '@babel/types': 7.22.4 assert-never: 1.2.1 babel-walk: 3.0.0-canary-5 From ff56511638de8b0fca59e2d97fd4d2b37b65a692 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 17:20:25 +0900 Subject: [PATCH 157/213] 13.13.0-beta.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 089df44db1..d9e5d9f7fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0-beta.6", + "version": "13.13.0-beta.7", "codename": "nasubi", "repository": { "type": "git", From f6830885d74dffddb75b36d2afb54d0feecaede4 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 17:34:56 +0900 Subject: [PATCH 158/213] tweak of cd8274888 --- locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + .../frontend/src/pages/settings/general.vue | 23 +++++++++++++++---- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 3bdb37b9dc..7047f42eff 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1064,6 +1064,7 @@ export interface Locale { "later": string; "goToMisskey": string; "additionalEmojiDictionary": string; + "installed": string; "_initialAccountSetting": { "accountCreated": string; "letsStartAccountSetup": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 40fad285ca..fcba3fb822 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1061,6 +1061,7 @@ changeReactionConfirm: "リアクションを変更しますか?" later: "あとで" goToMisskey: "Misskeyへ" additionalEmojiDictionary: "絵文字の追加辞書" +installed: "インストール済み" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index 4ac077a5e3..20b36f0fcb 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -24,6 +24,7 @@ <div class="_gaps_s"> <MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch> <MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch> + <MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> </div> </FormSection> @@ -149,9 +150,11 @@ <div class="_gaps"> <MkFolder> <template #label>{{ i18n.ts.additionalEmojiDictionary }}</template> - <MkButton @click="downloadEmojiIndex('en-US')"><i class="ti ti-download"></i> en-US</MkButton> + <div v-for="lang in emojiIndexLangs" class="_buttons"> + <MkButton @click="downloadEmojiIndex(lang)"><i class="ti ti-download"></i> {{ lang }}{{ defaultStore.reactiveState.additionalUnicodeEmojiIndexes.value[lang] ? ` (${ i18n.ts.installed })` : '' }}</MkButton> + <MkButton v-if="defaultStore.reactiveState.additionalUnicodeEmojiIndexes.value[lang]" danger @click="removeEmojiIndex(lang)"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton> + </div> </MkFolder> - <MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> <FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink> <FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink> </div> @@ -259,7 +262,9 @@ watch([ await reloadAsk(); }); -async function downloadEmojiIndex(lang: string) { +const emojiIndexLangs = ['en-US']; + +function downloadEmojiIndex(lang: string) { async function main() { const currentIndexes = defaultStore.state.additionalUnicodeEmojiIndexes; function download() { @@ -269,7 +274,17 @@ async function downloadEmojiIndex(lang: string) { } } currentIndexes[lang] = await download(); - defaultStore.set('additionalUnicodeEmojiIndexes', currentIndexes); + await defaultStore.set('additionalUnicodeEmojiIndexes', currentIndexes); + } + + os.promiseDialog(main()); +} + +function removeEmojiIndex(lang: string) { + async function main() { + const currentIndexes = defaultStore.state.additionalUnicodeEmojiIndexes; + delete currentIndexes[lang]; + await defaultStore.set('additionalUnicodeEmojiIndexes', currentIndexes); } os.promiseDialog(main()); From 3b30ee3130bccd30693bc1df17f38e7c6e56947c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Thu, 1 Jun 2023 08:50:26 +0000 Subject: [PATCH 159/213] test: fix vitest --- packages/frontend/src/components/MkImgWithBlurhash.vue | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 3750dacddc..b07617b37e 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -23,6 +23,11 @@ import { WorkerMultiDispatch } from '@/scripts/worker-multi-dispatch'; import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; const workerPromise = new Promise<WorkerMultiDispatch | null>(resolve => { + // テスト環境で Web Worker インスタンスは作成できない + if (import.meta.env.MODE === 'test') { + resolve(null); + return; + } const testWorker = new TestWebGL2(); testWorker.addEventListener('message', event => { if (event.data.result) { From 861bfa06a84ba95ff47e12f69325999ac6909452 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 18:07:30 +0900 Subject: [PATCH 160/213] :art: --- packages/frontend/src/ui/deck/column.vue | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 8296c46691..9fb8498731 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -24,6 +24,9 @@ <template v-else><i class="ti ti-chevron-down"></i></template> </button> <span :class="$style.title"><slot name="header"></slot></span> + <svg viewBox="0 0 16 16" version="1.1" :class="$style.grabber"> + <path fill="currentColor" d="M10 13a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm0-4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm-4 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm5-9a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM7 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM6 5a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path> + </svg> <button v-tooltip="i18n.ts.settings" :class="$style.menu" class="_button" @click.stop="showSettingsMenu"><i class="ti ti-dots"></i></button> </header> <div v-if="active" ref="body" :class="$style.body"> @@ -364,23 +367,24 @@ function onDrop(ev) { z-index: 1; width: var(--deckColumnHeaderHeight); line-height: var(--deckColumnHeaderHeight); - color: var(--faceTextButton); - - &:hover { - color: var(--faceTextButtonHover); - } - - &:active { - color: var(--faceTextButtonActive); - } } .toggleActive { margin-left: -16px; } -.menu { +.grabber { margin-left: auto; + margin-right: 10px; + padding: 8px 8px; + box-sizing: border-box; + height: var(--deckColumnHeaderHeight); + cursor: move; + user-select: none; + opacity: 0.7; +} + +.menu { margin-right: -16px; } From 50aeaf7498eb1daca66c26e5be517781e488e03f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 19:45:06 +0900 Subject: [PATCH 161/213] [ci skip] :art: --- packages/frontend/src/ui/deck/column.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 9fb8498731..1051f643dc 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -381,7 +381,7 @@ function onDrop(ev) { height: var(--deckColumnHeaderHeight); cursor: move; user-select: none; - opacity: 0.7; + opacity: 0.5; } .menu { From 15450b18e85c65a45366c3d390053a467f92bba8 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 19:50:51 +0900 Subject: [PATCH 162/213] [ci skip] make enableCondensedLineForAcct false by default for performance --- packages/frontend/src/store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 4e43c8e745..6ba05c36ab 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -336,7 +336,7 @@ export const defaultStore = markRaw(new Storage('base', { }, enableCondensedLineForAcct: { where: 'device', - default: true, + default: false, }, additionalUnicodeEmojiIndexes: { where: 'device', From 23f272cc7dacb066c4217bac44888dd784e1a000 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 1 Jun 2023 19:55:33 +0900 Subject: [PATCH 163/213] [ci skip] update patrons --- packages/frontend/src/pages/about-misskey.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index d86a5e1126..0017145fa1 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -149,6 +149,12 @@ const patronsWithIcon = [{ }, { name: 'かみらえっと', icon: 'https://misskey-hub.net/patrons/be1326bda7d940a482f3758ffd9ffaf6.jpg', +}, { + name: 'へてて', + icon: 'https://misskey-hub.net/patrons/0431eacd7c6843d09de8ea9984307e86.jpg', +}, { + name: 'spinlock', + icon: 'https://misskey-hub.net/patrons/6a1cebc819d540a78bf20e9e3115baa8.jpg', }]; const patrons = [ From eedc8049db0da028f3231609bc4841e8fcdd095f Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Thu, 1 Jun 2023 12:03:07 +0000 Subject: [PATCH 164/213] fix(frontend): make scrollbar-color track transparent Fix #9414 --- packages/frontend/src/style.scss | 2 +- packages/frontend/src/ui/deck/column.vue | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 70d48d2da0..b376e4c42d 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -34,7 +34,7 @@ html { tab-size: 2; &, * { - scrollbar-color: var(--scrollbarHandle) inherit; + scrollbar-color: var(--scrollbarHandle) transparent; scrollbar-width: thin; &::-webkit-scrollbar { diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index 1051f643dc..c376eb2b47 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -304,6 +304,7 @@ function onDrop(ev) { &::-webkit-scrollbar-track { background: transparent; } + scrollbar-color: var(--scrollbarHandle) transparent; } } @@ -316,6 +317,7 @@ function onDrop(ev) { &::-webkit-scrollbar-track { background: inherit; } + scrollbar-color: var(--scrollbarHandle) transparent; } } } @@ -400,5 +402,6 @@ function onDrop(ev) { &::-webkit-scrollbar-track { background: var(--panel); } + scrollbar-color: var(--scrollbarHandle) var(--panel); } </style> From 8bdf0dd135a2455a2a8fefb3b5c324b0ecb04e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= <root@acid-chicken.com> Date: Thu, 1 Jun 2023 23:27:58 +0900 Subject: [PATCH 165/213] test: ignore `MkImgWithBlurhash` to avoid unstable snapshots --- packages/frontend/src/components/MkImgWithBlurhash.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index b07617b37e..672a28f6d0 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -1,5 +1,5 @@ <template> -<div ref="root" :class="[$style.root, { [$style.cover]: cover }]" :title="title ?? ''"> +<div ref="root" :class="['chromatic-ignore', $style.root, { [$style.cover]: cover }]" :title="title ?? ''"> <TransitionGroup :duration="defaultStore.state.animation && props.transition?.duration || undefined" :enterActiveClass="defaultStore.state.animation && props.transition?.enterActiveClass || undefined" From 9eaca966a480fc2b0a3da503d413994c5bf0cbe0 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 2 Jun 2023 09:13:41 +0900 Subject: [PATCH 166/213] perf(backend): terminate stalled websocket connections Resolve #10885 --- .../server/api/StreamingApiServerService.ts | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index fdda581ada..893dfe956e 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -19,6 +19,8 @@ import type * as http from 'node:http'; @Injectable() export class StreamingApiServerService { #wss: WebSocket.WebSocketServer; + #connections = new Map<WebSocket.WebSocket, number>(); + #cleanConnectionsIntervalId: NodeJS.Timeout | null = null; constructor( @Inject(DI.config) @@ -109,7 +111,9 @@ export class StreamingApiServerService { await stream.listen(ev, connection); - const intervalId = user ? setInterval(() => { + this.#connections.set(connection, Date.now()); + + const userUpdateIntervalId = user ? setInterval(() => { this.usersRepository.update(user.id, { lastActiveDate: new Date(), }); @@ -124,19 +128,34 @@ export class StreamingApiServerService { ev.removeAllListeners(); stream.dispose(); this.redisForSub.off('message', onRedisMessage); - if (intervalId) clearInterval(intervalId); + if (userUpdateIntervalId) clearInterval(userUpdateIntervalId); }); connection.on('message', async (data) => { + this.#connections.set(connection, Date.now()); if (data.toString() === 'ping') { connection.send('pong'); } }); }); + + this.#cleanConnectionsIntervalId = setInterval(() => { + const now = Date.now(); + for (const [connection, lastActive] of this.#connections.entries()) { + if (now - lastActive > 1000 * 60 * 5) { + connection.terminate(); + this.#connections.delete(connection); + } + } + }, 1000 * 60 * 5); } @bindThis public detach(): Promise<void> { + if (this.#cleanConnectionsIntervalId) { + clearInterval(this.#cleanConnectionsIntervalId); + this.#cleanConnectionsIntervalId = null; + } return new Promise((resolve) => { this.#wss.close(() => resolve()); }); From 3857cd589f3a73b4dd796dba08f507ac4d8095fa Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 2 Jun 2023 09:13:51 +0900 Subject: [PATCH 167/213] New Crowdin updates (#10935) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (German) * New translations ja-JP.yml (English) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Norwegian) * New translations ja-JP.yml (Norwegian) * New translations ja-JP.yml (Chinese Simplified) --- locales/de-DE.yml | 2 ++ locales/en-US.yml | 2 ++ locales/ko-KR.yml | 6 +++-- locales/no-NO.yml | 58 +++++++++++++++++++++++++++++++++++++++++------ locales/zh-CN.yml | 1 + 5 files changed, 60 insertions(+), 9 deletions(-) diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 8001a55764..c4c12cb1aa 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -1060,6 +1060,8 @@ cancelReactionConfirm: "Möchtest du deine Reaktion wirklich löschen?" changeReactionConfirm: "Möchtest du deine Reaktion wirklich ändern?" later: "Später" goToMisskey: "Zu Misskey" +additionalEmojiDictionary: "Zusätzliche Emoji-Wörterbücher" +installed: "Installiert" _initialAccountSetting: accountCreated: "Dein Konto wurde erfolgreich erstellt!" letsStartAccountSetup: "Lass uns nun dein Konto einrichten." diff --git a/locales/en-US.yml b/locales/en-US.yml index 1af33cb5a7..0f1c7c89fe 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1060,6 +1060,8 @@ cancelReactionConfirm: "Really delete your reaction?" changeReactionConfirm: "Really change your reaction?" later: "Later" goToMisskey: "To Misskey" +additionalEmojiDictionary: "Additional emoji dictionaries" +installed: "Installed" _initialAccountSetting: accountCreated: "Your account was successfully created!" letsStartAccountSetup: "For starters, let's set up your profile." diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index b4a9507b04..c36305137c 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1060,6 +1060,8 @@ cancelReactionConfirm: "리액션을 취소하시겠습니까?" changeReactionConfirm: "리액션을 변경하시겠습니까?" later: "나중에" goToMisskey: "Misskey로" +additionalEmojiDictionary: "이모지 추가 사전" +installed: "설치됨" _initialAccountSetting: accountCreated: "계정 생성이 완료되었습니다!" letsStartAccountSetup: "계정의 초기 설정을 진행합니다." @@ -1080,12 +1082,12 @@ _serverRules: _accountMigration: moveFrom: "다른 계정에서 이 계정으로 이사" moveFromSub: "다른 계정에 대한 별칭을 생성" - moveFromLabel: "기존 계정 #{n}" + moveFromLabel: "기존 계정 #{n}" moveFromDescription: "다른 계정에서 이 계정으로 팔로워를 가져오려면, 우선 여기에서 별칭을 지정해야 합니다. 반드시 이사하기 전에 지정해야 합니다! 기존 계정을 다음과 같은 형식으로 입력해 주십시오: @person@instance.com" moveTo: "이 계정에서 다른 계정으로 이사" moveToLabel: "이사할 계정:" moveCannotBeUndone: "한 번 이사하면, 두 번 다시 되돌릴 수 없습니다." - moveAccountDescription: "새 계정으로 이전합니다.\n ・팔로워가 새 계정을 자동으로 팔로우 합니다\n ・이 계정에서 팔로우는 모두 해제됩니다\n ・이 계정으로는 노트 작성 등을 할 수 없게 됩니다\n\n팔로워의 이전은 자동이지만, 팔로우는 수동으로 진행해야 합니다. 이전하기 전에 이 계정에서 팔로우를 내보내고, 이전 후에는 즉시 이전한 계정에서 가져오기를 진행하십시오.\n리스트・뮤트・차단에 대해서도 마찬가지이므로 수동으로 이전해야 합니다.\n\n(이 설명은 이 서버(Misskey v13.12.0 이후)의 사양입니다. Mastodon 등의 다른 ActivityPub 소프트웨어에서는 작동이 다를 수 있습니다.)" + moveAccountDescription: "새 계정으로 이전합니다.\n ・팔로워가 새 계정을 자동으로 팔로우 합니다\n ・이 계정에서 팔로우는 모두 해제됩니다\n ・이 계정으로는 노트 작성 등을 할 수 없게 됩니다\n\n팔로워는 자동으로 이전되지만, 팔로우는 수동으로 진행해야 합니다. 이전하기 전에 이 계정에서 팔로우를 내보내고, 이전 후에는 즉시 이전한 계정에서 가져오기를 진행하십시오.\n리스트・뮤트・차단에 대해서도 마찬가지이므로 수동으로 이전해야 합니다.\n\n(이 설명은 이 서버(Misskey v13.12.0 이후)의 사양입니다. Mastodon 등의 다른 ActivityPub 소프트웨어에서는 작동이 다를 수 있습니다.)" moveAccountHowTo: "계정을 이사하려면 우선 이사갈 계정에서 이 계정에 대한 별칭을 지정해야 합니다.\n별칭을 작성한 다음, 이사갈 계정을 다음과 같이 입력하십시오:\n@username@server.example.com" startMigration: "이사하기" migrationConfirm: "정말로 이 계정을 {account} 으로 이전하시겠습니까? 한 번 이전한 다음에는 취소할 수 없으며, 두 번 다시 원래 상태로 복구할 수 없습니다.\n이사할 계정에서 계정 별칭을 지정하였는지 다시 한 번 확인하십시오." diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 9d6c5fc501..ec2900527b 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -25,7 +25,7 @@ otherSettings: "Andre innstillinger" openInWindow: "Åpne i vindu" profile: "Profil" timeline: "Tidslinje" -noAccountDescription: "Denne brukeren har ikke skrevet sin bio ennå." +noAccountDescription: "Denne brukeren har ikke skrevet sin biografi ennå." login: "Logg inn" loggingIn: "Logget inn" logout: "Logg ut" @@ -81,6 +81,7 @@ pageLoadError: "Kunne ikke hente side." serverIsDead: "Denne serveren svarer ikke. Vennligst vent en stund og prøv igjen." enterListName: "Skriv inn et navn på listen" privacy: "Personvern" +defaultNoteVisibility: "Standard synlighet" follow: "Følg" followRequest: "Følgeforespørsel" followRequests: "Følgeforespørsel" @@ -92,6 +93,8 @@ renoted: "Renotet." cantRenote: "Dette innlegget kan ikke renotes." cantReRenote: "En Renote kan ikke renotes." quote: "Sitat" +inChannelRenote: "Renote kun for kanal" +inChannelQuote: "Sitat kun for kanal" pinnedNote: "Festet Note" pinned: "Fest til profil" you: "Du" @@ -145,14 +148,18 @@ instances: "Servere" registeredAt: "Registrerte seg" latestRequestReceivedAt: "Siste forespørsel mottatt" latestStatus: "Siste status" +charts: "Diagrammer" perHour: "Per time" perDay: "Per dag" stopActivityDelivery: "Slutt å sende aktiviteter" blockThisInstance: "Blokker denne serveren" +operations: "Operasjoner" software: "Programvare" version: "Versjon" +metadata: "Metadata" withNFiles: "{n} fil(er)" network: "Nettverk" +instanceInfo: "Serverinformasjon" statistics: "Statistikk" clearQueue: "Tøm kø" clearQueueConfirmTitle: "Er du sikker på at du vil tømme køen?" @@ -167,6 +174,8 @@ noteDeleteConfirm: "Er du sikker på at du vil slette denne Noten?" pinLimitExceeded: "Du kan ikke feste flere." intro: "Installasjonen av Misskey er ferdig! Vennligst opprett en administratorkonto." done: "Ferdig" +default: "Standard" +defaultValueIs: "Standard: {value}" noCustomEmojis: "Det er ingen emoji" noJobs: "Det er ingen jobber" blocked: "Blokkert" @@ -175,10 +184,13 @@ all: "Alle" notResponding: "Svarer ikke" changePassword: "Endre passord" security: "Sikkerhet" +retypedNotMatch: "Inngangene stemmer ikke overens." +currentPassword: "Nåværende passord" newPassword: "Nytt passord" newPasswordRetype: "Nytt passord (gjenta)" attachFile: "Legg ved filer" more: "Mer!" +noSuchUser: "Bruker ikke funnet" announcements: "Kunngjøringer" remove: "Slett" removed: "Vellykket slettet" @@ -188,9 +200,15 @@ saved: "Lagret" upload: "Laste opp" keepOriginalUploading: "Behold originalbildet" fromUrl: "Fra URL" +uploadFromUrl: "Last opp fra en URL" +uploadFromUrlDescription: "URL til filen du vil laste opp" explore: "Utforsk" messageRead: "Lest" -agree: "Jeg godtar" +nUsersRead: "lest av {n}" +agreeTo: "Jeg godtar {0}" +agree: "Godta" +agreeBelow: "Jeg godtar følgende" +basicNotesBeforeCreateAccount: "Viktige merknader" termsOfService: "Vilkår for bruk" home: "Hjem" activity: "Aktivitet" @@ -198,8 +216,12 @@ images: "Bilder" image: "Bilde" birthday: "Bursdag" yearsOld: "{age} år gammel" +theme: "Temaer" light: "Lys" dark: "Mørk" +lightThemes: "Lyse temaer" +darkThemes: "Mørke temaer" +syncDeviceDarkMode: "Synkroniser mørkmodus med enhetens innstillinger" fileName: "Filnavn" selectFile: "Velg en fil" selectFiles: "Velg filer" @@ -213,6 +235,9 @@ deleteFolder: "Slett denne mappen" addFile: "Legg til en fil" emptyFolder: "Denne mappen er tom" unableToDelete: "Kan ikke slette" +inputNewFileName: "Skriv inn et nytt filnavn" +inputNewDescription: "Skriv inn ny bildetekst" +inputNewFolderName: "Skriv inn et nytt mappenavn" circularReferenceFolder: "Målmappen er en undermappe til mappen du ønsker å flytte." hasChildFilesOrFolders: "Siden denne mappen ikke er tom, kan den ikke slettes." copyUrl: "Kopier URL" @@ -251,13 +276,23 @@ turnstile: "Turnstile" enableTurnstile: "Aktiver Turnstile" antennas: "Antenner" name: "Navn" +antennaSource: "Antennekilde" +notifyAntenna: "Varsle om nye Notes" +withFileAntenna: "Bare Notes med filer" +notesAndReplies: "Notes og svar" popularUsers: "Populære brukere" exploreUsersCount: "Det finnes {count} brukere" +exploreFediverse: "Utforsk Fediverse" userList: "Lister" -about: "Infomasjon" +about: "Informasjon" aboutMisskey: "Om Misskey" +newPasswordIs: "Det nye passordet er \"{password}\"." share: "Del" +notFound: "Ikke funnet" +markAsReadAllNotifications: "Merk alle varsler som lest" +markAsReadAllUnreadNotes: "Merk alle Notes som lest" help: "Hjelp" +inputMessageHere: "Skriv inn melding her" close: "Lukk" invites: "Inviter" members: "Medlemmer" @@ -265,6 +300,10 @@ title: "Tittel" text: "Tekst" next: "Neste" retype: "Gjenta" +quoteAttached: "Sitat" +noMessagesYet: "Ingen meldinger ennå" +newMessageExists: "Det er nye meldinger" +onlyOneFileCanBeAttached: "Du kan bare legge ved én fil i en melding" invitations: "Inviter" available: "Tilgjengelig" unavailable: "Utilgjengelig" @@ -564,6 +603,7 @@ _time: day: "Dager" _timelineTutorial: title: "Hvordan bruke Misskey" + step2_2: "Hva med å skrive en selvpresentasjon, eller bare \"Hei {name}!\" hvis du ikke har lyst?" _2fa: renewTOTPCancel: "Avbryt" _weekday: @@ -576,6 +616,7 @@ _weekday: saturday: "Lørdag" _widgets: profile: "Profil" + instanceInfo: "Serverinformasjon" notifications: "Varsler" timeline: "Tidslinje" calendar: "Kalender" @@ -611,6 +652,7 @@ _postForm: _profile: name: "Navn" username: "Brukernavn" + description: "Biografi" metadataContent: "Innhold" _exportOrImport: followingList: "Følg" @@ -652,12 +694,14 @@ _pages: button: "Knapp" _notification: youWereFollowed: "fulgte deg" + unreadAntennaNote: "Antenne {name}" + achievementEarned: "Prestasjon låst opp" _types: - follow: "Følg" + follow: "Nye følgere" reply: "Svar" - renote: "Renote" - quote: "Sitat" - reaction: "Reaksjon" + renote: "Renotes" + quote: "Sitater" + reaction: "Reaksjoner" _actions: reply: "Svar" renote: "Renote" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index a9ef92e7d3..9c278ea751 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1060,6 +1060,7 @@ cancelReactionConfirm: "要取消回应吗?" changeReactionConfirm: "要更改回应吗?" later: "一会再说" goToMisskey: "去往Misskey" +installed: "已安装" _initialAccountSetting: accountCreated: "账户创建完成了!" letsStartAccountSetup: "来进行帐户的初始设置吧。" From 40295ae57ddb99b673553030315762a47b76c952 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 2 Jun 2023 11:03:59 +0900 Subject: [PATCH 168/213] fix style Fix #10870 --- packages/frontend/src/components/MkUserInfo.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue index fea3842a5b..172b517511 100644 --- a/packages/frontend/src/components/MkUserInfo.vue +++ b/packages/frontend/src/components/MkUserInfo.vue @@ -8,7 +8,7 @@ </div> <span v-if="$i && $i.id !== user.id && user.isFollowed" :class="$style.followed">{{ i18n.ts.followsYou }}</span> <div :class="$style.description"> - <div v-if="user.description" class="mfm"> + <div v-if="user.description" :class="$style.mfm"> <Mfm :text="user.description" :author="user" :i="$i"/> </div> <span v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</span> From 91d790bbb65521eedc783aba9e863d188d30540b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 2 Jun 2023 11:34:38 +0900 Subject: [PATCH 169/213] update deps --- package.json | 8 +- packages/backend/package.json | 40 +- .../server/api/endpoints/i/2fa/key-done.ts | 2 +- .../backend/src/server/web/views/base.pug | 2 +- .../frontend/.storybook/preview-head.html | 2 +- packages/frontend/package.json | 26 +- pnpm-lock.yaml | 990 +++++++++++------- 7 files changed, 631 insertions(+), 439 deletions(-) diff --git a/package.json b/package.json index d9e5d9f7fd..81029514c3 100644 --- a/package.json +++ b/package.json @@ -51,16 +51,16 @@ "gulp-replace": "1.1.4", "gulp-terser": "2.1.0", "js-yaml": "4.1.0", - "typescript": "5.0.4" + "typescript": "5.1.3" }, "devDependencies": { "@types/gulp": "4.0.10", "@types/gulp-rename": "2.0.1", - "@typescript-eslint/eslint-plugin": "5.59.5", - "@typescript-eslint/parser": "5.59.5", + "@typescript-eslint/eslint-plugin": "5.59.8", + "@typescript-eslint/parser": "5.59.8", "cross-env": "7.0.3", "cypress": "12.13.0", - "eslint": "8.40.0", + "eslint": "8.41.0", "start-server-and-test": "2.0.0" }, "optionalDependencies": { diff --git a/packages/backend/package.json b/packages/backend/package.json index 66bc7ee478..56ecbc2eaf 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -60,27 +60,27 @@ "@discordapp/twemoji": "14.1.2", "@fastify/accepts": "4.1.0", "@fastify/cookie": "8.3.0", - "@fastify/cors": "8.2.1", + "@fastify/cors": "8.3.0", "@fastify/http-proxy": "9.1.0", "@fastify/multipart": "7.6.0", - "@fastify/static": "6.10.1", + "@fastify/static": "6.10.2", "@fastify/view": "7.4.1", "@nestjs/common": "9.4.2", "@nestjs/core": "9.4.2", "@nestjs/testing": "9.4.2", "@peertube/http-signature": "1.7.0", - "@sinonjs/fake-timers": "10.0.2", + "@sinonjs/fake-timers": "10.2.0", "@swc/cli": "0.1.62", - "@swc/core": "1.3.59", + "@swc/core": "1.3.61", "accepts": "1.3.8", "ajv": "8.12.0", "archiver": "5.3.1", "autwh": "0.1.0", "bcryptjs": "2.4.3", "blurhash": "2.0.5", - "bullmq": "3.14.1", + "bullmq": "3.15.0", "cacheable-lookup": "6.1.0", - "cbor": "8.1.0", + "cbor": "9.0.0", "chalk": "5.2.0", "chalk-template": "0.4.0", "chokidar": "3.5.3", @@ -96,24 +96,24 @@ "fluent-ffmpeg": "2.1.2", "form-data": "4.0.0", "got": "12.6.0", - "happy-dom": "9.19.2", + "happy-dom": "9.20.3", "hpagent": "1.2.0", "ioredis": "5.3.2", "ip-cidr": "3.1.0", "is-svg": "4.3.2", "js-yaml": "4.1.0", - "jsdom": "21.1.1", + "jsdom": "22.1.0", "json5": "2.2.3", - "jsonld": "8.1.1", + "jsonld": "8.2.0", "jsrsasign": "10.8.6", - "meilisearch": "0.32.4", + "meilisearch": "0.32.5", "mfm-js": "0.23.3", "mime-types": "2.1.35", "misskey-js": "workspace:*", "ms": "3.0.0-canary.1", "nested-property": "4.0.0", "node-fetch": "3.3.1", - "nodemailer": "6.9.2", + "nodemailer": "6.9.3", "nsfwjs": "2.4.2", "oauth": "0.10.0", "os-utils": "0.0.14", @@ -129,7 +129,7 @@ "qrcode": "1.5.3", "random-seed": "0.3.0", "ratelimiter": "3.4.1", - "re2": "1.18.0", + "re2": "1.19.0", "redis-lock": "0.1.4", "reflect-metadata": "0.1.13", "rename": "1.0.4", @@ -146,16 +146,16 @@ "strict-event-emitter-types": "2.0.0", "stringz": "2.1.0", "summaly": "github:misskey-dev/summaly", - "systeminformation": "5.17.12", + "systeminformation": "5.17.16", "tinycolor2": "1.6.0", "tmp": "0.2.1", "tsc-alias": "1.8.6", "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", "typeorm": "0.3.16", - "typescript": "5.0.4", + "typescript": "5.1.3", "ulid": "2.3.0", - "unzipper": "0.10.11", + "unzipper": "0.10.14", "uuid": "9.0.0", "vary": "1.1.2", "web-push": "3.6.1", @@ -173,13 +173,13 @@ "@types/content-disposition": "0.5.5", "@types/escape-regexp": "0.0.1", "@types/fluent-ffmpeg": "2.1.21", - "@types/jest": "29.5.1", + "@types/jest": "29.5.2", "@types/js-yaml": "4.0.5", "@types/jsdom": "21.1.1", "@types/jsonld": "1.5.8", "@types/jsrsasign": "10.5.8", "@types/mime-types": "2.1.1", - "@types/node": "20.2.3", + "@types/node": "20.2.5", "@types/node-fetch": "3.0.3", "@types/nodemailer": "6.4.8", "@types/oauth": "0.9.1", @@ -203,11 +203,11 @@ "@types/web-push": "3.3.2", "@types/websocket": "1.0.5", "@types/ws": "8.5.4", - "@typescript-eslint/eslint-plugin": "5.59.5", - "@typescript-eslint/parser": "5.59.5", + "@typescript-eslint/eslint-plugin": "5.59.8", + "@typescript-eslint/parser": "5.59.8", "aws-sdk-client-mock": "2.1.1", "cross-env": "7.0.3", - "eslint": "8.40.0", + "eslint": "8.41.0", "eslint-plugin-import": "2.27.5", "execa": "6.1.0", "jest": "29.5.0", diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts index ad33398da6..e8985a9cd8 100644 --- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts +++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts @@ -1,6 +1,6 @@ import { promisify } from 'node:util'; import bcrypt from 'bcryptjs'; -import * as cbor from 'cbor'; +import cbor from 'cbor'; import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 25513cc4cc..69b3f68e05 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -35,7 +35,7 @@ html link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') //- https://github.com/misskey-dev/misskey/issues/9842 - link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.17.0') + link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.21.0') link(rel='modulepreload' href=`/vite/${clientEntry.file}`) if !config.clientManifestExists diff --git a/packages/frontend/.storybook/preview-head.html b/packages/frontend/.storybook/preview-head.html index ab694f64fb..f6a9a4875d 100644 --- a/packages/frontend/.storybook/preview-head.html +++ b/packages/frontend/.storybook/preview-head.html @@ -1,6 +1,6 @@ <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true" as="image" type="image/png" crossorigin="anonymous"> <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true" as="image" type="image/jpeg" crossorigin="anonymous"> -<link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@2.12.0/tabler-icons.min.css"> +<link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@2.21.0/tabler-icons.min.css"> <link rel="stylesheet" href="https://unpkg.com/@fontsource/m-plus-rounded-1c/index.css"> <style> html { diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 6720a5939b..506d187901 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -20,13 +20,13 @@ "@rollup/plugin-replace": "5.0.2", "@rollup/pluginutils": "5.0.2", "@syuilo/aiscript": "0.13.3", - "@tabler/icons-webfont": "2.17.0", + "@tabler/icons-webfont": "2.21.0", "@vitejs/plugin-vue": "4.2.3", - "@vue-macros/reactivity-transform": "0.3.8", + "@vue-macros/reactivity-transform": "0.3.9", "@vue/compiler-sfc": "3.3.4", - "astring": "1.8.5", + "astring": "1.8.6", "autosize": "6.0.1", - "broadcast-channel": "4.20.2", + "broadcast-channel": "5.1.0", "browser-image-resizer": "github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3", "buraha": "github:misskey-dev/buraha", "canvas-confetti": "1.6.0", @@ -35,7 +35,7 @@ "chartjs-chart-matrix": "2.0.1", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.0.1", - "chromatic": "6.17.4", + "chromatic": "6.18.0", "compare-versions": "5.0.3", "cropperjs": "2.0.0-beta.2", "date-fns": "2.30.0", @@ -63,13 +63,13 @@ "strict-event-emitter-types": "2.0.0", "syuilo-password-strength": "0.0.1", "textarea-caret": "3.1.0", - "three": "0.151.3", + "three": "0.153.0", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tsc-alias": "1.8.6", "tsconfig-paths": "4.2.0", "twemoji-parser": "14.0.0", - "typescript": "5.0.4", + "typescript": "5.1.3", "uuid": "9.0.0", "vanilla-tilt": "1.8.0", "vite": "4.3.9", @@ -114,19 +114,19 @@ "@types/uuid": "9.0.1", "@types/websocket": "1.0.5", "@types/ws": "8.5.4", - "@typescript-eslint/eslint-plugin": "5.59.5", - "@typescript-eslint/parser": "5.59.5", - "@vitest/coverage-c8": "0.31.1", + "@typescript-eslint/eslint-plugin": "5.59.8", + "@typescript-eslint/parser": "5.59.8", + "@vitest/coverage-c8": "0.31.4", "@vue/runtime-core": "3.3.4", "acorn": "^8.8.2", "chokidar-cli": "3.0.0", "cross-env": "7.0.3", "cypress": "12.13.0", - "eslint": "8.40.0", + "eslint": "8.41.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-vue": "9.14.1", "fast-glob": "3.2.12", - "happy-dom": "9.19.2", + "happy-dom": "9.20.3", "micromatch": "3.1.10", "msw": "1.2.1", "msw-storybook-addon": "1.8.0", @@ -138,7 +138,7 @@ "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "summaly": "github:misskey-dev/summaly", "vite-plugin-turbosnap": "1.0.2", - "vitest": "0.31.1", + "vitest": "0.31.4", "vitest-fetch-mock": "0.2.2", "vue-eslint-parser": "9.3.0", "vue-tsc": "1.6.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4b66a1ff5..f48fac3f47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,8 +34,8 @@ importers: specifier: 4.1.0 version: 4.1.0 typescript: - specifier: 5.0.4 - version: 5.0.4 + specifier: 5.1.3 + version: 5.1.3 optionalDependencies: '@tensorflow/tfjs-core': specifier: 4.4.0 @@ -48,11 +48,11 @@ importers: specifier: 2.0.1 version: 2.0.1 '@typescript-eslint/eslint-plugin': - specifier: 5.59.5 - version: 5.59.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0)(typescript@5.0.4) + specifier: 5.59.8 + version: 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.41.0)(typescript@5.1.3) '@typescript-eslint/parser': - specifier: 5.59.5 - version: 5.59.5(eslint@8.40.0)(typescript@5.0.4) + specifier: 5.59.8 + version: 5.59.8(eslint@8.41.0)(typescript@5.1.3) cross-env: specifier: 7.0.3 version: 7.0.3 @@ -60,8 +60,8 @@ importers: specifier: 12.13.0 version: 12.13.0 eslint: - specifier: 8.40.0 - version: 8.40.0 + specifier: 8.41.0 + version: 8.41.0 start-server-and-test: specifier: 2.0.0 version: 2.0.0 @@ -96,8 +96,8 @@ importers: specifier: 8.3.0 version: 8.3.0 '@fastify/cors': - specifier: 8.2.1 - version: 8.2.1 + specifier: 8.3.0 + version: 8.3.0 '@fastify/http-proxy': specifier: 9.1.0 version: 9.1.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) @@ -105,8 +105,8 @@ importers: specifier: 7.6.0 version: 7.6.0 '@fastify/static': - specifier: 6.10.1 - version: 6.10.1 + specifier: 6.10.2 + version: 6.10.2 '@fastify/view': specifier: 7.4.1 version: 7.4.1 @@ -123,14 +123,14 @@ importers: specifier: 1.7.0 version: 1.7.0 '@sinonjs/fake-timers': - specifier: 10.0.2 - version: 10.0.2 + specifier: 10.2.0 + version: 10.2.0 '@swc/cli': specifier: 0.1.62 - version: 0.1.62(@swc/core@1.3.59)(chokidar@3.5.3) + version: 0.1.62(@swc/core@1.3.61)(chokidar@3.5.3) '@swc/core': - specifier: 1.3.59 - version: 1.3.59 + specifier: 1.3.61 + version: 1.3.61 accepts: specifier: 1.3.8 version: 1.3.8 @@ -150,14 +150,14 @@ importers: specifier: 2.0.5 version: 2.0.5 bullmq: - specifier: 3.14.1 - version: 3.14.1 + specifier: 3.15.0 + version: 3.15.0 cacheable-lookup: specifier: 6.1.0 version: 6.1.0 cbor: - specifier: 8.1.0 - version: 8.1.0 + specifier: 9.0.0 + version: 9.0.0 chalk: specifier: 5.2.0 version: 5.2.0 @@ -204,8 +204,8 @@ importers: specifier: 12.6.0 version: 12.6.0 happy-dom: - specifier: 9.19.2 - version: 9.19.2 + specifier: 9.20.3 + version: 9.20.3 hpagent: specifier: 1.2.0 version: 1.2.0 @@ -222,20 +222,20 @@ importers: specifier: 4.1.0 version: 4.1.0 jsdom: - specifier: 21.1.1 - version: 21.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3) + specifier: 22.1.0 + version: 22.1.0(bufferutil@4.0.7)(utf-8-validate@6.0.3) json5: specifier: 2.2.3 version: 2.2.3 jsonld: - specifier: 8.1.1 - version: 8.1.1 + specifier: 8.2.0 + version: 8.2.0 jsrsasign: specifier: 10.8.6 version: 10.8.6 meilisearch: - specifier: 0.32.4 - version: 0.32.4 + specifier: 0.32.5 + version: 0.32.5 mfm-js: specifier: 0.23.3 version: 0.23.3 @@ -255,8 +255,8 @@ importers: specifier: 3.3.1 version: 3.3.1 nodemailer: - specifier: 6.9.2 - version: 6.9.2 + specifier: 6.9.3 + version: 6.9.3 nsfwjs: specifier: 2.4.2 version: 2.4.2(@tensorflow/tfjs@4.4.0) @@ -303,8 +303,8 @@ importers: specifier: 3.4.1 version: 3.4.1 re2: - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.19.0 + version: 1.19.0 redis-lock: specifier: 0.1.4 version: 0.1.4 @@ -354,8 +354,8 @@ importers: specifier: github:misskey-dev/summaly version: github.com/misskey-dev/summaly/77dd5654bb82280b38c1f50e51a771c33f3df503 systeminformation: - specifier: 5.17.12 - version: 5.17.12 + specifier: 5.17.16 + version: 5.17.16 tinycolor2: specifier: 1.6.0 version: 1.6.0 @@ -375,14 +375,14 @@ importers: specifier: 0.3.16 version: 0.3.16(ioredis@5.3.2)(pg@8.11.0) typescript: - specifier: 5.0.4 - version: 5.0.4 + specifier: 5.1.3 + version: 5.1.3 ulid: specifier: 2.3.0 version: 2.3.0 unzipper: - specifier: 0.10.11 - version: 0.10.11 + specifier: 0.10.14 + version: 0.10.14 uuid: specifier: 9.0.0 version: 9.0.0 @@ -486,7 +486,7 @@ importers: version: 29.5.0 '@swc/jest': specifier: 0.2.26 - version: 0.2.26(@swc/core@1.3.59) + version: 0.2.26(@swc/core@1.3.61) '@types/accepts': specifier: 1.3.5 version: 1.3.5 @@ -512,8 +512,8 @@ importers: specifier: 2.1.21 version: 2.1.21 '@types/jest': - specifier: 29.5.1 - version: 29.5.1 + specifier: 29.5.2 + version: 29.5.2 '@types/js-yaml': specifier: 4.0.5 version: 4.0.5 @@ -530,8 +530,8 @@ importers: specifier: 2.1.1 version: 2.1.1 '@types/node': - specifier: 20.2.3 - version: 20.2.3 + specifier: 20.2.5 + version: 20.2.5 '@types/node-fetch': specifier: 3.0.3 version: 3.0.3 @@ -602,11 +602,11 @@ importers: specifier: 8.5.4 version: 8.5.4 '@typescript-eslint/eslint-plugin': - specifier: 5.59.5 - version: 5.59.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0)(typescript@5.0.4) + specifier: 5.59.8 + version: 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.41.0)(typescript@5.1.3) '@typescript-eslint/parser': - specifier: 5.59.5 - version: 5.59.5(eslint@8.40.0)(typescript@5.0.4) + specifier: 5.59.8 + version: 5.59.8(eslint@8.41.0)(typescript@5.1.3) aws-sdk-client-mock: specifier: 2.1.1 version: 2.1.1 @@ -614,17 +614,17 @@ importers: specifier: 7.0.3 version: 7.0.3 eslint: - specifier: 8.40.0 - version: 8.40.0 + specifier: 8.41.0 + version: 8.41.0 eslint-plugin-import: specifier: 2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0) + version: 2.27.5(@typescript-eslint/parser@5.59.8)(eslint@8.41.0) execa: specifier: 6.1.0 version: 6.1.0 jest: specifier: 29.5.0 - version: 29.5.0(@types/node@20.2.3) + version: 29.5.0(@types/node@20.2.5) jest-mock: specifier: 29.5.0 version: 29.5.0 @@ -650,26 +650,26 @@ importers: specifier: 0.13.3 version: 0.13.3 '@tabler/icons-webfont': - specifier: 2.17.0 - version: 2.17.0 + specifier: 2.21.0 + version: 2.21.0 '@vitejs/plugin-vue': specifier: 4.2.3 version: 4.2.3(vite@4.3.9)(vue@3.3.4) '@vue-macros/reactivity-transform': - specifier: 0.3.8 - version: 0.3.8(rollup@3.23.0)(vue@3.3.4) + specifier: 0.3.9 + version: 0.3.9(rollup@3.23.0)(vue@3.3.4) '@vue/compiler-sfc': specifier: 3.3.4 version: 3.3.4 astring: - specifier: 1.8.5 - version: 1.8.5 + specifier: 1.8.6 + version: 1.8.6 autosize: specifier: 6.0.1 version: 6.0.1 broadcast-channel: - specifier: 4.20.2 - version: 4.20.2 + specifier: 5.1.0 + version: 5.1.0 browser-image-resizer: specifier: github:misskey-dev/browser-image-resizer#v2.2.1-misskey.3 version: github.com/misskey-dev/browser-image-resizer/0227e860621e55cbed0aabe6dc601096a7748c4a @@ -695,8 +695,8 @@ importers: specifier: 2.0.1 version: 2.0.1(chart.js@4.3.0) chromatic: - specifier: 6.17.4 - version: 6.17.4 + specifier: 6.18.0 + version: 6.18.0 compare-versions: specifier: 5.0.3 version: 5.0.3 @@ -779,8 +779,8 @@ importers: specifier: 3.1.0 version: 3.1.0 three: - specifier: 0.151.3 - version: 0.151.3 + specifier: 0.153.0 + version: 0.153.0 throttle-debounce: specifier: 5.0.0 version: 5.0.0 @@ -797,8 +797,8 @@ importers: specifier: 14.0.0 version: 14.0.0 typescript: - specifier: 5.0.4 - version: 5.0.4 + specifier: 5.1.3 + version: 5.1.3 uuid: specifier: 9.0.0 version: 9.0.0 @@ -853,10 +853,10 @@ importers: version: 7.0.18 '@storybook/react': specifier: 7.0.18 - version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3) '@storybook/react-vite': specifier: 7.0.18 - version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9) + version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(vite@4.3.9) '@storybook/testing-library': specifier: 0.1.0 version: 0.1.0 @@ -871,7 +871,7 @@ importers: version: 7.0.18(vue@3.3.4) '@storybook/vue3-vite': specifier: 7.0.18 - version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9)(vue@3.3.4) + version: 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(vite@4.3.9)(vue@3.3.4) '@testing-library/jest-dom': specifier: 5.16.5 version: 5.16.5 @@ -927,14 +927,14 @@ importers: specifier: 8.5.4 version: 8.5.4 '@typescript-eslint/eslint-plugin': - specifier: 5.59.5 - version: 5.59.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0)(typescript@5.0.4) + specifier: 5.59.8 + version: 5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.41.0)(typescript@5.1.3) '@typescript-eslint/parser': - specifier: 5.59.5 - version: 5.59.5(eslint@8.40.0)(typescript@5.0.4) + specifier: 5.59.8 + version: 5.59.8(eslint@8.41.0)(typescript@5.1.3) '@vitest/coverage-c8': - specifier: 0.31.1 - version: 0.31.1(vitest@0.31.1) + specifier: 0.31.4 + version: 0.31.4(vitest@0.31.4) '@vue/runtime-core': specifier: 3.3.4 version: 3.3.4 @@ -951,26 +951,26 @@ importers: specifier: 12.13.0 version: 12.13.0 eslint: - specifier: 8.40.0 - version: 8.40.0 + specifier: 8.41.0 + version: 8.41.0 eslint-plugin-import: specifier: 2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0) + version: 2.27.5(@typescript-eslint/parser@5.59.8)(eslint@8.41.0) eslint-plugin-vue: specifier: 9.14.1 - version: 9.14.1(eslint@8.40.0) + version: 9.14.1(eslint@8.41.0) fast-glob: specifier: 3.2.12 version: 3.2.12 happy-dom: - specifier: 9.19.2 - version: 9.19.2 + specifier: 9.20.3 + version: 9.20.3 micromatch: specifier: 3.1.10 version: 3.1.10 msw: specifier: 1.2.1 - version: 1.2.1(typescript@5.0.4) + version: 1.2.1(typescript@5.1.3) msw-storybook-addon: specifier: 1.8.0 version: 1.8.0(msw@1.2.1) @@ -999,23 +999,23 @@ importers: specifier: 1.0.2 version: 1.0.2 vitest: - specifier: 0.31.1 - version: 0.31.1(happy-dom@9.19.2)(sass@1.62.1) + specifier: 0.31.4 + version: 0.31.4(happy-dom@9.20.3)(sass@1.62.1) vitest-fetch-mock: specifier: 0.2.2 - version: 0.2.2(vitest@0.31.1) + version: 0.2.2(vitest@0.31.4) vue-eslint-parser: specifier: 9.3.0 - version: 9.3.0(eslint@8.40.0) + version: 9.3.0(eslint@8.41.0) vue-tsc: specifier: 1.6.5 - version: 1.6.5(typescript@5.0.4) + version: 1.6.5(typescript@5.1.3) packages/misskey-js: dependencies: '@swc/cli': specifier: 0.1.62 - version: 0.1.62(@swc/core@1.3.59)(chokidar@3.5.3) + version: 0.1.62(@swc/core@1.3.61)(chokidar@3.5.3) '@swc/core': specifier: 1.3.56 version: 1.3.56 @@ -2092,7 +2092,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 - dev: true /@babel/compat-data@7.22.3: resolution: {integrity: sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==} @@ -2153,7 +2152,6 @@ packages: '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 jsesc: 2.5.2 - dev: true /@babel/generator@7.22.3: resolution: {integrity: sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==} @@ -2163,7 +2161,6 @@ packages: '@jridgewell/gen-mapping': 0.3.2 '@jridgewell/trace-mapping': 0.3.17 jsesc: 2.5.2 - dev: true /@babel/helper-annotate-as-pure@7.18.6: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} @@ -2303,7 +2300,6 @@ packages: /@babel/helper-environment-visitor@7.22.1: resolution: {integrity: sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-explode-assignable-expression@7.18.6: resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} @@ -2318,14 +2314,12 @@ packages: dependencies: '@babel/template': 7.21.9 '@babel/types': 7.22.4 - dev: true /@babel/helper-hoist-variables@7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.4 - dev: true /@babel/helper-member-expression-to-functions@7.21.0: resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==} @@ -2432,7 +2426,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.22.4 - dev: true /@babel/helper-string-parser@7.21.5: resolution: {integrity: sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==} @@ -2477,7 +2470,6 @@ packages: '@babel/helper-validator-identifier': 7.19.1 chalk: 2.4.2 js-tokens: 4.0.0 - dev: true /@babel/parser@7.21.8: resolution: {integrity: sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==} @@ -4285,6 +4277,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 + dev: true /@babel/runtime@7.21.0: resolution: {integrity: sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==} @@ -4299,7 +4292,6 @@ packages: '@babel/code-frame': 7.21.4 '@babel/parser': 7.22.4 '@babel/types': 7.22.4 - dev: true /@babel/traverse@7.21.3: resolution: {integrity: sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==} @@ -4317,7 +4309,6 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true /@babel/traverse@7.22.4: resolution: {integrity: sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==} @@ -4344,7 +4335,6 @@ packages: '@babel/helper-string-parser': 7.21.5 '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - dev: true /@babel/types@7.22.4: resolution: {integrity: sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==} @@ -4376,7 +4366,7 @@ packages: dependencies: '@bull-board/api': 5.2.0(@bull-board/ui@5.2.0) '@bull-board/ui': 5.2.0 - '@fastify/static': 6.10.1 + '@fastify/static': 6.10.2 '@fastify/view': 7.4.1 ejs: 3.1.8 dev: false @@ -4523,13 +4513,13 @@ packages: - supports-color dev: true - /@digitalbazaar/http-client@3.2.0: - resolution: {integrity: sha512-NhYXcWE/JDE7AnJikNX7q0S6zNuUPA2NuIoRdUpmvHlarjmRqyr6hIO3Awu2FxlUzbdiI1uzuWrZyB9mD1tTvw==} + /@digitalbazaar/http-client@3.4.1: + resolution: {integrity: sha512-Ahk1N+s7urkgj7WvvUND5f8GiWEPfUw0D41hdElaqLgu8wZScI8gdI0q+qWw5N1d35x7GCRH2uk9mi+Uzo9M3g==} engines: {node: '>=14.0'} dependencies: - ky: 0.30.0 - ky-universal: 0.10.1(ky@0.30.0) - undici: 5.16.0 + ky: 0.33.3 + ky-universal: 0.11.0(ky@0.33.3) + undici: 5.22.1 transitivePeerDependencies: - web-streams-polyfill dev: false @@ -4741,6 +4731,16 @@ packages: eslint-visitor-keys: 3.4.1 dev: true + /@eslint-community/eslint-utils@4.4.0(eslint@8.41.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.41.0 + eslint-visitor-keys: 3.4.1 + dev: true + /@eslint-community/regexpp@4.5.0: resolution: {integrity: sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -4768,6 +4768,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@eslint/js@8.41.0: + resolution: {integrity: sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@fal-works/esbuild-plugin-global-externals@2.1.2: resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} dev: true @@ -4806,8 +4811,8 @@ packages: fastify-plugin: 4.5.0 dev: false - /@fastify/cors@8.2.1: - resolution: {integrity: sha512-2H2MrDD3ea7g707g1CNNLWb9/tYbmw7HS+MK2SDcgjxwzbOFR93JortelTIO8DBFsZqFtEpKNxiZfSyrGgYcbw==} + /@fastify/cors@8.3.0: + resolution: {integrity: sha512-oj9xkka2Tg0MrwuKhsSUumcAkfp2YCnKxmFEusi01pjk1YrdDsuSYTHXEelWNW+ilSy/ApZq0c2SvhKrLX0H1g==} dependencies: fastify-plugin: 4.5.0 mnemonist: 0.39.5 @@ -4873,8 +4878,8 @@ packages: mime: 3.0.0 dev: false - /@fastify/static@6.10.1: - resolution: {integrity: sha512-DNnG+5QenQcTQw37qk0/191STThnN6SbU+2XMpWtpYR3gQUfUvMax14jTT/jqNINNbCkQJaKMnPtpFPKo4/68g==} + /@fastify/static@6.10.2: + resolution: {integrity: sha512-UoaMvIHSBLCZBYOVZwFRYqX2ufUhd7FFMYGDeSf0Z+D8jhYtwljjmuQGuanUP8kS4y/ZEV1a8mfLha3zNwsnnQ==} dependencies: '@fastify/accept-negotiator': 1.0.0 '@fastify/send': 2.0.1 @@ -5039,7 +5044,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@sinonjs/fake-timers': 10.0.2 + '@sinonjs/fake-timers': 10.2.0 '@types/node': 20.2.5 jest-message-util: 29.5.0 jest-mock: 29.5.0 @@ -5184,7 +5189,7 @@ packages: chalk: 4.1.2 dev: true - /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.0.4)(vite@4.3.9): + /@joshwooding/vite-plugin-react-docgen-typescript@0.2.1(typescript@5.1.3)(vite@4.3.9): resolution: {integrity: sha512-ou4ZJSXMMWHqGS4g8uNRbC5TiTWxAgQZiVucoUrOCWuPrTbkpJbmVyIi9jU72SBry7gQtuMEDp4YR8EEXAg7VQ==} peerDependencies: typescript: '>= 4.3.x' @@ -5196,8 +5201,8 @@ packages: glob: 7.2.3 glob-promise: 4.2.2(glob@7.2.3) magic-string: 0.27.0 - react-docgen-typescript: 2.2.2(typescript@5.0.4) - typescript: 5.0.4 + react-docgen-typescript: 2.2.2(typescript@5.1.3) + typescript: 5.1.3 vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) dev: true @@ -5518,6 +5523,7 @@ packages: /@npmcli/move-file@2.0.1: resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This functionality has been moved to @npmcli/fs dependencies: mkdirp: 1.0.4 rimraf: 3.0.2 @@ -5753,11 +5759,17 @@ packages: resolution: {integrity: sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==} dependencies: type-detect: 4.0.8 + dev: true - /@sinonjs/fake-timers@10.0.2: - resolution: {integrity: sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==} + /@sinonjs/commons@3.0.0: + resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==} dependencies: - '@sinonjs/commons': 2.0.0 + type-detect: 4.0.8 + + /@sinonjs/fake-timers@10.2.0: + resolution: {integrity: sha512-OPwQlEdg40HAj5KNF8WW6q2KG4Z+cBCZb3m4ninfTZKaBmbIJodviQsDBoYMPHkOyJJMHnOJo5j2+LKDOhOACg==} + dependencies: + '@sinonjs/commons': 3.0.0 /@sinonjs/fake-timers@9.1.2: resolution: {integrity: sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==} @@ -6216,7 +6228,7 @@ packages: - supports-color dev: true - /@storybook/builder-vite@7.0.18(typescript@5.0.4)(vite@4.3.9): + /@storybook/builder-vite@7.0.18(typescript@5.1.3)(vite@4.3.9): resolution: {integrity: sha512-Qze6/PwUJq+z776dBoG5uinAEVZyPalZIaU/VOWpTrN8L9FQbL0+HDrZU2E/BMNW+ZfnSjF3V2USLyiutsC1Tw==} peerDependencies: '@preact/preset-vite': '*' @@ -6251,7 +6263,7 @@ packages: remark-external-links: 8.0.0 remark-slug: 6.1.0 rollup: 3.23.0 - typescript: 5.0.4 + typescript: 5.1.3 vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) transitivePeerDependencies: - supports-color @@ -6301,7 +6313,6 @@ packages: /@storybook/channels@7.0.18: resolution: {integrity: sha512-rkA7ea0M3+dWS+71iHJdiZ5R2QuIdiVg0CgyLJHDagc1qej7pEVNhMWtppeq+X5Pwp9nkz8ZTQ7aCjTf6th0/A==} - dev: true /@storybook/channels@7.0.2: resolution: {integrity: sha512-qkI8mFy9c8mxN2f01etayKhCaauL6RAsxRzbX1/pKj6UqhHWqqUbtHwymrv4hG5qDYjV1e9pd7ae5eNF8Kui0g==} @@ -6537,13 +6548,11 @@ packages: ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - dev: true /@storybook/csf@0.1.0: resolution: {integrity: sha512-uk+jMXCZ8t38jSTHk2o5btI+aV2Ksbvl6DoOv3r6VaCM1KZqeuMwtwywIQdflkA8/6q/dKT8z8L+g8hC4GC3VQ==} dependencies: type-fest: 2.19.0 - dev: true /@storybook/docs-mdx@0.1.0: resolution: {integrity: sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg==} @@ -6566,7 +6575,7 @@ packages: /@storybook/expect@27.5.2-0: resolution: {integrity: sha512-cP99mhWN/JeCp7VSIiymvj5tmuMY050iFohvp8Zq+kewKsBSZ6/qpTJAGCCZk6pneTcp4S0Fm5BSqyxzbyJ3gw==} dependencies: - '@types/jest': 29.5.1 + '@types/jest': 29.5.2 dev: true /@storybook/global@5.0.0: @@ -6732,7 +6741,7 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /@storybook/react-vite@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9): + /@storybook/react-vite@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(vite@4.3.9): resolution: {integrity: sha512-rxJwp/b0dPazn15xLIeRgwrdZGWmoqoLhU7Mm+AXKToXvbe77i2bjHhkFbz34dpKFtD0i/ajcZSpmsxpxfB0HA==} engines: {node: '>=16'} peerDependencies: @@ -6740,10 +6749,10 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.0.4)(vite@4.3.9) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.2.1(typescript@5.1.3)(vite@4.3.9) '@rollup/pluginutils': 4.2.1 - '@storybook/builder-vite': 7.0.18(typescript@5.0.4)(vite@4.3.9) - '@storybook/react': 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4) + '@storybook/builder-vite': 7.0.18(typescript@5.1.3)(vite@4.3.9) + '@storybook/react': 7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3) '@vitejs/plugin-react': 3.1.0(vite@4.3.9) ast-types: 0.14.2 magic-string: 0.27.0 @@ -6758,7 +6767,7 @@ packages: - vite-plugin-glimmerx dev: true - /@storybook/react@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4): + /@storybook/react@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3): resolution: {integrity: sha512-lumUbHYeuL3qa4SZR9K2YC4UIt1hwW19GuI/6f2HEV5gR9QHHSJHg9HD9pjcxv4fQaiG81ACZ0Sg6lyUkcJvuQ==} engines: {node: '>=16.0.0'} peerDependencies: @@ -6791,7 +6800,7 @@ packages: react-element-to-jsx-string: 15.0.0(react-dom@18.2.0)(react@18.2.0) ts-dedent: 2.2.0 type-fest: 2.19.0 - typescript: 5.0.4 + typescript: 5.1.3 util-deprecate: 1.0.2 transitivePeerDependencies: - supports-color @@ -6873,7 +6882,6 @@ packages: '@types/babel__core': 7.20.0 '@types/express': 4.17.17 file-system-cache: 2.0.2 - dev: true /@storybook/types@7.0.2: resolution: {integrity: sha512-0OCt/kAexa8MCcljxA+yZxGMn0n2U2Ync0KxotItqNbKBKVkaLQUls0+IXTWSCpC/QJvNZ049jxUHHanNi/96w==} @@ -6893,7 +6901,7 @@ packages: file-system-cache: 2.0.2 dev: true - /@storybook/vue3-vite@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.0.4)(vite@4.3.9)(vue@3.3.4): + /@storybook/vue3-vite@7.0.18(react-dom@18.2.0)(react@18.2.0)(typescript@5.1.3)(vite@4.3.9)(vue@3.3.4): resolution: {integrity: sha512-dwkwBQRDUSvf44Z4ZDftusP6obuczPkApxALxsTczkbpOxK/13SXArlrKgyUaFrcqto9i2e8HbAYb7y1ymO3ig==} engines: {node: ^14.18 || >=16} peerDependencies: @@ -6901,7 +6909,7 @@ packages: react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 vite: ^3.0.0 || ^4.0.0 dependencies: - '@storybook/builder-vite': 7.0.18(typescript@5.0.4)(vite@4.3.9) + '@storybook/builder-vite': 7.0.18(typescript@5.1.3)(vite@4.3.9) '@storybook/core-server': 7.0.18 '@storybook/vue3': 7.0.18(vue@3.3.4) '@vitejs/plugin-vue': 4.2.3(vite@4.3.9)(vue@3.3.4) @@ -6940,7 +6948,7 @@ packages: - supports-color dev: true - /@swc/cli@0.1.62(@swc/core@1.3.59)(chokidar@3.5.3): + /@swc/cli@0.1.62(@swc/core@1.3.61)(chokidar@3.5.3): resolution: {integrity: sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==} engines: {node: '>= 12.13'} hasBin: true @@ -6952,7 +6960,7 @@ packages: optional: true dependencies: '@mole-inc/bin-wrapper': 8.0.1 - '@swc/core': 1.3.59 + '@swc/core': 1.3.61 chokidar: 3.5.3 commander: 7.2.0 fast-glob: 3.2.12 @@ -6980,8 +6988,8 @@ packages: requiresBuild: true optional: true - /@swc/core-darwin-arm64@1.3.59: - resolution: {integrity: sha512-AnqWFBgEKHP0jb4iZqx7eVQT9/rX45+DE4Ox7GpwCahUKxxrsDLyXzKhwLwQuAjUvtu5JcSB77szKpPGDM49fQ==} + /@swc/core-darwin-arm64@1.3.61: + resolution: {integrity: sha512-Ra1CZIYYyIp/Y64VcKyaLjIPUwT83JmGduvHu8vhUZOvWV4dWL4s5DrcxQVaQJjjb7Z2N/IUYYS55US1TGnxZw==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] @@ -6996,8 +7004,8 @@ packages: requiresBuild: true optional: true - /@swc/core-darwin-x64@1.3.59: - resolution: {integrity: sha512-iqDs+yii9mOsmpJez82SEi4d4prWDRlapHxKnDVJ0x1AqRo41vIq8t3fujrvCHYU5VQgOYGh4ooXQpaP2H3B2A==} + /@swc/core-darwin-x64@1.3.61: + resolution: {integrity: sha512-LUia75UByUFkYH1Ddw7IE0X9usNVGJ7aL6+cgOTju7P0dsU0f8h/OGc/GDfp1E4qnKxDCJE+GwDRLoi4SjIxpg==} engines: {node: '>=10'} cpu: [x64] os: [darwin] @@ -7012,8 +7020,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-arm-gnueabihf@1.3.59: - resolution: {integrity: sha512-PB0PP+SgkCSd/kYmltnPiGv42cOSaih1OjXCEjxvNwUFEmWqluW6uGdWaNiR1LoYMxhcHZTc336jL2+O3l6p0Q==} + /@swc/core-linux-arm-gnueabihf@1.3.61: + resolution: {integrity: sha512-aalPlicYxHAn2PxNlo3JFEZkMXzCtUwjP27AgMqnfV4cSz7Omo56OtC+413e/kGyCH86Er9gJRQQsxNKP8Qbsg==} engines: {node: '>=10'} cpu: [arm] os: [linux] @@ -7028,8 +7036,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-arm64-gnu@1.3.59: - resolution: {integrity: sha512-Ol/JPszWZ+OZ44FOdJe35TfJ1ckG4pYaisZJ4E7PzfwfVe2ygX85C5WWR4e5L0Y1zFvzpcI7gdyC2wzcXk4Cig==} + /@swc/core-linux-arm64-gnu@1.3.61: + resolution: {integrity: sha512-9hGdsbQrYNPo1c7YzWF57yl17bsIuuEQi3I1fOFSv3puL3l5M/C/oCD0Bz6IdKh6mEDC5UNJE4LWtV1gFA995A==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -7044,8 +7052,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-arm64-musl@1.3.59: - resolution: {integrity: sha512-PtTTtGbj9GiY5gJdoSFL2A0vL6BRaS1haAhp6g3hZvLDkTTg+rJURmzwBMMjaQlnGC62x/lLf6MoszHG/05//Q==} + /@swc/core-linux-arm64-musl@1.3.61: + resolution: {integrity: sha512-mVmcNfFQRP4SYbGC08IPB3B9Xox+VpGIQqA3Qg7LMCcejLAQLi4Lfe8CDvvBPlQzXHso0Cv+BicJnQVKs8JLOA==} engines: {node: '>=10'} cpu: [arm64] os: [linux] @@ -7060,8 +7068,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-x64-gnu@1.3.59: - resolution: {integrity: sha512-XBW9AGi0YsIN76IfesnDSBn/5sjR69J75KUNte8sH6seYlHJ0/kblqUMbUcfr0CiGoJadbzAZeKZZmfN7EsHpg==} + /@swc/core-linux-x64-gnu@1.3.61: + resolution: {integrity: sha512-ZkRHs7GEikN6JiVL1/stvq9BVHKrSKoRn9ulVK2hMr+mAGNOKm3Y06NSzOO+BWwMaFOgnO2dWlszCUICsQ0kpg==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -7076,8 +7084,8 @@ packages: requiresBuild: true optional: true - /@swc/core-linux-x64-musl@1.3.59: - resolution: {integrity: sha512-Cy5E939SdWPQ34cg6UABNO0RyEe0FuWqzZ/GLKtK11Ir4fjttVlucZiY59uQNyUVUc8T2qE0VBFCyD/zYGuHtg==} + /@swc/core-linux-x64-musl@1.3.61: + resolution: {integrity: sha512-zK7VqQ5JlK20+7fxI4AgvIUckeZyX0XIbliGXNMR3i+39SJq1vs9scYEmq8VnAfvNdMU5BG+DewbFJlMfCtkxQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] @@ -7092,8 +7100,8 @@ packages: requiresBuild: true optional: true - /@swc/core-win32-arm64-msvc@1.3.59: - resolution: {integrity: sha512-z5ZJxizRvRoSAaevRIi3YjQh74OFWEIhonSDWNdqDL7RbjEivcatYcG7OikH6s+rtPhOcwNm3PbGV2Prcgh/gg==} + /@swc/core-win32-arm64-msvc@1.3.61: + resolution: {integrity: sha512-e9kVVPk5iVNhO41TvLvcExDHn5iATQ5/M4U7/CdcC7s0fK19TKSEUqkdoTLIJvHBFhgR7w3JJSErfnauO0xXoA==} engines: {node: '>=10'} cpu: [arm64] os: [win32] @@ -7108,8 +7116,8 @@ packages: requiresBuild: true optional: true - /@swc/core-win32-ia32-msvc@1.3.59: - resolution: {integrity: sha512-vxpsn+hrKAhi5YusQfB/JXUJJVX40rIRE/L49ilBEqdbH8Khkoego6AD+2vWqTdJcUHo1WiAIAEZ0rTsjyorLQ==} + /@swc/core-win32-ia32-msvc@1.3.61: + resolution: {integrity: sha512-7cJULfa6HvKqvFh6M/f7mKiNRhE2AjgFUCZfdOuy5r8vbtpk+qBK94TXwaDjJYDUGKzDVZw/tJ1eN4Y9n9Ls/Q==} engines: {node: '>=10'} cpu: [ia32] os: [win32] @@ -7124,8 +7132,8 @@ packages: requiresBuild: true optional: true - /@swc/core-win32-x64-msvc@1.3.59: - resolution: {integrity: sha512-Ris/cJbURylcLwqz4RZUUBCEGsuaIHOJsvf69W5pGKHKBryVoOTNhBKpo3Km2hoAi5qFQ/ou0trAT4hBsVPZvQ==} + /@swc/core-win32-x64-msvc@1.3.61: + resolution: {integrity: sha512-Jx8S+21WcKF/wlhW+sYpystWUyymDTEsbBpOgBRpXZelakVcNBCIIYSZOKW/A9PwWTpu6S8yvbs9nUOzKiVPqA==} engines: {node: '>=10'} cpu: [x64] os: [win32] @@ -7153,8 +7161,8 @@ packages: '@swc/core-win32-ia32-msvc': 1.3.56 '@swc/core-win32-x64-msvc': 1.3.56 - /@swc/core@1.3.59: - resolution: {integrity: sha512-ZBw31zd2E5SXiodwGvjQdx5ZC90b2uyX/i2LeMMs8LKfXD86pfOfQac+JVrnyEKDhASXj9icgsF9NXBhaMr3Kw==} + /@swc/core@1.3.61: + resolution: {integrity: sha512-p58Ltdjo7Yy8CU3zK0cp4/eAgy5qkHs35znGedqVGPiA67cuYZM63DuTfmyrOntMRwQnaFkMLklDAPCizDdDng==} engines: {node: '>=10'} requiresBuild: true peerDependencies: @@ -7163,16 +7171,16 @@ packages: '@swc/helpers': optional: true optionalDependencies: - '@swc/core-darwin-arm64': 1.3.59 - '@swc/core-darwin-x64': 1.3.59 - '@swc/core-linux-arm-gnueabihf': 1.3.59 - '@swc/core-linux-arm64-gnu': 1.3.59 - '@swc/core-linux-arm64-musl': 1.3.59 - '@swc/core-linux-x64-gnu': 1.3.59 - '@swc/core-linux-x64-musl': 1.3.59 - '@swc/core-win32-arm64-msvc': 1.3.59 - '@swc/core-win32-ia32-msvc': 1.3.59 - '@swc/core-win32-x64-msvc': 1.3.59 + '@swc/core-darwin-arm64': 1.3.61 + '@swc/core-darwin-x64': 1.3.61 + '@swc/core-linux-arm-gnueabihf': 1.3.61 + '@swc/core-linux-arm64-gnu': 1.3.61 + '@swc/core-linux-arm64-musl': 1.3.61 + '@swc/core-linux-x64-gnu': 1.3.61 + '@swc/core-linux-x64-musl': 1.3.61 + '@swc/core-win32-arm64-msvc': 1.3.61 + '@swc/core-win32-ia32-msvc': 1.3.61 + '@swc/core-win32-x64-msvc': 1.3.61 /@swc/jest@0.2.26(@swc/core@1.3.56): resolution: {integrity: sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==} @@ -7185,14 +7193,14 @@ packages: jsonc-parser: 3.2.0 dev: true - /@swc/jest@0.2.26(@swc/core@1.3.59): + /@swc/jest@0.2.26(@swc/core@1.3.61): resolution: {integrity: sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==} engines: {npm: '>= 7.0.0'} peerDependencies: '@swc/core': '*' dependencies: '@jest/create-cache-key-function': 27.5.1 - '@swc/core': 1.3.59 + '@swc/core': 1.3.61 jsonc-parser: 3.2.0 dev: true @@ -7224,14 +7232,14 @@ packages: dependencies: defer-to-connect: 2.0.1 - /@tabler/icons-webfont@2.17.0: - resolution: {integrity: sha512-jgRZWiWCaG++jFTIU/dbOT+JmSgoFlALwBUUS31mt1b5py7B0YWelnfxf5s3ctE+0dlnoIS+r7rDOeDSAWx8SA==} + /@tabler/icons-webfont@2.21.0: + resolution: {integrity: sha512-WCa57zYBjD9NF3/g96WKePgKUkKKD95Y+mo27/fzXOGxuoP9lGRjd01UCeLTGVxdEPErwlCjHXSi8HoDX2jevg==} dependencies: - '@tabler/icons': 2.17.0 + '@tabler/icons': 2.21.0 dev: false - /@tabler/icons@2.17.0: - resolution: {integrity: sha512-UeJaylOGNRhQKyDlgZfrQ3UPSGlfVQuXcmCsTYeXioKKepibW6VZ3H36Lo1jvBTBkQD2e9m+k2NxwkztOTXwrA==} + /@tabler/icons@2.21.0: + resolution: {integrity: sha512-XKrTEHMX6XzCOwcOU8ZNA+Xqm51sI+0abn2jk1fyQUpWeFnGsOEiC+fpQ4EISc+v+U9jqgTSbh8bZ6JBuKU5sw==} dev: false /@tensorflow/tfjs-backend-cpu@4.4.0(@tensorflow/tfjs-core@4.4.0): @@ -7429,7 +7437,7 @@ packages: /@types/accepts@1.3.5: resolution: {integrity: sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/archiver@5.3.2: @@ -7454,26 +7462,22 @@ packages: '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.20.0 - dev: true /@types/babel__generator@7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: '@babel/types': 7.22.4 - dev: true /@types/babel__template@7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: '@babel/parser': 7.22.4 '@babel/types': 7.22.4 - dev: true /@types/babel__traverse@7.20.0: resolution: {integrity: sha512-TBOjqAGf0hmaqRwpii5LLkJLg7c6OMm4nHLmpsUxwk9bBHtoTC6dAHdVWdGv4TBxj2CZOZY8Xfq8WmfoVi7n4Q==} dependencies: '@babel/types': 7.22.4 - dev: true /@types/bcryptjs@2.4.2: resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==} @@ -7484,7 +7488,6 @@ packages: dependencies: '@types/connect': 3.4.35 '@types/node': 20.2.5 - dev: true /@types/braces@3.0.1: resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==} @@ -7502,7 +7505,7 @@ packages: /@types/cbor@6.0.0: resolution: {integrity: sha512-mGQ1lbYOwVti5Xlarn1bTeBZqgY0kstsdjnkoEovgohYKdBjGejHyNGXHdMBeqyQazIv32Jjp33+5pBEaSRy2w==} dependencies: - cbor: 8.1.0 + cbor: 9.0.0 dev: true /@types/chai-subset@1.3.3: @@ -7529,7 +7532,6 @@ packages: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: '@types/node': 20.2.5 - dev: true /@types/content-disposition@0.5.5: resolution: {integrity: sha512-v6LCdKfK6BwcqMo+wYW05rLS12S0ZO0Fl4w1h4aaZMD7bqT3gVUns6FvLJKGZHQmYn3SX55JWGpziwJRwVgutA==} @@ -7596,7 +7598,6 @@ packages: '@types/node': 20.2.5 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 - dev: true /@types/express@4.17.17: resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} @@ -7605,7 +7606,6 @@ packages: '@types/express-serve-static-core': 4.17.33 '@types/qs': 6.9.7 '@types/serve-static': 1.15.1 - dev: true /@types/find-cache-dir@3.2.1: resolution: {integrity: sha512-frsJrz2t/CeGifcu/6uRo4b+SzAwT4NYCVPu1GN8IB9XTzrpPkGuV0tmh9mN+/L0PklAlsC3u5Fxt0ju00LXIw==} @@ -7614,7 +7614,7 @@ packages: /@types/fluent-ffmpeg@2.1.21: resolution: {integrity: sha512-+n3dy/Tegt6n+YwGZUiGq6i8Jrnt8+MoyPiW1L6J5EWUl7GSt18a/VyReecfCsvTTNBXNMIKOMHDstiQM8nJLA==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/glob-stream@6.1.1: @@ -7698,6 +7698,13 @@ packages: pretty-format: 29.5.0 dev: true + /@types/jest@29.5.2: + resolution: {integrity: sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==} + dependencies: + expect: 29.5.0 + pretty-format: 29.5.0 + dev: true + /@types/js-levenshtein@1.1.1: resolution: {integrity: sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==} dev: true @@ -7709,7 +7716,7 @@ packages: /@types/jsdom@21.1.1: resolution: {integrity: sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 dev: true @@ -7764,7 +7771,6 @@ packages: /@types/mime@3.0.1: resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} - dev: true /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} @@ -7809,17 +7815,13 @@ packages: resolution: {integrity: sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==} dev: true - /@types/node@20.2.3: - resolution: {integrity: sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==} - dev: true - /@types/node@20.2.5: resolution: {integrity: sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==} /@types/nodemailer@6.4.8: resolution: {integrity: sha512-oVsJSCkqViCn8/pEu2hfjwVO+Gb3e+eTWjg3PcjeFKRItfKpKwHphQqbYmPQrlMk+op7pNNWPbsJIEthpFN/OQ==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/normalize-package-data@2.4.1: @@ -7833,7 +7835,7 @@ packages: /@types/oauth@0.9.1: resolution: {integrity: sha512-a1iY62/a3yhZ7qH7cNUsxoI3U/0Fe9+RnuFrpTKr+0WVOzbKlSLojShCKe20aOD1Sppv+i8Zlq0pLDuTJnwS4A==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/offscreencanvas@2019.3.0: @@ -7847,7 +7849,7 @@ packages: /@types/pg@8.10.1: resolution: {integrity: sha512-AmEHA/XxMxemQom5iDwP62FYNkv+gDDnetRG7v2N2dPtju7UKI7FknUimcZo7SodKTHtckYPzaTqUEvUKbVJEA==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 pg-protocol: 1.6.0 pg-types: 4.0.1 dev: true @@ -7875,12 +7877,11 @@ packages: /@types/qrcode@1.5.0: resolution: {integrity: sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/qs@6.9.7: resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} - dev: true /@types/random-seed@0.3.3: resolution: {integrity: sha512-kHsCbIRHNXJo6EN5W8EA5b4i1hdT6jaZke5crBPLUcLqaLdZ0QBq8QVMbafHzhjFF83Cl9qlee2dChD18d/kPg==} @@ -7888,7 +7889,6 @@ packages: /@types/range-parser@1.2.4: resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} - dev: true /@types/ratelimiter@3.4.4: resolution: {integrity: sha512-GSMb93iSA8KKFDgVL2Wzs/kqrHMJcU8xhLdwI5omoACcj7K18SacklLtY1C4G02HC5drd6GygtsIaGbfxJSe0g==} @@ -7950,7 +7950,6 @@ packages: dependencies: '@types/mime': 3.0.1 '@types/node': 20.2.5 - dev: true /@types/serviceworker@0.0.67: resolution: {integrity: sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q==} @@ -7994,7 +7993,7 @@ packages: /@types/testing-library__jest-dom@5.14.6: resolution: {integrity: sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==} dependencies: - '@types/jest': 29.5.1 + '@types/jest': 29.5.2 dev: true /@types/throttle-debounce@5.0.0: @@ -8036,7 +8035,7 @@ packages: /@types/unzipper@0.10.6: resolution: {integrity: sha512-zcBj329AHgKLQyz209N/S9R0GZqXSkUQO4tJSYE3x02qg4JuDFpgKMj50r82Erk1natCWQDIvSccDddt7jPzjA==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/uuid@9.0.1: @@ -8046,7 +8045,7 @@ packages: /@types/vary@1.1.0: resolution: {integrity: sha512-LQWqrIa0dvEOOH37lGksMEXbypRLUFqu6Gx0pmX7zIUisD2I/qaVgEX/vJ/PSVSW0Hk6yz1BNkFpqg6dZm3Wug==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/vinyl-fs@2.4.12: @@ -8066,7 +8065,7 @@ packages: /@types/web-push@3.3.2: resolution: {integrity: sha512-JxWGVL/m7mWTIg4mRYO+A6s0jPmBkr4iJr39DqJpRJAc+jrPiEe1/asmkwerzRon8ZZDxaZJpsxpv0Z18Wo9gw==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/webgl-ext@0.0.30: @@ -8080,13 +8079,13 @@ packages: /@types/websocket@1.0.5: resolution: {integrity: sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/ws@8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 20.2.3 + '@types/node': 20.2.5 dev: true /@types/yargs-parser@21.0.0: @@ -8141,6 +8140,34 @@ packages: - supports-color dev: true + /@typescript-eslint/eslint-plugin@5.59.8(@typescript-eslint/parser@5.59.8)(eslint@8.41.0)(typescript@5.1.3): + resolution: {integrity: sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.5.0 + '@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.1.3) + '@typescript-eslint/scope-manager': 5.59.8 + '@typescript-eslint/type-utils': 5.59.8(eslint@8.41.0)(typescript@5.1.3) + '@typescript-eslint/utils': 5.59.8(eslint@8.41.0)(typescript@5.1.3) + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.41.0 + grapheme-splitter: 1.0.4 + ignore: 5.2.4 + natural-compare-lite: 1.4.0 + semver: 7.5.1 + tsutils: 3.21.0(typescript@5.1.3) + typescript: 5.1.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/parser@5.59.5(eslint@8.40.0)(typescript@5.0.4): resolution: {integrity: sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -8161,6 +8188,26 @@ packages: - supports-color dev: true + /@typescript-eslint/parser@5.59.8(eslint@8.41.0)(typescript@5.1.3): + resolution: {integrity: sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.59.8 + '@typescript-eslint/types': 5.59.8 + '@typescript-eslint/typescript-estree': 5.59.8(typescript@5.1.3) + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.41.0 + typescript: 5.1.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager@5.59.5: resolution: {integrity: sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -8169,6 +8216,14 @@ packages: '@typescript-eslint/visitor-keys': 5.59.5 dev: true + /@typescript-eslint/scope-manager@5.59.8: + resolution: {integrity: sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.59.8 + '@typescript-eslint/visitor-keys': 5.59.8 + dev: true + /@typescript-eslint/type-utils@5.59.5(eslint@8.40.0)(typescript@5.0.4): resolution: {integrity: sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -8189,11 +8244,36 @@ packages: - supports-color dev: true + /@typescript-eslint/type-utils@5.59.8(eslint@8.41.0)(typescript@5.1.3): + resolution: {integrity: sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 5.59.8(typescript@5.1.3) + '@typescript-eslint/utils': 5.59.8(eslint@8.41.0)(typescript@5.1.3) + debug: 4.3.4(supports-color@8.1.1) + eslint: 8.41.0 + tsutils: 3.21.0(typescript@5.1.3) + typescript: 5.1.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types@5.59.5: resolution: {integrity: sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@typescript-eslint/types@5.59.8: + resolution: {integrity: sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@typescript-eslint/typescript-estree@5.59.5(typescript@5.0.4): resolution: {integrity: sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -8215,6 +8295,27 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@5.59.8(typescript@5.1.3): + resolution: {integrity: sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.59.8 + '@typescript-eslint/visitor-keys': 5.59.8 + debug: 4.3.4(supports-color@8.1.1) + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.1 + tsutils: 3.21.0(typescript@5.1.3) + typescript: 5.1.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils@5.59.5(eslint@8.40.0)(typescript@5.0.4): resolution: {integrity: sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -8235,6 +8336,26 @@ packages: - typescript dev: true + /@typescript-eslint/utils@5.59.8(eslint@8.41.0)(typescript@5.1.3): + resolution: {integrity: sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.41.0) + '@types/json-schema': 7.0.11 + '@types/semver': 7.5.0 + '@typescript-eslint/scope-manager': 5.59.8 + '@typescript-eslint/types': 5.59.8 + '@typescript-eslint/typescript-estree': 5.59.8(typescript@5.1.3) + eslint: 8.41.0 + eslint-scope: 5.1.1 + semver: 7.5.1 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@5.59.5: resolution: {integrity: sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -8243,6 +8364,14 @@ packages: eslint-visitor-keys: 3.4.1 dev: true + /@typescript-eslint/visitor-keys@5.59.8: + resolution: {integrity: sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.59.8 + eslint-visitor-keys: 3.4.1 + dev: true + /@vitejs/plugin-react@3.1.0(vite@4.3.9): resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} engines: {node: ^14.18.0 || >=16.0.0} @@ -8269,8 +8398,8 @@ packages: vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) vue: 3.3.4 - /@vitest/coverage-c8@0.31.1(vitest@0.31.1): - resolution: {integrity: sha512-6TkjQpmgYez7e3dbAUoYdRXxWN81BojCmUILJwgCy39uZFG33DsQ0rSRSZC9beAEdCZTpxR63nOvd9hxDQcJ0g==} + /@vitest/coverage-c8@0.31.4(vitest@0.31.4): + resolution: {integrity: sha512-VPx368m4DTcpA/P0v3YdVxl4QOSh1DbUcXURLRvDShrIB5KxOgfzw4Bn2R8AhAe/GyiWW/FIsJ/OJdYXCCiC1w==} peerDependencies: vitest: '>=0.30.0 <1' dependencies: @@ -8279,42 +8408,42 @@ packages: magic-string: 0.30.0 picocolors: 1.0.0 std-env: 3.3.2 - vitest: 0.31.1(happy-dom@9.19.2)(sass@1.62.1) + vitest: 0.31.4(happy-dom@9.20.3)(sass@1.62.1) dev: true - /@vitest/expect@0.31.1: - resolution: {integrity: sha512-BV1LyNvhnX+eNYzJxlHIGPWZpwJFZaCcOIzp2CNG0P+bbetenTupk6EO0LANm4QFt0TTit+yqx7Rxd1qxi/SQA==} + /@vitest/expect@0.31.4: + resolution: {integrity: sha512-tibyx8o7GUyGHZGyPgzwiaPaLDQ9MMuCOrc03BYT0nryUuhLbL7NV2r/q98iv5STlwMgaKuFJkgBW/8iPKwlSg==} dependencies: - '@vitest/spy': 0.31.1 - '@vitest/utils': 0.31.1 + '@vitest/spy': 0.31.4 + '@vitest/utils': 0.31.4 chai: 4.3.7 dev: true - /@vitest/runner@0.31.1: - resolution: {integrity: sha512-imWuc82ngOtxdCUpXwtEzZIuc1KMr+VlQ3Ondph45VhWoQWit5yvG/fFcldbnCi8DUuFi+NmNx5ehMUw/cGLUw==} + /@vitest/runner@0.31.4: + resolution: {integrity: sha512-Wgm6UER+gwq6zkyrm5/wbpXGF+g+UBB78asJlFkIOwyse0pz8lZoiC6SW5i4gPnls/zUcPLWS7Zog0LVepXnpg==} dependencies: - '@vitest/utils': 0.31.1 + '@vitest/utils': 0.31.4 concordance: 5.0.4 p-limit: 4.0.0 pathe: 1.1.0 dev: true - /@vitest/snapshot@0.31.1: - resolution: {integrity: sha512-L3w5uU9bMe6asrNzJ8WZzN+jUTX4KSgCinEJPXyny0o90fG4FPQMV0OWsq7vrCWfQlAilMjDnOF9nP8lidsJ+g==} + /@vitest/snapshot@0.31.4: + resolution: {integrity: sha512-LemvNumL3NdWSmfVAMpXILGyaXPkZbG5tyl6+RQSdcHnTj6hvA49UAI8jzez9oQyE/FWLKRSNqTGzsHuk89LRA==} dependencies: magic-string: 0.30.0 pathe: 1.1.0 pretty-format: 27.5.1 dev: true - /@vitest/spy@0.31.1: - resolution: {integrity: sha512-1cTpt2m9mdo3hRLDyCG2hDQvRrePTDgEJBFQQNz1ydHHZy03EiA6EpFxY+7ODaY7vMRCie+WlFZBZ0/dQWyssQ==} + /@vitest/spy@0.31.4: + resolution: {integrity: sha512-3ei5ZH1s3aqbEyftPAzSuunGICRuhE+IXOmpURFdkm5ybUADk+viyQfejNk6q8M5QGX8/EVKw+QWMEP3DTJDag==} dependencies: tinyspy: 2.1.0 dev: true - /@vitest/utils@0.31.1: - resolution: {integrity: sha512-yFyRD5ilwojsZfo3E0BnH72pSVSuLg2356cN1tCEe/0RtDzxTPYwOomIC+eQbot7m6DRy4tPZw+09mB7NkbMmA==} + /@vitest/utils@0.31.4: + resolution: {integrity: sha512-DobZbHacWznoGUfYU8XDPY78UubJxXfMNY1+SUdOp1NsI34eopSA6aZMeaGu10waSOeYwE8lxrd/pLfT0RMxjQ==} dependencies: concordance: 5.0.4 loupe: 2.3.6 @@ -8333,13 +8462,13 @@ packages: muggle-string: 0.2.2 dev: true - /@volar/typescript@1.4.1-patch.2(typescript@5.0.4): + /@volar/typescript@1.4.1-patch.2(typescript@5.1.3): resolution: {integrity: sha512-lPFYaGt8OdMEzNGJJChF40uYqMO4Z/7Q9fHPQC/NRVtht43KotSXLrkPandVVMf9aPbiJ059eAT+fwHGX16k4w==} peerDependencies: typescript: '*' dependencies: '@volar/language-core': 1.4.1 - typescript: 5.0.4 + typescript: 5.1.3 dev: true /@volar/vue-language-core@1.6.5: @@ -8356,18 +8485,18 @@ packages: vue-template-compiler: 2.7.14 dev: true - /@volar/vue-typescript@1.6.5(typescript@5.0.4): + /@volar/vue-typescript@1.6.5(typescript@5.1.3): resolution: {integrity: sha512-er9rVClS4PHztMUmtPMDTl+7c7JyrxweKSAEe/o/Noeq2bQx6v3/jZHVHBe8ZNUti5ubJL/+Tg8L3bzmlalV8A==} peerDependencies: typescript: '*' dependencies: - '@volar/typescript': 1.4.1-patch.2(typescript@5.0.4) + '@volar/typescript': 1.4.1-patch.2(typescript@5.1.3) '@volar/vue-language-core': 1.6.5 - typescript: 5.0.4 + typescript: 5.1.3 dev: true - /@vue-macros/common@1.3.2(rollup@3.23.0)(vue@3.3.4): - resolution: {integrity: sha512-D/hNU0+0HPGFpGf1TO2eKpBKVFTIsHMjzu7/IXe9+hz0TY+WJOGtnlpJyMWFWnM56mXvBOMiQ74zW8MTFlbMMQ==} + /@vue-macros/common@1.3.3(rollup@3.23.0)(vue@3.3.4): + resolution: {integrity: sha512-bjHomaf3mu+ARMD4DX22C/lLVVocbmwgcLH7bg1rK4kB5ghesgShZTQIrNR6ZjifQmdGc/2jjZ/25kSb364uEA==} engines: {node: '>=16.14.0'} peerDependencies: vue: ^2.7.0 || ^3.2.25 @@ -8385,14 +8514,14 @@ packages: - rollup dev: false - /@vue-macros/reactivity-transform@0.3.8(rollup@3.23.0)(vue@3.3.4): - resolution: {integrity: sha512-a9GBGy7ZCJdbOvynGl+gBGy0EQlhbUkJxnpEPdxQDWKTEiqW3xQGPCaqonVvHFH1DxQrbfKyxsPy+72Ssr6tKA==} + /@vue-macros/reactivity-transform@0.3.9(rollup@3.23.0)(vue@3.3.4): + resolution: {integrity: sha512-lzzH2qzIxc1LWRrSR+ax0TVeBTgwTpG9qTZOo4Au+ODgJyXpIWHGCnc9rjcxGfu6LitjZ75NmyjbEnaEkomefw==} engines: {node: '>=16.14.0'} peerDependencies: vue: ^2.7.0 || ^3.2.25 dependencies: - '@babel/parser': 7.21.9 - '@vue-macros/common': 1.3.2(rollup@3.23.0)(vue@3.3.4) + '@babel/parser': 7.22.4 + '@vue-macros/common': 1.3.3(rollup@3.23.0)(vue@3.3.4) '@vue/compiler-core': 3.3.4 '@vue/shared': 3.3.4 magic-string: 0.30.0 @@ -8634,13 +8763,6 @@ packages: mime-types: 2.1.35 negotiator: 0.6.3 - /acorn-globals@7.0.1: - resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} - dependencies: - acorn: 8.8.2 - acorn-walk: 8.2.0 - dev: false - /acorn-jsx@5.3.2(acorn@7.4.1): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -8665,6 +8787,7 @@ packages: /acorn-walk@8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} + dev: true /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} @@ -8814,7 +8937,6 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -9079,7 +9201,6 @@ packages: is-nan: 1.3.2 object-is: 1.1.5 util: 0.12.5 - dev: true /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -9108,15 +9229,14 @@ packages: engines: {node: '>=4'} dependencies: tslib: 2.5.2 - dev: true /astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} dev: true - /astring@1.8.5: - resolution: {integrity: sha512-TuBbdn7jWVzf8dmFGTaRpW8qgANtWLi1qJLnkfGO5uVf6jf9f/F4B1H35tnOI+qVYZo3p3i8WZlbZOuPAE0wEA==} + /astring@1.8.6: + resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true dev: false @@ -9190,7 +9310,6 @@ packages: /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - dev: true /avvio@8.2.0: resolution: {integrity: sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==} @@ -9627,10 +9746,10 @@ packages: dependencies: fill-range: 7.0.1 - /broadcast-channel@4.20.2: - resolution: {integrity: sha512-v0lJgMzC+MX4e2KCFWYXChZ2mKTqm5mnJGId6tqJp3NfylggbNd8c2uKeP4MQxD2ucKOesY68aN98zwl9d6Tvg==} + /broadcast-channel@5.1.0: + resolution: {integrity: sha512-wAbP+mtQ28N+iX3scX6Q97UN39ER5jRWOtM3r1BNPLWFOMt3AGmwN9kS3fqwgaUW0tbWHRSfTpsT+pAvrzQz0Q==} dependencies: - '@babel/runtime': 7.20.7 + '@babel/runtime': 7.21.0 oblivious-set: 1.1.1 p-queue: 6.6.2 rimraf: 3.0.2 @@ -9730,8 +9849,8 @@ packages: dependencies: node-gyp-build: 4.6.0 - /bullmq@3.14.1: - resolution: {integrity: sha512-Fom78UKljYsnJmwbROVPx3eFLuVfQjQbw9KCnVupLzT31RQHhFHV2xd/4J4oWl4u34bZ1JmEUfNnqNBz+IOJuA==} + /bullmq@3.15.0: + resolution: {integrity: sha512-U0LSRjuoyIBpnE62T4maCWMYEt3qdBCa1lnlPxYKQmRF/Y+FQ9W6iW5JvNNN+NA5Jet7k0uX71a93EX1zGnrhw==} dependencies: cron-parser: 4.8.1 glob: 8.1.0 @@ -9932,9 +10051,9 @@ packages: /caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - /cbor@8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} + /cbor@9.0.0: + resolution: {integrity: sha512-87cFgOKxjUOnGpNeQMBVER4Mc/rZAk9xC+Ygfx5FLCAUt/tpVHphuZC5fJmp/KSDsEsBEDIPtEt0YbD/GFQw8Q==} + engines: {node: '>=16'} dependencies: nofilter: 3.1.0 @@ -9982,7 +10101,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true /chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} @@ -10141,11 +10259,12 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - /chromatic@6.17.4: - resolution: {integrity: sha512-vnlvsv2lkp8BVtTn1OumJzqkDk2qB3pcGxEDIfZtVboKtzIPjnIlGa+c1fVKQe8NvHDU8R39k8klqgKHIXUVJw==} + /chromatic@6.18.0: + resolution: {integrity: sha512-Sj7xMFGQ6jSTBrsdgMMjSQAP2OMNogg4GXV4djf4kAp6Dp+pY4FwByIagvbtQRjC33kQVi592FS52vMBOBMEzw==} hasBin: true dependencies: '@discoveryjs/json-ext': 0.5.7 + '@storybook/csf-tools': 7.0.18 '@types/webpack-env': 1.18.0 snyk-nodejs-lockfile-parser: 1.49.0 transitivePeerDependencies: @@ -11003,6 +11122,7 @@ packages: /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true /deepmerge@4.2.2: resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} @@ -11471,7 +11591,6 @@ packages: /es6-object-assign@1.1.0: resolution: {integrity: sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==} - dev: true /es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} @@ -11584,6 +11703,7 @@ packages: optionator: 0.8.3 optionalDependencies: source-map: 0.6.1 + dev: true /eslint-formatter-pretty@4.1.0: resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==} @@ -11638,6 +11758,35 @@ packages: - supports-color dev: true + /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-node@0.3.7)(eslint@8.41.0): + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.1.3) + debug: 3.2.7(supports-color@8.1.1) + eslint: 8.41.0 + eslint-import-resolver-node: 0.3.7 + transitivePeerDependencies: + - supports-color + dev: true + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.5)(eslint@8.40.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} @@ -11671,19 +11820,52 @@ packages: - supports-color dev: true - /eslint-plugin-vue@9.14.1(eslint@8.40.0): + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.8)(eslint@8.41.0): + resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@typescript-eslint/parser': 5.59.8(eslint@8.41.0)(typescript@5.1.3) + array-includes: 3.1.6 + array.prototype.flat: 1.3.1 + array.prototype.flatmap: 1.3.1 + debug: 3.2.7(supports-color@8.1.1) + doctrine: 2.1.0 + eslint: 8.41.0 + eslint-import-resolver-node: 0.3.7 + eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.59.8)(eslint-import-resolver-node@0.3.7)(eslint@8.41.0) + has: 1.0.3 + is-core-module: 2.11.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.values: 1.1.6 + resolve: 1.22.1 + semver: 6.3.0 + tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: true + + /eslint-plugin-vue@9.14.1(eslint@8.41.0): resolution: {integrity: sha512-LQazDB1qkNEKejLe/b5a9VfEbtbczcOaui5lQ4Qw0tbRBbQYREyxxOV5BQgNDTqGPs9pxqiEpbMi9ywuIaF7vw==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.40.0) - eslint: 8.40.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.41.0) + eslint: 8.41.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.11 semver: 7.5.1 - vue-eslint-parser: 9.3.0(eslint@8.40.0) + vue-eslint-parser: 9.3.0(eslint@8.41.0) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -11763,6 +11945,54 @@ packages: - supports-color dev: true + /eslint@8.41.0: + resolution: {integrity: sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.41.0) + '@eslint-community/regexpp': 4.5.0 + '@eslint/eslintrc': 2.0.3 + '@eslint/js': 8.41.0 + '@humanwhocodes/config-array': 0.11.8 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.4(supports-color@8.1.1) + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.0 + eslint-visitor-keys: 3.4.1 + espree: 9.5.2 + esquery: 1.4.2 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.19.0 + graphemer: 1.4.0 + ignore: 5.2.4 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.1 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + dev: true + /espree@9.5.2: resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -11805,6 +12035,7 @@ packages: /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + dev: true /estree-to-babel@3.2.1: resolution: {integrity: sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==} @@ -11829,6 +12060,7 @@ packages: /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + dev: true /etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} @@ -12163,6 +12395,7 @@ packages: /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true /fast-querystring@1.1.0: resolution: {integrity: sha512-LWkjBCZlxjnSanuPpZ6mHswjy8hQv3VcPJsQB3ltUF2zjvrycr0leP3TSTEEfvQ1WEMSRl5YNsGqaft9bjLqEw==} @@ -12283,7 +12516,6 @@ packages: dependencies: fs-extra: 11.1.0 ramda: 0.28.0 - dev: true /file-type@17.1.6: resolution: {integrity: sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==} @@ -12507,7 +12739,6 @@ packages: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 - dev: true /for-in@1.0.2: resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} @@ -12599,7 +12830,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 - dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -12967,7 +13197,6 @@ packages: /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - dev: true /globals@13.19.0: resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} @@ -13003,7 +13232,6 @@ packages: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.0 - dev: true /got@11.8.5: resolution: {integrity: sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==} @@ -13038,16 +13266,16 @@ packages: p-cancelable: 3.0.0 responselike: 3.0.0 - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - dev: false - /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} /grapheme-splitter@1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + /graphql@16.6.0: resolution: {integrity: sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -13168,8 +13396,8 @@ packages: uglify-js: 3.17.4 dev: true - /happy-dom@9.19.2: - resolution: {integrity: sha512-WBey64FErn5niCLddcjXxkgDk6burN/5doiJpMUQXpgEG3TUJdbygJV1bzcj1Ey+pz+0QGCZH1pwe24uPW+WnQ==} + /happy-dom@9.20.3: + resolution: {integrity: sha512-eBsgauT435fXFvQDNcmm5QbGtYzxEzOaX35Ia+h6yP/wwa4xSWZh1CfP+mGby8Hk6Xu59mTkpyf72rUXHNxY7A==} dependencies: css.escape: 1.5.1 entities: 4.5.0 @@ -13215,7 +13443,6 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -13590,8 +13817,9 @@ packages: resolution: {integrity: sha512-/nPtyeX9xPUvxZf+r0518B7uqNKlP+LqNJqSiXFEaa2T71rWIwTVXGH7hB9xO/EVdwa5/pWlFCPwShOW81XIxQ==} dev: false - /install-artifact-from-github@1.3.2: - resolution: {integrity: sha512-yCFcLvqk0yQdxx0uJz4t9Z3adDMLAYrcGYv546uRXCSvxE+GqNYhhz/KmrGcUKGI/gVLR9n/e/zM9jX/+ASMJQ==} + /install-artifact-from-github@1.3.3: + resolution: {integrity: sha512-x79SL0d8WOi1ZjXSTUqqs0GPQZ92YArJAN9O46wgU9wdH2U9ecyyhB9YGDbPe2OLV4ptmt6AZYRQZ2GydQZosQ==} + hasBin: true dev: false /internal-slot@1.0.5: @@ -13721,7 +13949,6 @@ packages: dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: true /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} @@ -13875,7 +14102,6 @@ packages: engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 - dev: true /is-glob@3.1.0: resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} @@ -13932,7 +14158,6 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - dev: true /is-negated-glob@1.0.0: resolution: {integrity: sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==} @@ -14080,7 +14305,6 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - dev: true /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -14306,7 +14530,7 @@ packages: - ts-node dev: true - /jest-cli@29.5.0(@types/node@20.2.3): + /jest-cli@29.5.0(@types/node@20.2.5): resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -14323,7 +14547,7 @@ packages: exit: 0.1.2 graceful-fs: 4.2.11 import-local: 3.1.0 - jest-config: 29.5.0(@types/node@20.2.3) + jest-config: 29.5.0(@types/node@20.2.5) jest-util: 29.5.0 jest-validate: 29.5.0 prompts: 2.4.2 @@ -14373,45 +14597,6 @@ packages: - supports-color dev: true - /jest-config@29.5.0(@types/node@20.2.3): - resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.21.3 - '@jest/test-sequencer': 29.5.0 - '@jest/types': 29.5.0 - '@types/node': 20.2.3 - babel-jest: 29.5.0(@babel/core@7.21.3) - chalk: 4.1.2 - ci-info: 3.7.1 - deepmerge: 4.2.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.5.0 - jest-environment-node: 29.5.0 - jest-get-type: 29.4.3 - jest-regex-util: 29.4.3 - jest-resolve: 29.5.0 - jest-runner: 29.5.0 - jest-util: 29.5.0 - jest-validate: 29.5.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.5.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /jest-config@29.5.0(@types/node@20.2.5): resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -14585,7 +14770,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.5.0 - '@types/node': 20.2.3 + '@types/node': 20.2.5 jest-util: 29.5.0 dev: true @@ -14796,7 +14981,7 @@ packages: - ts-node dev: true - /jest@29.5.0(@types/node@20.2.3): + /jest@29.5.0(@types/node@20.2.5): resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -14809,7 +14994,7 @@ packages: '@jest/core': 29.5.0 '@jest/types': 29.5.0 import-local: 3.1.0 - jest-cli: 29.5.0(@types/node@20.2.3) + jest-cli: 29.5.0(@types/node@20.2.5) transitivePeerDependencies: - '@types/node' - supports-color @@ -14872,7 +15057,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} @@ -14935,9 +15119,9 @@ packages: - supports-color dev: true - /jsdom@21.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3): - resolution: {integrity: sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==} - engines: {node: '>=14'} + /jsdom@22.1.0(bufferutil@4.0.7)(utf-8-validate@6.0.3): + resolution: {integrity: sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==} + engines: {node: '>=16'} peerDependencies: canvas: ^2.5.0 peerDependenciesMeta: @@ -14945,19 +15129,16 @@ packages: optional: true dependencies: abab: 2.0.6 - acorn: 8.8.2 - acorn-globals: 7.0.1 cssstyle: 3.0.0 data-urls: 4.0.0 decimal.js: 10.4.3 domexception: 4.0.0 - escodegen: 2.0.0 form-data: 4.0.0 html-encoding-sniffer: 3.0.0 http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.2 + nwsapi: 2.2.5 parse5: 7.1.2 rrweb-cssom: 0.6.0 saxes: 6.0.0 @@ -14985,7 +15166,6 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true - dev: true /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -15055,16 +15235,15 @@ packages: universalify: 2.0.0 optionalDependencies: graceful-fs: 4.2.11 - dev: true - /jsonld@8.1.1: - resolution: {integrity: sha512-TbtV1hlnoDYxbscazbxcS7seDGV+pc0yktxpMySh0OBFvnLw/TIth0jiQtP/9r+ywuCbtj10XjDNBIkRgiyeUg==} + /jsonld@8.2.0: + resolution: {integrity: sha512-qHUa9pn3/cdAZw26HY1Jmy9+sHOxaLrveTRWUcrSDx5apTa20bBTe+X4nzI7dlqc+M5GkwQW6RgRdqO6LF5nkw==} engines: {node: '>=14'} dependencies: - '@digitalbazaar/http-client': 3.2.0 + '@digitalbazaar/http-client': 3.4.1 canonicalize: 1.0.8 lru-cache: 6.0.0 - rdf-canonize: 3.3.0 + rdf-canonize: 3.4.0 transitivePeerDependencies: - web-streams-polyfill dev: false @@ -15156,24 +15335,24 @@ packages: engines: {node: '>=6'} dev: true - /ky-universal@0.10.1(ky@0.30.0): - resolution: {integrity: sha512-r8909k+ELKZAxhVA5c440x22hqw5XcMRwLRbgpPQk4JHy3/ddJnvzcnSo5Ww3HdKdNeS3Y8dBgcIYyVahMa46g==} - engines: {node: '>=14'} + /ky-universal@0.11.0(ky@0.33.3): + resolution: {integrity: sha512-65KyweaWvk+uKKkCrfAf+xqN2/epw1IJDtlyCPxYffFCMR8u1sp2U65NtWpnozYfZxQ6IUzIlvUcw+hQ82U2Xw==} + engines: {node: '>=14.16'} peerDependencies: - ky: '>=0.26.0' - web-streams-polyfill: '>=3.0.1' + ky: '>=0.31.4' + web-streams-polyfill: '>=3.2.1' peerDependenciesMeta: web-streams-polyfill: optional: true dependencies: abort-controller: 3.0.0 - ky: 0.30.0 + ky: 0.33.3 node-fetch: 3.3.1 dev: false - /ky@0.30.0: - resolution: {integrity: sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==} - engines: {node: '>=12'} + /ky@0.33.3: + resolution: {integrity: sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==} + engines: {node: '>=14.16'} dev: false /last-run@1.1.1: @@ -15230,6 +15409,7 @@ packages: dependencies: prelude-ls: 1.1.2 type-check: 0.3.2 + dev: true /levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} @@ -15695,8 +15875,8 @@ packages: engines: {node: '>= 0.6'} dev: true - /meilisearch@0.32.4: - resolution: {integrity: sha512-QvPtQ6F2TaqAT9fw072/MDjSCMpQifdtUBFeIk3M5jSnFpeSiv1iwfJWNfP6ByaCgR/s++K1Cqtf9vjcZe7prg==} + /meilisearch@0.32.5: + resolution: {integrity: sha512-pVccjGAGP1IDSLg3lx9VhyQjUo7kN8x/HVjSurtb8U24V5/pALpf5H2hj6f60QhJd0Ea4tnGRv8fGr2YqWMo9A==} dependencies: cross-fetch: 3.1.6 transitivePeerDependencies: @@ -16038,10 +16218,10 @@ packages: msw: '>=0.35.0 <2.0.0' dependencies: is-node-process: 1.0.1 - msw: 1.2.1(typescript@5.0.4) + msw: 1.2.1(typescript@5.1.3) dev: true - /msw@1.2.1(typescript@5.0.4): + /msw@1.2.1(typescript@5.1.3): resolution: {integrity: sha512-bF7qWJQSmKn6bwGYVPXOxhexTCGD5oJSZg8yt8IBClxvo3Dx/1W0zqE1nX9BSWmzRsCKWfeGWcB/vpqV6aclpw==} engines: {node: '>=14'} hasBin: true @@ -16070,7 +16250,7 @@ packages: path-to-regexp: 6.2.1 strict-event-emitter: 0.4.6 type-fest: 2.19.0 - typescript: 5.0.4 + typescript: 5.1.3 yargs: 17.6.2 transitivePeerDependencies: - encoding @@ -16213,7 +16393,7 @@ packages: resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==} dependencies: '@sinonjs/commons': 2.0.0 - '@sinonjs/fake-timers': 10.0.2 + '@sinonjs/fake-timers': 10.2.0 '@sinonjs/text-encoding': 0.7.2 just-extend: 4.2.1 path-to-regexp: 1.8.0 @@ -16295,6 +16475,7 @@ packages: /node-gyp@9.3.1: resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} engines: {node: ^12.13 || ^14.13 || >=16} + hasBin: true dependencies: env-paths: 2.2.1 glob: 7.2.3 @@ -16327,8 +16508,8 @@ packages: is: 3.3.0 dev: false - /nodemailer@6.9.2: - resolution: {integrity: sha512-4+TYaa/e1nIxQfyw/WzNPYTEZ5OvHIDEnmjs4LPmIfccPQN+2CYKmGHjWixn/chzD3bmUTu5FMfpltizMxqzdg==} + /nodemailer@6.9.3: + resolution: {integrity: sha512-fy9v3NgTzBngrMFkDsKEj0r02U7jm6XfC3b52eoNV+GCrGj+s8pt5OqhiJdWKuw51zCTdiNR/IUD1z33LIIGpg==} engines: {node: '>=6.0.0'} dev: false @@ -16473,8 +16654,8 @@ packages: engines: {node: '>=0.10.0'} dev: false - /nwsapi@2.2.2: - resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==} + /nwsapi@2.2.5: + resolution: {integrity: sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==} dev: false /oauth-sign@0.9.0: @@ -16516,7 +16697,6 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - dev: true /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} @@ -16665,6 +16845,7 @@ packages: prelude-ls: 1.1.2 type-check: 0.3.2 word-wrap: 1.2.3 + dev: true /optionator@0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} @@ -17576,6 +17757,7 @@ packages: /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} + dev: true /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -17993,7 +18175,6 @@ packages: /ramda@0.28.0: resolution: {integrity: sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==} - dev: true /random-seed@0.3.0: resolution: {integrity: sha512-y13xtn3kcTlLub3HKWXxJNeC2qK4mB59evwZ5EkeRlolx+Bp2ztF7LbcZmyCnOqlHQrLnfuNbi1sVmm9lPDlDA==} @@ -18034,18 +18215,18 @@ packages: minimist: 1.2.8 strip-json-comments: 2.0.1 - /rdf-canonize@3.3.0: - resolution: {integrity: sha512-gfSNkMua/VWC1eYbSkVaL/9LQhFeOh0QULwv7Or0f+po8pMgQ1blYQFe1r9Mv2GJZXw88Cz/drnAnB9UlNnHfQ==} + /rdf-canonize@3.4.0: + resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==} engines: {node: '>=12'} dependencies: setimmediate: 1.0.5 dev: false - /re2@1.18.0: - resolution: {integrity: sha512-MoCYZlJ9YUgksND9asyNF2/x532daXU/ARp1UeJbQ5flMY6ryKNEhrWt85aw3YluzOJlC3vXpGgK2a1jb0b4GA==} + /re2@1.19.0: + resolution: {integrity: sha512-y0LcLZgBF3L7mDtNfbghb7dCmChYQO2QsUGklNueAJUH+HAZO8UZUubgNsf6OxRTAQpeE4KMPR7vcpK3+Q+GiA==} requiresBuild: true dependencies: - install-artifact-from-github: 1.3.2 + install-artifact-from-github: 1.3.3 nan: 2.17.0 node-gyp: 9.3.1 transitivePeerDependencies: @@ -18063,12 +18244,12 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true - /react-docgen-typescript@2.2.2(typescript@5.0.4): + /react-docgen-typescript@2.2.2(typescript@5.1.3): resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==} peerDependencies: typescript: '>= 4.3.x' dependencies: - typescript: 5.0.4 + typescript: 5.1.3 dev: true /react-docgen@6.0.0-alpha.3: @@ -18290,7 +18471,6 @@ packages: esprima: 4.0.1 source-map: 0.6.1 tslib: 2.5.2 - dev: true /rechoir@0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} @@ -19771,7 +19951,6 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -19825,8 +20004,8 @@ packages: resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} dev: true - /systeminformation@5.17.12: - resolution: {integrity: sha512-I3pfMW2vue53u+X08BNxaJieaHkRoMMKjWetY9lbYJeWFaeWPO6P4FkNc4XOCX8F9vbQ0HqQ25RJoz3U/B7liw==} + /systeminformation@5.17.16: + resolution: {integrity: sha512-dl2QLa7yp9QbBl9um+51CAr3p/40tbz+f34X1lUXkk1SnDcNeJR2iWu/8HD7GM2yRukmy3RCRXFYcPZs0lCs0Q==} engines: {node: '>=8.0.0'} os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] hasBin: true @@ -19963,8 +20142,8 @@ packages: real-require: 0.2.0 dev: false - /three@0.151.3: - resolution: {integrity: sha512-+vbuqxFy8kzLeO5MgpBHUvP/EAiecaDwDuOPPDe6SbrZr96kccF0ktLngXc7xA7bzyd3N0t2f6mw3Z9y6JCojQ==} + /three@0.153.0: + resolution: {integrity: sha512-OCP2/uQR6GcDpSLnJt/3a4mdS0kNWcbfUXIwLoEMgLzEUIVIYsSDwskpmOii/AkDM+BBwrl6+CKgrjX9+E2aWg==} dev: false /throttle-debounce@5.0.0: @@ -20177,7 +20356,6 @@ packages: /ts-dedent@2.2.0: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} - dev: true /ts-map@1.0.3: resolution: {integrity: sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w==} @@ -20246,6 +20424,16 @@ packages: typescript: 5.0.4 dev: true + /tsutils@3.21.0(typescript@5.1.3): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 5.1.3 + dev: true + /tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} dependencies: @@ -20268,6 +20456,7 @@ packages: engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.1.2 + dev: true /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -20313,7 +20502,6 @@ packages: /type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - dev: true /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} @@ -20423,6 +20611,12 @@ packages: resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} engines: {node: '>=12.20'} hasBin: true + dev: true + + /typescript@5.1.3: + resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} + engines: {node: '>=14.17'} + hasBin: true /ufo@1.1.1: resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==} @@ -20482,16 +20676,16 @@ packages: undertaker-registry: 1.0.1 dev: false - /undici@5.16.0: - resolution: {integrity: sha512-KWBOXNv6VX+oJQhchXieUznEmnJMqgXMbs0xxH2t8q/FUAWSJvOSr/rMaZKnX5RIVq7JDn0JbP4BOnKG2SGXLQ==} + /undici@5.21.0: + resolution: {integrity: sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==} engines: {node: '>=12.18'} dependencies: busboy: 1.6.0 dev: false - /undici@5.21.0: - resolution: {integrity: sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA==} - engines: {node: '>=12.18'} + /undici@5.22.1: + resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==} + engines: {node: '>=14.0'} dependencies: busboy: 1.6.0 dev: false @@ -20599,7 +20793,6 @@ packages: /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} - dev: true /unload@2.4.1: resolution: {integrity: sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw==} @@ -20640,8 +20833,8 @@ packages: engines: {node: '>=8'} dev: true - /unzipper@0.10.11: - resolution: {integrity: sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==} + /unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} dependencies: big-integer: 1.6.51 binary: 0.3.0 @@ -20649,7 +20842,7 @@ packages: buffer-indexof-polyfill: 1.0.2 duplexer2: 0.1.4 fstream: 1.0.12 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 listenercount: 1.0.1 readable-stream: 2.3.7 setimmediate: 1.0.5 @@ -20719,7 +20912,6 @@ packages: is-generator-function: 1.0.10 is-typed-array: 1.1.10 which-typed-array: 1.1.9 - dev: true /utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} @@ -20845,8 +21037,8 @@ packages: replace-ext: 1.0.1 dev: false - /vite-node@0.31.1(@types/node@20.2.5)(sass@1.62.1): - resolution: {integrity: sha512-BajE/IsNQ6JyizPzu9zRgHrBwczkAs0erQf/JRpgTIESpKvNj9/Gd0vxX905klLkb0I0SJVCKbdrl5c6FnqYKA==} + /vite-node@0.31.4(@types/node@20.2.5)(sass@1.62.1): + resolution: {integrity: sha512-uzL377GjJtTbuc5KQxVbDu2xfU/x0wVjUtXQR2ihS21q/NK6ROr4oG0rsSkBBddZUVCwzfx22in76/0ZZHXgkQ==} engines: {node: '>=v14.18.0'} hasBin: true dependencies: @@ -20903,20 +21095,20 @@ packages: optionalDependencies: fsevents: 2.3.2 - /vitest-fetch-mock@0.2.2(vitest@0.31.1): + /vitest-fetch-mock@0.2.2(vitest@0.31.4): resolution: {integrity: sha512-XmH6QgTSjCWrqXoPREIdbj40T7i1xnGmAsTAgfckoO75W1IEHKR8hcPCQ7SO16RsdW1t85oUm6pcQRLeBgjVYQ==} engines: {node: '>=14.14.0'} peerDependencies: vitest: '>=0.16.0' dependencies: cross-fetch: 3.1.5 - vitest: 0.31.1(happy-dom@9.19.2)(sass@1.62.1) + vitest: 0.31.4(happy-dom@9.20.3)(sass@1.62.1) transitivePeerDependencies: - encoding dev: true - /vitest@0.31.1(happy-dom@9.19.2)(sass@1.62.1): - resolution: {integrity: sha512-/dOoOgzoFk/5pTvg1E65WVaobknWREN15+HF+0ucudo3dDG/vCZoXTQrjIfEaWvQXmqScwkRodrTbM/ScMpRcQ==} + /vitest@0.31.4(happy-dom@9.20.3)(sass@1.62.1): + resolution: {integrity: sha512-GoV0VQPmWrUFOZSg3RpQAPN+LPmHg2/gxlMNJlyxJihkz6qReHDV6b0pPDcqFLNEPya4tWJ1pgwUNP9MLmUfvQ==} engines: {node: '>=v14.18.0'} hasBin: true peerDependencies: @@ -20949,18 +21141,18 @@ packages: '@types/chai': 4.3.5 '@types/chai-subset': 1.3.3 '@types/node': 20.2.5 - '@vitest/expect': 0.31.1 - '@vitest/runner': 0.31.1 - '@vitest/snapshot': 0.31.1 - '@vitest/spy': 0.31.1 - '@vitest/utils': 0.31.1 + '@vitest/expect': 0.31.4 + '@vitest/runner': 0.31.4 + '@vitest/snapshot': 0.31.4 + '@vitest/spy': 0.31.4 + '@vitest/utils': 0.31.4 acorn: 8.8.2 acorn-walk: 8.2.0 cac: 6.7.14 chai: 4.3.7 concordance: 5.0.4 debug: 4.3.4(supports-color@8.1.1) - happy-dom: 9.19.2 + happy-dom: 9.20.3 local-pkg: 0.4.3 magic-string: 0.30.0 pathe: 1.1.0 @@ -20970,7 +21162,7 @@ packages: tinybench: 2.5.0 tinypool: 0.5.0 vite: 4.3.9(@types/node@20.2.5)(sass@1.62.1) - vite-node: 0.31.1(@types/node@20.2.5)(sass@1.62.1) + vite-node: 0.31.4(@types/node@20.2.5)(sass@1.62.1) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -21007,14 +21199,14 @@ packages: - vue dev: true - /vue-eslint-parser@9.3.0(eslint@8.40.0): + /vue-eslint-parser@9.3.0(eslint@8.41.0): resolution: {integrity: sha512-48IxT9d0+wArT1+3wNIy0tascRoywqSUe2E1YalIC1L8jsUGe5aJQItWfRok7DVFGz3UYvzEI7n5wiTXsCMAcQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4(supports-color@8.1.1) - eslint: 8.40.0 + eslint: 8.41.0 eslint-scope: 7.2.0 eslint-visitor-keys: 3.4.1 espree: 9.5.2 @@ -21049,16 +21241,16 @@ packages: he: 1.2.0 dev: true - /vue-tsc@1.6.5(typescript@5.0.4): + /vue-tsc@1.6.5(typescript@5.1.3): resolution: {integrity: sha512-Wtw3J7CC+JM2OR56huRd5iKlvFWpvDiU+fO1+rqyu4V2nMTotShz4zbOZpW5g9fUOcjnyZYfBo5q5q+D/q27JA==} hasBin: true peerDependencies: typescript: '*' dependencies: '@volar/vue-language-core': 1.6.5 - '@volar/vue-typescript': 1.6.5(typescript@5.0.4) + '@volar/vue-typescript': 1.6.5(typescript@5.1.3) semver: 7.5.1 - typescript: 5.0.4 + typescript: 5.1.3 dev: true /vue@3.3.4: @@ -21236,7 +21428,6 @@ packages: gopd: 1.0.1 has-tostringtag: 1.0.0 is-typed-array: 1.1.10 - dev: true /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} @@ -21285,6 +21476,7 @@ packages: /word-wrap@1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} + dev: true /wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} From 482b00df777b772e3877dca094129aef3461862a Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 2 Jun 2023 14:13:36 +0900 Subject: [PATCH 170/213] :art: --- packages/frontend/src/components/MkMediaImage.vue | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index b921a066f7..b29871c363 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -32,7 +32,7 @@ <div v-if="image.comment" :class="$style.indicator">ALT</div> <div v-if="image.isSensitive" :class="$style.indicator" style="color: var(--warn);">NSFW</div> </div> - <button :class="$style.menu" class="_button" @click.stop="showMenu"><i class="ti ti-dots"></i></button> + <button :class="$style.menu" class="_button" @click.stop="showMenu"><i class="ti ti-dots" style="vertical-align: middle;"></i></button> </template> </div> </template> @@ -131,13 +131,14 @@ function showMenu(ev: MouseEvent) { .menu { display: block; position: absolute; - border-radius: 6px; + border-radius: 999px; background-color: rgba(0, 0, 0, 0.3); -webkit-backdrop-filter: var(--blur, blur(15px)); backdrop-filter: var(--blur, blur(15px)); color: #fff; font-size: 0.8em; - padding: 6px 8px; + width: 32px; + height: 32px; text-align: center; bottom: 10px; right: 10px; From 5230ec883e351429a3638b39439cbcd18d921c69 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 2 Jun 2023 15:18:34 +0900 Subject: [PATCH 171/213] =?UTF-8?q?fix(backend):=207=E6=97=A5=E7=B5=8C?= =?UTF-8?q?=E9=81=8E=E3=81=97=E3=81=A6=E7=84=A1=E5=8A=B9=E5=8C=96=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=81=9F=E3=82=A2=E3=83=B3=E3=83=86=E3=83=8A=E3=82=92?= =?UTF-8?q?=E5=86=8D=E5=BA=A6=E6=9C=89=E5=8A=B9=E5=8C=96=E3=81=99=E3=82=8B?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E3=81=8C=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #10476 --- CHANGELOG.md | 1 + packages/backend/src/server/api/endpoints/antennas/notes.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a17c9c231b..cb8ab8f30f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ ### Server - bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 - ストリーミングのパフォーマンスを改善 +- Fix: 無効化されたアンテナにアクセスがあった際に再度有効化するように - Fix: お知らせの画像URLを空にできない問題を修正 - Fix: i/notificationsのsinceIdが機能しない問題を修正 diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index dca0f443b7..e756a9b510 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -113,6 +113,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { } this.antennasRepository.update(antenna.id, { + isActive: true, lastUsedAt: new Date(), }); From a7abf941c08937e78885c754caf75d73caf63782 Mon Sep 17 00:00:00 2001 From: mappi <mappi@mizuiromoon.com> Date: Fri, 2 Jun 2023 16:31:25 +0900 Subject: [PATCH 172/213] =?UTF-8?q?fix:vue-plyr=E5=BB=83=E6=AD=A2=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E5=AF=BE=E5=BF=9C=EF=BC=88Audio=E8=A6=81=E7=B4=A0?= =?UTF-8?q?=E3=81=AE=E3=82=B3=E3=83=B3=E3=83=86=E3=82=AD=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC=E3=82=92=E3=83=96=E3=83=A9?= =?UTF-8?q?=E3=82=A6=E3=82=B6=E3=83=87=E3=83=95=E3=82=A9=E3=83=AB=E3=83=88?= =?UTF-8?q?=E3=81=AB=EF=BC=89=20(#10940)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * add comment * fix quotes --- packages/frontend/src/components/MkNote.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 2483204d4c..7c9ddadbf8 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -382,6 +382,8 @@ function undoReact(note): void { function onContextmenu(ev: MouseEvent): void { const isLink = (el: HTMLElement) => { if (el.tagName === 'A') return true; + // 再生速度の選択などのために、Audio要素のコンテキストメニューはブラウザデフォルトとする。 + if (el.tagName === 'AUDIO') return true; if (el.parentElement) { return isLink(el.parentElement); } From 1177528c259cafd6df30b62bfd3c0f4e74f64251 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 4 Jun 2023 14:03:46 +0900 Subject: [PATCH 173/213] fix backend e2e --- packages/backend/test/e2e/2fa.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/test/e2e/2fa.ts b/packages/backend/test/e2e/2fa.ts index 0addb430c9..5da997f28b 100644 --- a/packages/backend/test/e2e/2fa.ts +++ b/packages/backend/test/e2e/2fa.ts @@ -2,7 +2,7 @@ process.env.NODE_ENV = 'test'; import * as assert from 'assert'; import * as crypto from 'node:crypto'; -import * as cbor from 'cbor'; +import cbor from 'cbor'; import * as OTPAuth from 'otpauth'; import { loadConfig } from '../../src/config.js'; import { signup, api, post, react, startServer, waitFire } from '../utils.js'; From db623dda22a3fce43c4bbe8876dc33ebbbd285c0 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 4 Jun 2023 14:31:03 +0900 Subject: [PATCH 174/213] New Crowdin updates (#10943) * New translations ja-JP.yml (Russian) * New translations ja-JP.yml (Russian) * New translations ja-JP.yml (Arabic) * New translations ja-JP.yml (Russian) * New translations ja-JP.yml (Russian) * New translations ja-JP.yml (Russian) --- locales/ar-SA.yml | 6 +++--- locales/ru-RU.yml | 31 +++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 3b97f435d2..5d0fd201b3 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -267,8 +267,8 @@ start: "البداية" home: "الرئيسي" remoteUserCaution: "هذه المعلومات قد لا تكون مكتملة بما أن المستخدم من مثيل بعيد." activity: "النشاط" -images: "الصور" -image: "الصور" +images: "صور" +image: "صور" birthday: "تاريخ الميلاد" yearsOld: "{age} سنة" registeredDate: "انضم في" @@ -1331,7 +1331,7 @@ _pages: text: "نص" textarea: "حقل نصي" section: "قسم" - image: "الصور" + image: "صور" button: "زرّ" note: "ملاحظة مضمّنة" _note: diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 8c79a4502d..e92449fdb9 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -2,7 +2,7 @@ _lang_: "Русский" headlineMisskey: "Сеть, сплетённая из заметок" introMisskey: "Добро пожаловать! Misskey — это децентрализованный сервис микроблогов с открытым исходным кодом.\nПишите «заметки» — делитесь со всеми происходящим вокруг или рассказывайте о себе 📡\nСтавьте «реакции» — выражайте свои чувства и эмоции от заметок других 👍\nОткройте для себя новый мир 🚀" -poweredByMisskeyDescription: "{name} – один из инстансов (также называемый экземпляром Misskey), использующий платформу с открытым исходным кодом <b>Misskey</b>." +poweredByMisskeyDescription: "{name} – сервис на платформе с открытым исходным кодом <b>Misskey</b>, называемый инстансом Misskey." monthAndDay: "{day}.{month}" search: "Поиск" notifications: "Уведомления" @@ -649,8 +649,8 @@ abuseReported: "Жалоба отправлена. Большое спасибо reporter: "Сообщивший" reporteeOrigin: "О ком сообщено" reporterOrigin: "Кто сообщил" -forwardReport: "Перенаправление отчета на инстант." -forwardReportIsAnonymous: "Удаленный инстант не сможет увидеть вашу информацию и будет отображаться как анонимная системная учетная запись." +forwardReport: "Отправить жалобу на инстанс автора." +forwardReportIsAnonymous: "Жалоба на удалённый инстанс будет отправлена анонимно. Вместо ваших данных у получателя будет отображена системная учётная запись." send: "Отправить" abuseMarkAsResolved: "Отметить жалобу как решённую" openInNewTab: "Открыть в новой вкладке" @@ -823,6 +823,7 @@ translatedFrom: "Перевод. Язык оригинала — {x}" accountDeletionInProgress: "В настоящее время выполняется удаление учетной записи" usernameInfo: "Имя, которое отличает вашу учетную запись от других на этом сервере. Вы можете использовать алфавит (a~z, A~Z), цифры (0~9) или символы подчеркивания (_). Имена пользователей не могут быть изменены позже." aiChanMode: "Режим Ай" +devMode: "Режим разработчика" keepCw: "Сохраняйте Предупреждения о содержимом" pubSub: "Учётные записи Pub/Sub" lastCommunication: "Последнее сообщение" @@ -914,8 +915,8 @@ cannotUploadBecauseInappropriate: "Файл не может быть загру cannotUploadBecauseNoFreeSpace: "Файл не может быть загружен, так как не осталось места на диске" cannotUploadBecauseExceedsFileSizeLimit: "Файл не может быть загружен, так как он превышает лимит размера файла." beta: "Бета" -enableAutoSensitive: "Автоматическое определение NSFW" -enableAutoSensitiveDescription: "Если доступно, используйте машинное обучение для автоматической установки флага NSFW на носителе. Даже если эта функция отключена, она может быть установлена автоматически в зависимости от инстанта." +enableAutoSensitive: "Автоматическое определение содержимого не для всех" +enableAutoSensitiveDescription: "Позволяет определять наличие содержимого не для всех при помощи искусственного интеллекта там, где это возможно. Даже если эту опцию отключить, она всё равно может быть включена на весь инстанс." activeEmailValidationDescription: "Если включено, будет проводиться более строгая проверка адреса электронной почты, в том числе на то, что он действительный и не временный. Если же отключено, то проверяется только корректность написания адреса." navbar: "Панель навигации" shuffle: "Перемешать" @@ -1006,6 +1007,7 @@ noteIdOrUrl: "ID или ссылка на заметку" video: "Видео" videos: "Видео" dataSaver: "Экономия трафика" +renotesList: "Репосты" horizontal: "Сбоку" youFollowing: "Подписки" options: "Настройки ролей" @@ -1180,6 +1182,9 @@ _achievements: _client30min: title: "Перерыв на обед" description: "Прошло 30 минут с момента запуска клиента" + _client60min: + title: "Не наглядеться на Misskey" + description: "Misskey был открыт 60 минут подряд" _noteDeletedWithin1min: title: "Ой, нет!" description: "Заметка удалена через минуту после публикации" @@ -1282,6 +1287,7 @@ _role: canInvite: "Может создавать пригласительные коды" canManageCustomEmojis: "Управлять пользовательскими эмодзи" driveCapacity: "Доступное пространство на «диске»" + alwaysMarkNsfw: "Всегда отмечать файлы как «не для всех»" pinMax: "Доступное количество закреплённых заметок" antennaMax: "Доступное количество антенн" wordMuteMax: "Доступное количество знаков в списке скрытия слов" @@ -1309,7 +1315,7 @@ _sensitiveMediaDetection: description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно." sensitivity: "Чувствительность обнаружения" sensitivityDescription: "Более низкая чувствительность уменьшает количество ложных срабатываний (false positives). Повышение чувствительности уменьшает утечку при обнаружении (ложноотрицательные результаты)." - setSensitiveFlagAutomatically: "Установить флаг NSFW" + setSensitiveFlagAutomatically: "Обозначить как не для всех" setSensitiveFlagAutomaticallyDescription: "Даже если этот параметр отключен, результат оценки сохраняется внутри системы." analyzeVideos: "Анализировать видео?" analyzeVideosDescription: "Анализируйте видео в дополнение к неподвижным изображениям. Нагрузка на сервер немного увеличивается." @@ -1528,6 +1534,16 @@ _time: minute: "мин" hour: "ч" day: "сут" +_timelineTutorial: + title: "Как пользоваться Misskey" + step1_1: "Это лицо Misskey, так называемая лента. Ваш инстанс, {name}, покажет тут все опубликованные на нём заметки в хронологическом порядке." + step1_2: "Здесь есть несколько лент. К примеру «персональная» лента отображает заметки тех, на кого вы подписаны. А «местная» — заметки тех, кого приютил {name}." + step2_1: "Что ж, теперь самое время опубликовать заметку. Если нажать вверху страницы на изображение карандаша, появится форма для текста." + step2_2: "Почему бы не написать немного о себе? Ну, или хотя бы «Привет, {name}»?" + step3_1: "Справились с первой заметкой?" + step3_2: "Отлично, теперь она должна появиться в вашей ленте." + step4_1: "А ещё здесь можно делиться своими реакциями на заметки." + step4_2: "Отмечайте реакции, нажимая на символ «+» под заметкой и выбирая значок по душе." _2fa: alreadyRegistered: "Двухфакторная аутентификация уже настроена." registerTOTP: "Начните настраивать приложение-аутентификатор" @@ -1868,6 +1884,9 @@ _deck: _dialog: charactersExceeded: "Превышено максимальное количество символов! У вас {current} / из {max}" charactersBelow: "Это ниже минимального количества символов! У вас {current} / из {min}" +_disabledTimeline: + title: "Лента отключена" + description: "Ваша текущая роль не позволяет пользоваться этой лентой." _webhookSettings: name: "Название" active: "Вкл." From 0cb3c7481c35a70760fff12f76d31903c2577375 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 5 Jun 2023 10:55:18 +0900 Subject: [PATCH 175/213] fix typo: schema -> scheme --- packages/backend/src/server/web/boot.js | 6 +++--- packages/frontend/src/local-storage.ts | 2 +- packages/frontend/src/scripts/theme.ts | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index 825f02e835..38ae8ad2e5 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -116,9 +116,9 @@ } } } - const colorSchema = localStorage.getItem('colorSchema'); - if (colorSchema) { - document.documentElement.style.setProperty('color-schema', colorSchema); + const colorScheme = localStorage.getItem('colorScheme'); + if (colorScheme) { + document.documentElement.style.setProperty('color-scheme', colorScheme); } //#endregion diff --git a/packages/frontend/src/local-storage.ts b/packages/frontend/src/local-storage.ts index 441a35747a..ca4f21f79b 100644 --- a/packages/frontend/src/local-storage.ts +++ b/packages/frontend/src/local-storage.ts @@ -13,7 +13,7 @@ type Keys = 'hashtags' | 'wallpaper' | 'theme' | - 'colorSchema' | + 'colorScheme' | 'useSystemFont' | 'fontSize' | 'ui' | diff --git a/packages/frontend/src/scripts/theme.ts b/packages/frontend/src/scripts/theme.ts index 28284c7bcf..f2e8253565 100644 --- a/packages/frontend/src/scripts/theme.ts +++ b/packages/frontend/src/scripts/theme.ts @@ -60,7 +60,7 @@ export function applyTheme(theme: Theme, persist = true) { document.documentElement.classList.remove('_themeChanging_'); }, 1000); - const colorSchema = theme.base === 'dark' ? 'dark' : 'light'; + const colorScheme = theme.base === 'dark' ? 'dark' : 'light'; // Deep copy const _theme = deepClone(theme); @@ -83,11 +83,11 @@ export function applyTheme(theme: Theme, persist = true) { document.documentElement.style.setProperty(`--${k}`, v.toString()); } - document.documentElement.style.setProperty('color-schema', colorSchema); + document.documentElement.style.setProperty('color-scheme', colorScheme); if (persist) { miLocalStorage.setItem('theme', JSON.stringify(props)); - miLocalStorage.setItem('colorSchema', colorSchema); + miLocalStorage.setItem('colorScheme', colorScheme); } // 色計算など再度行えるようにクライアント全体に通知 From 34e1b52b3846eaa5b599cf0cad13581e4e44eb45 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 5 Jun 2023 17:45:24 +0900 Subject: [PATCH 176/213] Update e2e.js --- cypress/support/e2e.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js index 9185be344c..827a326d18 100644 --- a/cypress/support/e2e.js +++ b/cypress/support/e2e.js @@ -21,6 +21,8 @@ import './commands' Cypress.on('uncaught:exception', (err, runnable) => { if ([ + 'The source image cannot be decoded', + // Chrome 'ResizeObserver loop limit exceeded', From 9e716fd8135e85402e266551b2c9be6220f5eead Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Mon, 5 Jun 2023 08:58:00 +0000 Subject: [PATCH 177/213] =?UTF-8?q?fix(frontend):=20MkUserPopup=E3=81=8C?= =?UTF-8?q?=E7=9C=81=E7=95=A5=E3=81=95=E3=82=8C=E3=81=AA=E3=81=84=E3=81=AE?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20Fix=20#10870?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkUserPopup.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue index c9ff02cc76..c3b777a12e 100644 --- a/packages/frontend/src/components/MkUserPopup.vue +++ b/packages/frontend/src/components/MkUserPopup.vue @@ -22,7 +22,7 @@ <div :class="$style.username"><MkAcct :user="user"/></div> </div> <div :class="$style.description"> - <Mfm v-if="user.description" :text="user.description" :author="user" :i="$i"/> + <Mfm v-if="user.description" :class="$style.mfm" :text="user.description" :author="user" :i="$i"/> <div v-else style="opacity: 0.7;">{{ i18n.ts.noAccountDescription }}</div> </div> <div :class="$style.status"> @@ -192,6 +192,13 @@ onMounted(() => { border-bottom: solid 1px var(--divider); } +.mfm { + display: -webkit-box; + -webkit-line-clamp: 5; + -webkit-box-orient: vertical; + overflow: hidden; +} + .status { padding: 16px 26px 16px 26px; } From 565c502bbf67fffc9cd045f364c7b2d49b2329e8 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Mon, 5 Jun 2023 09:04:30 +0000 Subject: [PATCH 178/213] =?UTF-8?q?fix(backend):=20page=E3=81=AE=E3=83=94?= =?UTF-8?q?=E3=83=B3=E7=95=99=E3=82=81=E3=82=92=E8=A7=A3=E9=99=A4=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=81=93=E3=81=A8=E3=81=8C=E3=81=A7=E3=81=8D=E3=81=AA?= =?UTF-8?q?=E3=81=84=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3=20Fix=20?= =?UTF-8?q?#10950?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + packages/backend/src/server/api/endpoints/i/update.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb8ab8f30f..a063006566 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ - Fix: 無効化されたアンテナにアクセスがあった際に再度有効化するように - Fix: お知らせの画像URLを空にできない問題を修正 - Fix: i/notificationsのsinceIdが機能しない問題を修正 +- Fix: pageのピン留めを解除することができない問題を修正 ## 13.12.2 diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index d10f690a32..8f5e6177c2 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -146,7 +146,7 @@ export const paramDef = { alwaysMarkNsfw: { type: 'boolean' }, autoSensitive: { type: 'boolean' }, ffVisibility: { type: 'string', enum: ['public', 'followers', 'private'] }, - pinnedPageId: { type: 'string', format: 'misskey:id' }, + pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true }, mutedWords: { type: 'array' }, mutedInstances: { type: 'array', items: { type: 'string', From 4443dba71790761016c5b84d56b1462949a97752 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 5 Jun 2023 18:04:51 +0900 Subject: [PATCH 179/213] Update basic.cy.js --- cypress/e2e/basic.cy.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cypress/e2e/basic.cy.js b/cypress/e2e/basic.cy.js index 652e0c2d70..2515c14ad6 100644 --- a/cypress/e2e/basic.cy.js +++ b/cypress/e2e/basic.cy.js @@ -169,25 +169,20 @@ describe('After user signed in', () => { cy.get('[data-cy-user-setup-user-description] textarea').type('ほげ'); // TODO: アイコン設定テスト - cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); // プライバシー設定 - cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); // フォローはスキップ - cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); // プッシュ通知設定はスキップ - cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); - cy.get('[data-cy-user-setup-back]').click(); cy.get('[data-cy-user-setup-continue]').click(); }); }); From 618d07158a7425448d57002f4a398f3276e39155 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 5 Jun 2023 18:05:03 +0900 Subject: [PATCH 180/213] 13.13.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 81029514c3..8cf7d37f63 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0-beta.7", + "version": "13.13.0", "codename": "nasubi", "repository": { "type": "git", From 6b0685a25c5eb08df232516f77f86bbb55492dfe Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 5 Jun 2023 18:05:20 +0900 Subject: [PATCH 181/213] [ci skip] New Crowdin updates (#10947) * New translations ja-JP.yml (Korean) * New translations ja-JP.yml (Chinese Traditional) --- locales/ko-KR.yml | 2 +- locales/zh-TW.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index c36305137c..fd46eef1ff 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -870,7 +870,7 @@ instanceDefaultLightTheme: "서버 기본 라이트 테마" instanceDefaultDarkTheme: "서버 기본 다크 테마" instanceDefaultThemeDescription: "객체 형식의 테마 코드를 입력해 주세요." mutePeriod: "뮤트할 기간" -period: "투표 기한" +period: "기간" indefinitely: "무기한" tenMinutes: "10분" oneHour: "1시간" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 04c14b2c65..ef0baeef50 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1060,6 +1060,8 @@ cancelReactionConfirm: "要取消做出的反應嗎?" changeReactionConfirm: "要變更做出的反應嗎?" later: "稍後再說" goToMisskey: "往Misskey" +additionalEmojiDictionary: "表情符號的附加辭典" +installed: "已安裝" _initialAccountSetting: accountCreated: "帳戶已建立完成!" letsStartAccountSetup: "來進行帳戶的初始設定吧。" From 2d5bb40ad0be6ea1066b4a383682cfbe2332e813 Mon Sep 17 00:00:00 2001 From: Yuriha <121590760+yuriha-chan@users.noreply.github.com> Date: Mon, 5 Jun 2023 18:06:33 +0900 Subject: [PATCH 182/213] Condensedlines reflow once (#10944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: Update MkCondensedLine styles after reading all dimensions * perf: reduce reflow in MkCondensedLine * lint * Update packages/frontend/src/components/global/MkCondensedLine.vue Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> * Update packages/frontend/src/components/global/MkCondensedLine.vue Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> Co-authored-by: Acid Chicken (硫酸鶏) <root@acid-chicken.com> --- .../frontend/src/components/global/MkCondensedLine.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/components/global/MkCondensedLine.vue b/packages/frontend/src/components/global/MkCondensedLine.vue index 1d46ff1ec9..4b2e8e4750 100644 --- a/packages/frontend/src/components/global/MkCondensedLine.vue +++ b/packages/frontend/src/components/global/MkCondensedLine.vue @@ -13,13 +13,20 @@ interface Props { const contentSymbol = Symbol(); const observer = new ResizeObserver((entries) => { + const results: { + container: HTMLSpanElement; + transform: string; + }[] = []; for (const entry of entries) { const content = (entry.target[contentSymbol] ? entry.target : entry.target.firstElementChild) as HTMLSpanElement; const props: Required<Props> = content[contentSymbol]; const container = content.parentElement as HTMLSpanElement; const contentWidth = content.getBoundingClientRect().width; const containerWidth = container.getBoundingClientRect().width; - container.style.transform = `scaleX(${Math.max(props.minScale, Math.min(1, containerWidth / contentWidth))})`; + results.push({ container, transform: `scaleX(${Math.max(props.minScale, Math.min(1, containerWidth / contentWidth))})` }); + } + for (const result of results) { + result.container.style.transform = result.transform; } }); </script> From ce252143c34fbd5b416ddd5417216345117c2f83 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Mon, 5 Jun 2023 12:29:37 +0000 Subject: [PATCH 183/213] chore: Please write more detailed environmental information in your bug report. --- .github/ISSUE_TEMPLATE/01_bug-report.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.md b/.github/ISSUE_TEMPLATE/01_bug-report.md index f6fd593c85..26487e9d22 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.md +++ b/.github/ISSUE_TEMPLATE/01_bug-report.md @@ -39,8 +39,20 @@ Please include errors from the developer console and/or server log files if you <!-- Tell us where on the platform it happens --> <!-- DO NOT WRITE "latest". Please provide the specific version. --> -Misskey version: -PostgreSQL version: -Redis version: -Your OS: -Your browser: +### 💻 Frontend +* **Model and OS of the device(s):** + <!-- Example: MacBook Pro (14inch, 2021), macOS Ventura 13.4 --> +* **Browser:** + <!-- Example: Chrome 113.0.5672.126 --> +* **Server URL:** + <!-- Example: misskey.io --> + +### 🛰 Backend (for instance admin) +<!-- If you are using a managed service, put that after the version. --> + +* **Installation Method or Hosting Service:** <!-- Example: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment --> +* **Misskey:** 13.x.x +* **Node:** 18.x.x +* **PostgreSQL:** 15.x.x +* **Redis:** 7.x.x +* **OS and Architecture:** <!-- Example: Ubuntu 22.04.2 LTS aarch64 --> From fa051a2a5fa04c8cc48807ef5021470ebce15d82 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Mon, 5 Jun 2023 12:35:23 +0000 Subject: [PATCH 184/213] :art: --- .github/ISSUE_TEMPLATE/01_bug-report.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.md b/.github/ISSUE_TEMPLATE/01_bug-report.md index 26487e9d22..46ce16f073 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.md +++ b/.github/ISSUE_TEMPLATE/01_bug-report.md @@ -40,19 +40,19 @@ Please include errors from the developer console and/or server log files if you <!-- DO NOT WRITE "latest". Please provide the specific version. --> ### 💻 Frontend -* **Model and OS of the device(s):** +* Model and OS of the device(s): <!-- Example: MacBook Pro (14inch, 2021), macOS Ventura 13.4 --> -* **Browser:** +* Browser: <!-- Example: Chrome 113.0.5672.126 --> -* **Server URL:** +* Server URL: <!-- Example: misskey.io --> ### 🛰 Backend (for instance admin) <!-- If you are using a managed service, put that after the version. --> -* **Installation Method or Hosting Service:** <!-- Example: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment --> -* **Misskey:** 13.x.x -* **Node:** 18.x.x -* **PostgreSQL:** 15.x.x -* **Redis:** 7.x.x -* **OS and Architecture:** <!-- Example: Ubuntu 22.04.2 LTS aarch64 --> +* Installation Method or Hosting Service: <!-- Example: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment --> +* Misskey: 13.x.x +* Node: 18.x.x +* PostgreSQL: 15.x.x +* Redis: 7.x.x +* OS and Architecture: <!-- Example: Ubuntu 22.04.2 LTS aarch64 --> From 8263cc0094b69db28ac06914108908cfd9d41ea1 Mon Sep 17 00:00:00 2001 From: CaffeeLake <PascalCoffeeLake@gmail.com> Date: Mon, 5 Jun 2023 21:44:28 +0900 Subject: [PATCH 185/213] Fix: #10955 TypeError: JSON5.parse is not a function (#10956) * Fix: JSON5.parse is not a function * update changelog * update chglog --------- Co-authored-by: tamaina <tamaina@hotmail.co.jp> --- CHANGELOG.md | 5 +++++ packages/backend/src/server/api/endpoints/meta.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a063006566..4296288788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ --> +## 13.13.1 (unreleased) + +### Server +- Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正 + ## 13.13.0 ### General diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 53d724a9dd..fe68467a64 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -1,6 +1,6 @@ import { IsNull, LessThanOrEqual, MoreThan } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; -import * as JSON5 from 'json5'; +import JSON5 from 'json5'; import type { AdsRepository, UsersRepository } from '@/models/index.js'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; From 981e6f996ec632f4ccb27d24d107c37a5d070b32 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 6 Jun 2023 09:04:57 +0900 Subject: [PATCH 186/213] =?UTF-8?q?fix(frontend):=20=E3=82=BF=E3=83=96?= =?UTF-8?q?=E3=81=8C=E3=82=A2=E3=82=AF=E3=83=86=E3=82=A3=E3=83=96=E3=81=AA?= =?UTF-8?q?=E9=96=93=E3=81=AFstream=E3=81=8C=E5=88=87=E6=96=AD=E3=81=95?= =?UTF-8?q?=E3=82=8C=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #10952 --- CHANGELOG.md | 3 +++ packages/frontend/src/stream.ts | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4296288788..cc13749caf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ ## 13.13.1 (unreleased) +### Client +- Fix: タブがアクティブな間はstreamが切断されないように + ### Server - Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正 diff --git a/packages/frontend/src/stream.ts b/packages/frontend/src/stream.ts index 9cae58a26a..a807d1d306 100644 --- a/packages/frontend/src/stream.ts +++ b/packages/frontend/src/stream.ts @@ -12,5 +12,14 @@ export function useStream(): Misskey.Stream { token: $i.token, } : null)); + window.setTimeout(heartbeat, 1000 * 60); + return stream; } + +function heartbeat(): void { + if (stream != null && document.visibilityState === 'visible') { + stream.send('ping'); + } + window.setTimeout(heartbeat, 1000 * 60); +} From aeb8955ca2600e801d44dcac2005fc994e665a6c Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 6 Jun 2023 09:09:23 +0900 Subject: [PATCH 187/213] =?UTF-8?q?perf(frontend):=20WebGL=20context?= =?UTF-8?q?=E3=81=AE=E6=95=B0=E3=82=92=E6=B8=9B=E3=82=89=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #10960 --- packages/frontend/src/components/global/MkAvatar.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index 422b35c9dd..efe74b7cc3 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -1,6 +1,6 @@ <template> <component :is="link ? MkA : 'span'" v-user-preview="preview ? user.id : undefined" v-bind="bound" class="_noSelect" :class="[$style.root, { [$style.animation]: animation, [$style.cat]: user.isCat, [$style.square]: squareAvatars }]" :style="{ color }" :title="acct(user)" @click="onClick"> - <MkImgWithBlurhash :class="$style.inner" :src="url" :hash="user?.avatarBlurhash" :cover="true"/> + <img :class="$style.inner" :src="url" :hash="user?.avatarBlurhash" :cover="true"/> <MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/> <div v-if="user.isCat" :class="[$style.ears]"> <div :class="$style.earLeft"> @@ -24,7 +24,6 @@ <script lang="ts" setup> import { watch } from 'vue'; import * as misskey from 'misskey-js'; -import MkImgWithBlurhash from '../MkImgWithBlurhash.vue'; import MkA from './MkA.vue'; import { getStaticImageUrl } from '@/scripts/media-proxy'; import { extractAvgColorFromBlurhash } from '@/scripts/extract-avg-color-from-blurhash'; From f4943bc5bbb809d94521b87afb9c69c503dd3ce3 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 6 Jun 2023 09:09:46 +0900 Subject: [PATCH 188/213] New translations ja-JP.yml (Japanese, Kansai) (#10954) --- locales/ja-KS.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 652814ca98..aa0f31fcd2 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -792,6 +792,7 @@ noMaintainerInformationWarning: "管理者情報が設定されてへんで" noBotProtectionWarning: "Botプロテクションが設定されてへんで。" configure: "設定する" postToGallery: "ギャラリーへ投稿" +postToHashtag: "このハッシュタグで投稿" gallery: "ギャラリー" recentPosts: "最近の投稿" popularPosts: "人気の投稿" @@ -825,6 +826,7 @@ translatedFrom: "{x}から翻訳するで" accountDeletionInProgress: "アカウント削除しとるで待っとってなー" usernameInfo: "サーバー上であんたのアカウントをあんたやと分かるようにするための名前やで。アルファベット(a~z, A~Z)、数字(0~9)、それとアンダーバー(_)が使って考えてな。この名前は後から変更することはできへんからちゃんと考えるんやで。" aiChanMode: "藍モードやで" +devMode: "開発者モード" keepCw: "CWを維持するで" pubSub: "Pub/Subのアカウント" lastCommunication: "直近の通信" @@ -834,6 +836,8 @@ breakFollow: "フォロワーを解除するで" breakFollowConfirm: "フォロワー解除してもええか?" itsOn: "オンになっとるよ" itsOff: "オフになってるで" +on: "オン" +off: "オフ" emailRequiredForSignup: "アカウント登録にメールアドレスを必須にするで" unread: "未読" filter: "フィルタ" @@ -988,6 +992,8 @@ cannotBeChangedLater: "後からは変えられへんで。" reactionAcceptance: "ツッコミの受け入れ" likeOnly: "いいねだけ" likeOnlyForRemote: "リモートからはいいねだけな" +nonSensitiveOnly: "センシティブじゃないやつだけ" +nonSensitiveOnlyForLocalLikeOnlyForRemote: "センシティブじゃないやつだけ (リモートはいいねだけ)" rolesAssignedToMe: "自分に割り当てられたロール" resetPasswordConfirm: "パスワード作り直すんでええな?" sensitiveWords: "けったいな単語" @@ -1045,10 +1051,17 @@ preventAiLearning: "生成AIの学習に使わんといて" preventAiLearningDescription: "他の文章生成AIとか画像生成AIに、投稿したノートとか画像なんかを勝手に使わんように頼むで。具体的にはnoaiフラグをHTMLレスポンスに含めるんやけど、これ聞いてくれるんはAIの気分次第やから、使われる可能性もちょっとはあるな。" options: "オプション" specifyUser: "ユーザー指定" +failedToPreviewUrl: "プレビューできへん" +update: "更新" rolesThatCanBeUsedThisEmojiAsReaction: "ツッコミとして使えるロール" rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールが一個も指定されてへんかったら、誰でもツッコミとして使えるで。" +rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロールじゃないとアカンで。" cancelReactionConfirm: "ツッコむんをやっぱやめるか?" changeReactionConfirm: "ツッコミを別のに変えるか?" +later: "あとで" +goToMisskey: "Misskeyへ" +additionalEmojiDictionary: "絵文字の追加辞書" +installed: "インストール済み" _initialAccountSetting: accountCreated: "アカウント作り終わったで。" letsStartAccountSetup: "アカウントの初期設定をしよか。" @@ -1063,6 +1076,7 @@ _initialAccountSetting: haveFun: "{name}、楽しんでな~" ifYouNeedLearnMore: "{name}(Misskey)の使い方とかをよー知りたいんやったら{link}をみてな。" skipAreYouSure: "初期設定飛ばすか?" + laterAreYouSure: "初期設定あとでやり直すん?" _serverRules: description: "新規登録前に見せる、サーバーの簡潔なルールを設定すんで。内容は使うための決め事の要約とすることを推奨するわ。" _accountMigration: From 29856a9129495cf64b7b5f0d287485cf4e6963c1 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 6 Jun 2023 09:16:38 +0900 Subject: [PATCH 189/213] tweak of 981e6f996 --- packages/frontend/src/stream.ts | 2 +- packages/misskey-js/src/streaming.ts | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/stream.ts b/packages/frontend/src/stream.ts index a807d1d306..a7e4ecd42d 100644 --- a/packages/frontend/src/stream.ts +++ b/packages/frontend/src/stream.ts @@ -19,7 +19,7 @@ export function useStream(): Misskey.Stream { function heartbeat(): void { if (stream != null && document.visibilityState === 'visible') { - stream.send('ping'); + stream.heartbeat(); } window.setTimeout(heartbeat, 1000 * 60); } diff --git a/packages/misskey-js/src/streaming.ts b/packages/misskey-js/src/streaming.ts index 0218b40a03..92a220b496 100644 --- a/packages/misskey-js/src/streaming.ts +++ b/packages/misskey-js/src/streaming.ts @@ -186,6 +186,14 @@ export default class Stream extends EventEmitter<StreamEvents> { this.stream.send(JSON.stringify(typeOrPayload)); } + public ping(): void { + this.stream.send('ping'); + } + + public heartbeat(): void { + this.stream.send('h'); + } + /** * Close this connection */ From e456c6a9c145e982ae42377f2d6ae1c74a341b31 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 6 Jun 2023 09:17:11 +0900 Subject: [PATCH 190/213] 13.13.1 --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc13749caf..d735ec71ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ --> -## 13.13.1 (unreleased) +## 13.13.1 ### Client - Fix: タブがアクティブな間はstreamが切断されないように diff --git a/package.json b/package.json index 8cf7d37f63..eff0bf2dc2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.0", + "version": "13.13.1", "codename": "nasubi", "repository": { "type": "git", From 8ccf954065a4930a8b2577b79ae3a87d5dd05449 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 6 Jun 2023 09:37:36 +0900 Subject: [PATCH 191/213] Update misskey-js.api.md --- packages/misskey-js/etc/misskey-js.api.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 19e5b75443..396187a439 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2606,6 +2606,10 @@ export class Stream extends EventEmitter<StreamEvents> { // // (undocumented) disconnectToChannel(connection: NonSharedConnection): void; + // (undocumented) + heartbeat(): void; + // (undocumented) + ping(): void; // Warning: (ae-forgotten-export) The symbol "SharedConnection" needs to be exported by the entry point index.d.ts // // (undocumented) From 95b2148bfe04ebd46fa4550b4ad37c73fc385ad5 Mon Sep 17 00:00:00 2001 From: Outvi V <19144373+outloudvi@users.noreply.github.com> Date: Fri, 9 Jun 2023 09:13:46 +0800 Subject: [PATCH 192/213] fix: correctly check the sensitivity flag (#10976) --- packages/backend/src/server/web/views/note.pug | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index 874c48c602..ea0917a80e 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -5,8 +5,8 @@ block vars - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`; - const url = `${config.url}/notes/${note.id}`; - const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null; - - const image = (note.files || []).find(file => file.type.startsWith('image/') && !file.type.isSensitive) - - const video = (note.files || []).find(file => file.type.startsWith('video/') && !file.type.isSensitive) + - const image = (note.files || []).find(file => file.type.startsWith('image/') && !file.isSensitive) + - const video = (note.files || []).find(file => file.type.startsWith('video/') && !file.isSensitive) block title = `${title} | ${instanceName}` From 88083925ce0f21bd700640ae233e32b6f5cb9e95 Mon Sep 17 00:00:00 2001 From: mappi <mappi@mizuiromoon.com> Date: Fri, 9 Jun 2023 12:09:21 +0900 Subject: [PATCH 193/213] Update CHANGELOG.md (#10979) --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d735ec71ed..9c4cba38a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,11 +96,12 @@ Meilisearchの設定に`index`が必要になりました。値はMisskeyサー ## 13.12.0 ### NOTE -- Node.js 18.6.0以上が必要になりました +- Node.js 18.16.0以上が必要になりました ### General - アカウントの引っ越し(フォロワー引き継ぎ)に対応 - Meilisearchを全文検索に使用できるようになりました + * 「フォロワーのみ」の投稿は検索結果に表示されません。 - 新規登録前に簡潔なルールをユーザーに表示できる、サーバールール機能を追加 - ユーザーへの自分用メモ機能 * ユーザーに対して、自分だけが見られるメモを追加できるようになりました。 From 13870c63b065b9e800fec0ed831cfcfdc7ab5ba7 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 9 Jun 2023 12:47:36 +0900 Subject: [PATCH 194/213] add note --- packages/backend/src/server/api/StreamingApiServerService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index 893dfe956e..a1758fd051 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -139,6 +139,7 @@ export class StreamingApiServerService { }); }); + // 一定期間通信が無いコネクションは実際には切断されている可能性があるため定期的にterminateする this.#cleanConnectionsIntervalId = setInterval(() => { const now = Date.now(); for (const [connection, lastActive] of this.#connections.entries()) { From 6032c2be1c357335359fe7823680bf99af2cee21 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 9 Jun 2023 12:51:16 +0900 Subject: [PATCH 195/213] fix(frontend): Scrolling Issue in Safari for Top and Bottom Bars fix #10977 --- packages/frontend/src/ui/deck.vue | 21 +++++++++++++++++++++ packages/frontend/src/ui/universal.vue | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index c828731773..1b0f7ae9d4 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -254,6 +254,27 @@ async function deleteProfile() { } </script> +<style> +html, +body { + width: 100%; + height: 100%; + overflow: clip; + position: fixed; + top: 0; + left: 0; +} + +#misskey_app { + width: 100%; + height: 100%; + overflow: clip; + position: absolute; + top: 0; + left: 0; +} +</style> + <style lang="scss" module> .transition_menuDrawerBg_enterActive, .transition_menuDrawerBg_leaveActive { diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index c0da59a57d..4f13040451 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -215,6 +215,27 @@ watch($$(navFooter), () => { }); </script> +<style> +html, +body { + width: 100%; + height: 100%; + overflow: clip; + position: fixed; + top: 0; + left: 0; +} + +#misskey_app { + width: 100%; + height: 100%; + overflow: clip; + position: absolute; + top: 0; + left: 0; +} +</style> + <style lang="scss" module> $ui-font-size: 1em; // TODO: どこかに集約したい $widgets-hide-threshold: 1090px; From 3941c73db0b0d9e0a3c7d4a638f57cb291c09a9f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 9 Jun 2023 12:55:27 +0900 Subject: [PATCH 196/213] tweak of 6032c2be1 --- packages/frontend/src/ui/deck.vue | 25 +++++++++++++------------ packages/frontend/src/ui/universal.vue | 25 +++++++++++++------------ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 1b0f7ae9d4..bd5d5beb84 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -257,21 +257,22 @@ async function deleteProfile() { <style> html, body { - width: 100%; - height: 100%; - overflow: clip; - position: fixed; - top: 0; - left: 0; + width: 100%; + height: 100%; + overflow: clip; + position: fixed; + top: 0; + left: 0; + overscroll-behavior: none; } #misskey_app { - width: 100%; - height: 100%; - overflow: clip; - position: absolute; - top: 0; - left: 0; + width: 100%; + height: 100%; + overflow: clip; + position: absolute; + top: 0; + left: 0; } </style> diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 4f13040451..8abb20300f 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -218,21 +218,22 @@ watch($$(navFooter), () => { <style> html, body { - width: 100%; - height: 100%; - overflow: clip; - position: fixed; - top: 0; - left: 0; + width: 100%; + height: 100%; + overflow: clip; + position: fixed; + top: 0; + left: 0; + overscroll-behavior: none; } #misskey_app { - width: 100%; - height: 100%; - overflow: clip; - position: absolute; - top: 0; - left: 0; + width: 100%; + height: 100%; + overflow: clip; + position: absolute; + top: 0; + left: 0; } </style> From 34a32a8334b332de1fd202c9e3fd871d566bab0b Mon Sep 17 00:00:00 2001 From: Ebise Lutica <7106976+EbiseLutica@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:00:53 +0900 Subject: [PATCH 197/213] =?UTF-8?q?=E3=82=A8=E3=83=A9=E3=83=BC=E7=94=BB?= =?UTF-8?q?=E5=83=8FURL=E3=82=92=E8=A8=AD=E5=AE=9A=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E3=81=AB=20(#10959)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * エラー画像URLを設定可能に * Update CHANGELOG.md * 設定したエラーアイコンをprefetchするようにbase.pugを変更 * 不足していたデータを追加 * enhance(frontend): デザイン調整 --- CHANGELOG.md | 3 ++ .../migration/1685973839966-errorImageUrl.js | 17 +++++++ packages/backend/src/models/entities/Meta.ts | 16 ++++++- .../src/server/api/endpoints/admin/meta.ts | 15 ++++-- .../server/api/endpoints/admin/update-meta.ts | 20 ++++++-- .../backend/src/server/api/endpoints/meta.ts | 17 +++++-- .../src/server/web/ClientServerService.ts | 48 +++++++++---------- .../backend/src/server/web/views/base.pug | 6 +-- .../frontend/src/components/MkChannelList.vue | 3 +- packages/frontend/src/components/MkNotes.vue | 3 +- .../src/components/MkNotifications.vue | 3 +- .../frontend/src/components/MkPagination.vue | 4 +- .../src/components/MkReactedUsersDialog.vue | 3 +- .../src/components/MkRenotedUsersDialog.vue | 3 +- .../frontend/src/components/MkUserList.vue | 3 +- .../src/components/global/MkError.vue | 3 +- packages/frontend/src/const.ts | 4 ++ packages/frontend/src/instance.ts | 9 +++- packages/frontend/src/pages/_error_.vue | 3 +- .../frontend/src/pages/admin/roles.role.vue | 3 +- .../frontend/src/pages/admin/settings.vue | 24 ++++++++++ packages/frontend/src/pages/favorites.vue | 3 +- .../frontend/src/pages/follow-requests.vue | 3 +- packages/frontend/src/pages/list.vue | 3 +- packages/frontend/src/pages/not-found.vue | 3 +- packages/frontend/src/pages/role.vue | 3 +- packages/frontend/src/pages/settings/apps.vue | 3 +- .../src/pages/settings/mute-block.vue | 7 +-- packages/frontend/src/widgets/WidgetRss.vue | 3 +- packages/misskey-js/src/entities.ts | 4 +- 30 files changed, 177 insertions(+), 65 deletions(-) create mode 100644 packages/backend/migration/1685973839966-errorImageUrl.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c4cba38a5..76d3b886db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ ### Client - Fix: タブがアクティブな間はstreamが切断されないように +### General +- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるようになりました + ### Server - Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正 diff --git a/packages/backend/migration/1685973839966-errorImageUrl.js b/packages/backend/migration/1685973839966-errorImageUrl.js new file mode 100644 index 0000000000..fd5d467162 --- /dev/null +++ b/packages/backend/migration/1685973839966-errorImageUrl.js @@ -0,0 +1,17 @@ +export class ErrorImageUrl1685973839966 { + name = 'ErrorImageUrl1685973839966' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "errorImageUrl"`); + await queryRunner.query(`ALTER TABLE "meta" ADD "serverErrorImageUrl" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "notFoundImageUrl" character varying(1024)`); + await queryRunner.query(`ALTER TABLE "meta" ADD "infoImageUrl" character varying(1024)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "infoImageUrl"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "notFoundImageUrl"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "serverErrorImageUrl"`); + await queryRunner.query(`ALTER TABLE "meta" ADD "errorImageUrl" character varying(1024) DEFAULT 'https://xn--931a.moe/aiart/yubitun.png'`); + } +} diff --git a/packages/backend/src/models/entities/Meta.ts b/packages/backend/src/models/entities/Meta.ts index 6d44e4edc7..f799551f30 100644 --- a/packages/backend/src/models/entities/Meta.ts +++ b/packages/backend/src/models/entities/Meta.ts @@ -101,13 +101,25 @@ export class Meta { length: 1024, nullable: true, }) - public errorImageUrl: string | null; + public iconUrl: string | null; @Column('varchar', { length: 1024, nullable: true, }) - public iconUrl: string | null; + public serverErrorImageUrl: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public notFoundImageUrl: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public infoImageUrl: string | null; @Column('boolean', { default: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 87a2d22ac2..4cc1b6011f 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -61,10 +61,17 @@ export const meta = { type: 'string', optional: false, nullable: true, }, - errorImageUrl: { + serverErrorImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + infoImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + notFoundImageUrl: { type: 'string', optional: false, nullable: true, - default: 'https://xn--931a.moe/aiart/yubitun.png', }, iconUrl: { type: 'string', @@ -305,7 +312,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { themeColor: instance.themeColor, mascotImageUrl: instance.mascotImageUrl, bannerUrl: instance.bannerUrl, - errorImageUrl: instance.errorImageUrl, + serverErrorImageUrl: instance.serverErrorImageUrl, + notFoundImageUrl: instance.notFoundImageUrl, + infoImageUrl: instance.infoImageUrl, iconUrl: instance.iconUrl, backgroundImageUrl: instance.backgroundImageUrl, logoImageUrl: instance.logoImageUrl, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 0e94f56cfd..1de5e9efd3 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -32,7 +32,9 @@ export const paramDef = { themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' }, mascotImageUrl: { type: 'string', nullable: true }, bannerUrl: { type: 'string', nullable: true }, - errorImageUrl: { type: 'string', nullable: true }, + serverErrorImageUrl: { type: 'string', nullable: true }, + infoImageUrl: { type: 'string', nullable: true }, + notFoundImageUrl: { type: 'string', nullable: true }, iconUrl: { type: 'string', nullable: true }, backgroundImageUrl: { type: 'string', nullable: true }, logoImageUrl: { type: 'string', nullable: true }, @@ -149,6 +151,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { set.iconUrl = ps.iconUrl; } + if (ps.serverErrorImageUrl !== undefined) { + set.serverErrorImageUrl = ps.serverErrorImageUrl; + } + + if (ps.infoImageUrl !== undefined) { + set.infoImageUrl = ps.infoImageUrl; + } + + if (ps.notFoundImageUrl !== undefined) { + set.notFoundImageUrl = ps.notFoundImageUrl; + } + if (ps.backgroundImageUrl !== undefined) { set.backgroundImageUrl = ps.backgroundImageUrl; } @@ -281,10 +295,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { set.smtpPass = ps.smtpPass; } - if (ps.errorImageUrl !== undefined) { - set.errorImageUrl = ps.errorImageUrl; - } - if (ps.enableServiceWorker !== undefined) { set.enableServiceWorker = ps.enableServiceWorker; } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index fe68467a64..3b3c5caa00 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -124,10 +124,17 @@ export const meta = { type: 'string', optional: false, nullable: false, }, - errorImageUrl: { + serverErrorImageUrl: { type: 'string', - optional: false, nullable: false, - default: 'https://xn--931a.moe/aiart/yubitun.png', + optional: false, nullable: true, + }, + infoImageUrl: { + type: 'string', + optional: false, nullable: true, + }, + notFoundImageUrl: { + type: 'string', + optional: false, nullable: true, }, iconUrl: { type: 'string', @@ -288,7 +295,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { themeColor: instance.themeColor, mascotImageUrl: instance.mascotImageUrl, bannerUrl: instance.bannerUrl, - errorImageUrl: instance.errorImageUrl, + infoImageUrl: instance.infoImageUrl, + serverErrorImageUrl: instance.serverErrorImageUrl, + notFoundImageUrl: instance.notFoundImageUrl, iconUrl: instance.iconUrl, backgroundImageUrl: instance.backgroundImageUrl, logoImageUrl: instance.logoImageUrl, diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index f780280c1f..07ba2731c3 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -26,7 +26,7 @@ import { PageEntityService } from '@/core/entities/PageEntityService.js'; import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js'; import { ClipEntityService } from '@/core/entities/ClipEntityService.js'; import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; -import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js'; +import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, Meta, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js'; import type Logger from '@/logger.js'; import { deepClone } from '@/misc/clone.js'; import { bindThis } from '@/decorators.js'; @@ -117,6 +117,18 @@ export class ClientServerService { return (res); } + @bindThis + private generateCommonPugData(meta: Meta) { + return { + instanceName: meta.name ?? 'Misskey', + icon: meta.iconUrl, + themeColor: meta.themeColor, + serverErrorImageUrl: meta.serverErrorImageUrl ?? 'https://xn--931a.moe/assets/error.jpg', + infoImageUrl: meta.infoImageUrl ?? 'https://xn--931a.moe/assets/info.jpg', + notFoundImageUrl: meta.notFoundImageUrl ?? 'https://xn--931a.moe/assets/not-found.jpg', + }; + } + @bindThis public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) { fastify.register(fastifyCookie, {}); @@ -341,12 +353,10 @@ export class ClientServerService { reply.header('Cache-Control', 'public, max-age=30'); return await reply.view('base', { img: meta.bannerUrl, - title: meta.name ?? 'Misskey', - instanceName: meta.name ?? 'Misskey', url: this.config.url, + title: meta.name ?? 'Misskey', desc: meta.description, - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); }; @@ -431,9 +441,7 @@ export class ClientServerService { user, profile, me, avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user), sub: request.params.sub, - instanceName: meta.name ?? 'Misskey', - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); } else { // リモートユーザーなので @@ -481,9 +489,7 @@ export class ClientServerService { avatarUrl: _note.user.avatarUrl, // TODO: Let locale changeable by instance setting summary: getNoteSummary(_note), - instanceName: meta.name ?? 'Misskey', - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -522,9 +528,7 @@ export class ClientServerService { page: _page, profile, avatarUrl: _page.user.avatarUrl, - instanceName: meta.name ?? 'Misskey', - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -550,9 +554,7 @@ export class ClientServerService { flash: _flash, profile, avatarUrl: _flash.user.avatarUrl, - instanceName: meta.name ?? 'Misskey', - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -578,9 +580,7 @@ export class ClientServerService { clip: _clip, profile, avatarUrl: _clip.user.avatarUrl, - instanceName: meta.name ?? 'Misskey', - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -604,9 +604,7 @@ export class ClientServerService { post: _post, profile, avatarUrl: _post.user.avatarUrl, - instanceName: meta.name ?? 'Misskey', - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); } else { return await renderBase(reply); @@ -625,9 +623,7 @@ export class ClientServerService { reply.header('Cache-Control', 'public, max-age=15'); return await reply.view('channel', { channel: _channel, - instanceName: meta.name ?? 'Misskey', - icon: meta.iconUrl, - themeColor: meta.themeColor, + ...this.generateCommonPugData(meta), }); } else { return await renderBase(reply); diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug index 69b3f68e05..1216fc73f7 100644 --- a/packages/backend/src/server/web/views/base.pug +++ b/packages/backend/src/server/web/views/base.pug @@ -31,9 +31,9 @@ html link(rel='apple-touch-icon' href= icon || '/apple-touch-icon.png') link(rel='manifest' href='/manifest.json') link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${url}/opensearch.xml`) - link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg') - link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg') - link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg') + link(rel='prefetch' href=serverErrorImageUrl) + link(rel='prefetch' href=infoImageUrl) + link(rel='prefetch' href=notFoundImageUrl) //- https://github.com/misskey-dev/misskey/issues/9842 link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.21.0') link(rel='modulepreload' href=`/vite/${clientEntry.file}`) diff --git a/packages/frontend/src/components/MkChannelList.vue b/packages/frontend/src/components/MkChannelList.vue index 4050520eb9..2d3ea8d177 100644 --- a/packages/frontend/src/components/MkChannelList.vue +++ b/packages/frontend/src/components/MkChannelList.vue @@ -2,7 +2,7 @@ <MkPagination :pagination="pagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.notFound }}</div> </div> </template> @@ -17,6 +17,7 @@ import MkChannelPreview from '@/components/MkChannelPreview.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; import { i18n } from '@/i18n'; +import { infoImageUrl } from '@/instance'; const props = withDefaults(defineProps<{ pagination: Paging; diff --git a/packages/frontend/src/components/MkNotes.vue b/packages/frontend/src/components/MkNotes.vue index 9cc2b7a967..b49c8fa8b7 100644 --- a/packages/frontend/src/components/MkNotes.vue +++ b/packages/frontend/src/components/MkNotes.vue @@ -2,7 +2,7 @@ <MkPagination ref="pagingComponent" :pagination="pagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noNotes }}</div> </div> </template> @@ -32,6 +32,7 @@ import MkNote from '@/components/MkNote.vue'; import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; import { i18n } from '@/i18n'; +import { infoImageUrl } from '@/instance'; const props = defineProps<{ pagination: Paging; diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index 70224bffa1..d4a30d1916 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -2,7 +2,7 @@ <MkPagination ref="pagingComponent" :pagination="pagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noNotifications }}</div> </div> </template> @@ -26,6 +26,7 @@ import { useStream } from '@/stream'; import { $i } from '@/account'; import { i18n } from '@/i18n'; import { notificationTypes } from '@/const'; +import { infoImageUrl } from '@/instance'; const props = defineProps<{ includeTypes?: typeof notificationTypes[number][]; diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index 740094b113..598529bf58 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -13,7 +13,7 @@ <div v-else-if="empty" key="_empty_" class="empty"> <slot name="empty"> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.nothing }}</div> </div> </slot> @@ -73,6 +73,8 @@ export type Paging<E extends keyof misskey.Endpoints = keyof misskey.Endpoints> }; </script> <script lang="ts" setup> +import { infoImageUrl } from '@/instance'; + const props = withDefaults(defineProps<{ pagination: Paging; disableAutoLoad?: boolean; diff --git a/packages/frontend/src/components/MkReactedUsersDialog.vue b/packages/frontend/src/components/MkReactedUsersDialog.vue index cd2a359d5c..0a858a8965 100644 --- a/packages/frontend/src/components/MkReactedUsersDialog.vue +++ b/packages/frontend/src/components/MkReactedUsersDialog.vue @@ -11,7 +11,7 @@ <MkSpacer :marginMin="20" :marginMax="28"> <div v-if="note" class="_gaps"> <div v-if="reactions.length === 0" class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.nothing }}</div> </div> <template v-else> @@ -42,6 +42,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue'; import { userPage } from '@/filters/user'; import { i18n } from '@/i18n'; import * as os from '@/os'; +import { infoImageUrl } from '@/instance'; const emit = defineEmits<{ (ev: 'closed'): void, diff --git a/packages/frontend/src/components/MkRenotedUsersDialog.vue b/packages/frontend/src/components/MkRenotedUsersDialog.vue index 814a68d4da..484cb2f9a7 100644 --- a/packages/frontend/src/components/MkRenotedUsersDialog.vue +++ b/packages/frontend/src/components/MkRenotedUsersDialog.vue @@ -11,7 +11,7 @@ <MkSpacer :marginMin="20" :marginMax="28"> <div v-if="renotes" class="_gaps"> <div v-if="renotes.length === 0" class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.nothing }}</div> </div> <template v-else> @@ -35,6 +35,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue'; import { userPage } from '@/filters/user'; import { i18n } from '@/i18n'; import * as os from '@/os'; +import { infoImageUrl } from '@/instance'; const emit = defineEmits<{ (ev: 'closed'): void, diff --git a/packages/frontend/src/components/MkUserList.vue b/packages/frontend/src/components/MkUserList.vue index 3571ca84d9..2a23f3e70d 100644 --- a/packages/frontend/src/components/MkUserList.vue +++ b/packages/frontend/src/components/MkUserList.vue @@ -2,7 +2,7 @@ <MkPagination :pagination="pagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noUsers }}</div> </div> </template> @@ -19,6 +19,7 @@ import MkUserInfo from '@/components/MkUserInfo.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; import { i18n } from '@/i18n'; +import { infoImageUrl } from '@/instance'; const props = withDefaults(defineProps<{ pagination: Paging; diff --git a/packages/frontend/src/components/global/MkError.vue b/packages/frontend/src/components/global/MkError.vue index 513ef21d35..24b0835135 100644 --- a/packages/frontend/src/components/global/MkError.vue +++ b/packages/frontend/src/components/global/MkError.vue @@ -1,7 +1,7 @@ <template> <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear> <div :class="$style.root"> - <img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> + <img :class="$style.img" :src="infoImageUrl" class="_ghost"/> <p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p> <MkButton :class="$style.button" @click="() => emit('retry')">{{ i18n.ts.retry }}</MkButton> </div> @@ -12,6 +12,7 @@ import MkButton from '@/components/MkButton.vue'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; +import { infoImageUrl } from '@/instance'; const emit = defineEmits<{ (ev: 'retry'): void; diff --git a/packages/frontend/src/const.ts b/packages/frontend/src/const.ts index aaa3d10302..ad7fa372e9 100644 --- a/packages/frontend/src/const.ts +++ b/packages/frontend/src/const.ts @@ -78,3 +78,7 @@ export const ROLE_POLICIES = [ //export const CURRENT_STICKY_BOTTOM = Symbol('CURRENT_STICKY_BOTTOM'); export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP'; export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM'; + +export const DEFAULT_SERVER_ERROR_IMAGE_URL = 'https://xn--931a.moe/assets/error.jpg'; +export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg'; +export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg'; diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts index f4c1988704..9cfcbcbc3f 100644 --- a/packages/frontend/src/instance.ts +++ b/packages/frontend/src/instance.ts @@ -1,7 +1,8 @@ -import { reactive } from 'vue'; +import { computed, reactive } from 'vue'; import * as Misskey from 'misskey-js'; import { api } from './os'; import { miLocalStorage } from './local-storage'; +import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@/const'; // TODO: 他のタブと永続化されたstateを同期 @@ -13,6 +14,12 @@ export const instance: Misskey.entities.InstanceMetadata = reactive(cached ? JSO // TODO: set default values }); +export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL); + +export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO_IMAGE_URL); + +export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL); + export async function fetchInstance() { const meta = await api('meta', { detail: false, diff --git a/packages/frontend/src/pages/_error_.vue b/packages/frontend/src/pages/_error_.vue index f27d2df336..eee661bd8a 100644 --- a/packages/frontend/src/pages/_error_.vue +++ b/packages/frontend/src/pages/_error_.vue @@ -2,7 +2,7 @@ <MkLoading v-if="!loaded"/> <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear> <div v-show="loaded" :class="$style.root"> - <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost" :class="$style.img"/> + <img :src="serverErrorImageUrl" class="_ghost" :class="$style.img"/> <div class="_gaps"> <p><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p> <p v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</p> @@ -30,6 +30,7 @@ import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import { miLocalStorage } from '@/local-storage'; import { defaultStore } from '@/store'; +import { serverErrorImageUrl } from '@/instance'; const props = withDefaults(defineProps<{ error?: Error; diff --git a/packages/frontend/src/pages/admin/roles.role.vue b/packages/frontend/src/pages/admin/roles.role.vue index 4ed6abf200..6cbe7ae658 100644 --- a/packages/frontend/src/pages/admin/roles.role.vue +++ b/packages/frontend/src/pages/admin/roles.role.vue @@ -23,7 +23,7 @@ <MkPagination :pagination="usersPagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noUsers }}</div> </div> </template> @@ -69,6 +69,7 @@ import MkButton from '@/components/MkButton.vue'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkInfo from '@/components/MkInfo.vue'; import MkPagination, { Paging } from '@/components/MkPagination.vue'; +import { infoImageUrl } from '@/instance'; const router = useRouter(); diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index 39d5ae8607..e98e1432a2 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -48,6 +48,21 @@ <template #label>{{ i18n.ts.backgroundImageUrl }}</template> </MkInput> + <MkInput v-model="notFoundImageUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.notFoundDescription }}</template> + </MkInput> + + <MkInput v-model="infoImageUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.nothing }}</template> + </MkInput> + + <MkInput v-model="serverErrorImageUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.somethingHappened }}</template> + </MkInput> + <MkColorInput v-model="themeColor"> <template #label>{{ i18n.ts.themeColor }}</template> </MkColorInput> @@ -151,6 +166,9 @@ let backgroundImageUrl: string | null = $ref(null); let themeColor: any = $ref(null); let defaultLightTheme: any = $ref(null); let defaultDarkTheme: any = $ref(null); +let serverErrorImageUrl: string | null = $ref(null); +let infoImageUrl: string | null = $ref(null); +let notFoundImageUrl: string | null = $ref(null); let pinnedUsers: string = $ref(''); let cacheRemoteFiles: boolean = $ref(false); let enableServiceWorker: boolean = $ref(false); @@ -169,6 +187,9 @@ async function init() { themeColor = meta.themeColor; defaultLightTheme = meta.defaultLightTheme; defaultDarkTheme = meta.defaultDarkTheme; + serverErrorImageUrl = meta.serverErrorImageUrl; + infoImageUrl = meta.infoImageUrl; + notFoundImageUrl = meta.notFoundImageUrl; maintainerName = meta.maintainerName; maintainerEmail = meta.maintainerEmail; pinnedUsers = meta.pinnedUsers.join('\n'); @@ -190,6 +211,9 @@ function save() { themeColor: themeColor === '' ? null : themeColor, defaultLightTheme: defaultLightTheme === '' ? null : defaultLightTheme, defaultDarkTheme: defaultDarkTheme === '' ? null : defaultDarkTheme, + infoImageUrl, + notFoundImageUrl, + serverErrorImageUrl, maintainerName, maintainerEmail, pinnedUsers: pinnedUsers.split('\n'), diff --git a/packages/frontend/src/pages/favorites.vue b/packages/frontend/src/pages/favorites.vue index 460bf65d1e..21c306148b 100644 --- a/packages/frontend/src/pages/favorites.vue +++ b/packages/frontend/src/pages/favorites.vue @@ -5,7 +5,7 @@ <MkPagination :pagination="pagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noNotes }}</div> </div> </template> @@ -26,6 +26,7 @@ import MkNote from '@/components/MkNote.vue'; import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { infoImageUrl } from '@/instance'; const pagination = { endpoint: 'i/favorites' as const, diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue index 1452942a1e..a70a4894a5 100644 --- a/packages/frontend/src/pages/follow-requests.vue +++ b/packages/frontend/src/pages/follow-requests.vue @@ -5,7 +5,7 @@ <MkPagination ref="paginationComponent" :pagination="pagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noFollowRequests }}</div> </div> </template> @@ -39,6 +39,7 @@ import { userPage, acct } from '@/filters/user'; import * as os from '@/os'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { infoImageUrl } from '@/instance'; const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>(); diff --git a/packages/frontend/src/pages/list.vue b/packages/frontend/src/pages/list.vue index f92c06d1c5..40934fb71d 100644 --- a/packages/frontend/src/pages/list.vue +++ b/packages/frontend/src/pages/list.vue @@ -3,7 +3,7 @@ <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200"> <div :class="$style.root"> - <img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> + <img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/> <p :class="$style.text"> <i class="ti ti-alert-triangle"></i> {{ i18n.ts.nothing }} @@ -36,6 +36,7 @@ import { i18n } from '@/i18n'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkButton from '@/components/MkButton.vue'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { serverErrorImageUrl } from '@/instance'; const props = defineProps<{ listId: string; diff --git a/packages/frontend/src/pages/not-found.vue b/packages/frontend/src/pages/not-found.vue index 2c9d949017..43dc41e7cc 100644 --- a/packages/frontend/src/pages/not-found.vue +++ b/packages/frontend/src/pages/not-found.vue @@ -1,7 +1,7 @@ <template> <div> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/not-found.jpg" class="_ghost"/> + <img :src="notFoundImageUrl" class="_ghost"/> <div>{{ i18n.ts.notFoundDescription }}</div> </div> </div> @@ -10,6 +10,7 @@ <script lang="ts" setup> import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { notFoundImageUrl } from '@/instance'; const headerActions = $computed(() => []); diff --git a/packages/frontend/src/pages/role.vue b/packages/frontend/src/pages/role.vue index e85ab0917a..fc04468d5a 100644 --- a/packages/frontend/src/pages/role.vue +++ b/packages/frontend/src/pages/role.vue @@ -3,7 +3,7 @@ <template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template> <MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200"> <div :class="$style.root"> - <img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/> + <img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/> <p :class="$style.text"> <i class="ti ti-alert-triangle"></i> {{ error }} @@ -30,6 +30,7 @@ import { definePageMetadata } from '@/scripts/page-metadata'; import { i18n } from '@/i18n'; import MkTimeline from '@/components/MkTimeline.vue'; import { instanceName } from '@/config'; +import { serverErrorImageUrl } from '@/instance'; const props = withDefaults(defineProps<{ role: string; diff --git a/packages/frontend/src/pages/settings/apps.vue b/packages/frontend/src/pages/settings/apps.vue index fbb78200d4..cadce49230 100644 --- a/packages/frontend/src/pages/settings/apps.vue +++ b/packages/frontend/src/pages/settings/apps.vue @@ -3,7 +3,7 @@ <FormPagination ref="list" :pagination="pagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.nothing }}</div> </div> </template> @@ -47,6 +47,7 @@ import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import MkKeyValue from '@/components/MkKeyValue.vue'; import MkButton from '@/components/MkButton.vue'; +import { infoImageUrl } from '@/instance'; const list = ref<any>(null); diff --git a/packages/frontend/src/pages/settings/mute-block.vue b/packages/frontend/src/pages/settings/mute-block.vue index 3d0463f708..e0785ab9fe 100644 --- a/packages/frontend/src/pages/settings/mute-block.vue +++ b/packages/frontend/src/pages/settings/mute-block.vue @@ -10,7 +10,7 @@ <MkPagination :pagination="renoteMutingPagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noUsers }}</div> </div> </template> @@ -38,7 +38,7 @@ <MkPagination :pagination="mutingPagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noUsers }}</div> </div> </template> @@ -68,7 +68,7 @@ <MkPagination :pagination="blockingPagination"> <template #empty> <div class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.noUsers }}</div> </div> </template> @@ -107,6 +107,7 @@ import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import * as os from '@/os'; +import { infoImageUrl } from '@/instance'; let tab = $ref('renoteMute'); diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue index 1be882c66d..953ce2908d 100644 --- a/packages/frontend/src/widgets/WidgetRss.vue +++ b/packages/frontend/src/widgets/WidgetRss.vue @@ -7,7 +7,7 @@ <div class="ekmkgxbj"> <MkLoading v-if="fetching"/> <div v-else-if="(!items || items.length === 0) && widgetProps.showHeader" class="_fullinfo"> - <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> + <img :src="infoImageUrl" class="_ghost"/> <div>{{ i18n.ts.nothing }}</div> </div> <div v-else :class="$style.feed"> @@ -25,6 +25,7 @@ import MkContainer from '@/components/MkContainer.vue'; import { url as base } from '@/config'; import { i18n } from '@/i18n'; import { useInterval } from '@/scripts/use-interval'; +import { infoImageUrl } from '@/instance'; const name = 'rss'; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 04065c51c9..383b17f0b9 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -294,7 +294,9 @@ export type LiteInstanceMetadata = { themeColor: string | null; mascotImageUrl: string | null; bannerUrl: string | null; - errorImageUrl: string | null; + serverErrorImageUrl: string | null; + infoImageUrl: string | null; + notFoundImageUrl: string | null; iconUrl: string | null; backgroundImageUrl: string | null; logoImageUrl: string | null; From 0465e74521d6beb151eb04d523b2a244a887647b Mon Sep 17 00:00:00 2001 From: atsuchan <83960488+atsu1125@users.noreply.github.com> Date: Fri, 9 Jun 2023 14:08:35 +0900 Subject: [PATCH 198/213] =?UTF-8?q?Fix:=20enhance:=20=E3=82=BF=E3=82=A4?= =?UTF-8?q?=E3=83=A0=E3=83=A9=E3=82=A4=E3=83=B3=E3=81=AB=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=AD=E3=82=A4=E3=83=BC=E3=81=AE=E8=A1=8C=E3=81=A3=E3=81=9F?= =?UTF-8?q?=E4=BB=96=E4=BA=BA=E3=81=B8=E3=81=AE=E3=83=AA=E3=83=97=E3=83=A9?= =?UTF-8?q?=E3=82=A4=E3=82=92=E5=90=AB=E3=82=81=E3=82=8B=E3=81=8B=E3=81=A9?= =?UTF-8?q?=E3=81=86=E3=81=8B=E3=81=AE=E8=A8=AD=E5=AE=9A=E3=82=92=E3=82=A2?= =?UTF-8?q?=E3=82=AB=E3=82=A6=E3=83=B3=E3=83=88=E3=81=AB=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=81=AE=E3=82=92=E3=82=84=E3=82=81=E3=82=8B?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(#10982)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/pages/settings/profile.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 58217d0475..81f0518a06 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -127,7 +127,6 @@ const profile = reactive({ lang: $i.lang, isBot: $i.isBot, isCat: $i.isCat, - showTimelineReplies: $i.showTimelineReplies, }); watch(() => profile, () => { @@ -151,7 +150,7 @@ while (fields.value.length < 4) { addField(); } -function deleteField(index: number) { +function deleteField(index: number) { fields.value.splice(index, 1); } @@ -176,7 +175,6 @@ function save() { lang: profile.lang || null, isBot: !!profile.isBot, isCat: !!profile.isCat, - showTimelineReplies: !!profile.showTimelineReplies, }); claimAchievement('profileFilled'); if (profile.name === 'syuilo' || profile.name === 'しゅいろ') { From 5e680500e5bf0da4828bd1d16ac32234a499fc33 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Fri, 9 Jun 2023 06:32:09 +0000 Subject: [PATCH 199/213] =?UTF-8?q?chore:=20instance=20=E2=86=92=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/ISSUE_TEMPLATE/01_bug-report.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/01_bug-report.md b/.github/ISSUE_TEMPLATE/01_bug-report.md index 46ce16f073..25e7fc8b20 100644 --- a/.github/ISSUE_TEMPLATE/01_bug-report.md +++ b/.github/ISSUE_TEMPLATE/01_bug-report.md @@ -46,8 +46,10 @@ Please include errors from the developer console and/or server log files if you <!-- Example: Chrome 113.0.5672.126 --> * Server URL: <!-- Example: misskey.io --> +* Misskey: + 13.x.x -### 🛰 Backend (for instance admin) +### 🛰 Backend (for server admin) <!-- If you are using a managed service, put that after the version. --> * Installation Method or Hosting Service: <!-- Example: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment --> From dd733ec1d00b6668542a2ee45f9d3632c270873d Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 9 Jun 2023 15:53:40 +0900 Subject: [PATCH 200/213] =?UTF-8?q?enhance(frontend):=20=E3=82=B5=E3=83=BC?= =?UTF-8?q?=E3=83=90=E3=83=BC=E3=81=AE=E3=83=86=E3=83=BC=E3=83=9E=E8=A8=AD?= =?UTF-8?q?=E5=AE=9A=E3=82=92=E5=88=A5=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AB?= =?UTF-8?q?=E5=88=86=E9=9B=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + .../frontend/src/pages/admin/branding.vue | 133 ++++++++++++++++++ packages/frontend/src/pages/admin/index.vue | 5 + .../frontend/src/pages/admin/settings.vue | 77 ---------- packages/frontend/src/router.ts | 4 + 6 files changed, 144 insertions(+), 77 deletions(-) create mode 100644 packages/frontend/src/pages/admin/branding.vue diff --git a/locales/index.d.ts b/locales/index.d.ts index 7047f42eff..eed29f408c 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1065,6 +1065,7 @@ export interface Locale { "goToMisskey": string; "additionalEmojiDictionary": string; "installed": string; + "branding": string; "_initialAccountSetting": { "accountCreated": string; "letsStartAccountSetup": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index fcba3fb822..723d0ac988 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1062,6 +1062,7 @@ later: "あとで" goToMisskey: "Misskeyへ" additionalEmojiDictionary: "絵文字の追加辞書" installed: "インストール済み" +branding: "ブランディング" _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" diff --git a/packages/frontend/src/pages/admin/branding.vue b/packages/frontend/src/pages/admin/branding.vue new file mode 100644 index 0000000000..65ce9e0068 --- /dev/null +++ b/packages/frontend/src/pages/admin/branding.vue @@ -0,0 +1,133 @@ +<template> +<div> + <MkStickyContainer> + <template #header><XHeader :tabs="headerTabs"/></template> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="32"> + <FormSuspense :p="init"> + <div class="_gaps_m"> + <MkInput v-model="iconUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.iconUrl }}</template> + </MkInput> + + <MkInput v-model="bannerUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.bannerUrl }}</template> + </MkInput> + + <MkInput v-model="backgroundImageUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.backgroundImageUrl }}</template> + </MkInput> + + <MkInput v-model="notFoundImageUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.notFoundDescription }}</template> + </MkInput> + + <MkInput v-model="infoImageUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.nothing }}</template> + </MkInput> + + <MkInput v-model="serverErrorImageUrl"> + <template #prefix><i class="ti ti-link"></i></template> + <template #label>{{ i18n.ts.somethingHappened }}</template> + </MkInput> + + <MkColorInput v-model="themeColor"> + <template #label>{{ i18n.ts.themeColor }}</template> + </MkColorInput> + + <MkTextarea v-model="defaultLightTheme"> + <template #label>{{ i18n.ts.instanceDefaultLightTheme }}</template> + <template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template> + </MkTextarea> + + <MkTextarea v-model="defaultDarkTheme"> + <template #label>{{ i18n.ts.instanceDefaultDarkTheme }}</template> + <template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template> + </MkTextarea> + </div> + </FormSuspense> + </MkSpacer> + <template #footer> + <div :class="$style.footer"> + <MkSpacer :contentMax="700" :marginMin="16" :marginMax="16"> + <MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton> + </MkSpacer> + </div> + </template> + </MkStickyContainer> +</div> +</template> + +<script lang="ts" setup> +import { } from 'vue'; +import XHeader from './_header_.vue'; +import MkSwitch from '@/components/MkSwitch.vue'; +import MkInput from '@/components/MkInput.vue'; +import MkTextarea from '@/components/MkTextarea.vue'; +import FormSection from '@/components/form/section.vue'; +import FormSplit from '@/components/form/split.vue'; +import FormSuspense from '@/components/form/suspense.vue'; +import * as os from '@/os'; +import { fetchInstance } from '@/instance'; +import { i18n } from '@/i18n'; +import { definePageMetadata } from '@/scripts/page-metadata'; +import MkButton from '@/components/MkButton.vue'; +import MkColorInput from '@/components/MkColorInput.vue'; + +let iconUrl: string | null = $ref(null); +let bannerUrl: string | null = $ref(null); +let backgroundImageUrl: string | null = $ref(null); +let themeColor: any = $ref(null); +let defaultLightTheme: any = $ref(null); +let defaultDarkTheme: any = $ref(null); +let serverErrorImageUrl: string | null = $ref(null); +let infoImageUrl: string | null = $ref(null); +let notFoundImageUrl: string | null = $ref(null); + +async function init() { + const meta = await os.api('admin/meta'); + iconUrl = meta.iconUrl; + bannerUrl = meta.bannerUrl; + backgroundImageUrl = meta.backgroundImageUrl; + themeColor = meta.themeColor; + defaultLightTheme = meta.defaultLightTheme; + defaultDarkTheme = meta.defaultDarkTheme; + serverErrorImageUrl = meta.serverErrorImageUrl; + infoImageUrl = meta.infoImageUrl; + notFoundImageUrl = meta.notFoundImageUrl; +} + +function save() { + os.apiWithDialog('admin/update-meta', { + iconUrl, + bannerUrl, + backgroundImageUrl, + themeColor: themeColor === '' ? null : themeColor, + defaultLightTheme: defaultLightTheme === '' ? null : defaultLightTheme, + defaultDarkTheme: defaultDarkTheme === '' ? null : defaultDarkTheme, + infoImageUrl, + notFoundImageUrl, + serverErrorImageUrl, + }).then(() => { + fetchInstance(); + }); +} + +const headerTabs = $computed(() => []); + +definePageMetadata({ + title: i18n.ts.branding, + icon: 'ti ti-paint', +}); +</script> + +<style lang="scss" module> +.footer { + -webkit-backdrop-filter: var(--blur, blur(15px)); + backdrop-filter: var(--blur, blur(15px)); +} +</style> diff --git a/packages/frontend/src/pages/admin/index.vue b/packages/frontend/src/pages/admin/index.vue index 5cbbcaa44c..8b083bc896 100644 --- a/packages/frontend/src/pages/admin/index.vue +++ b/packages/frontend/src/pages/admin/index.vue @@ -143,6 +143,11 @@ const menuDef = $computed(() => [{ text: i18n.ts.general, to: '/admin/settings', active: currentPage?.route.name === 'settings', + }, { + icon: 'ti ti-paint', + text: i18n.ts.branding, + to: '/admin/branding', + active: currentPage?.route.name === 'branding', }, { icon: 'ti ti-shield', text: i18n.ts.moderation, diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index e98e1432a2..4c2fe46f28 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -29,56 +29,6 @@ <template #caption>{{ i18n.ts.pinnedUsersDescription }}</template> </MkTextarea> - <FormSection> - <template #label>{{ i18n.ts.theme }}</template> - - <div class="_gaps_m"> - <MkInput v-model="iconUrl"> - <template #prefix><i class="ti ti-link"></i></template> - <template #label>{{ i18n.ts.iconUrl }}</template> - </MkInput> - - <MkInput v-model="bannerUrl"> - <template #prefix><i class="ti ti-link"></i></template> - <template #label>{{ i18n.ts.bannerUrl }}</template> - </MkInput> - - <MkInput v-model="backgroundImageUrl"> - <template #prefix><i class="ti ti-link"></i></template> - <template #label>{{ i18n.ts.backgroundImageUrl }}</template> - </MkInput> - - <MkInput v-model="notFoundImageUrl"> - <template #prefix><i class="ti ti-link"></i></template> - <template #label>{{ i18n.ts.notFoundDescription }}</template> - </MkInput> - - <MkInput v-model="infoImageUrl"> - <template #prefix><i class="ti ti-link"></i></template> - <template #label>{{ i18n.ts.nothing }}</template> - </MkInput> - - <MkInput v-model="serverErrorImageUrl"> - <template #prefix><i class="ti ti-link"></i></template> - <template #label>{{ i18n.ts.somethingHappened }}</template> - </MkInput> - - <MkColorInput v-model="themeColor"> - <template #label>{{ i18n.ts.themeColor }}</template> - </MkColorInput> - - <MkTextarea v-model="defaultLightTheme"> - <template #label>{{ i18n.ts.instanceDefaultLightTheme }}</template> - <template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template> - </MkTextarea> - - <MkTextarea v-model="defaultDarkTheme"> - <template #label>{{ i18n.ts.instanceDefaultDarkTheme }}</template> - <template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template> - </MkTextarea> - </div> - </FormSection> - <FormSection> <template #label>{{ i18n.ts.files }}</template> @@ -160,15 +110,6 @@ let name: string | null = $ref(null); let description: string | null = $ref(null); let maintainerName: string | null = $ref(null); let maintainerEmail: string | null = $ref(null); -let iconUrl: string | null = $ref(null); -let bannerUrl: string | null = $ref(null); -let backgroundImageUrl: string | null = $ref(null); -let themeColor: any = $ref(null); -let defaultLightTheme: any = $ref(null); -let defaultDarkTheme: any = $ref(null); -let serverErrorImageUrl: string | null = $ref(null); -let infoImageUrl: string | null = $ref(null); -let notFoundImageUrl: string | null = $ref(null); let pinnedUsers: string = $ref(''); let cacheRemoteFiles: boolean = $ref(false); let enableServiceWorker: boolean = $ref(false); @@ -181,15 +122,6 @@ async function init() { const meta = await os.api('admin/meta'); name = meta.name; description = meta.description; - iconUrl = meta.iconUrl; - bannerUrl = meta.bannerUrl; - backgroundImageUrl = meta.backgroundImageUrl; - themeColor = meta.themeColor; - defaultLightTheme = meta.defaultLightTheme; - defaultDarkTheme = meta.defaultDarkTheme; - serverErrorImageUrl = meta.serverErrorImageUrl; - infoImageUrl = meta.infoImageUrl; - notFoundImageUrl = meta.notFoundImageUrl; maintainerName = meta.maintainerName; maintainerEmail = meta.maintainerEmail; pinnedUsers = meta.pinnedUsers.join('\n'); @@ -205,15 +137,6 @@ function save() { os.apiWithDialog('admin/update-meta', { name, description, - iconUrl, - bannerUrl, - backgroundImageUrl, - themeColor: themeColor === '' ? null : themeColor, - defaultLightTheme: defaultLightTheme === '' ? null : defaultLightTheme, - defaultDarkTheme: defaultDarkTheme === '' ? null : defaultDarkTheme, - infoImageUrl, - notFoundImageUrl, - serverErrorImageUrl, maintainerName, maintainerEmail, pinnedUsers: pinnedUsers.split('\n'), diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index 6b11137d79..a95e8e6485 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -392,6 +392,10 @@ export const routes = [{ path: '/settings', name: 'settings', component: page(() => import('./pages/admin/settings.vue')), + }, { + path: '/branding', + name: 'branding', + component: page(() => import('./pages/admin/branding.vue')), }, { path: '/moderation', name: 'moderation', From 308ab8f1777d286d694f44874c6d4a8ef47fba68 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 9 Jun 2023 16:11:28 +0900 Subject: [PATCH 201/213] chore --- packages/backend/src/server/api/StreamingApiServerService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index a1758fd051..2e554c9ad1 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -128,6 +128,7 @@ export class StreamingApiServerService { ev.removeAllListeners(); stream.dispose(); this.redisForSub.off('message', onRedisMessage); + this.#connections.delete(connection); if (userUpdateIntervalId) clearInterval(userUpdateIntervalId); }); From 6182a1cb2c80cce573a17193e9309fbbbce3b08c Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 9 Jun 2023 17:07:57 +0900 Subject: [PATCH 202/213] =?UTF-8?q?enhance(backend):=20WebSocket=E3=81=AEP?= =?UTF-8?q?ing/Pong=E3=82=92=E3=83=97=E3=83=AD=E3=83=88=E3=82=B3=E3=83=AB?= =?UTF-8?q?=E5=88=B6=E5=BE=A1=E3=83=95=E3=83=AC=E3=83=BC=E3=83=A0=E3=81=AE?= =?UTF-8?q?=E7=89=A9=E3=81=A7=E5=88=A4=E5=88=A5=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve #10969 --- .../src/server/api/StreamingApiServerService.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index 2e554c9ad1..d1394d6d76 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -132,11 +132,8 @@ export class StreamingApiServerService { if (userUpdateIntervalId) clearInterval(userUpdateIntervalId); }); - connection.on('message', async (data) => { + connection.on('pong', () => { this.#connections.set(connection, Date.now()); - if (data.toString() === 'ping') { - connection.send('pong'); - } }); }); @@ -144,12 +141,14 @@ export class StreamingApiServerService { this.#cleanConnectionsIntervalId = setInterval(() => { const now = Date.now(); for (const [connection, lastActive] of this.#connections.entries()) { - if (now - lastActive > 1000 * 60 * 5) { + if (now - lastActive > 1000 * 60 * 2) { connection.terminate(); this.#connections.delete(connection); + } else { + connection.ping(); } } - }, 1000 * 60 * 5); + }, 1000 * 60); } @bindThis From e8420ad90bd290a2c10d563f6ccbffd0d4a0a97b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 10 Jun 2023 13:45:11 +0900 Subject: [PATCH 203/213] =?UTF-8?q?fix(backend):=20=E3=82=AD=E3=83=A3?= =?UTF-8?q?=E3=83=83=E3=82=B7=E3=83=A5=E3=81=8C=E6=BA=9C=E3=81=BE=E3=82=8A?= =?UTF-8?q?=E7=B6=9A=E3=81=91=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related #10984 --- CHANGELOG.md | 1 + packages/backend/src/core/CacheService.ts | 11 +++++++ .../backend/src/core/CustomEmojiService.ts | 14 ++++++-- .../src/core/FederatedInstanceService.ts | 14 ++++++-- .../src/core/PushNotificationService.ts | 14 ++++++-- packages/backend/src/core/RoleService.ts | 1 + .../backend/src/core/UserKeypairService.ts | 14 ++++++-- .../core/activitypub/ApDbResolverService.ts | 15 +++++++-- packages/backend/src/misc/cache.ts | 32 ++++++++++++++++++- .../src/server/api/AuthenticateService.ts | 14 ++++++-- 10 files changed, 117 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d3b886db..9806e0305c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるようになりました ### Server +- Fix: キャッシュが溜まり続けないように - Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正 ## 13.13.0 diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index de33e4c243..2b7f9a48da 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -168,6 +168,17 @@ export class CacheService implements OnApplicationShutdown { @bindThis public dispose(): void { this.redisForSub.off('message', this.onMessage); + this.userByIdCache.dispose(); + this.localUserByNativeTokenCache.dispose(); + this.localUserByIdCache.dispose(); + this.uriPersonCache.dispose(); + this.userProfileCache.dispose(); + this.userMutingsCache.dispose(); + this.userBlockingCache.dispose(); + this.userBlockedCache.dispose(); + this.renoteMutingsCache.dispose(); + this.userFollowingsCache.dispose(); + this.userFollowingChannelsCache.dispose(); } @bindThis diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 3499df38b7..5f2ced77eb 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { DataSource, In, IsNull } from 'typeorm'; import * as Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; @@ -18,7 +18,7 @@ import type { Serialized } from '@/server/api/stream/types.js'; const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/; @Injectable() -export class CustomEmojiService { +export class CustomEmojiService implements OnApplicationShutdown { private cache: MemoryKVCache<Emoji | null>; public localEmojisCache: RedisSingleCache<Map<string, Emoji>>; @@ -349,4 +349,14 @@ export class CustomEmojiService { this.cache.set(`${emoji.name} ${emoji.host}`, emoji); } } + + @bindThis + public dispose(): void { + this.cache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index 8b9a87a380..3603d59dcc 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Redis from 'ioredis'; import type { InstancesRepository } from '@/models/index.js'; import type { Instance } from '@/models/entities/Instance.js'; @@ -9,7 +9,7 @@ import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; @Injectable() -export class FederatedInstanceService { +export class FederatedInstanceService implements OnApplicationShutdown { public federatedInstanceCache: RedisKVCache<Instance | null>; constructor( @@ -77,4 +77,14 @@ export class FederatedInstanceService { this.federatedInstanceCache.set(result.host, result); } + + @bindThis + public dispose(): void { + this.federatedInstanceCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts index a4c569bdec..15a1d74878 100644 --- a/packages/backend/src/core/PushNotificationService.ts +++ b/packages/backend/src/core/PushNotificationService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import push from 'web-push'; import * as Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; @@ -42,7 +42,7 @@ function truncateBody<T extends keyof PushNotificationsTypes>(type: T, body: Pus } @Injectable() -export class PushNotificationService { +export class PushNotificationService implements OnApplicationShutdown { private subscriptionsCache: RedisKVCache<SwSubscription[]>; constructor( @@ -115,4 +115,14 @@ export class PushNotificationService { }); } } + + @bindThis + public dispose(): void { + this.subscriptionsCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 40ae106662..79922d0a87 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -435,6 +435,7 @@ export class RoleService implements OnApplicationShutdown { @bindThis public dispose(): void { this.redisForSub.off('message', this.onMessage); + this.roleAssignmentByUserIdCache.dispose(); } @bindThis diff --git a/packages/backend/src/core/UserKeypairService.ts b/packages/backend/src/core/UserKeypairService.ts index 72c35c529c..d768f08650 100644 --- a/packages/backend/src/core/UserKeypairService.ts +++ b/packages/backend/src/core/UserKeypairService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Redis from 'ioredis'; import type { User } from '@/models/entities/User.js'; import type { UserKeypairsRepository } from '@/models/index.js'; @@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; @Injectable() -export class UserKeypairService { +export class UserKeypairService implements OnApplicationShutdown { private cache: RedisKVCache<UserKeypair>; constructor( @@ -31,4 +31,14 @@ export class UserKeypairService { public async getUserKeypair(userId: User['id']): Promise<UserKeypair> { return await this.cache.fetch(userId); } + + @bindThis + public dispose(): void { + this.cache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 2b404ebeca..2d9e7a14ee 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import escapeRegexp from 'escape-regexp'; import { DI } from '@/di-symbols.js'; import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; @@ -30,7 +30,7 @@ export type UriParseResult = { }; @Injectable() -export class ApDbResolverService { +export class ApDbResolverService implements OnApplicationShutdown { private publicKeyCache: MemoryKVCache<UserPublickey | null>; private publicKeyByUserIdCache: MemoryKVCache<UserPublickey | null>; @@ -162,4 +162,15 @@ export class ApDbResolverService { key, }; } + + @bindThis + public dispose(): void { + this.publicKeyCache.dispose(); + this.publicKeyByUserIdCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index 5610929648..f130a7db8b 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -83,6 +83,16 @@ export class RedisKVCache<T> { // TODO: イベント発行して他プロセスのメモリキャッシュも更新できるようにする } + + @bindThis + public gc() { + this.memoryCache.gc(); + } + + @bindThis + public dispose() { + this.memoryCache.dispose(); + } } export class RedisSingleCache<T> { @@ -174,10 +184,15 @@ export class RedisSingleCache<T> { export class MemoryKVCache<T> { public cache: Map<string, { date: number; value: T; }>; private lifetime: number; + private gcIntervalHandle: NodeJS.Timer; constructor(lifetime: MemoryKVCache<never>['lifetime']) { this.cache = new Map(); this.lifetime = lifetime; + + this.gcIntervalHandle = setInterval(() => { + this.gc(); + }, 1000 * 60 * 3); } @bindThis @@ -200,7 +215,7 @@ export class MemoryKVCache<T> { } @bindThis - public delete(key: string) { + public delete(key: string): void { this.cache.delete(key); } @@ -255,6 +270,21 @@ export class MemoryKVCache<T> { } return value; } + + @bindThis + public gc(): void { + const now = Date.now(); + for (const [key, { date }] of this.cache.entries()) { + if ((now - date) > this.lifetime) { + this.cache.delete(key); + } + } + } + + @bindThis + public dispose(): void { + clearInterval(this.gcIntervalHandle); + } } export class MemorySingleCache<T> { diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index e23591d876..4ad0197d87 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { AccessTokensRepository, AppsRepository, UsersRepository } from '@/models/index.js'; import type { LocalUser } from '@/models/entities/User.js'; @@ -17,7 +17,7 @@ export class AuthenticationError extends Error { } @Injectable() -export class AuthenticateService { +export class AuthenticateService implements OnApplicationShutdown { private appCache: MemoryKVCache<App>; constructor( @@ -85,4 +85,14 @@ export class AuthenticateService { } } } + + @bindThis + public dispose(): void { + this.appCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } From f69627939bde5ac2e2d06bd6e9e70e2febc36f7d Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 10 Jun 2023 13:45:30 +0900 Subject: [PATCH 204/213] Update misskey-js.api.md --- packages/misskey-js/etc/misskey-js.api.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 396187a439..eddc5cf90c 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2324,7 +2324,9 @@ type LiteInstanceMetadata = { themeColor: string | null; mascotImageUrl: string | null; bannerUrl: string | null; - errorImageUrl: string | null; + serverErrorImageUrl: string | null; + infoImageUrl: string | null; + notFoundImageUrl: string | null; iconUrl: string | null; backgroundImageUrl: string | null; logoImageUrl: string | null; From f3a16bcd6d220059a02ab1e1b5e72a27c5e0eba7 Mon Sep 17 00:00:00 2001 From: nenohi <kimutipartylove@gmail.com> Date: Sat, 10 Jun 2023 17:26:48 +0900 Subject: [PATCH 205/213] =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=AB=E3=81=AE?= =?UTF-8?q?=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC=E3=83=AA=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=82=92=E9=9D=9E=E5=85=AC=E9=96=8B=E3=81=AB=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#10987)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ロールのユーザーリストを非公開にできるように * Changelog update --- CHANGELOG.md | 11 +++++++++++ locales/index.d.ts | 2 ++ locales/ja-JP.yml | 4 +++- .../backend/migration/1686381571997-roleuserhidden.js | 11 +++++++++++ packages/backend/src/models/entities/Role.ts | 5 +++++ .../src/server/api/endpoints/admin/roles/create.ts | 2 ++ .../src/server/api/endpoints/admin/roles/update.ts | 2 ++ .../backend/src/server/api/endpoints/roles/users.ts | 3 +++ packages/frontend/src/pages/admin/roles.editor.vue | 6 ++++++ 9 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 packages/backend/migration/1686381571997-roleuserhidden.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 9806e0305c..55dab31d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,17 @@ - --> +## 13.x.x (unreleased) + +### General +- ロールが付与されているユーザーリストを非公開にできるように + +### Client +- + +### Server +- + ## 13.13.1 diff --git a/locales/index.d.ts b/locales/index.d.ts index eed29f408c..638ac10e71 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1431,6 +1431,8 @@ export interface Locale { "isConditionalRole": string; "isPublic": string; "descriptionOfIsPublic": string; + "isPublicUsers": string; + "descriptionOfIsPublicUsers": string; "options": string; "policies": string; "baseRole": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 723d0ac988..5a7a2afd5f 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1353,7 +1353,9 @@ _role: condition: "条件" isConditionalRole: "これはコンディショナルロールです。" isPublic: "ロールを公開" - descriptionOfIsPublic: "ロールにアサインされたユーザーを誰でも見ることができます。また、ユーザーのプロフィールでこのロールが表示されます。" + descriptionOfIsPublic: "ユーザーのプロフィールでこのロールが表示されます。" + isPublicUsers: "ユーザーリストを公開" + descriptionOfIsPublicUsers: "ロールにアサインされたユーザーのリストを誰でも見ることができます。" options: "オプション" policies: "ポリシー" baseRole: "ベースロール" diff --git a/packages/backend/migration/1686381571997-roleuserhidden.js b/packages/backend/migration/1686381571997-roleuserhidden.js new file mode 100644 index 0000000000..5cfa9ab87f --- /dev/null +++ b/packages/backend/migration/1686381571997-roleuserhidden.js @@ -0,0 +1,11 @@ +export class roleuserhidden1686381571997 { + name = 'roleuserhidden1686381571997' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "role" ADD "isPublicUsers" boolean NOT NULL DEFAULT true`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "isPublicUsers"`); + } +} diff --git a/packages/backend/src/models/entities/Role.ts b/packages/backend/src/models/entities/Role.ts index 61f40d59da..067f7bf629 100644 --- a/packages/backend/src/models/entities/Role.ts +++ b/packages/backend/src/models/entities/Role.ts @@ -167,6 +167,11 @@ export class Role { }) public displayOrder: number; + @Column('boolean', { + default: true, + }) + public isPublicUsers: boolean; + @Column('jsonb', { default: { }, }) diff --git a/packages/backend/src/server/api/endpoints/admin/roles/create.ts b/packages/backend/src/server/api/endpoints/admin/roles/create.ts index 916172f54a..1cf3157acd 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/create.ts @@ -26,6 +26,7 @@ export const paramDef = { isModerator: { type: 'boolean' }, isAdministrator: { type: 'boolean' }, isExplorable: { type: 'boolean', default: false }, // optional for backward compatibility + isPublicUsers: { type: 'boolean', default: true }, // optional for backward compatibility asBadge: { type: 'boolean' }, canEditMembersByModerator: { type: 'boolean' }, displayOrder: { type: 'number' }, @@ -78,6 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { isAdministrator: ps.isAdministrator, isModerator: ps.isModerator, isExplorable: ps.isExplorable, + isPublicUsers: ps.isPublicUsers, asBadge: ps.asBadge, canEditMembersByModerator: ps.canEditMembersByModerator, displayOrder: ps.displayOrder, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts index 467f157a61..5108c4da1d 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts @@ -34,6 +34,7 @@ export const paramDef = { isModerator: { type: 'boolean' }, isAdministrator: { type: 'boolean' }, isExplorable: { type: 'boolean' }, + isPublicUsers: { type: 'boolean' }, asBadge: { type: 'boolean' }, canEditMembersByModerator: { type: 'boolean' }, displayOrder: { type: 'number' }, @@ -87,6 +88,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { isModerator: ps.isModerator, isAdministrator: ps.isAdministrator, isExplorable: ps.isExplorable, + isPublicUsers: ps.isPublicUsers, asBadge: ps.asBadge, canEditMembersByModerator: ps.canEditMembersByModerator, displayOrder: ps.displayOrder, diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts index 607dc24206..f4b30286a4 100644 --- a/packages/backend/src/server/api/endpoints/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/roles/users.ts @@ -54,6 +54,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { if (role == null) { throw new ApiError(meta.errors.noSuchRole); } + if (!role.isPublicUsers) { + return []; + } const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId) .andWhere('assign.roleId = :roleId', { roleId: role.id }) diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index a1fa9d2932..6aeef6cb1d 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -63,6 +63,11 @@ <template #caption>{{ i18n.ts._role.descriptionOfIsExplorable }}</template> </MkSwitch> + <MkSwitch v-model="role.isPublicUsers" :readonly="readonly"> + <template #label>{{ i18n.ts._role.isPublicUsers }}</template> + <template #caption>{{ i18n.ts._role.descriptionOfIsPublicUsers }}</template> + </MkSwitch> + <FormSlot> <template #label><i class="ti ti-license"></i> {{ i18n.ts._role.policies }}</template> <div class="_gaps_s"> @@ -501,6 +506,7 @@ const save = throttle(100, () => { isModerator: role.isModerator, isPublic: role.isPublic, isExplorable: role.isExplorable, + isPublicUsers: role.isPublicUsers, asBadge: role.asBadge, canEditMembersByModerator: role.canEditMembersByModerator, policies: role.policies, From c59a30ec09a6f1415a45bb7dfcea3186778d86c4 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 10 Jun 2023 17:27:35 +0900 Subject: [PATCH 206/213] Update CHANGELOG.md --- CHANGELOG.md | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55dab31d38..6a6632fbaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,25 +11,15 @@ - --> -## 13.x.x (unreleased) -### General -- ロールが付与されているユーザーリストを非公開にできるように - -### Client -- - -### Server -- - - -## 13.13.1 +## 13.13.1 (unreleased) ### Client - Fix: タブがアクティブな間はstreamが切断されないように ### General - エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるようになりました +- ロールが付与されているユーザーリストを非公開にできるように ### Server - Fix: キャッシュが溜まり続けないように From 46222d0258e75e9700976b6b092d595fc55fad4b Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 10 Jun 2023 17:41:52 +0900 Subject: [PATCH 207/213] tweak of f3a16bcd6 --- locales/index.d.ts | 2 -- locales/ja-JP.yml | 8 +++----- .../backend/migration/1686381571997-roleuserhidden.js | 11 ----------- packages/backend/src/models/entities/Role.ts | 5 ----- .../src/server/api/endpoints/admin/roles/create.ts | 2 -- .../src/server/api/endpoints/admin/roles/update.ts | 2 -- .../backend/src/server/api/endpoints/roles/list.ts | 1 + .../backend/src/server/api/endpoints/roles/users.ts | 4 +--- packages/frontend/src/pages/admin/roles.editor.vue | 6 ------ 9 files changed, 5 insertions(+), 36 deletions(-) delete mode 100644 packages/backend/migration/1686381571997-roleuserhidden.js diff --git a/locales/index.d.ts b/locales/index.d.ts index 638ac10e71..eed29f408c 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1431,8 +1431,6 @@ export interface Locale { "isConditionalRole": string; "isPublic": string; "descriptionOfIsPublic": string; - "isPublicUsers": string; - "descriptionOfIsPublicUsers": string; "options": string; "policies": string; "baseRole": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 5a7a2afd5f..8004e53575 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1352,10 +1352,8 @@ _role: conditional: "コンディショナル" condition: "条件" isConditionalRole: "これはコンディショナルロールです。" - isPublic: "ロールを公開" + isPublic: "公開ロール" descriptionOfIsPublic: "ユーザーのプロフィールでこのロールが表示されます。" - isPublicUsers: "ユーザーリストを公開" - descriptionOfIsPublicUsers: "ロールにアサインされたユーザーのリストを誰でも見ることができます。" options: "オプション" policies: "ポリシー" baseRole: "ベースロール" @@ -1364,8 +1362,8 @@ _role: iconUrl: "アイコン画像のURL" asBadge: "バッジとして表示" descriptionOfAsBadge: "オンにすると、ユーザー名の横にロールのアイコンが表示されます。" - isExplorable: "ロールタイムラインを公開" - descriptionOfIsExplorable: "オンにすると、ロールのタイムラインを公開します。ロールの公開がオフの場合、タイムラインの公開はされません。" + isExplorable: "ユーザーを見つけやすくする" + descriptionOfIsExplorable: "オンにすると、「みつける」でメンバー一覧が公開されるほか、ロールのタイムラインが利用可能になります。" displayOrder: "表示順" descriptionOfDisplayOrder: "数値が大きいほどUI上で先頭に表示されます。" canEditMembersByModerator: "モデレーターのメンバー編集を許可" diff --git a/packages/backend/migration/1686381571997-roleuserhidden.js b/packages/backend/migration/1686381571997-roleuserhidden.js deleted file mode 100644 index 5cfa9ab87f..0000000000 --- a/packages/backend/migration/1686381571997-roleuserhidden.js +++ /dev/null @@ -1,11 +0,0 @@ -export class roleuserhidden1686381571997 { - name = 'roleuserhidden1686381571997' - - async up(queryRunner) { - await queryRunner.query(`ALTER TABLE "role" ADD "isPublicUsers" boolean NOT NULL DEFAULT true`); - } - - async down(queryRunner) { - await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "isPublicUsers"`); - } -} diff --git a/packages/backend/src/models/entities/Role.ts b/packages/backend/src/models/entities/Role.ts index 067f7bf629..61f40d59da 100644 --- a/packages/backend/src/models/entities/Role.ts +++ b/packages/backend/src/models/entities/Role.ts @@ -167,11 +167,6 @@ export class Role { }) public displayOrder: number; - @Column('boolean', { - default: true, - }) - public isPublicUsers: boolean; - @Column('jsonb', { default: { }, }) diff --git a/packages/backend/src/server/api/endpoints/admin/roles/create.ts b/packages/backend/src/server/api/endpoints/admin/roles/create.ts index 1cf3157acd..916172f54a 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/create.ts @@ -26,7 +26,6 @@ export const paramDef = { isModerator: { type: 'boolean' }, isAdministrator: { type: 'boolean' }, isExplorable: { type: 'boolean', default: false }, // optional for backward compatibility - isPublicUsers: { type: 'boolean', default: true }, // optional for backward compatibility asBadge: { type: 'boolean' }, canEditMembersByModerator: { type: 'boolean' }, displayOrder: { type: 'number' }, @@ -79,7 +78,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { isAdministrator: ps.isAdministrator, isModerator: ps.isModerator, isExplorable: ps.isExplorable, - isPublicUsers: ps.isPublicUsers, asBadge: ps.asBadge, canEditMembersByModerator: ps.canEditMembersByModerator, displayOrder: ps.displayOrder, diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts index 5108c4da1d..467f157a61 100644 --- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts @@ -34,7 +34,6 @@ export const paramDef = { isModerator: { type: 'boolean' }, isAdministrator: { type: 'boolean' }, isExplorable: { type: 'boolean' }, - isPublicUsers: { type: 'boolean' }, asBadge: { type: 'boolean' }, canEditMembersByModerator: { type: 'boolean' }, displayOrder: { type: 'number' }, @@ -88,7 +87,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { isModerator: ps.isModerator, isAdministrator: ps.isAdministrator, isExplorable: ps.isExplorable, - isPublicUsers: ps.isPublicUsers, asBadge: ps.asBadge, canEditMembersByModerator: ps.canEditMembersByModerator, displayOrder: ps.displayOrder, diff --git a/packages/backend/src/server/api/endpoints/roles/list.ts b/packages/backend/src/server/api/endpoints/roles/list.ts index d61c6b8dc6..5ad29839c2 100644 --- a/packages/backend/src/server/api/endpoints/roles/list.ts +++ b/packages/backend/src/server/api/endpoints/roles/list.ts @@ -30,6 +30,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { super(meta, paramDef, async (ps, me) => { const roles = await this.rolesRepository.findBy({ isPublic: true, + isExplorable: true, }); return await this.roleEntityService.packMany(roles, me); }); diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts index f4b30286a4..b2cb8b42a8 100644 --- a/packages/backend/src/server/api/endpoints/roles/users.ts +++ b/packages/backend/src/server/api/endpoints/roles/users.ts @@ -49,14 +49,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { const role = await this.rolesRepository.findOneBy({ id: ps.roleId, isPublic: true, + isExplorable: true, }); if (role == null) { throw new ApiError(meta.errors.noSuchRole); } - if (!role.isPublicUsers) { - return []; - } const query = this.queryService.makePaginationQuery(this.roleAssignmentsRepository.createQueryBuilder('assign'), ps.sinceId, ps.untilId) .andWhere('assign.roleId = :roleId', { roleId: role.id }) diff --git a/packages/frontend/src/pages/admin/roles.editor.vue b/packages/frontend/src/pages/admin/roles.editor.vue index 6aeef6cb1d..a1fa9d2932 100644 --- a/packages/frontend/src/pages/admin/roles.editor.vue +++ b/packages/frontend/src/pages/admin/roles.editor.vue @@ -63,11 +63,6 @@ <template #caption>{{ i18n.ts._role.descriptionOfIsExplorable }}</template> </MkSwitch> - <MkSwitch v-model="role.isPublicUsers" :readonly="readonly"> - <template #label>{{ i18n.ts._role.isPublicUsers }}</template> - <template #caption>{{ i18n.ts._role.descriptionOfIsPublicUsers }}</template> - </MkSwitch> - <FormSlot> <template #label><i class="ti ti-license"></i> {{ i18n.ts._role.policies }}</template> <div class="_gaps_s"> @@ -506,7 +501,6 @@ const save = throttle(100, () => { isModerator: role.isModerator, isPublic: role.isPublic, isExplorable: role.isExplorable, - isPublicUsers: role.isPublicUsers, asBadge: role.asBadge, canEditMembersByModerator: role.canEditMembersByModerator, policies: role.policies, From 94c09f14414bb7ab89e9e98ead342dd8b3175c7c Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 11 Jun 2023 09:53:07 +0900 Subject: [PATCH 208/213] :art: --- packages/frontend/src/ui/deck/column.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index c376eb2b47..c8d6744a37 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -313,6 +313,7 @@ function onDrop(ev) { > .body { background: var(--bg) !important; + overflow-y: scroll !important; &::-webkit-scrollbar-track { background: inherit; From f1b0c54f6e923d869889ff528269862867428aa8 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 11 Jun 2023 10:01:30 +0900 Subject: [PATCH 209/213] New Crowdin updates (#10971) * New translations ja-JP.yml (Chinese Simplified) * New translations ja-JP.yml (German) * New translations ja-JP.yml (English) * New translations ja-JP.yml (Chinese Traditional) * New translations ja-JP.yml (Turkish) * New translations ja-JP.yml (German) * New translations ja-JP.yml (English) --- locales/de-DE.yml | 11 ++++---- locales/en-US.yml | 11 ++++---- locales/tr-TR.yml | 71 +++++++++++++++++++++++++++++++++++++++++++++++ locales/zh-CN.yml | 1 + locales/zh-TW.yml | 1 + 5 files changed, 85 insertions(+), 10 deletions(-) diff --git a/locales/de-DE.yml b/locales/de-DE.yml index c4c12cb1aa..9b52a50697 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -991,7 +991,7 @@ postToTheChannel: "In Kanal senden" cannotBeChangedLater: "Kann später nicht mehr geändert werden." reactionAcceptance: "Reaktionsannahme" likeOnly: "Nur \"Gefällt mir\"" -likeOnlyForRemote: "Nur \"Gefällt mir\" für fremde Instanzen" +likeOnlyForRemote: "Alle (Nur \"Gefällt mir\" für fremde Instanzen)" nonSensitiveOnly: "Keine Sensitiven" nonSensitiveOnlyForLocalLikeOnlyForRemote: "Keine Sensitiven (Nur \"Gefällt mir\" von fremden Instanzen)" rolesAssignedToMe: "Mir zugewiesene Rollen" @@ -1062,6 +1062,7 @@ later: "Später" goToMisskey: "Zu Misskey" additionalEmojiDictionary: "Zusätzliche Emoji-Wörterbücher" installed: "Installiert" +branding: "Branding" _initialAccountSetting: accountCreated: "Dein Konto wurde erfolgreich erstellt!" letsStartAccountSetup: "Lass uns nun dein Konto einrichten." @@ -1093,7 +1094,7 @@ _accountMigration: migrationConfirm: "Dieses Konto wirklich zu {account} umziehen? Sobald der Umzug beginnt, kann er nicht rückgängig gemacht werden, und dieses Konto nicht wieder im ursprünglichen Zustand verwendet werden." movedAndCannotBeUndone: "\nDieses Konto wurde migriert.\nDiese Aktion ist unwiderruflich." postMigrationNote: "Dieses Konto wird 24 Stunden nach Abschluss der Migration allen Konten, denen es derzeit folgt, nicht mehr folgen.\n\nSowohl die Anzahl der Follower als auch die der Konten, denen dieses Konto folgt, wird dann auf Null gesetzt. Um zu vermeiden, dass Follower dieses Kontos dessen Beiträge, welche nur für Follower bestimmt sind, nicht mehr sehen können, werden sie diesem Konto jedoch weiterhin folgen." - movedTo: "Umzugsziel:" + movedTo: "Neues Konto:" _achievements: earnedAt: "Freigeschaltet am" _types: @@ -1347,7 +1348,7 @@ _role: condition: "Bedingung" isConditionalRole: "Dies ist eine konditionale Rolle." isPublic: "Öffentliche Rolle" - descriptionOfIsPublic: "Ist dies aktiviert, so kann jeder die Liste der Benutzer, die dieser Rolle zugewiesen sind, einsehen. Zusätzlich wird diese Rolle im Profil zugewiesener Benutzer angezeigt." + descriptionOfIsPublic: "Diese Rolle wird im Profil zugewiesener Benutzer angezeigt." options: "Optionen" policies: "Richtlinien" baseRole: "Rollenvorlage" @@ -1356,8 +1357,8 @@ _role: iconUrl: "Icon-URL" asBadge: "Als Abzeichen anzeigen" descriptionOfAsBadge: "Ist dies aktiviert, so wird das Icon dieser Rolle an der Seite der Namen von Benutzern mit dieser Rolle angezeigt." - isExplorable: "Rollenchronik veröffentlichen" - descriptionOfIsExplorable: "Ist dies aktiviert, so ist die Rollenchronik dieser Rolle frei zugänglich. Die Chronik von Rollen, welche nicht öffentlich sind, wird auch bei Aktivierung nicht veröffentlicht." + isExplorable: "Benutzerliste veröffentlichen" + descriptionOfIsExplorable: "Ist dies aktiviert, so ist die Chronik dieser Rolle, sowie eine Liste der Benutzer mit dieser Rolle, frei zugänglich." displayOrder: "Position" descriptionOfDisplayOrder: "Je höher die Nummer, desto höher die UI-Position." canEditMembersByModerator: "Moderatoren können Benutzern diese Rolle zuweisen" diff --git a/locales/en-US.yml b/locales/en-US.yml index 0f1c7c89fe..8938208574 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -991,7 +991,7 @@ postToTheChannel: "Post to channel" cannotBeChangedLater: "This cannot be changed later." reactionAcceptance: "Reaction Acceptance" likeOnly: "Only likes" -likeOnlyForRemote: "Only likes for remote instances" +likeOnlyForRemote: "All (Only likes for remote instances)" nonSensitiveOnly: "Non-sensitive only" nonSensitiveOnlyForLocalLikeOnlyForRemote: "Non-sensitive only (Only likes from remote)" rolesAssignedToMe: "Roles assigned to me" @@ -1062,6 +1062,7 @@ later: "Later" goToMisskey: "To Misskey" additionalEmojiDictionary: "Additional emoji dictionaries" installed: "Installed" +branding: "Branding" _initialAccountSetting: accountCreated: "Your account was successfully created!" letsStartAccountSetup: "For starters, let's set up your profile." @@ -1093,7 +1094,7 @@ _accountMigration: migrationConfirm: "Really migrate this account to {account}? Once started, this process cannot be stopped or taken back, and you will not be able to use this account in its original state anymore." movedAndCannotBeUndone: "\nThis account has been migrated.\nMigration cannot be reversed." postMigrationNote: "This account will unfollow all accounts it is currently following 24 hours after migration finishes.\nBoth the number of follows and followers will then become zero. To avoid your followers from being unable to see followers only posts of this account, they will however continue following this account." - movedTo: "Account to move to:" + movedTo: "New account:" _achievements: earnedAt: "Unlocked at" _types: @@ -1347,7 +1348,7 @@ _role: condition: "Condition" isConditionalRole: "This is a conditional role." isPublic: "Public role" - descriptionOfIsPublic: "Anyone will be able to view a list of users assigned to this role. In addition, this role will be displayed in the profiles of assigned users." + descriptionOfIsPublic: "This role will be displayed in the profiles of assigned users." options: "Options" policies: "Policies" baseRole: "Role template" @@ -1356,8 +1357,8 @@ _role: iconUrl: "Icon URL" asBadge: "Show as badge" descriptionOfAsBadge: "This role's icon will be displayed next to the username of users with this role if turned on." - isExplorable: "Role timeline is public" - descriptionOfIsExplorable: "This role's timeline will become publicly accessible if enabled. Timelines of non-public roles will not be made public even if set." + isExplorable: "Make role explorable" + descriptionOfIsExplorable: "This role's timeline and the list of users with this will be made public if enabled." displayOrder: "Position" descriptionOfDisplayOrder: "The higher the number, the higher its UI position." canEditMembersByModerator: "Allow moderators to edit the list of members for this role" diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index 7bd8188a48..cc402eec48 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -1,6 +1,7 @@ --- _lang_: "Türkçe" introMisskey: "Açık kaynaklı bir dağıtılmış mikroblog hizmeti olan Misskey'e hoş geldiniz.\nMisskey, neler olup bittiğini paylaşmak ve herkese sizden bahsetmek için \"notlar\" oluşturmanıza olanak tanıyan, açık kaynaklı, dağıtılmış bir mikroblog hizmetidir.\nHerkesin notlarına kendi tepkilerinizi hızlıca eklemek için \"Tepkiler\" özelliğini de kullanabilirsiniz👍.\nYeni bir dünyayı keşfedin🚀." +poweredByMisskeyDescription: "name}Açık kaynak bir platform\n<b>Misskey</b>Dünya'nın en sunucularında biri。" monthAndDay: "{month}Ay {day}Gün" search: "Arama" notifications: "Bildirim" @@ -13,7 +14,9 @@ cancel: "İptal" enterUsername: "Kullanıcı adınızı giriniz" noNotes: "Notlar mevcut değil." noNotifications: "Bildirim bulunmuyor" +instance: "Sunucu" settings: "Ayarlar" +notificationSettings: "Bildirim Ayarları" basicSettings: "Temel Ayarlar" otherSettings: "Diğer Ayarlar" openInWindow: "Bir pencere ile aç" @@ -21,9 +24,11 @@ profile: "Profil" timeline: "Zaman çizelgesi" noAccountDescription: "Bu kullanıcı henüz biyografisini yazmadı" login: "Giriş Yap " +loggingIn: "Oturum aç" logout: "Çıkış Yap" signup: "Kayıt Ol" uploading: "Yükleniyor" +save: "Kaydet" users: "Kullanıcı" addUser: "Kullanıcı Ekle" favorite: "Favoriler" @@ -31,6 +36,7 @@ favorites: "Favoriler" unfavorite: "Favorilerden Kaldır" favorited: "Favorilerime eklendi." alreadyFavorited: "Zaten favorilerinizde kayıtlı." +cantFavorite: "Favorilere kayıt yapılamadı" pin: "Sabitlenmiş" unpin: "Sabitlemeyi kaldır" copyContent: "İçeriği kopyala" @@ -40,23 +46,88 @@ deleteAndEdit: "Sil ve yeniden düzenle" deleteAndEditConfirm: "Bu notu silip yeniden düzenlemek istiyor musunuz? Bu nota ilişkin tüm Tepkiler, Yeniden Notlar ve Yanıtlar da silinecektir." addToList: "Listeye ekle" sendMessage: "Mesaj Gönder" +copyRSS: "RSSKopyala" copyUsername: "Kullanıcı Adını Kopyala" +copyUserId: "KullanıcıyıKopyala" +copyNoteId: "Kimlik notunu kopyala" searchUser: "Kullanıcıları ara" +reply: "yanıt" +loadMore: "Devamını yükle" +showMore: "Devamını yükle" +lists: "Listeler" +noLists: "Liste yok" +note: "not" +notes: "notlar" +following: "takipçi" +followers: "takipçi" +followsYou: "seni takip ediyor" +createList: "Liste oluştur" +manageLists: "Yönetici Listeleri" +error: "hata" +follow: "takipçi" +followRequest: "Takip isteği" +followRequests: "Takip istekleri" +unfollow: "takip etmeyi bırak" +followRequestPending: "Bekleyen Takip Etme Talebi" +enterEmoji: "Emoji Giriniz" +renote: "vazgeçme" +unrenote: "not alma" +renoted: "yeniden adlandırılmış" +cantRenote: "Ayrılamama" +cantReRenote: "not alabilirmiyim" +quote: "alıntı" +pinnedNote: "Sabitlenen" pinned: "Sabitlenmiş" +you: "sen" +unmute: "sesi aç" +renoteMute: "sesi kapat" +renoteUnmute: "sesi açmayı iptal et" +block: "engelle" +unblock: "engellemeyi kaldır" +suspend: "askıya al" +unsuspend: "askıya alma" +blockConfirm: "Onayı engelle" +unblockConfirm: "engellemeyi kaldır onayla" +selectChannel: "Kanal seç" +flagAsBot: "Bot olarak işaretle" +instances: "Sunucu" remove: "Sil" +pinnedNotes: "Sabitlenen" +userList: "Listeler" smtpUser: "Kullanıcı Adı" smtpPass: "Şifre" user: "Kullanıcı" searchByGoogle: "Arama" +_theme: + keys: + renote: "vazgeçme" _sfx: + note: "notlar" notification: "Bildirim" _widgets: profile: "Profil" notifications: "Bildirim" timeline: "Zaman çizelgesi" +_cw: + show: "Devamını yükle" +_visibility: + followers: "takipçi" _profile: username: "Kullanıcı Adı" +_exportOrImport: + followingList: "takipçi" + blockingList: "engelle" + userLists: "Listeler" +_notification: + _types: + follow: "takipçi" + renote: "vazgeçme" + quote: "alıntı" + _actions: + reply: "yanıt" + renote: "vazgeçme" _deck: _columns: notifications: "Bildirim" tl: "Zaman çizelgesi" + list: "Listeler" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 9c278ea751..313c254c79 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1060,6 +1060,7 @@ cancelReactionConfirm: "要取消回应吗?" changeReactionConfirm: "要更改回应吗?" later: "一会再说" goToMisskey: "去往Misskey" +additionalEmojiDictionary: "表情符号追加字典" installed: "已安装" _initialAccountSetting: accountCreated: "账户创建完成了!" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index ef0baeef50..8017018507 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1062,6 +1062,7 @@ later: "稍後再說" goToMisskey: "往Misskey" additionalEmojiDictionary: "表情符號的附加辭典" installed: "已安裝" +branding: "品牌宣傳" _initialAccountSetting: accountCreated: "帳戶已建立完成!" letsStartAccountSetup: "來進行帳戶的初始設定吧。" From 63971f1cd85e27fc81dd147f004e181579c8e1ef Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 11 Jun 2023 10:03:33 +0900 Subject: [PATCH 210/213] 13.13.2 --- CHANGELOG.md | 19 +++++++++++++------ package.json | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a6632fbaf..f75f9f6b3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,17 +12,24 @@ --> -## 13.13.1 (unreleased) +## 13.13.2 + +### General +- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるように +- ロールが付与されているユーザーリストを非公開にできるように + +### Client +- Fix: タブがバックグラウンドでもstreamが切断されないように + +### Server +- Fix: キャッシュが溜まり続けないように + +## 13.13.1 ### Client - Fix: タブがアクティブな間はstreamが切断されないように -### General -- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるようになりました -- ロールが付与されているユーザーリストを非公開にできるように - ### Server -- Fix: キャッシュが溜まり続けないように - Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正 ## 13.13.0 diff --git a/package.json b/package.json index eff0bf2dc2..dd0c1d57e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "13.13.1", + "version": "13.13.2", "codename": "nasubi", "repository": { "type": "git", From fa7fd9ce2530a50fe2318304ab223e1a4dc2fbc2 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sun, 11 Jun 2023 15:38:06 +0900 Subject: [PATCH 211/213] fix image of MkError.vue --- packages/frontend/src/components/global/MkError.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/global/MkError.vue b/packages/frontend/src/components/global/MkError.vue index 24b0835135..503e00387c 100644 --- a/packages/frontend/src/components/global/MkError.vue +++ b/packages/frontend/src/components/global/MkError.vue @@ -1,7 +1,7 @@ <template> <Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear> <div :class="$style.root"> - <img :class="$style.img" :src="infoImageUrl" class="_ghost"/> + <img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/> <p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p> <MkButton :class="$style.button" @click="() => emit('retry')">{{ i18n.ts.retry }}</MkButton> </div> @@ -12,7 +12,7 @@ import MkButton from '@/components/MkButton.vue'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; -import { infoImageUrl } from '@/instance'; +import { serverErrorImageUrl } from '@/instance'; const emit = defineEmits<{ (ev: 'retry'): void; From f5dfb64a528d705970d606d3f84ec9de2ef55d84 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Tue, 13 Jun 2023 14:13:33 +0900 Subject: [PATCH 212/213] =?UTF-8?q?=E3=83=A6=E3=83=BC=E3=82=B6=E3=83=BC?= =?UTF-8?q?=E7=B5=B1=E8=A8=88=E8=A1=A8=E7=A4=BA=E6=A9=9F=E8=83=BD=E3=82=92?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve #10998 --- CHANGELOG.md | 1 + .../backend/src/server/api/EndpointsModule.ts | 4 - packages/backend/src/server/api/endpoints.ts | 2 - .../src/server/api/endpoints/users/stats.ts | 228 ------------------ .../src/pages/settings/account-stats.vue | 146 ----------- .../frontend/src/pages/settings/other.vue | 2 - packages/frontend/src/router.ts | 4 - packages/misskey-js/etc/misskey-js.api.md | 4 - packages/misskey-js/src/api.types.ts | 1 - 9 files changed, 1 insertion(+), 391 deletions(-) delete mode 100644 packages/backend/src/server/api/endpoints/users/stats.ts delete mode 100644 packages/frontend/src/pages/settings/account-stats.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index f75f9f6b3c..45dc0e3c90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### General - エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるように - ロールが付与されているユーザーリストを非公開にできるように +- サーバーの負荷が非常に高いため、ユーザー統計表示機能を削除しました ### Client - Fix: タブがバックグラウンドでもstreamが切断されないように diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 1e32e9988d..d1ff3fe925 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -333,7 +333,6 @@ import * as ep___users_reportAbuse from './endpoints/users/report-abuse.js'; import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js'; import * as ep___users_search from './endpoints/users/search.js'; import * as ep___users_show from './endpoints/users/show.js'; -import * as ep___users_stats from './endpoints/users/stats.js'; import * as ep___users_achievements from './endpoints/users/achievements.js'; import * as ep___users_updateMemo from './endpoints/users/update-memo.js'; import * as ep___fetchRss from './endpoints/fetch-rss.js'; @@ -674,7 +673,6 @@ const $users_reportAbuse: Provider = { provide: 'ep:users/report-abuse', useClas const $users_searchByUsernameAndHost: Provider = { provide: 'ep:users/search-by-username-and-host', useClass: ep___users_searchByUsernameAndHost.default }; const $users_search: Provider = { provide: 'ep:users/search', useClass: ep___users_search.default }; const $users_show: Provider = { provide: 'ep:users/show', useClass: ep___users_show.default }; -const $users_stats: Provider = { provide: 'ep:users/stats', useClass: ep___users_stats.default }; const $users_achievements: Provider = { provide: 'ep:users/achievements', useClass: ep___users_achievements.default }; const $users_updateMemo: Provider = { provide: 'ep:users/update-memo', useClass: ep___users_updateMemo.default }; const $fetchRss: Provider = { provide: 'ep:fetch-rss', useClass: ep___fetchRss.default }; @@ -1019,7 +1017,6 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $users_searchByUsernameAndHost, $users_search, $users_show, - $users_stats, $users_achievements, $users_updateMemo, $fetchRss, @@ -1356,7 +1353,6 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $users_searchByUsernameAndHost, $users_search, $users_show, - $users_stats, $users_achievements, $users_updateMemo, $fetchRss, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 7e678a6404..94206ef870 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -333,7 +333,6 @@ import * as ep___users_reportAbuse from './endpoints/users/report-abuse.js'; import * as ep___users_searchByUsernameAndHost from './endpoints/users/search-by-username-and-host.js'; import * as ep___users_search from './endpoints/users/search.js'; import * as ep___users_show from './endpoints/users/show.js'; -import * as ep___users_stats from './endpoints/users/stats.js'; import * as ep___users_achievements from './endpoints/users/achievements.js'; import * as ep___users_updateMemo from './endpoints/users/update-memo.js'; import * as ep___fetchRss from './endpoints/fetch-rss.js'; @@ -672,7 +671,6 @@ const eps = [ ['users/search-by-username-and-host', ep___users_searchByUsernameAndHost], ['users/search', ep___users_search], ['users/show', ep___users_show], - ['users/stats', ep___users_stats], ['users/achievements', ep___users_achievements], ['users/update-memo', ep___users_updateMemo], ['fetch-rss', ep___fetchRss], diff --git a/packages/backend/src/server/api/endpoints/users/stats.ts b/packages/backend/src/server/api/endpoints/users/stats.ts deleted file mode 100644 index 7479793afe..0000000000 --- a/packages/backend/src/server/api/endpoints/users/stats.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { Inject, Injectable } from '@nestjs/common'; -import { awaitAll } from '@/misc/prelude/await-all.js'; -import { Endpoint } from '@/server/api/endpoint-base.js'; -import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; -import { DI } from '@/di-symbols.js'; -import type { UsersRepository, NotesRepository, FollowingsRepository, DriveFilesRepository, NoteReactionsRepository, PageLikesRepository, NoteFavoritesRepository, PollVotesRepository } from '@/models/index.js'; -import { ApiError } from '../../error.js'; - -export const meta = { - tags: ['users'], - - requireCredential: false, - - description: 'Show statistics about a user.', - - errors: { - noSuchUser: { - message: 'No such user.', - code: 'NO_SUCH_USER', - id: '9e638e45-3b25-4ef7-8f95-07e8498f1819', - }, - }, - - res: { - type: 'object', - optional: false, nullable: false, - properties: { - notesCount: { - type: 'integer', - optional: false, nullable: false, - }, - repliesCount: { - type: 'integer', - optional: false, nullable: false, - }, - renotesCount: { - type: 'integer', - optional: false, nullable: false, - }, - repliedCount: { - type: 'integer', - optional: false, nullable: false, - }, - renotedCount: { - type: 'integer', - optional: false, nullable: false, - }, - pollVotesCount: { - type: 'integer', - optional: false, nullable: false, - }, - pollVotedCount: { - type: 'integer', - optional: false, nullable: false, - }, - localFollowingCount: { - type: 'integer', - optional: false, nullable: false, - }, - remoteFollowingCount: { - type: 'integer', - optional: false, nullable: false, - }, - localFollowersCount: { - type: 'integer', - optional: false, nullable: false, - }, - remoteFollowersCount: { - type: 'integer', - optional: false, nullable: false, - }, - followingCount: { - type: 'integer', - optional: false, nullable: false, - }, - followersCount: { - type: 'integer', - optional: false, nullable: false, - }, - sentReactionsCount: { - type: 'integer', - optional: false, nullable: false, - }, - receivedReactionsCount: { - type: 'integer', - optional: false, nullable: false, - }, - noteFavoritesCount: { - type: 'integer', - optional: false, nullable: false, - }, - pageLikesCount: { - type: 'integer', - optional: false, nullable: false, - }, - pageLikedCount: { - type: 'integer', - optional: false, nullable: false, - }, - driveFilesCount: { - type: 'integer', - optional: false, nullable: false, - }, - driveUsage: { - type: 'integer', - optional: false, nullable: false, - description: 'Drive usage in bytes', - }, - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - userId: { type: 'string', format: 'misskey:id' }, - }, - required: ['userId'], -} as const; - -// eslint-disable-next-line import/no-default-export -@Injectable() -export default class extends Endpoint<typeof meta, typeof paramDef> { - constructor( - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.notesRepository) - private notesRepository: NotesRepository, - - @Inject(DI.followingsRepository) - private followingsRepository: FollowingsRepository, - - @Inject(DI.driveFilesRepository) - private driveFilesRepository: DriveFilesRepository, - - @Inject(DI.noteReactionsRepository) - private noteReactionsRepository: NoteReactionsRepository, - - @Inject(DI.pageLikesRepository) - private pageLikesRepository: PageLikesRepository, - - @Inject(DI.noteFavoritesRepository) - private noteFavoritesRepository: NoteFavoritesRepository, - - @Inject(DI.pollVotesRepository) - private pollVotesRepository: PollVotesRepository, - - private driveFileEntityService: DriveFileEntityService, - ) { - super(meta, paramDef, async (ps, me) => { - const user = await this.usersRepository.findOneBy({ id: ps.userId }); - if (user == null) { - throw new ApiError(meta.errors.noSuchUser); - } - - const result = await awaitAll({ - notesCount: this.notesRepository.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .getCount(), - repliesCount: this.notesRepository.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .andWhere('note.replyId IS NOT NULL') - .getCount(), - renotesCount: this.notesRepository.createQueryBuilder('note') - .where('note.userId = :userId', { userId: user.id }) - .andWhere('note.renoteId IS NOT NULL') - .getCount(), - repliedCount: this.notesRepository.createQueryBuilder('note') - .where('note.replyUserId = :userId', { userId: user.id }) - .getCount(), - renotedCount: this.notesRepository.createQueryBuilder('note') - .where('note.renoteUserId = :userId', { userId: user.id }) - .getCount(), - pollVotesCount: this.pollVotesRepository.createQueryBuilder('vote') - .where('vote.userId = :userId', { userId: user.id }) - .getCount(), - pollVotedCount: this.pollVotesRepository.createQueryBuilder('vote') - .innerJoin('vote.note', 'note') - .where('note.userId = :userId', { userId: user.id }) - .getCount(), - localFollowingCount: this.followingsRepository.createQueryBuilder('following') - .where('following.followerId = :userId', { userId: user.id }) - .andWhere('following.followeeHost IS NULL') - .getCount(), - remoteFollowingCount: this.followingsRepository.createQueryBuilder('following') - .where('following.followerId = :userId', { userId: user.id }) - .andWhere('following.followeeHost IS NOT NULL') - .getCount(), - localFollowersCount: this.followingsRepository.createQueryBuilder('following') - .where('following.followeeId = :userId', { userId: user.id }) - .andWhere('following.followerHost IS NULL') - .getCount(), - remoteFollowersCount: this.followingsRepository.createQueryBuilder('following') - .where('following.followeeId = :userId', { userId: user.id }) - .andWhere('following.followerHost IS NOT NULL') - .getCount(), - sentReactionsCount: this.noteReactionsRepository.createQueryBuilder('reaction') - .where('reaction.userId = :userId', { userId: user.id }) - .getCount(), - receivedReactionsCount: this.noteReactionsRepository.createQueryBuilder('reaction') - .innerJoin('reaction.note', 'note') - .where('note.userId = :userId', { userId: user.id }) - .getCount(), - noteFavoritesCount: this.noteFavoritesRepository.createQueryBuilder('favorite') - .where('favorite.userId = :userId', { userId: user.id }) - .getCount(), - pageLikesCount: this.pageLikesRepository.createQueryBuilder('like') - .where('like.userId = :userId', { userId: user.id }) - .getCount(), - pageLikedCount: this.pageLikesRepository.createQueryBuilder('like') - .innerJoin('like.page', 'page') - .where('page.userId = :userId', { userId: user.id }) - .getCount(), - driveFilesCount: this.driveFilesRepository.createQueryBuilder('file') - .where('file.userId = :userId', { userId: user.id }) - .getCount(), - driveUsage: this.driveFileEntityService.calcDriveUsageOf(user), - }); - - return { - ...result, - followingCount: result.localFollowingCount + result.remoteFollowingCount, - followersCount: result.localFollowersCount + result.remoteFollowersCount, - }; - }); - } -} diff --git a/packages/frontend/src/pages/settings/account-stats.vue b/packages/frontend/src/pages/settings/account-stats.vue deleted file mode 100644 index a0f1541b40..0000000000 --- a/packages/frontend/src/pages/settings/account-stats.vue +++ /dev/null @@ -1,146 +0,0 @@ -<template> -<div class="_gaps_m"> - <FormSection v-if="stats" first> - <template #label>{{ i18n.ts.statistics }}</template> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.notesCount }}</template> - <template #value>{{ number(stats.notesCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.repliesCount }}</template> - <template #value>{{ number(stats.repliesCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.renotesCount }}</template> - <template #value>{{ number(stats.renotesCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.repliedCount }}</template> - <template #value>{{ number(stats.repliedCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.renotedCount }}</template> - <template #value>{{ number(stats.renotedCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.pollVotesCount }}</template> - <template #value>{{ number(stats.pollVotesCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.pollVotedCount }}</template> - <template #value>{{ number(stats.pollVotedCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.sentReactionsCount }}</template> - <template #value>{{ number(stats.sentReactionsCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.receivedReactionsCount }}</template> - <template #value>{{ number(stats.receivedReactionsCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.noteFavoritesCount }}</template> - <template #value>{{ number(stats.noteFavoritesCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.followingCount }}</template> - <template #value>{{ number(stats.followingCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.followingCount }} ({{ i18n.ts.local }})</template> - <template #value>{{ number(stats.localFollowingCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.followingCount }} ({{ i18n.ts.remote }})</template> - <template #value>{{ number(stats.remoteFollowingCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.followersCount }}</template> - <template #value>{{ number(stats.followersCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.followersCount }} ({{ i18n.ts.local }})</template> - <template #value>{{ number(stats.localFollowersCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.followersCount }} ({{ i18n.ts.remote }})</template> - <template #value>{{ number(stats.remoteFollowersCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.pageLikesCount }}</template> - <template #value>{{ number(stats.pageLikesCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.pageLikedCount }}</template> - <template #value>{{ number(stats.pageLikedCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.driveFilesCount }}</template> - <template #value>{{ number(stats.driveFilesCount) }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>{{ i18n.ts.driveUsage }}</template> - <template #value>{{ bytes(stats.driveUsage) }}</template> - </MkKeyValue> - </FormSection> - - <FormSection> - <template #label>{{ i18n.ts.other }}</template> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>emailVerified</template> - <template #value>{{ $i.emailVerified ? i18n.ts.yes : i18n.ts.no }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>twoFactorEnabled</template> - <template #value>{{ $i.twoFactorEnabled ? i18n.ts.yes : i18n.ts.no }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>securityKeys</template> - <template #value>{{ $i.securityKeys ? i18n.ts.yes : i18n.ts.no }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>usePasswordLessLogin</template> - <template #value>{{ $i.usePasswordLessLogin ? i18n.ts.yes : i18n.ts.no }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>isModerator</template> - <template #value>{{ $i.isModerator ? i18n.ts.yes : i18n.ts.no }}</template> - </MkKeyValue> - <MkKeyValue oneline style="margin: 1em 0;"> - <template #key>isAdmin</template> - <template #value>{{ $i.isAdmin ? i18n.ts.yes : i18n.ts.no }}</template> - </MkKeyValue> - </FormSection> -</div> -</template> - -<script lang="ts" setup> -import { onMounted, ref } from 'vue'; -import FormSection from '@/components/form/section.vue'; -import MkKeyValue from '@/components/MkKeyValue.vue'; -import * as os from '@/os'; -import number from '@/filters/number'; -import bytes from '@/filters/bytes'; -import { $i } from '@/account'; -import { i18n } from '@/i18n'; -import { definePageMetadata } from '@/scripts/page-metadata'; - -const stats = ref<any>({}); - -onMounted(() => { - os.api('users/stats', { - userId: $i!.id, - }).then(response => { - stats.value = response; - }); -}); - -const headerActions = $computed(() => []); - -const headerTabs = $computed(() => []); - -definePageMetadata({ - title: i18n.ts.accountInfo, - icon: 'ti ti-info-circle', -}); -</script> diff --git a/packages/frontend/src/pages/settings/other.vue b/packages/frontend/src/pages/settings/other.vue index 0b73780a8b..3d8bb59277 100644 --- a/packages/frontend/src/pages/settings/other.vue +++ b/packages/frontend/src/pages/settings/other.vue @@ -26,8 +26,6 @@ <template #key>{{ i18n.ts.registeredDate }}</template> <template #value><MkTime :time="$i.createdAt" mode="detail"/></template> </MkKeyValue> - - <FormLink to="/settings/account-stats"><template #icon><i class="ti ti-info-circle"></i></template>{{ i18n.ts.statistics }}</FormLink> </div> </MkFolder> diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index a95e8e6485..fe9bc5938e 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -177,10 +177,6 @@ export const routes = [{ path: '/accounts', name: 'profile', component: page(() => import('./pages/settings/accounts.vue')), - }, { - path: '/account-stats', - name: 'other', - component: page(() => import('./pages/settings/account-stats.vue')), }, { path: '/other', name: 'other', diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index eddc5cf90c..ca8eee01a1 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -2147,10 +2147,6 @@ export type Endpoints = { }; }; }; - 'users/stats': { - req: TODO; - res: TODO; - }; }; declare namespace entities { diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index cc88c4b1a4..b8c59e7b15 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -602,5 +602,4 @@ export type Endpoints = { $default: UserDetailed; }; }; }; - 'users/stats': { req: TODO; res: TODO; }; }; From d4903a476ae1ffdbd579c90d2072bb94fdefcf08 Mon Sep 17 00:00:00 2001 From: riku6460 <17585784+riku6460@users.noreply.github.com> Date: Tue, 13 Jun 2023 17:05:18 +0900 Subject: [PATCH 213/213] fix --- gulpfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 55bc8d368f..97e5c30b95 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -38,8 +38,8 @@ gulp.task('copy:frontend:locales', cb => { gulp.task('build:backend:script', () => { const clientManifestExists = fs.existsSync('./built/_vite_/manifest.json'); const clientEntry = clientManifestExists ? - JSON.parse(fs.readFileSync('./built/_vite_/manifest.json', 'utf-8'))['src/init.ts'].file - : 'src/init.ts' + JSON.parse(fs.readFileSync('./built/_vite_/manifest.json', 'utf-8'))['src/_boot_.ts'].file + : 'src/_boot_.ts' return gulp.src(['./packages/backend/src/server/web/boot.js', './packages/backend/src/server/web/bios.js', './packages/backend/src/server/web/cli.js', './packages/backend/src/server/web/flush.js']) .pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))