feat(ui): enable and style shortcuts modal
This commit is contained in:
parent
74958dcf34
commit
1740fa7c11
|
@ -1,12 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
// import LegacyLayout from '~/LegacyLayout.vue'
|
||||
// TODO: Check if we ever need LegacyLayout
|
||||
// TODO: see below (isUIv2)
|
||||
import UiApp from '~/ui/App.vue'
|
||||
|
||||
import type { QueueTrack } from '~/composables/audio/queue'
|
||||
|
||||
import { watchEffect, computed, onMounted, nextTick } from 'vue'
|
||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut'
|
||||
|
||||
import { useQueue } from '~/composables/audio/queue'
|
||||
import { useStore } from '~/store'
|
||||
|
@ -24,9 +23,9 @@ const ShortcutsModal = defineAsyncComponent(() => import('~/components/Shortcuts
|
|||
const AudioPlayer = defineAsyncComponent(() => import('~/components/audio/Player.vue'))
|
||||
const Sidebar = defineAsyncComponent(() => import('~/components/Sidebar.vue'))
|
||||
const Queue = defineAsyncComponent(() => import('~/components/Queue.vue'))
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
|
||||
import { useLocalStorage, useStyleTag, useIntervalFn, useToggle, useWindowSize } from '@vueuse/core'
|
||||
import { useLocalStorage, useStyleTag, useIntervalFn, useToggle } from '@vueuse/core'
|
||||
|
||||
|
||||
const logger = useLogger()
|
||||
logger.debug('App setup()')
|
||||
|
@ -70,10 +69,6 @@ useIntervalFn(() => {
|
|||
store.commit('ui/computeLastDate')
|
||||
}, 1000 * 60)
|
||||
|
||||
// Shortcuts
|
||||
const [_, toggleShortcutsModal] = useToggle(false)
|
||||
onKeyboardShortcut('h', () => toggleShortcutsModal())
|
||||
|
||||
// Fetch user data on startup
|
||||
// NOTE: We're not checking if we're authenticated in the store,
|
||||
// because we want to learn if we are authenticated at all
|
||||
|
|
|
@ -3,6 +3,7 @@ import Modal from '~/components/ui/Modal.vue'
|
|||
import { computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import Button from '~/components/ui/Button.vue'
|
||||
import Layout from '~/components/ui/Layout.vue'
|
||||
|
||||
const model = defineModel<boolean>()
|
||||
|
||||
|
@ -98,52 +99,57 @@ const player = computed(() => [
|
|||
|
||||
<template>
|
||||
<Modal
|
||||
overPopover
|
||||
:title="t('components.ShortcutsModal.header.modal')"
|
||||
v-model="model">
|
||||
<section class="scrolling content">
|
||||
<div class="ui stackable two column grid">
|
||||
<div class="column">
|
||||
<Layout flex>
|
||||
<div class="column" :class="$style.withPadding">
|
||||
<table
|
||||
v-for="section in player"
|
||||
:key="section.title"
|
||||
class="ui compact basic table"
|
||||
>
|
||||
<caption>{{ section.title }}</caption>
|
||||
<h3>{{ section.title }}</h3>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="shortcut in section.shortcuts"
|
||||
:key="shortcut.summary"
|
||||
>
|
||||
<td>{{ shortcut.summary }}</td>
|
||||
<td><span class="ui label">{{ shortcut.key }}</span></td>
|
||||
<td :class="$style.description">{{ shortcut.summary }}</td>
|
||||
<td> <Button style="pointer-events:none;" class="is-icon-only">{{ shortcut.key }}</Button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="column" :class="$style.withPadding">
|
||||
<table
|
||||
v-for="section in general"
|
||||
:key="section.title"
|
||||
class="ui compact basic table"
|
||||
>
|
||||
<caption>{{ section.title }}</caption>
|
||||
<h3>{{ section.title }}</h3>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="shortcut in section.shortcuts"
|
||||
:key="shortcut.summary"
|
||||
>
|
||||
<td>{{ shortcut.summary }}</td>
|
||||
<td><span class="ui label">{{ shortcut.key }}</span></td>
|
||||
<td :class="$style.description">{{ shortcut.summary }}</td>
|
||||
<td> <Button style="pointer-events:none;" class="is-icon-only">{{ shortcut.key }}</Button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</section>
|
||||
<footer class="actions">
|
||||
<Button color="secondary">
|
||||
{{ t('components.ShortcutsModal.button.close') }}
|
||||
</Button>
|
||||
</footer>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style module>
|
||||
.withPadding {
|
||||
padding:8px;
|
||||
}
|
||||
.description {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import Button from '~/components/ui/Button.vue'
|
||||
import Spacer from '~/components/ui/layout/Spacer.vue'
|
||||
|
||||
const { title, overPopover = false } = defineProps<{ title:string, overPopover?:true }>()
|
||||
const isOpen = defineModel<boolean>({ default:false })
|
||||
|
@ -34,6 +35,7 @@ const isOpen = defineModel<boolean>({ default:false })
|
|||
<div v-if="$slots.actions" class="modal-actions">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
<Spacer :size="128" v-else />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
box-shadow: 0 2px 4px 2px rgba(#000, 0.2);
|
||||
border-radius: 1rem;
|
||||
max-width: min(90vw, 40rem);
|
||||
max-width: min(90vw, 55rem);
|
||||
width: 100%;
|
||||
|
||||
display: grid;
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
<script setup lang="ts">
|
||||
import { onMounted, nextTick } from 'vue'
|
||||
import { onMounted, nextTick, ref, defineAsyncComponent } from 'vue'
|
||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut';
|
||||
import Sidebar from '~/ui/components/Sidebar.vue'
|
||||
import ShortcutsModal from '~/components/ShortcutsModal.vue'
|
||||
|
||||
// Fake content
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
document.getElementById('fake-app')?.remove()
|
||||
})
|
||||
|
||||
const isShortcutsModalOpen = ref(false)
|
||||
onKeyboardShortcut('h', () => isShortcutsModalOpen.value = !isShortcutsModalOpen.value)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="funkwhale grid">
|
||||
<Sidebar />
|
||||
<Sidebar :openShortcutsModal = "() => isShortcutsModalOpen=true" />
|
||||
<main>
|
||||
<RouterView />
|
||||
</main>
|
||||
<ShortcutsModal v-model="isShortcutsModalOpen" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import Button from '~/components/ui/Button.vue'
|
|||
import Layout from '~/components/ui/Layout.vue'
|
||||
import Spacer from '~/components/ui/layout/Spacer.vue'
|
||||
|
||||
const { openShortcutsModal } = defineProps<{ openShortcutsModal: ()=> void }>()
|
||||
|
||||
const searchQuery = ref('')
|
||||
|
||||
// Hide the fake app when the real one is loaded
|
||||
|
@ -62,7 +64,7 @@ const uploads = useUploadsStore()
|
|||
</Button>
|
||||
</Link>
|
||||
|
||||
<UserMenu />
|
||||
<UserMenu :showShortcutsModal="openShortcutsModal" />
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
|
@ -129,7 +131,7 @@ const uploads = useUploadsStore()
|
|||
{{ t('components.Sidebar.link.favorites') }}
|
||||
</Link>
|
||||
</nav>
|
||||
<Spacer grow />
|
||||
<Spacer />
|
||||
<h3>{{ t('components.Sidebar.link.channels') }}</h3>
|
||||
<Spacer grow />
|
||||
<nav>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { SUPPORTED_LOCALES, setI18nLanguage } from '~/init/locale'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, ref, watch, watchEffect } from 'vue'
|
||||
import { useStore } from '~/store'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
|
@ -16,16 +16,17 @@ import PopoverRadio from '~/components/ui/popover/PopoverRadio.vue'
|
|||
import PopoverRadioItem from '~/components/ui/popover/PopoverRadioItem.vue'
|
||||
import PopoverSubmenu from '~/components/ui/popover/PopoverSubmenu.vue'
|
||||
import Link from '~/components/ui/Link.vue'
|
||||
import Modal from '~/components/ui/Modal.vue'
|
||||
|
||||
const { showShortcutsModal } = defineProps<{
|
||||
showShortcutsModal : () => void
|
||||
}>()
|
||||
|
||||
|
||||
interface Events {
|
||||
(e: 'show:shortcuts-modal'): void
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const store = useStore()
|
||||
|
||||
const emit = defineEmits<Events>()
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
|
||||
const themes = useThemeList()
|
||||
|
@ -33,6 +34,8 @@ const { theme } = useTheme()
|
|||
|
||||
const openUserMenu = ref(false)
|
||||
|
||||
const isLanguageModelOpen = ref(false)
|
||||
|
||||
const labels = computed(() => ({
|
||||
profile: t('components.common.UserMenu.link.profile'),
|
||||
settings: t('components.common.UserMenu.link.settings'),
|
||||
|
@ -50,6 +53,10 @@ const labels = computed(() => ({
|
|||
signup: t('components.common.UserMenu.link.signup'),
|
||||
notifications: t('components.common.UserMenu.link.notifications')
|
||||
}))
|
||||
|
||||
watchEffect(()=> {
|
||||
isLanguageModelOpen.value = isLanguageModelOpen.value && openUserMenu.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -57,7 +64,7 @@ const labels = computed(() => ({
|
|||
<Button
|
||||
@click="openUserMenu = !openUserMenu"
|
||||
round
|
||||
icon
|
||||
icon=""
|
||||
ghost
|
||||
class="is-icon-only"
|
||||
>
|
||||
|
@ -69,11 +76,11 @@ const labels = computed(() => ({
|
|||
<i v-else class="bi bi-gear-fill" />
|
||||
</Button>
|
||||
<template #items>
|
||||
<PopoverItem v-if="store.state.ui.notifications.inbox + additionalNotifications > 0">
|
||||
<PopoverItem v-if="store.state.ui.notifications.inbox /* TODO: Check: + additionalNotifications */ > 0">
|
||||
<Link :to="{name: 'notifications'}">
|
||||
<i class="bi bi-inbox-fill" />
|
||||
>
|
||||
{{ store.state.ui.notifications.inbox + additionalNotifications }}
|
||||
{{ store.state.ui.notifications.inbox /* TODO: Check: + additionalNotifications */ }}
|
||||
{{ labels.notifications }}
|
||||
</Link>
|
||||
</PopoverItem>
|
||||
|
@ -94,6 +101,17 @@ const labels = computed(() => ({
|
|||
</Link>
|
||||
</PopoverItem>
|
||||
<hr v-if="store.state.auth.authenticated"/>
|
||||
<PopoverItem @click="isLanguageModelOpen = true">
|
||||
<i class="bi bi-translate" />
|
||||
{{ labels.language }}...
|
||||
<Modal v-model="isLanguageModelOpen" :title="labels.language" overPopover>
|
||||
<Button ghost v-for="(language, key) in SUPPORTED_LOCALES"
|
||||
:key="key"
|
||||
@click="setI18nLanguage(key)" >
|
||||
{{ language }}
|
||||
</Button>
|
||||
</Modal>
|
||||
</PopoverItem>
|
||||
<PopoverSubmenu>
|
||||
<i class="bi bi-translate" />
|
||||
{{ labels.language }}
|
||||
|
@ -161,7 +179,7 @@ const labels = computed(() => ({
|
|||
</nav>
|
||||
</PopoverItem>
|
||||
<PopoverItem
|
||||
@click.prevent="emit('show:shortcuts-modal')"
|
||||
@click.prevent="showShortcutsModal ()"
|
||||
>
|
||||
<i class="bi bi-keyboard" />
|
||||
{{ labels.shortcuts }}
|
||||
|
|
Loading…
Reference in New Issue