diff options
Diffstat (limited to 'packages/frontend/src/components')
35 files changed, 239 insertions, 323 deletions
diff --git a/packages/frontend/src/components/MkAbuseReportWindow.vue b/packages/frontend/src/components/MkAbuseReportWindow.vue index dbac5e9dd7..61297fdc76 100644 --- a/packages/frontend/src/components/MkAbuseReportWindow.vue +++ b/packages/frontend/src/components/MkAbuseReportWindow.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> </I18n> </template> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps_m" :class="$style.root"> <div class=""> <MkTextarea v-model="comment"> @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton primary full :disabled="comment.length === 0" @click="send">{{ i18n.ts.send }}</MkButton> </div> </div> - </MkSpacer> + </div> </MkWindow> </template> diff --git a/packages/frontend/src/components/MkAntennaEditor.vue b/packages/frontend/src/components/MkAntennaEditor.vue index 59099d54bd..e2febf7225 100644 --- a/packages/frontend/src/components/MkAntennaEditor.vue +++ b/packages/frontend/src/components/MkAntennaEditor.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<MkSpacer :contentMax="700"> +<div class="_spacer" style="--MI_SPACER-w: 700px;"> <div> <div class="_gaps_m"> <MkInput v-model="name"> @@ -48,7 +48,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> </div> -</MkSpacer> +</div> </template> <script lang="ts" setup> diff --git a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue index 54fda6bf7c..ed5a20b4eb 100644 --- a/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue +++ b/packages/frontend/src/components/MkCustomEmojiDetailedDialog.vue @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkModalWindow ref="dialogEl" @close="cancel()" @closed="emit('closed')"> <template #header>:{{ emoji.name }}:</template> <template #default> - <MkSpacer> + <div class="_spacer"> <div style="display: flex; flex-direction: column; gap: 1em;"> <div :class="$style.emojiImgWrapper"> <MkCustomEmoji :name="emoji.name" :normal="true" :useOriginalSize="true" style="height: 100%;"></MkCustomEmoji> @@ -50,7 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> </MkKeyValue> </div> - </MkSpacer> + </div> </template> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index cb7c270e91..3627704c1b 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -52,6 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only @contextmenu.stop="onContextmenu" > <div ref="contents"> + <MkInfo v-if="!store.r.readDriveTip.value" closable @close="closeTip()"><div v-html="i18n.ts.driveAboutTip"></div></MkInfo> <div v-show="folders.length > 0" ref="foldersContainer" :class="$style.folders"> <XFolder v-for="(f, i) in folders" @@ -108,6 +109,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { nextTick, onActivated, onBeforeUnmount, onMounted, ref, useTemplateRef, watch } from 'vue'; import * as Misskey from 'misskey-js'; import MkButton from './MkButton.vue'; +import MkInfo from './MkInfo.vue'; import type { MenuItem } from '@/types/menu.js'; import XNavFolder from '@/components/MkDrive.navFolder.vue'; import XFolder from '@/components/MkDrive.folder.vue'; @@ -121,6 +123,7 @@ import { uploadFile, uploads } from '@/utility/upload.js'; import { claimAchievement } from '@/utility/achievements.js'; import { prefer } from '@/preferences.js'; import { chooseFileFromPc } from '@/utility/select-file.js'; +import { store } from '@/store.js'; const searchQuery = ref(''); @@ -723,6 +726,10 @@ function onContextmenu(ev: MouseEvent) { os.contextMenu(getMenu(), ev); } +function closeTip() { + store.set('readDriveTip', true); +} + onMounted(() => { if (prefer.s.enableInfiniteScroll && loadMoreFiles.value) { nextTick(() => { diff --git a/packages/frontend/src/components/MkFileCaptionEditWindow.vue b/packages/frontend/src/components/MkFileCaptionEditWindow.vue index 7b5eefdc10..bdfbe13fb4 100644 --- a/packages/frontend/src/components/MkFileCaptionEditWindow.vue +++ b/packages/frontend/src/components/MkFileCaptionEditWindow.vue @@ -15,12 +15,12 @@ SPDX-License-Identifier: AGPL-3.0-only @closed="emit('closed')" > <template #header>{{ i18n.ts.describeFile }}</template> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <MkDriveFileThumbnail :file="file" fit="contain" style="height: 193px; margin-bottom: 16px;"/> <MkTextarea v-model="caption" autofocus :placeholder="i18n.ts.inputNewDescription" @keydown="onKeydown($event)"> <template #label>{{ i18n.ts.caption }}</template> </MkTextarea> - </MkSpacer> + </div> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index c228853bea..2e5d0a3dea 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -31,10 +31,6 @@ SPDX-License-Identifier: AGPL-3.0-only :leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''" :enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''" :leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''" - @enter="enter" - @afterEnter="afterEnter" - @leave="leave" - @afterLeave="afterLeave" > <KeepAlive> <div v-show="opened"> @@ -45,9 +41,9 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </template> - <MkSpacer v-if="withSpacer" :marginMin="spacerMin" :marginMax="spacerMax"> + <div v-if="withSpacer" class="_spacer" :style="{ '--MI_SPACER-min': props.spacerMin + 'px', '--MI_SPACER-max': props.spacerMax + 'px' }"> <slot></slot> - </MkSpacer> + </div> <div v-else> <slot></slot> </div> @@ -90,32 +86,6 @@ const bgSame = ref(false); const opened = ref(props.defaultOpen); const openedAtLeastOnce = ref(props.defaultOpen); -function enter(el: Element) { - if (!(el instanceof HTMLElement)) return; - const elementHeight = el.getBoundingClientRect().height; - el.style.height = '0'; - el.offsetHeight; // reflow - el.style.height = `${Math.min(elementHeight, props.maxHeight ?? Infinity)}px`; -} - -function afterEnter(el: Element) { - if (!(el instanceof HTMLElement)) return; - el.style.height = ''; -} - -function leave(el: Element) { - if (!(el instanceof HTMLElement)) return; - const elementHeight = el.getBoundingClientRect().height; - el.style.height = `${elementHeight}px`; - el.offsetHeight; // reflow - el.style.height = '0'; -} - -function afterLeave(el: Element) { - if (!(el instanceof HTMLElement)) return; - el.style.height = ''; -} - function toggle() { if (!opened.value) { openedAtLeastOnce.value = true; @@ -137,16 +107,18 @@ onMounted(() => { <style lang="scss" module> .transition_toggle_enterActive, .transition_toggle_leaveActive { - overflow-y: clip; - transition: opacity 0.3s, height 0.3s, transform 0.3s !important; + overflow-y: hidden; // 子要素のmarginが突き出るため clip を使ってはいけない + transition: opacity 0.3s, height 0.3s !important; } .transition_toggle_enterFrom, .transition_toggle_leaveTo { opacity: 0; + height: 0; } .root { display: block; + interpolate-size: allow-keywords; // heightのtransitionを動作させるために必要 } .header { diff --git a/packages/frontend/src/components/MkForgotPassword.vue b/packages/frontend/src/components/MkForgotPassword.vue index 35112ad45d..57946aaf2b 100644 --- a/packages/frontend/src/components/MkForgotPassword.vue +++ b/packages/frontend/src/components/MkForgotPassword.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only > <template #header>{{ i18n.ts.forgotPassword }}</template> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <form v-if="instance.enableEmail" @submit.prevent="onSubmit"> <div class="_gaps_m"> <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required> @@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div v-else> {{ i18n.ts._forgotPassword.contactAdmin }} </div> - </MkSpacer> + </div> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkFormDialog.vue b/packages/frontend/src/components/MkFormDialog.vue index 4756079e76..0884cdc016 100644 --- a/packages/frontend/src/components/MkFormDialog.vue +++ b/packages/frontend/src/components/MkFormDialog.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ title }} </template> - <MkSpacer :marginMin="20" :marginMax="32"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 32px;"> <div v-if="Object.keys(form).filter(item => !form[item].hidden).length > 0" class="_gaps_m"> <template v-for="(v, k) in Object.fromEntries(Object.entries(form))"> <template v-if="typeof v.hidden == 'function' ? v.hidden(values) : v.hidden"></template> @@ -66,7 +66,7 @@ SPDX-License-Identifier: AGPL-3.0-only <img :src="infoImageUrl" draggable="false"/> <div>{{ i18n.ts.nothing }}</div> </div> - </MkSpacer> + </div> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkInfo.vue b/packages/frontend/src/components/MkInfo.vue index 410e3accab..fb66098a54 100644 --- a/packages/frontend/src/components/MkInfo.vue +++ b/packages/frontend/src/components/MkInfo.vue @@ -39,7 +39,6 @@ function closeInfo() { background: color-mix(in srgb, var(--MI_THEME-infoBg) 65%, transparent); color: var(--MI_THEME-infoFg); border-radius: var(--MI-radius); - white-space: pre-wrap; z-index: 1; &.warn { diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 51836ce093..55efc3c193 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -114,7 +114,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA> </bdi> </div> - <MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" :note="appearNote" :maxNumber="16" @click.stop @mockUpdateMyReaction="emitUpdReaction"> + <MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" style="margin-top: 6px;" :note="appearNote" :maxNumber="16" @click.stop @mockUpdateMyReaction="emitUpdReaction"> <template #more> <MkA :to="`/notes/${appearNote.id}/reactions`" :class="[$style.reactionOmitted]">{{ i18n.ts.more }}</MkA> </template> diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 3c3136a705..488ee16e62 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -133,7 +133,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkTime :time="appearNote.createdAt" mode="detail" colored/> </MkA> </div> - <MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" :note="appearNote"/> + <MkReactionsViewer v-if="appearNote.reactionAcceptance !== 'likeOnly'" ref="reactionsViewer" style="margin-top: 6px;" :note="appearNote"/> <button class="_button" :class="$style.noteFooterButton" @click="reply()"> <i class="ti ti-arrow-back-up"></i> <p v-if="appearNote.repliesCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.repliesCount) }}</p> diff --git a/packages/frontend/src/components/MkNotes.vue b/packages/frontend/src/components/MkNotes.vue index 5edae908b0..602619402a 100644 --- a/packages/frontend/src/components/MkNotes.vue +++ b/packages/frontend/src/components/MkNotes.vue @@ -13,16 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <template #default="{ items: notes }"> - <component - :is="prefer.s.animation ? TransitionGroup : 'div'" - :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap, [$style.reverse]: pagination.reversed }]" - :enterActiveClass="$style.transition_x_enterActive" - :leaveActiveClass="$style.transition_x_leaveActive" - :enterFromClass="$style.transition_x_enterFrom" - :leaveToClass="$style.transition_x_leaveTo" - :moveClass=" $style.transition_x_move" - tag="div" - > + <div :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap, [$style.reverse]: pagination.reversed }]"> <template v-for="(note, i) in notes" :key="note.id"> <div v-if="note._shouldInsertAd_" :class="[$style.noteWithAd, { '_gaps': !noGap }]" :data-scroll-anchor="note.id"> <DynamicNote :class="$style.note" :note="note as Misskey.entities.Note" :withHardMute="true"/> @@ -32,20 +23,19 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <DynamicNote v-else :class="$style.note" :note="note as Misskey.entities.Note" :withHardMute="true" :data-scroll-anchor="note.id"/> </template> - </component> + </div> </template> </MkPagination> </template> <script lang="ts" setup> import * as Misskey from 'misskey-js'; -import { useTemplateRef, TransitionGroup } from 'vue'; +import { useTemplateRef } from 'vue'; import type { Paging } from '@/components/MkPagination.vue'; import DynamicNote from '@/components/DynamicNote.vue'; import MkPagination from '@/components/MkPagination.vue'; import { i18n } from '@/i18n.js'; import { infoImageUrl } from '@/instance.js'; -import { prefer } from '@/preferences.js'; const props = defineProps<{ pagination: Paging; @@ -61,20 +51,6 @@ defineExpose({ </script> <style lang="scss" module> -.transition_x_move, -.transition_x_enterActive, -.transition_x_leaveActive { - transition: opacity 0.3s cubic-bezier(0,.5,.5,1), transform 0.3s cubic-bezier(0,.5,.5,1) !important; -} -.transition_x_enterFrom, -.transition_x_leaveTo { - opacity: 0; - transform: translateY(-50%); -} -.transition_x_leaveActive { - position: absolute; -} - .reverse { display: flex; flex-direction: column-reverse; diff --git a/packages/frontend/src/components/MkNotificationSelectWindow.vue b/packages/frontend/src/components/MkNotificationSelectWindow.vue index d074dceb2f..bb01a008bd 100644 --- a/packages/frontend/src/components/MkNotificationSelectWindow.vue +++ b/packages/frontend/src/components/MkNotificationSelectWindow.vue @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only > <template #header>{{ i18n.ts.notificationSetting }}</template> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps_m"> <MkInfo>{{ i18n.ts.notificationSettingDesc }}</MkInfo> <div class="_buttons"> @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <MkSwitch v-for="ntype in notificationTypes" :key="ntype" v-model="typesMap[ntype].value">{{ i18n.ts._notification._types[ntype] }}</MkSwitch> </div> - </MkSpacer> + </div> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index d5b43cbf2e..a9e4704b24 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> </template> - <div :class="$style.root"> + <div :class="$style.root" class="_forceShrinkSpacer"> <StackingRouterView v-if="prefer.s['experimental.stackingRouterView']" :key="reloadCount" :router="windowRouter"/> <RouterView v-else :key="reloadCount" :router="windowRouter"/> </div> @@ -121,7 +121,6 @@ provideMetadataReceiver((metadataGetter) => { provideReactiveMetadata(pageMetadata); provide('shouldOmitHeaderTitle', true); provide('shouldHeaderThin', true); -provide(DI.forceSpacerMin, true); provide('shouldBackButton', false); const contextmenu = computed(() => ([{ diff --git a/packages/frontend/src/components/MkPasswordDialog.vue b/packages/frontend/src/components/MkPasswordDialog.vue index 2abf8669ed..826081ffe5 100644 --- a/packages/frontend/src/components/MkPasswordDialog.vue +++ b/packages/frontend/src/components/MkPasswordDialog.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only > <template #header>{{ i18n.ts.authentication }}</template> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div style="padding: 0 0 16px 0; text-align: center;"> <img src="/client-assets/locked_with_key_3d.png" alt="🔐" style="display: block; margin: 0 auto; width: 48px;"> <div style="margin-top: 16px;">{{ i18n.ts.authenticationRequiredToContinue }}</div> @@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton :disabled="(password ?? '') == '' || ($i.twoFactorEnabled && (token ?? '') == '')" type="submit" primary rounded style="margin: 0 auto;"><i class="ti ti-lock-open"></i> {{ i18n.ts.continue }}</MkButton> </div> </form> - </MkSpacer> + </div> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index e66a056a3f..494b61ca9d 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -182,7 +182,6 @@ if (!mock) { .root { display: inline-flex; height: 42px; - margin: 2px; padding: 0 6px; font-size: 1.5em; border-radius: var(--MI-radius-sm); diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue index 6b19f4a55c..70d0ddca0a 100644 --- a/packages/frontend/src/components/MkReactionsViewer.vue +++ b/packages/frontend/src/components/MkReactionsViewer.vue @@ -106,7 +106,7 @@ watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumbe display: flex; flex-wrap: wrap; align-items: center; - margin: 4px -2px 0 -2px; + gap: 4px; cursor: auto; /* not clickToOpen-able */ &:empty { diff --git a/packages/frontend/src/components/MkRemoteEmojiEditDialog.vue b/packages/frontend/src/components/MkRemoteEmojiEditDialog.vue index dc9bacf481..cb50df1743 100644 --- a/packages/frontend/src/components/MkRemoteEmojiEditDialog.vue +++ b/packages/frontend/src/components/MkRemoteEmojiEditDialog.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #header>:{{ name }}:</template> <div style="display: flex; flex-direction: column; min-height: 100%;"> - <MkSpacer :marginMin="20" :marginMax="28" style="flex-grow: 1;"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px; flex-grow: 1;"> <div class="_gaps_m"> <div v-if="imgUrl != null" :class="$style.imgs"> <div style="background: #000;" :class="$style.imgContainer"> @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #value>{{ license }}</template> </MkKeyValue> </div> - </MkSpacer> + </div> <div :class="$style.footer"> <MkButton primary rounded style="margin: 0 auto;" @click="done"> <i class="ti ti-plus"></i> {{ i18n.ts.import }} diff --git a/packages/frontend/src/components/MkRoleSelectDialog.vue b/packages/frontend/src/components/MkRoleSelectDialog.vue index fd56e4902c..6888824437 100644 --- a/packages/frontend/src/components/MkRoleSelectDialog.vue +++ b/packages/frontend/src/components/MkRoleSelectDialog.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only @closed="emit('closed')" > <template #header>{{ title }}</template> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <MkLoading v-if="fetching"/> <div v-else class="_gaps" :class="$style.root"> <div :class="$style.header"> @@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton @click="onCancelClicked">{{ i18n.ts.cancel }}</MkButton> </div> </div> - </MkSpacer> + </div> </MkModalWindow> </template> @@ -51,7 +51,6 @@ import MkInfo from '@/components/MkInfo.vue'; import MkRolePreview from '@/components/MkRolePreview.vue'; import { misskeyApi } from '@/utility/misskey-api.js'; import * as os from '@/os.js'; -import MkSpacer from '@/components/global/MkSpacer.vue'; import MkModalWindow from '@/components/MkModalWindow.vue'; import MkLoading from '@/components/global/MkLoading.vue'; diff --git a/packages/frontend/src/components/MkSchedulePostListDialog.vue b/packages/frontend/src/components/MkSchedulePostListDialog.vue index 0bcbb41192..41f366b082 100644 --- a/packages/frontend/src/components/MkSchedulePostListDialog.vue +++ b/packages/frontend/src/components/MkSchedulePostListDialog.vue @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only @close="cancel()" > <template #header>{{ i18n.ts.schedulePostList }}</template> - <MkSpacer :marginMin="14" :marginMax="16"> + <div class="_spacer" style="--MI_SPACER-min: 14px; --MI_SPACER-max: 16px;"> <MkPagination ref="paginationEl" :pagination="pagination"> <template #empty> <div class="_fullinfo"> @@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </template> </MkPagination> - </MkSpacer> + </div> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index b152ba81a6..365b23f4ce 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.banner"> <i class="ti ti-user-edit"></i> </div> - <MkSpacer :marginMin="20" :marginMax="32"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 32px;"> <form class="_gaps_m" autocomplete="new-password" @submit.prevent="onSubmit"> <MkInput v-if="instance.disableRegistration" v-model="invitationCode" type="text" :spellcheck="false" required> <template #label>{{ i18n.ts.invitationCode }}</template> @@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else>{{ i18n.ts.start }}</template> </MkButton> </form> - </MkSpacer> + </div> </div> </template> diff --git a/packages/frontend/src/components/MkSignupDialog.rules.vue b/packages/frontend/src/components/MkSignupDialog.rules.vue index f3d358c874..3034f2269b 100644 --- a/packages/frontend/src/components/MkSignupDialog.rules.vue +++ b/packages/frontend/src/components/MkSignupDialog.rules.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.banner"> <i class="ti ti-checklist"></i> </div> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps_m"> <div v-if="instance.disableRegistration || instance.federation !== 'all'" class="_gaps_s"> <MkInfo v-if="instance.disableRegistration" warn>{{ i18n.ts.invitationRequiredToRegister }}</MkInfo> @@ -59,7 +59,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton inline primary rounded gradate :disabled="!agreed" data-cy-signup-rules-continue @click="emit('done')">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> </div> </div> - </MkSpacer> + </div> </div> </template> diff --git a/packages/frontend/src/components/MkSystemWebhookEditor.vue b/packages/frontend/src/components/MkSystemWebhookEditor.vue index 86e755a3c3..cd72204fce 100644 --- a/packages/frontend/src/components/MkSystemWebhookEditor.vue +++ b/packages/frontend/src/components/MkSystemWebhookEditor.vue @@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <div style="display: flex; flex-direction: column; min-height: 100%;"> - <MkSpacer :marginMin="20" :marginMax="28" style="flex-grow: 1;"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px; flex-grow: 1;"> <MkLoading v-if="loading !== 0"/> <div v-else :class="$style.root" class="_gaps_m"> <MkInput v-model="title"> @@ -79,7 +79,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>{{ i18n.ts.enable }}</template> </MkSwitch> </div> - </MkSpacer> + </div> <div :class="$style.footer" class="_buttonsCenter"> <MkButton primary rounded :disabled="disableSubmitButton" @click="onSubmitClicked"> <i class="ti ti-check"></i> diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index 7b740167ec..32b2e1ae11 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -5,29 +5,55 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <MkPullToRefresh ref="prComponent" :refresher="() => reloadTimeline()"> - <MkNotes - v-if="paginationQuery" - ref="tlComponent" - :pagination="paginationQuery" - :noGap="!prefer.s.showGapBetweenNotesInTimeline" - @queue="emit('queue', $event)" - @status="prComponent?.setDisabled($event)" - /> + <MkPagination v-if="paginationQuery" ref="pagingComponent" :pagination="paginationQuery" @queue="emit('queue', $event)" @status="prComponent?.setDisabled($event)"> + <template #empty> + <div class="_fullinfo"> + <img :src="infoImageUrl" draggable="false"/> + <div>{{ i18n.ts.noNotes }}</div> + </div> + </template> + + <template #default="{ items: notes }"> + <component + :is="prefer.s.animation ? TransitionGroup : 'div'" + :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap, [$style.reverse]: paginationQuery.reversed }]" + :enterActiveClass="$style.transition_x_enterActive" + :leaveActiveClass="$style.transition_x_leaveActive" + :enterFromClass="$style.transition_x_enterFrom" + :leaveToClass="$style.transition_x_leaveTo" + :moveClass=" $style.transition_x_move" + tag="div" + > + <template v-for="(note, i) in notes" :key="note.id"> + <div v-if="note._shouldInsertAd_" :class="[$style.noteWithAd, { '_gaps': !noGap }]" :data-scroll-anchor="note.id"> + <MkNote :class="$style.note" :note="note" :withHardMute="true"/> + <div :class="$style.ad"> + <MkAd :preferForms="['horizontal', 'horizontal-big']"/> + </div> + </div> + <MkNote v-else :class="$style.note" :note="note" :withHardMute="true" :data-scroll-anchor="note.id"/> + </template> + </component> + </template> + </MkPagination> </MkPullToRefresh> </template> <script lang="ts" setup> -import { computed, watch, onUnmounted, provide, useTemplateRef } from 'vue'; +import { computed, watch, onUnmounted, provide, useTemplateRef, TransitionGroup } from 'vue'; import * as Misskey from 'misskey-js'; import type { BasicTimelineType } from '@/timelines.js'; import type { Paging } from '@/components/MkPagination.vue'; -import MkNotes from '@/components/MkNotes.vue'; import MkPullToRefresh from '@/components/MkPullToRefresh.vue'; import { useStream } from '@/stream.js'; import * as sound from '@/utility/sound.js'; import { $i } from '@/i.js'; import { instance } from '@/instance.js'; import { prefer } from '@/preferences.js'; +import MkNote from '@/components/MkNote.vue'; +import MkPagination from '@/components/MkPagination.vue'; +import { i18n } from '@/i18n.js'; +import { infoImageUrl } from '@/instance.js'; const props = withDefaults(defineProps<{ src: BasicTimelineType | 'mentions' | 'directs' | 'list' | 'antenna' | 'channel' | 'role'; @@ -71,12 +97,12 @@ type TimelineQueryType = { }; const prComponent = useTemplateRef('prComponent'); -const tlComponent = useTemplateRef('tlComponent'); +const pagingComponent = useTemplateRef('pagingComponent'); let tlNotesCount = 0; function prepend(note: Misskey.entities.Note) { - if (tlComponent.value == null) return; + if (pagingComponent.value == null) return; tlNotesCount++; @@ -84,7 +110,7 @@ function prepend(note: Misskey.entities.Note) { note._shouldInsertAd_ = true; } - tlComponent.value.pagingComponent?.prepend(note); + pagingComponent.value.prepend(note); emit('note'); @@ -96,6 +122,7 @@ function prepend(note: Misskey.entities.Note) { let connection: Misskey.ChannelConnection | null = null; let connection2: Misskey.ChannelConnection | null = null; let paginationQuery: Paging | null = null; +const noGap = !prefer.s.showGapBetweenNotesInTimeline; const stream = useStream(); @@ -290,11 +317,11 @@ onUnmounted(() => { function reloadTimeline() { return new Promise<void>((res) => { - if (tlComponent.value == null) return; + if (pagingComponent.value == null) return; tlNotesCount = 0; - tlComponent.value.pagingComponent?.reload().then(() => { + pagingComponent.value.reload().then(() => { res(); }); }); @@ -304,3 +331,56 @@ defineExpose({ reloadTimeline, }); </script> + +<style lang="scss" module> +.transition_x_move, +.transition_x_enterActive, +.transition_x_leaveActive { + transition: opacity 0.3s cubic-bezier(0,.5,.5,1), transform 0.3s cubic-bezier(0,.5,.5,1) !important; +} +.transition_x_enterFrom, +.transition_x_leaveTo { + opacity: 0; + transform: translateY(-50%); +} +.transition_x_leaveActive { + position: absolute; +} + +.reverse { + display: flex; + flex-direction: column-reverse; +} + +.root { + container-type: inline-size; + + &.noGap { + background: var(--MI_THEME-panel); + + .note { + border-bottom: solid 0.5px var(--MI_THEME-divider); + } + + .ad { + padding: 8px; + background-size: auto auto; + background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--MI_THEME-bg) 8px, var(--MI_THEME-bg) 14px); + border-bottom: solid 0.5px var(--MI_THEME-divider); + } + } + + &:not(.noGap) { + background: var(--MI_THEME-bg); + + .note { + background: var(--MI_THEME-panel); + border-radius: var(--MI-radius); + } + } +} + +.ad:empty { + display: none; +} +</style> diff --git a/packages/frontend/src/components/MkTokenGenerateWindow.vue b/packages/frontend/src/components/MkTokenGenerateWindow.vue index b449155edb..42cb6f1e82 100644 --- a/packages/frontend/src/components/MkTokenGenerateWindow.vue +++ b/packages/frontend/src/components/MkTokenGenerateWindow.vue @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only > <template #header>{{ title || i18n.ts.generateAccessToken }}</template> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps_m"> <div v-if="information"> <MkInfo warn>{{ information }}</MkInfo> @@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> </div> - </MkSpacer> + </div> </MkModalWindow> </template> diff --git a/packages/frontend/src/components/MkTutorialDialog.vue b/packages/frontend/src/components/MkTutorialDialog.vue index 92f71b01af..d6abbf6504 100644 --- a/packages/frontend/src/components/MkTutorialDialog.vue +++ b/packages/frontend/src/components/MkTutorialDialog.vue @@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-if="page === 0"> <div :class="$style.centerPage"> <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-confetti" style="display: block; margin: auto; font-size: 3em; color: var(--MI_THEME-accent);"></i> <div style="font-size: 120%;">{{ i18n.ts._initialTutorial._landing.title }}</div> @@ -37,15 +37,15 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" @click="page++">{{ i18n.ts._initialTutorial.launchTutorial }} <i class="ti ti-arrow-right"></i></MkButton> <MkButton style="margin: 0 auto;" transparent rounded @click="close(true)">{{ i18n.ts.close }}</MkButton> </div> - </MkSpacer> + </div> </div> </template> <template v-else-if="page === 1"> <div style="height: 100cqh; overflow: auto;"> <div :class="$style.pageRoot"> - <MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;" :class="$style.pageMain"> <XNote phase="aboutNote"/> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton v-if="initialPage !== 1" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -58,12 +58,12 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else-if="page === 2"> <div style="height: 100cqh; overflow: auto;"> <div :class="$style.pageRoot"> - <MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;" :class="$style.pageMain"> <div class="_gaps"> <XNote phase="howToReact" @reacted="isReactionTutorialPushed = true"/> <div v-if="!isReactionTutorialPushed">{{ i18n.ts._initialTutorial._reaction.reactToContinue }}</div> </div> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton v-if="initialPage !== 2" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -76,9 +76,9 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else-if="page === 3"> <div style="height: 100cqh; overflow: auto;"> <div :class="$style.pageRoot"> - <MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;" :class="$style.pageMain"> <XTimeline/> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton v-if="initialPage !== 3" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -91,9 +91,9 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else-if="page === 4"> <div style="height: 100cqh; overflow: auto;"> <div :class="$style.pageRoot"> - <MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;" :class="$style.pageMain"> <XPostNote/> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton v-if="initialPage !== 3" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -106,12 +106,12 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else-if="page === 5"> <div style="height: 100cqh; overflow: auto;"> <div :class="$style.pageRoot"> - <MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;" :class="$style.pageMain"> <div class="_gaps"> <XSensitive @succeeded="isSensitiveTutorialSucceeded = true"/> <div v-if="!isSensitiveTutorialSucceeded">{{ i18n.ts._initialTutorial._howToMakeAttachmentsSensitive.doItToContinue }}</div> </div> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton v-if="initialPage !== 2" rounded @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -124,7 +124,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else-if="page === 6"> <div :class="$style.centerPage"> <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--MI_THEME-accent);"></i> <div style="font-size: 120%;">{{ i18n.ts._initialTutorial._done.title }}</div> @@ -139,7 +139,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton rounded primary gradate @click="close(false)">{{ i18n.ts.close }}</MkButton> </div> </div> - </MkSpacer> + </div> </div> </template> </Transition> diff --git a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue index 34e86444ad..aaefa5036a 100644 --- a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue +++ b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else #header>New announcement</template> <div> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps_m"> <MkInput v-model="title"> <template #label>{{ i18n.ts.title }}</template> @@ -41,7 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only </MkSwitch> <MkButton v-if="announcement" danger @click="del()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> </div> - </MkSpacer> + </div> <div :class="$style.footer"> <MkButton primary rounded style="margin: 0 auto;" @click="done"><i class="ti ti-check"></i> {{ props.announcement ? i18n.ts.update : i18n.ts.create }}</MkButton> </div> diff --git a/packages/frontend/src/components/MkUserSetupDialog.vue b/packages/frontend/src/components/MkUserSetupDialog.vue index 767f5c591a..82214ed5a5 100644 --- a/packages/frontend/src/components/MkUserSetupDialog.vue +++ b/packages/frontend/src/components/MkUserSetupDialog.vue @@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-if="page === 0"> <div :class="$style.centerPage"> <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-confetti" style="display: block; margin: auto; font-size: 3em; color: var(--MI_THEME-accent);"></i> <div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.accountCreated }}</div> @@ -41,15 +41,15 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton primary rounded gradate style="margin: 16px auto 0 auto;" data-cy-user-setup-continue @click="page++">{{ i18n.ts._initialAccountSetting.profileSetting }} <i class="ti ti-arrow-right"></i></MkButton> <MkButton style="margin: 0 auto;" transparent rounded @click="later(true)">{{ i18n.ts.later }}</MkButton> </div> - </MkSpacer> + </div> </div> </template> <template v-else-if="page === 1"> <div style="height: 100cqh; overflow: auto;"> <div :class="$style.pageRoot"> - <MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;" :class="$style.pageMain"> <XProfile/> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -62,9 +62,9 @@ SPDX-License-Identifier: AGPL-3.0-only <template v-else-if="page === 2"> <div style="height: 100cqh; overflow: auto;"> <div :class="$style.pageRoot"> - <MkSpacer :marginMin="20" :marginMax="28" :class="$style.pageMain"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;" :class="$style.pageMain"> <XPrivacy/> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -76,9 +76,9 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <template v-else-if="page === 3"> <div style="height: 100cqh; overflow: auto;"> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <XFollow/> - </MkSpacer> + </div> <div :class="$style.pageFooter"> <div class="_buttonsCenter"> <MkButton rounded data-cy-user-setup-back @click="page--"><i class="ti ti-arrow-left"></i> {{ i18n.ts.goBack }}</MkButton> @@ -89,7 +89,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <template v-else-if="page === 4"> <div :class="$style.centerPage"> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-bell-ringing-2" style="display: block; margin: auto; font-size: 3em; color: var(--MI_THEME-accent);"></i> <div style="font-size: 120%;">{{ i18n.ts.pushNotification }}</div> @@ -100,13 +100,13 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton primary rounded gradate data-cy-user-setup-continue @click="page++">{{ i18n.ts.continue }} <i class="ti ti-arrow-right"></i></MkButton> </div> </div> - </MkSpacer> + </div> </div> </template> <template v-else-if="page === 5"> <div :class="$style.centerPage"> <MkAnimBg style="position: absolute; top: 0;" :scale="1.5"/> - <MkSpacer :marginMin="20" :marginMax="28"> + <div class="_spacer" style="--MI_SPACER-min: 20px; --MI_SPACER-max: 28px;"> <div class="_gaps" style="text-align: center;"> <i class="ti ti-check" style="display: block; margin: auto; font-size: 3em; color: var(--MI_THEME-accent);"></i> <div style="font-size: 120%;">{{ i18n.ts._initialAccountSetting.initialAccountSettingCompleted }}</div> @@ -119,7 +119,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkButton rounded primary data-cy-user-setup-continue @click="setupComplete()">{{ i18n.ts.close }}</MkButton> </div> </div> - </MkSpacer> + </div> </div> </template> </Transition> @@ -147,7 +147,7 @@ const emit = defineEmits<{ }>(); const dialog = useTemplateRef('dialog'); - + const page = ref(store.s.accountSetupWizard); watch(page, () => { diff --git a/packages/frontend/src/components/SkMfmWindow.vue b/packages/frontend/src/components/SkMfmWindow.vue index a628758a0f..14d309b7ba 100644 --- a/packages/frontend/src/components/SkMfmWindow.vue +++ b/packages/frontend/src/components/SkMfmWindow.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only MFM Cheatsheet </template> <MkStickyContainer> - <MkSpacer :contentMax="800"> + <div class="_spacer" style="--MI_SPACER-w: 800px;"> <div class="mfm-cheat-sheet"> <div>{{ i18n.ts._mfm.intro }}</div> <br/> @@ -402,7 +402,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> </div> - </MkSpacer> + </div> </MkStickyContainer> </MkWindow> </template> diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 42bb49e8d9..c939f0b44e 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -49,19 +49,12 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </template> -<script lang="ts" setup> -import { onMounted, onUnmounted, ref, inject, useTemplateRef, computed } from 'vue'; -import { scrollToTop } from '@@/js/scroll.js'; -import XTabs from './MkPageHeader.tabs.vue'; -import type { Tab } from './MkPageHeader.tabs.vue'; +<script lang="ts"> import type { PageHeaderItem } from '@/types/page-header.js'; import type { PageMetadata } from '@/page.js'; -import { globalEvents } from '@/events.js'; -import { openAccountMenu as openAccountMenu_ } from '@/accounts.js'; -import { $i } from '@/i.js'; -import { DI } from '@/di.js'; +import type { Tab } from './MkPageHeader.tabs.vue'; -const props = withDefaults(defineProps<{ +export type PageHeaderProps = { overridePageMetadata?: PageMetadata; tabs?: Tab[]; tab?: string; @@ -70,7 +63,19 @@ const props = withDefaults(defineProps<{ hideTitle?: boolean; displayMyAvatar?: boolean; displayBackButton?: boolean; -}>(), { +}; +</script> + +<script lang="ts" setup> +import { onMounted, onUnmounted, ref, inject, useTemplateRef, computed } from 'vue'; +import { scrollToTop } from '@@/js/scroll.js'; +import XTabs from './MkPageHeader.tabs.vue'; +import { globalEvents } from '@/events.js'; +import { openAccountMenu as openAccountMenu_ } from '@/accounts.js'; +import { $i } from '@/i.js'; +import { DI } from '@/di.js'; + +const props = withDefaults(defineProps<PageHeaderProps>(), { tabs: () => ([] as Tab[]), }); diff --git a/packages/frontend/src/components/global/MkSpacer.vue b/packages/frontend/src/components/global/MkSpacer.vue deleted file mode 100644 index c3bc37cb92..0000000000 --- a/packages/frontend/src/components/global/MkSpacer.vue +++ /dev/null @@ -1,58 +0,0 @@ -<!-- -SPDX-FileCopyrightText: syuilo and misskey-project -SPDX-License-Identifier: AGPL-3.0-only ---> - -<template> -<div :class="[$style.root, { [$style.rootMin]: forceSpacerMin }]"> - <div :class="$style.content"> - <slot></slot> - </div> -</div> -</template> - -<script lang="ts" setup> -import { inject } from 'vue'; -import { deviceKind } from '@/utility/device-kind.js'; -import { DI } from '@/di.js'; - -const props = withDefaults(defineProps<{ - contentMax?: number | null; - marginMin?: number; - marginMax?: number; -}>(), { - contentMax: null, - marginMin: 12, - marginMax: 24, -}); - -const forceSpacerMin = inject(DI.forceSpacerMin, false) || deviceKind === 'smartphone'; -</script> - -<style lang="scss" module> -.root { - box-sizing: border-box; - width: 100%; -} -.rootMin { - padding: v-bind('props.marginMin + "px"') !important; -} - -.content { - margin: 0 auto; - max-width: v-bind('props.contentMax + "px"'); - container-type: inline-size; -} - -@container (max-width: 450px) { - .root { - padding: v-bind('props.marginMin + "px"'); - } -} - -@container (min-width: 451px) { - .root { - padding: v-bind('props.marginMax + "px"'); - } -} -</style> diff --git a/packages/frontend/src/components/global/PageWithHeader.vue b/packages/frontend/src/components/global/PageWithHeader.vue index 85e61fd532..58c222038a 100644 --- a/packages/frontend/src/components/global/PageWithHeader.vue +++ b/packages/frontend/src/components/global/PageWithHeader.vue @@ -6,9 +6,12 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div ref="rootEl" :class="[$style.root, reversed ? '_pageScrollableReversed' : '_pageScrollable']"> <MkStickyContainer> - <template #header><MkPageHeader v-model:tab="tab" :actions="actions" :tabs="tabs" :displayBackButton="displayBackButton"/></template> + <template #header><MkPageHeader v-model:tab="tab" v-bind="pageHeaderProps"/></template> <div :class="$style.body"> - <slot></slot> + <MkSwiper v-if="swipable && (props.tabs?.length ?? 1) > 1" v-model:tab="tab" :class="$style.swiper" :tabs="props.tabs"> + <slot></slot> + </MkSwiper> + <slot v-else></slot> </div> <template #footer><slot name="footer"></slot></template> </MkStickyContainer> @@ -16,22 +19,24 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { useTemplateRef } from 'vue'; +import { computed, useTemplateRef } from 'vue'; import { scrollInContainer } from '@@/js/scroll.js'; -import type { PageHeaderItem } from '@/types/page-header.js'; -import type { Tab } from './MkPageHeader.tabs.vue'; +import type { PageHeaderProps } from './MkPageHeader.vue'; import { useScrollPositionKeeper } from '@/use/use-scroll-position-keeper.js'; +import MkSwiper from '@/components/MkSwiper.vue'; +import { useRouter } from '@/router.js'; -const props = withDefaults(defineProps<{ - tabs?: Tab[]; - actions?: PageHeaderItem[] | null; - thin?: boolean; - hideTitle?: boolean; - displayMyAvatar?: boolean; +const props = withDefaults(defineProps<PageHeaderProps & { reversed?: boolean; - displayBackButton?: boolean; + swipable?: boolean; }>(), { - tabs: () => ([] as Tab[]), + reversed: false, + swipable: true, +}); + +const pageHeaderProps = computed(() => { + const { reversed, ...rest } = props; + return rest; }); const tab = defineModel<string>('tab'); @@ -39,10 +44,18 @@ const rootEl = useTemplateRef('rootEl'); useScrollPositionKeeper(rootEl); +const router = useRouter(); + +router.useListener('same', () => { + scrollToTop(); +}); + +function scrollToTop() { + if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'smooth' }); +} + defineExpose({ - scrollToTop: () => { - if (rootEl.value) scrollInContainer(rootEl.value, { top: 0, behavior: 'smooth' }); - }, + scrollToTop, }); </script> @@ -51,7 +64,7 @@ defineExpose({ } -.body { +.body, .swiper { min-height: calc(100cqh - (var(--MI-stickyTop, 0px) + var(--MI-stickyBottom, 0px))); } </style> diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 78ac6900a3..27f7b18559 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div ref="rootEl" class="_pageContainer" :class="$style.root"> +<div class="_pageContainer" :class="$style.root"> <KeepAlive :max="prefer.s.numberOfPageCache"> <Suspense :timeout="0"> <component :is="currentPageComponent" :key="key" v-bind="Object.fromEntries(currentPageProps)"/> @@ -42,37 +42,6 @@ provide(DI.viewId, viewId); const currentDepth = inject(DI.routerCurrentDepth, 0); provide(DI.routerCurrentDepth, currentDepth + 1); -const rootEl = useTemplateRef('rootEl'); -onMounted(() => { - if (prefer.s.animation) { - rootEl.value.style.viewTransitionName = viewId; // view-transition-nameにcss varが使えないっぽいため直接代入 - } -}); - -// view-transition-newなどの<pt-name-selector>にはcss varが使えず、v-bindできないため直接スタイルを生成 -const viewTransitionStylesTag = window.document.createElement('style'); -viewTransitionStylesTag.textContent = ` -@keyframes ${viewId}-old { - to { transform: scale(0.95); opacity: 0; } -} - -@keyframes ${viewId}-new { - from { transform: scale(0.95); opacity: 0; } -} - -::view-transition-old(${viewId}) { - animation-duration: 0.2s; - animation-name: ${viewId}-old; -} - -::view-transition-new(${viewId}) { - animation-duration: 0.2s; - animation-name: ${viewId}-new; -} -`; - -window.document.head.appendChild(viewTransitionStylesTag); - const current = router.current!; const currentPageComponent = shallowRef('component' in current.route ? current.route.component : MkLoadingPage); const currentPageProps = ref(current.props); @@ -90,18 +59,7 @@ router.useListener('change', ({ resolved }) => { currentRoutePath = resolved.route.path; } - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (prefer.s.animation && window.document.startViewTransition) { - window.document.startViewTransition(() => new Promise((res) => { - _(); - nextTick(() => { - res(); - //setTimeout(res, 100); - }); - })); - } else { - _(); - } + _(); }); </script> diff --git a/packages/frontend/src/components/grid/MkGrid.vue b/packages/frontend/src/components/grid/MkGrid.vue index c37f3df0d3..f80f037285 100644 --- a/packages/frontend/src/components/grid/MkGrid.vue +++ b/packages/frontend/src/components/grid/MkGrid.vue @@ -38,7 +38,6 @@ SPDX-License-Identifier: AGPL-3.0-only :setting="rowSetting" :bus="bus" :using="row.using" - :class="[lastLine === row.index ? 'last_row' : '']" @operation:beginEdit="onCellEditBegin" @operation:endEdit="onCellEditEnd" @change:value="onChangeCellValue" @@ -1301,8 +1300,6 @@ onMounted(() => { </style> <style lang="scss"> -$borderSetting: solid 0.5px var(--MI_THEME-divider); - // 配下コンポーネントを含めて一括してコントロールするため、scopedもmoduleも使用できない .mk_grid_border { --rootBorderSetting: none; @@ -1310,66 +1307,39 @@ $borderSetting: solid 0.5px var(--MI_THEME-divider); border-spacing: 0; - &.mk_grid_root_border { - --rootBorderSetting: #{$borderSetting}; - } - &.mk_grid_root_rounded { --borderRadius: var(--MI-radius); } .mk_grid_thead { + position: sticky; + z-index: 1; + left: 0; + top: 0; + -webkit-backdrop-filter: var(--MI-blur, blur(8px)); + backdrop-filter: var(--MI-blur, blur(20px)); + background: color(from var(--MI_THEME-bg) srgb r g b / 0.5); + .mk_grid_tr { .mk_grid_th { - border-left: $borderSetting; - border-top: var(--rootBorderSetting); - &:first-child { - // 左上セル - border-left: var(--rootBorderSetting); - border-top-left-radius: var(--borderRadius); - } - - &:last-child { - // 右上セル - border-top-right-radius: var(--borderRadius); - border-right: var(--rootBorderSetting); - } } } } .mk_grid_tbody { .mk_grid_tr { - .mk_grid_td, .mk_grid_th { - border-left: $borderSetting; - border-top: $borderSetting; - - &:first-child { - // 左端の列 - border-left: var(--rootBorderSetting); - } + &:nth-child(odd) { + background: var(--MI_THEME-panel); + } - &:last-child { - // 一番右端の列 - border-right: var(--rootBorderSetting); - } + &:nth-child(even) { + background: var(--MI_THEME-bg); } - } - .last_row { .mk_grid_td, .mk_grid_th { - // 一番下の行 - border-bottom: var(--rootBorderSetting); - - &:first-child { - // 左下セル - border-bottom-left-radius: var(--borderRadius); - } - - &:last-child { - // 右下セル - border-bottom-right-radius: var(--borderRadius); + &:hover { + box-shadow: 0 0 0 1px var(--MI_THEME-divider) inset; } } } diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index 34cf598b84..ec6ea7c569 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -22,7 +22,6 @@ import MkLoading from './global/MkLoading.vue'; import MkError from './global/MkError.vue'; import MkAd from './global/MkAd.vue'; import MkPageHeader from './global/MkPageHeader.vue'; -import MkSpacer from './global/MkSpacer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue'; import MkLazy from './global/MkLazy.vue'; import PageWithHeader from './global/PageWithHeader.vue'; @@ -60,7 +59,6 @@ export const components = { MkError: MkError, MkAd: MkAd, MkPageHeader: MkPageHeader, - MkSpacer: MkSpacer, MkStickyContainer: MkStickyContainer, MkLazy: MkLazy, PageWithHeader: PageWithHeader, @@ -92,7 +90,6 @@ declare module '@vue/runtime-core' { MkError: typeof MkError; MkAd: typeof MkAd; MkPageHeader: typeof MkPageHeader; - MkSpacer: typeof MkSpacer; MkStickyContainer: typeof MkStickyContainer; MkLazy: typeof MkLazy; PageWithHeader: typeof PageWithHeader; |