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 01/33] 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 02/33] :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 03/33] :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 04/33] :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 05/33] 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 06/33] =?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 07/33] =?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 08/33] 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 09/33] 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 10/33] 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 11/33] 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 12/33] 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 13/33] :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 14/33] 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 15/33] 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 16/33] 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 17/33] 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 18/33] 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 19/33] =?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 20/33] 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 21/33] =?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 22/33] =?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 23/33] =?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 24/33] =?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 25/33] =?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 26/33] 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 27/33] 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 28/33] :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 29/33] :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 30/33] 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 31/33] =?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 32/33] =?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 33/33] 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