diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2026-01-07 21:46:03 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-07 21:46:03 +0900 |
| commit | 8c5572dd3ba11104493d8386fe56cb6ff96cfc56 (patch) | |
| tree | 440ca5048723e10258ad84729f095b60b2d4fe70 /packages/frontend/src/pages/settings | |
| parent | Update README.md (diff) | |
| download | misskey-8c5572dd3ba11104493d8386fe56cb6ff96cfc56.tar.gz misskey-8c5572dd3ba11104493d8386fe56cb6ff96cfc56.tar.bz2 misskey-8c5572dd3ba11104493d8386fe56cb6ff96cfc56.zip | |
enhance(frontend): remove vuedraggable (#17073)
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* Update page-editor.blocks.vue
* Update MkDraggable.vue
* refactor
* refactor
* ✌️
* refactor
* Update MkDraggable.vue
* ios
* 🎨
* 🎨
Diffstat (limited to 'packages/frontend/src/pages/settings')
| -rw-r--r-- | packages/frontend/src/pages/settings/emoji-palette.palette.vue | 25 | ||||
| -rw-r--r-- | packages/frontend/src/pages/settings/navbar.vue | 27 | ||||
| -rw-r--r-- | packages/frontend/src/pages/settings/profile.vue | 32 |
3 files changed, 37 insertions, 47 deletions
diff --git a/packages/frontend/src/pages/settings/emoji-palette.palette.vue b/packages/frontend/src/pages/settings/emoji-palette.palette.vue index b624d424f3..0282f62fb8 100644 --- a/packages/frontend/src/pages/settings/emoji-palette.palette.vue +++ b/packages/frontend/src/pages/settings/emoji-palette.palette.vue @@ -18,19 +18,18 @@ SPDX-License-Identifier: AGPL-3.0-only <div> <div v-panel style="border-radius: 6px;"> - <Sortable - v-model="emojis" + <MkDraggable + :modelValue="emojis.map(emoji => ({ id: emoji, emoji }))" + direction="horizontal" :class="$style.emojis" - :itemKey="item => item" - :animation="150" - :delay="100" - :delayOnTouchOnly="true" - :group="{ name: 'SortableEmojiPalettes' }" + group="emojiPalettes" + @update:modelValue="v => emojis = v.map(x => x.emoji)" > - <template #item="{element}"> - <button class="_button" :class="$style.emojisItem" @click="remove(element, $event)"> - <MkCustomEmoji v-if="element[0] === ':'" :name="element" :normal="true" :fallbackToImage="true"/> - <MkEmoji v-else :emoji="element" :normal="true"/> + <template #default="{ item }"> + <button class="_button" :class="$style.emojisItem" @click="remove(item.emoji, $event)"> + <!-- pointer-eventsをnoneにしておかないとiOSなどでドラッグしたときに画像の方に判定が持ってかれる --> + <MkCustomEmoji v-if="item.emoji[0] === ':'" style="pointer-events: none;" :name="item.emoji" :normal="true" :fallbackToImage="true"/> + <MkEmoji v-else style="pointer-events: none;" :emoji="item.emoji" :normal="true"/> </button> </template> <template #footer> @@ -38,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only <i class="ti ti-plus"></i> </button> </template> - </Sortable> + </MkDraggable> </div> <div :class="$style.editorCaption">{{ i18n.ts.reactionSettingDescription2 }}</div> </div> @@ -47,7 +46,6 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch } from 'vue'; -import Sortable from 'vuedraggable'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; @@ -55,6 +53,7 @@ import { deepClone } from '@/utility/clone.js'; import MkCustomEmoji from '@/components/global/MkCustomEmoji.vue'; import MkEmoji from '@/components/global/MkEmoji.vue'; import MkFolder from '@/components/MkFolder.vue'; +import MkDraggable from '@/components/MkDraggable.vue'; import { copyToClipboard } from '@/utility/copy-to-clipboard.js'; const props = defineProps<{ diff --git a/packages/frontend/src/pages/settings/navbar.vue b/packages/frontend/src/pages/settings/navbar.vue index baa8fdc967..880e4321ed 100644 --- a/packages/frontend/src/pages/settings/navbar.vue +++ b/packages/frontend/src/pages/settings/navbar.vue @@ -9,25 +9,21 @@ SPDX-License-Identifier: AGPL-3.0-only <FormSlot> <template #label>{{ i18n.ts.navbar }}</template> <MkContainer :showHeader="false"> - <Sortable + <MkDraggable v-model="items" - itemKey="id" - :animation="150" - :handle="'.' + $style.itemHandle" - @start="e => e.item.classList.add('active')" - @end="e => e.item.classList.remove('active')" + direction="vertical" > - <template #item="{element,index}"> + <template #default="{ item }"> <div - v-if="element.type === '-' || navbarItemDef[element.type]" + v-if="item.type === '-' || navbarItemDef[item.type]" :class="$style.item" > <button class="_button" :class="$style.itemHandle"><i class="ti ti-menu"></i></button> - <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[element.type]?.icon]"></i><span :class="$style.itemText">{{ navbarItemDef[element.type]?.title ?? i18n.ts.divider }}</span> - <button class="_button" :class="$style.itemRemove" @click="removeItem(index)"><i class="ti ti-x"></i></button> + <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item.type]?.icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item.type]?.title ?? i18n.ts.divider }}</span> + <button class="_button" :class="$style.itemRemove" @click="removeItem(item.id)"><i class="ti ti-x"></i></button> </div> </template> - </Sortable> + </MkDraggable> </MkContainer> </FormSlot> <div class="_buttons"> @@ -54,13 +50,14 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, defineAsyncComponent, ref, watch } from 'vue'; +import { computed, ref } from 'vue'; import MkRadios from '@/components/MkRadios.vue'; import MkButton from '@/components/MkButton.vue'; import FormSlot from '@/components/form/slot.vue'; import MkContainer from '@/components/MkContainer.vue'; import MkSwitch from '@/components/MkSwitch.vue'; import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue'; +import MkDraggable from '@/components/MkDraggable.vue'; import * as os from '@/os.js'; import { navbarItemDef } from '@/navbar.js'; import { store } from '@/store.js'; @@ -70,8 +67,6 @@ import { prefer } from '@/preferences.js'; import { getInitialPrefValue } from '@/preferences/manager.js'; import { genId } from '@/utility/id.js'; -const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default)); - const items = ref(prefer.s.menu.map(x => ({ id: genId(), type: x, @@ -98,8 +93,8 @@ async function addItem() { }]; } -function removeItem(index: number) { - items.value.splice(index, 1); +function removeItem(itemId: string) { + items.value = items.value.filter(i => i.id !== itemId); } function save() { diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index 8e4c39c8bb..27a1ed279b 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -75,30 +75,27 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.metadataRoot" class="_gaps_s"> <MkInfo>{{ i18n.ts._profile.verifiedLinkDescription }}</MkInfo> - <Sortable + <MkDraggable v-model="fields" - class="_gaps_s" - itemKey="id" - :animation="150" - :handle="'.' + $style.dragItemHandle" - @start="e => e.item.classList.add('active')" - @end="e => e.item.classList.remove('active')" + direction="vertical" + withGaps + manualDragStart > - <template #item="{element, index}"> + <template #default="{ item, dragStart }"> <div v-panel :class="$style.fieldDragItem"> - <button v-if="!fieldEditMode" class="_button" :class="$style.dragItemHandle" tabindex="-1"><i class="ti ti-menu"></i></button> - <button v-if="fieldEditMode" :disabled="fields.length <= 1" class="_button" :class="$style.dragItemRemove" @click="deleteField(index)"><i class="ti ti-x"></i></button> + <button v-if="!fieldEditMode" class="_button" :class="$style.dragItemHandle" tabindex="-1" :draggable="true" @dragstart.stop="dragStart"><i class="ti ti-menu"></i></button> + <button v-if="fieldEditMode" :disabled="fields.length <= 1" class="_button" :class="$style.dragItemRemove" @click="deleteField(item.id)"><i class="ti ti-x"></i></button> <div :class="$style.dragItemForm"> <FormSplit :minWidth="200"> - <MkInput v-model="element.name" small :placeholder="i18n.ts._profile.metadataLabel"> + <MkInput v-model="item.name" small :placeholder="i18n.ts._profile.metadataLabel"> </MkInput> - <MkInput v-model="element.value" small :placeholder="i18n.ts._profile.metadataContent"> + <MkInput v-model="item.value" small :placeholder="i18n.ts._profile.metadataContent"> </MkInput> </FormSplit> </div> </div> </template> - </Sortable> + </MkDraggable> </div> </MkFolder> <template #caption>{{ i18n.ts._profile.metadataDescription }}</template> @@ -165,7 +162,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { computed, reactive, ref, watch, defineAsyncComponent } from 'vue'; +import { computed, reactive, ref, watch } from 'vue'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkSwitch from '@/components/MkSwitch.vue'; @@ -174,6 +171,7 @@ import FormSplit from '@/components/form/split.vue'; import MkFolder from '@/components/MkFolder.vue'; import FormSlot from '@/components/form/slot.vue'; import FormLink from '@/components/form/link.vue'; +import MkDraggable from '@/components/MkDraggable.vue'; import { chooseDriveFile } from '@/utility/drive.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; @@ -188,8 +186,6 @@ import { genId } from '@/utility/id.js'; const $i = ensureSignin(); -const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default)); - const reactionAcceptance = store.model('reactionAcceptance'); function assertVaildLang(lang: string | null): lang is keyof typeof langmap { @@ -228,8 +224,8 @@ while (fields.value.length < 4) { addField(); } -function deleteField(index: number) { - fields.value.splice(index, 1); +function deleteField(itemId: string) { + fields.value = fields.value.filter(f => f.id !== itemId); } function saveFields() { |