mirror of
https://github.com/kokonect-link/cherrypick
synced 2024-11-23 22:56:53 +09:00
feat: Improved navigation bar editing experience
This commit is contained in:
parent
1d5434d5f8
commit
9570090daf
@ -29,6 +29,7 @@
|
||||
- 클라이언트: 모바일 환경에서 로그인 페이지 디자인 개선
|
||||
- 클라이언트: 타임라인 전환시 맨 위로 이동하도록 변경
|
||||
- 클라이언트: 위젯 위치 변경 방식 개선
|
||||
- 클라이언트: 네비게이션 바 편집 환경 개선
|
||||
|
||||
### Bugfixes
|
||||
- 클라이언트: 채팅방에서 메시지를 입력하고 있을 때 움직이지 않는 온점(.)이 표시되는 문제
|
||||
|
@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<div class="_formRoot">
|
||||
<FormTextarea v-model="items" tall manual-save class="_formBlock">
|
||||
<template #label>{{ i18n.ts.navbar }}</template>
|
||||
<template #caption><button class="_textButton" @click="addItem">{{ i18n.ts.addItem }}</button></template>
|
||||
</FormTextarea>
|
||||
|
||||
<FormRadios v-model="menuDisplay" class="_formBlock">
|
||||
<template #label>{{ i18n.ts.display }}</template>
|
||||
<option value="sideFull">{{ i18n.ts._menuDisplay.sideFull }}</option>
|
||||
@ -13,12 +8,30 @@
|
||||
<!-- <MkRadio v-model="menuDisplay" value="hide" disabled>{{ i18n.ts._menuDisplay.hide }}</MkRadio>--> <!-- TODO: サイドバーを完全に隠せるようにすると、別途ハンバーガーボタンのようなものをUIに表示する必要があり面倒 -->
|
||||
</FormRadios>
|
||||
|
||||
<div class="asdiokco _formItem _formPanel">
|
||||
<XDraggable class="draggable" v-model="items" :item-key="item => item" animation="150" delay="100" delay-on-touch-only="true">
|
||||
<template #item="{element: item}">
|
||||
<div class="item">
|
||||
<i v-if="!item.startsWith('-:')" :class="navbarItemDef[item].icon" />
|
||||
<template v-if="item.startsWith('-:')">
|
||||
<i class="fas fa-minus" />
|
||||
<span v-text="$ts.divider"/>
|
||||
</template>
|
||||
<span v-else v-text="$t(navbarItemDef[item] ? navbarItemDef[item].title : item)"/>
|
||||
<div class="del" @click="del(item)"><i class="fas fa-times" /></div>
|
||||
</div>
|
||||
</template>
|
||||
</XDraggable>
|
||||
</div>
|
||||
|
||||
<FormButton class="_formBlock" @click="addItem"><i class="fas fa-plus"></i> {{ i18n.ts.addItem }}</FormButton>
|
||||
<FormButton v-if="isChanged" class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton>
|
||||
<FormButton danger class="_formBlock" @click="reset()"><i class="fas fa-redo"></i> {{ i18n.ts.default }}</FormButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { computed, defineAsyncComponent, ref, watch } from 'vue';
|
||||
import FormTextarea from '@/components/form/textarea.vue';
|
||||
import FormRadios from '@/components/form/radios.vue';
|
||||
import FormButton from '@/components/MkButton.vue';
|
||||
@ -28,12 +41,19 @@ import { defaultStore } from '@/store';
|
||||
import { unisonReload } from '@/scripts/unison-reload';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
const items = ref(defaultStore.state.menu.join('\n'));
|
||||
const XDraggable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
|
||||
|
||||
const split = computed(() => items.value.trim().split('\n').filter(x => x.trim() !== ''));
|
||||
// const items = ref(defaultStore.state.menu.join('\n'));
|
||||
const items = ref([]);
|
||||
items.value = defaultStore.state.menu.map(it => it === '-' ? '-:' + uuid() : it);
|
||||
|
||||
// const split = computed(() => items.value.trim().split('\n').filter(x => x.trim() !== ''));
|
||||
const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay'));
|
||||
|
||||
let isChanged = false;
|
||||
|
||||
async function reloadAsk() {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'info',
|
||||
@ -51,25 +71,33 @@ async function addItem() {
|
||||
items: [...menu.map(k => ({
|
||||
value: k, text: i18n.ts[navbarItemDef[k].title],
|
||||
})), {
|
||||
value: '-', text: i18n.ts.divider,
|
||||
value: '-:' + uuid(), text: i18n.ts.divider,
|
||||
}],
|
||||
});
|
||||
if (canceled) return;
|
||||
items.value = [...split.value, item].join('\n');
|
||||
items.value = [...items.value, item];
|
||||
}
|
||||
|
||||
async function del(item) {
|
||||
items.value = items.value.filter(it => it !== item);
|
||||
}
|
||||
|
||||
async function save() {
|
||||
defaultStore.set('menu', split.value);
|
||||
// defaultStore.set('menu', split.value);
|
||||
defaultStore.set('menu', items.value.map(it => it.startsWith('-:') ? '-' : it));
|
||||
await reloadAsk();
|
||||
}
|
||||
|
||||
function reset() {
|
||||
defaultStore.reset('menu');
|
||||
items.value = defaultStore.state.menu.join('\n');
|
||||
// items.value = defaultStore.state.menu.join('\n');
|
||||
items.value = defaultStore.state.menu.map(it => it === '-' ? '-:' + uuid() : it);
|
||||
}
|
||||
|
||||
watch(items, async () => {
|
||||
await save();
|
||||
isChanged = true;
|
||||
}, {
|
||||
deep: true,
|
||||
});
|
||||
|
||||
watch(menuDisplay, async () => {
|
||||
@ -85,3 +113,41 @@ definePageMetadata({
|
||||
icon: 'fas fa-list-ul',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.asdiokco {
|
||||
padding: 16px;
|
||||
|
||||
> .draggable {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.item, .otherItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: solid 1px var(--divider);
|
||||
border-bottom: none;
|
||||
cursor: move;
|
||||
|
||||
> i {
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
> .del {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--error);
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
cursor: pointer;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: solid 1px var(--divider);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user