126 lines
4.1 KiB
Vue
126 lines
4.1 KiB
Vue
|
<script setup lang="ts">
|
||
|
import type { NavButtonName } from '~/composables/settings'
|
||
|
import { STORAGE_KEY_BOTTOM_NAV_BUTTONS } from '~/constants'
|
||
|
|
||
|
interface NavButton {
|
||
|
name: NavButtonName
|
||
|
label: string
|
||
|
icon: string
|
||
|
}
|
||
|
|
||
|
const availableNavButtons: NavButton[] = [
|
||
|
{ name: 'home', label: 'nav.home', icon: 'i-ri:home-5-line' },
|
||
|
{ name: 'search', label: 'nav.search', icon: 'i-ri:search-line' },
|
||
|
{ name: 'notification', label: 'nav.notifications', icon: 'i-ri:notification-4-line' },
|
||
|
{ name: 'mention', label: 'nav.conversations', icon: 'i-ri:at-line' },
|
||
|
{ name: 'explore', label: 'nav.explore', icon: 'i-ri:compass-3-line' },
|
||
|
{ name: 'local', label: 'nav.local', icon: 'i-ri:group-2-line' },
|
||
|
{ name: 'federated', label: 'nav.federated', icon: 'i-ri:earth-line' },
|
||
|
{ name: 'moreMenu', label: 'nav.more_menu', icon: 'i-ri:more-fill' },
|
||
|
] as const
|
||
|
|
||
|
const defaultSelectedNavButtonNames = computed<NavButtonName[]>(() =>
|
||
|
currentUser.value
|
||
|
? ['home', 'search', 'notification', 'mention', 'moreMenu']
|
||
|
: ['explore', 'local', 'federated', 'moreMenu'],
|
||
|
)
|
||
|
const navButtonNamesSetting = useLocalStorage<NavButtonName[]>(STORAGE_KEY_BOTTOM_NAV_BUTTONS, defaultSelectedNavButtonNames.value)
|
||
|
const selectedNavButtonNames = ref(navButtonNamesSetting.value)
|
||
|
|
||
|
const selectedNavButtons = computed<NavButton[]>(() =>
|
||
|
selectedNavButtonNames.value.map(name =>
|
||
|
availableNavButtons.find(navButton => navButton.name === name)!,
|
||
|
),
|
||
|
)
|
||
|
|
||
|
const canSave = computed(() =>
|
||
|
selectedNavButtonNames.value.length > 0
|
||
|
&& selectedNavButtonNames.value.includes('moreMenu')
|
||
|
&& JSON.stringify(selectedNavButtonNames.value) !== JSON.stringify(navButtonNamesSetting.value),
|
||
|
)
|
||
|
|
||
|
function isAdded(name: NavButtonName) {
|
||
|
return selectedNavButtonNames.value.includes(name)
|
||
|
}
|
||
|
|
||
|
function append(navButtonName: NavButtonName) {
|
||
|
const maxButtonNumber = 5
|
||
|
if (selectedNavButtonNames.value.length < maxButtonNumber)
|
||
|
selectedNavButtonNames.value = [...selectedNavButtonNames.value, navButtonName]
|
||
|
}
|
||
|
|
||
|
function remove(navButtonName: NavButtonName) {
|
||
|
selectedNavButtonNames.value = selectedNavButtonNames.value.filter(name => name !== navButtonName)
|
||
|
}
|
||
|
|
||
|
function clear() {
|
||
|
selectedNavButtonNames.value = []
|
||
|
}
|
||
|
|
||
|
function reset() {
|
||
|
selectedNavButtonNames.value = defaultSelectedNavButtonNames.value
|
||
|
}
|
||
|
|
||
|
function save() {
|
||
|
navButtonNamesSetting.value = selectedNavButtonNames.value
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<template>
|
||
|
<!-- preview -->
|
||
|
<div flex="~ gap4 wrap" items-center select-settings h-14 p0>
|
||
|
<nav
|
||
|
v-for="availableNavButton in selectedNavButtons" :key="availableNavButton.name"
|
||
|
flex="~ 1" items-center justify-center text-xl
|
||
|
scrollbar-hide overscroll-none
|
||
|
>
|
||
|
<button btn-base :class="availableNavButton.icon" mx-4 tabindex="-1" />
|
||
|
</nav>
|
||
|
</div>
|
||
|
|
||
|
<!-- button selection -->
|
||
|
<div flex="~ gap4 wrap" py4>
|
||
|
<button
|
||
|
v-for="{ name, label, icon } in availableNavButtons"
|
||
|
:key="name"
|
||
|
btn-text flex="~ gap-2" items-center p2 border="~ base rounded" bg-base ws-nowrap
|
||
|
:class="isAdded(name) ? 'text-secondary hover:text-second bg-auto' : ''"
|
||
|
type="button"
|
||
|
role="switch"
|
||
|
:aria-checked="isAdded(name)"
|
||
|
@click="isAdded(name) ? remove(name) : append(name)"
|
||
|
>
|
||
|
<span :class="icon" />
|
||
|
{{ label ? $t(label) : 'More menu' }}
|
||
|
</button>
|
||
|
</div>
|
||
|
|
||
|
<div flex="~ col" gap-y-4 gap-x-2 py-1 sm="~ justify-end flex-row">
|
||
|
<button
|
||
|
btn-outline font-bold py2 full-w sm-wa flex="~ gap2 center"
|
||
|
type="button"
|
||
|
:disabled="selectedNavButtonNames.length === 0"
|
||
|
@click="clear"
|
||
|
>
|
||
|
<span aria-hidden="true" class="block i-ri:delete-bin-line" />
|
||
|
{{ $t('action.clear') }}
|
||
|
</button>
|
||
|
<button
|
||
|
btn-outline font-bold py2 full-w sm-wa flex="~ gap2 center"
|
||
|
type="button"
|
||
|
@click="reset"
|
||
|
>
|
||
|
<span aria-hidden="true" class="block i-ri:repeat-line" />
|
||
|
{{ $t('action.reset') }}
|
||
|
</button>
|
||
|
<button
|
||
|
btn-solid font-bold py2 full-w sm-wa flex="~ gap2 center"
|
||
|
:disabled="!canSave"
|
||
|
@click="save"
|
||
|
>
|
||
|
<span aria-hidden="true" i-ri:save-2-fill />
|
||
|
{{ $t('action.save') }}
|
||
|
</button>
|
||
|
</div>
|
||
|
</template>
|