fix(front): regressions after rebase on `develop`
This commit is contained in:
parent
d122f7cdf4
commit
af239917bc
|
@ -1,31 +1,33 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import LegacyLayout from '~/LegacyLayout.vue'
|
|
||||||
// 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 { watchEffect, computed, onMounted, nextTick } from 'vue'
|
||||||
|
|
||||||
import { useQueue } from '~/composables/audio/queue'
|
import { type QueueTrack, useQueue } from '~/composables/audio/queue'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
|
|
||||||
import useLogger from '~/composables/useLogger'
|
import useLogger from '~/composables/useLogger'
|
||||||
|
import { useLocalStorage, useStyleTag, useIntervalFn} from '@vueuse/core'
|
||||||
|
import { color } from '~/composables/color';
|
||||||
|
|
||||||
import { generateTrackCreditStringFromQueue } from '~/utils/utils'
|
import { generateTrackCreditStringFromQueue } from '~/utils/utils'
|
||||||
|
|
||||||
const ChannelUploadModal = defineAsyncComponent(() => import('~/components/channels/UploadModal.vue'))
|
// TODO: Check if these modals are still needed:
|
||||||
const PlaylistModal = defineAsyncComponent(() => import('~/components/playlists/PlaylistModal.vue'))
|
// import ChannelUploadModal from '~/components/channels/UploadModal.vue'
|
||||||
const FilterModal = defineAsyncComponent(() => import('~/components/moderation/FilterModal.vue'))
|
// import PlaylistModal from '~/components/playlists/PlaylistModal.vue'
|
||||||
const ReportModal = defineAsyncComponent(() => import('~/components/moderation/ReportModal.vue'))
|
// import FilterModal from '~/components/moderation/FilterModal.vue'
|
||||||
const ServiceMessages = defineAsyncComponent(() => import('~/components/ServiceMessages.vue'))
|
// import ReportModal from '~/components/moderation/ReportModal.vue'
|
||||||
const ShortcutsModal = defineAsyncComponent(() => import('~/components/ShortcutsModal.vue'))
|
// import ServiceMessages from '~/components/ServiceMessages.vue'
|
||||||
const AudioPlayer = defineAsyncComponent(() => import('~/components/audio/Player.vue'))
|
// TODO: Modernise and add player/queue:
|
||||||
const Sidebar = defineAsyncComponent(() => import('~/components/Sidebar.vue'))
|
// import AudioPlayer from '~/components/audio/Player.vue'
|
||||||
const Queue = defineAsyncComponent(() => import('~/components/Queue.vue'))
|
// import Queue from '~/components/Queue.vue'
|
||||||
|
import Sidebar from '~/ui/components/Sidebar.vue'
|
||||||
import { useLocalStorage, useStyleTag, useIntervalFn, useToggle, useWindowSize } from '@vueuse/core'
|
import ShortcutsModal from '~/ui/modals/Shortcuts.vue'
|
||||||
|
import LanguagesModal from '~/ui/modals/Languages.vue'
|
||||||
|
import UploadModal from '~/ui/modals/Upload.vue';
|
||||||
|
|
||||||
|
// Fake content
|
||||||
|
onMounted(async () => {
|
||||||
|
await nextTick()
|
||||||
|
document.getElementById('fake-app')?.remove()
|
||||||
|
})
|
||||||
|
|
||||||
const logger = useLogger()
|
const logger = useLogger()
|
||||||
logger.debug('App setup()')
|
logger.debug('App setup()')
|
||||||
|
@ -74,22 +76,34 @@ useIntervalFn(() => {
|
||||||
// because we want to learn if we are authenticated at all
|
// because we want to learn if we are authenticated at all
|
||||||
store.dispatch('auth/fetchUser')
|
store.dispatch('auth/fetchUser')
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// Research...
|
|
||||||
// - "What is the use case for this toggle?"
|
|
||||||
// - "Is Local Storage (persistence on a specific browser
|
|
||||||
// on a specific machine) the right place?"
|
|
||||||
const isUIv2 = useLocalStorage('ui-v2', true)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UiApp/>
|
<div class="funkwhale responsive">
|
||||||
<!-- <LegacyLayout v-else /> -->
|
<Sidebar/>
|
||||||
|
<RouterView v-bind="color({}, ['default', 'solid'])()" />
|
||||||
|
<LanguagesModal />
|
||||||
|
<ShortcutsModal />
|
||||||
|
<UploadModal />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style scoped lang="scss">
|
||||||
html, body {
|
.responsive {
|
||||||
font-size: 16px;
|
display: grid !important;
|
||||||
}
|
grid-template-columns: 100%;
|
||||||
|
grid-template-rows: min-content;
|
||||||
|
min-height: 100vh;
|
||||||
|
|
||||||
|
@media screen and (min-width: 1024px) {
|
||||||
|
grid-template-columns: 300px 5fr;
|
||||||
|
grid-template-rows: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
/* Make inert pages (behind modals) unscrollable */
|
||||||
|
body:has(#app[inert="true"]) {
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
import type { Actor } from '~/types'
|
import type { Actor } from '~/types'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
interface Events {
|
interface Events {
|
||||||
(e: 'unfollowed'): void
|
(e: 'unfollowed'): void
|
||||||
(e: 'followed'): void
|
(e: 'followed'): void
|
||||||
|
@ -39,13 +42,13 @@ const toggle = () => {
|
||||||
>
|
>
|
||||||
<i class="heart icon" />
|
<i class="heart icon" />
|
||||||
<span v-if="isApproved">
|
<span v-if="isApproved">
|
||||||
{{ $t('components.audio.LibraryFollowButton.button.unfollow') }}
|
{{ t('components.audio.LibraryFollowButton.button.unfollow') }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="isPending">
|
<span v-else-if="isPending">
|
||||||
{{ $t('components.audio.LibraryFollowButton.button.cancel') }}
|
{{ t('components.audio.LibraryFollowButton.button.cancel') }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
{{ $t('components.audio.LibraryFollowButton.button.follow') }}
|
{{ t('components.audio.LibraryFollowButton.button.follow') }}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -95,7 +95,7 @@ const triggerFileInput = () => {
|
||||||
{{ labels.export }}
|
{{ labels.export }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="$store.state.auth.authenticated && playlist.actor.full_username !== $store.state.auth.fullUsername"
|
v-if="store.state.auth.authenticated && playlist.actor.full_username !== store.state.auth.fullUsername"
|
||||||
role="button"
|
role="button"
|
||||||
class="basic item"
|
class="basic item"
|
||||||
:title="t('components.playlists.PlaylistDropdown.button.import.description')"
|
:title="t('components.playlists.PlaylistDropdown.button.import.description')"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { RouterLinkProps } from 'vue-router'
|
import type { RouterLinkProps } from 'vue-router'
|
||||||
|
import { useAttrs } from 'vue'
|
||||||
|
|
||||||
import Layout from '~/components/ui/Layout.vue'
|
import Layout from '~/components/ui/Layout.vue'
|
||||||
import Spacer from '~/components/ui/layout/Spacer.vue'
|
import Spacer from '~/components/ui/layout/Spacer.vue'
|
||||||
|
@ -20,13 +21,14 @@ const [headingLevel, title] =
|
||||||
const numberOfColumnsPerItem =
|
const numberOfColumnsPerItem =
|
||||||
'noItems' in props && props.noItems ? 1 : 'tinyItems' in props && props.tinyItems ? 2 : 'smallItems' in props && props['smallItems'] ? 3 : 4
|
'noItems' in props && props.noItems ? 1 : 'tinyItems' in props && props.tinyItems ? 2 : 'smallItems' in props && props['smallItems'] ? 3 : 4
|
||||||
|
|
||||||
|
const { style, ...fallthroughProps } = useAttrs()
|
||||||
|
|
||||||
const headerGrid =
|
const headerGrid =
|
||||||
`auto / repeat(auto-fit, calc(46px * ${numberOfColumnsPerItem} + 32px * ${numberOfColumnsPerItem - 1}))`
|
`auto / repeat(auto-fit, calc(46px * ${numberOfColumnsPerItem} + 32px * ${numberOfColumnsPerItem - 1}))`
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section style="flex-grow: 1;">
|
||||||
<Layout header :grid="headerGrid"
|
<Layout header :grid="headerGrid"
|
||||||
:style="`${'alignLeft' in props && props.alignLeft ? 'justify-content: start' : ''};
|
:style="`${'alignLeft' in props && props.alignLeft ? 'justify-content: start' : ''};
|
||||||
margin-top: -64px;`"
|
margin-top: -64px;`"
|
||||||
|
@ -49,10 +51,10 @@ const headerGrid =
|
||||||
<Spacer grow />
|
<Spacer grow />
|
||||||
<!-- Action! You can either specify `to` or `onClick`. -->
|
<!-- Action! You can either specify `to` or `onClick`. -->
|
||||||
<Button v-if="props.action && 'onClick' in props.action"
|
<Button v-if="props.action && 'onClick' in props.action"
|
||||||
ghost thin-font minWidth align-self="baseline"
|
ghost thin-font min-content align-self="baseline"
|
||||||
:style="`margin-right: ${('primary' in props || 'secondary' in props || 'destructive' in props) ? '0px' : '-16px'}`"
|
:style="`margin-right: ${('primary' in props || 'secondary' in props || 'destructive' in props) ? '0px' : '-16px'}`"
|
||||||
:onClick="props.action.onClick"
|
:onClick="props.action.onClick"
|
||||||
v-bind="$attrs"
|
v-bind="fallthroughProps"
|
||||||
>
|
>
|
||||||
{{ props.action.text }}
|
{{ props.action.text }}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -60,7 +62,7 @@ const headerGrid =
|
||||||
ghost force-underline thinFont align-self="baseline"
|
ghost force-underline thinFont align-self="baseline"
|
||||||
:style="`margin-right: ${('primary' in props || 'secondary' in props || 'destructive' in props) ? '0px' : '-16px'}`"
|
:style="`margin-right: ${('primary' in props || 'secondary' in props || 'destructive' in props) ? '0px' : '-16px'}`"
|
||||||
:to="props.action.to"
|
:to="props.action.to"
|
||||||
v-bind="$attrs"
|
v-bind="fallthroughProps"
|
||||||
>
|
>
|
||||||
{{ props.action.text }}
|
{{ props.action.text }}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -18,7 +18,7 @@ export type WidthProps =
|
||||||
export type Key = KeysOfUnion<WidthProps>
|
export type Key = KeysOfUnion<WidthProps>
|
||||||
|
|
||||||
const widths = {
|
const widths = {
|
||||||
minContent: 'width: min-content;',
|
minContent: 'width: min-content; flex-grow: 0;',
|
||||||
iconWidth: 'width: 40px;',
|
iconWidth: 'width: 40px;',
|
||||||
tiny: "width: 124px; grid-column: span 2;",
|
tiny: "width: 124px; grid-column: span 2;",
|
||||||
buttonWidth: "width: 136px; grid-column: span 2; flex-grow: 0; min-width: min-content;",
|
buttonWidth: "width: 136px; grid-column: span 2; flex-grow: 0; min-width: min-content;",
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import { onMounted, nextTick } from 'vue'
|
|
||||||
import { color } from '~/composables/color';
|
|
||||||
|
|
||||||
import Sidebar from '~/ui/components/Sidebar.vue'
|
|
||||||
import ShortcutsModal from './modals/Shortcuts.vue'
|
|
||||||
import LanguagesModal from './modals/Languages.vue'
|
|
||||||
import UploadModal from './modals/Upload.vue';
|
|
||||||
|
|
||||||
// Fake content
|
|
||||||
onMounted(async () => {
|
|
||||||
await nextTick()
|
|
||||||
document.getElementById('fake-app')?.remove()
|
|
||||||
})
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="funkwhale responsive">
|
|
||||||
<Sidebar/>
|
|
||||||
<RouterView v-bind="color({}, ['default', 'solid'])()" />
|
|
||||||
<LanguagesModal />
|
|
||||||
<ShortcutsModal />
|
|
||||||
<UploadModal />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.responsive {
|
|
||||||
display: grid !important;
|
|
||||||
grid-template-columns: 100%;
|
|
||||||
grid-template-rows: min-content;
|
|
||||||
min-height: 100vh;
|
|
||||||
|
|
||||||
@media screen and (min-width: 1024px) {
|
|
||||||
grid-template-columns: 300px 5fr;
|
|
||||||
grid-template-rows: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<style>
|
|
||||||
body:has(#app[inert="true"]) {
|
|
||||||
overflow:hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -3,12 +3,10 @@ import { ref, onMounted, watch, computed } from 'vue'
|
||||||
import { useUploadsStore } from '../stores/upload'
|
import { useUploadsStore } from '../stores/upload'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
import { color } from '~/composables/color'
|
|
||||||
|
|
||||||
import Logo from '~/components/Logo.vue'
|
import Logo from '~/components/Logo.vue'
|
||||||
import Input from '~/components/ui/Input.vue'
|
import Input from '~/components/ui/Input.vue'
|
||||||
import Link from '~/components/ui/Link.vue'
|
import Link from '~/components/ui/Link.vue'
|
||||||
import ActorAvatar from '~/components/common/ActorAvatar.vue'
|
|
||||||
import UserMenu from './UserMenu.vue'
|
import UserMenu from './UserMenu.vue'
|
||||||
import Button from '~/components/ui/Button.vue'
|
import Button from '~/components/ui/Button.vue'
|
||||||
import Layout from '~/components/ui/Layout.vue'
|
import Layout from '~/components/ui/Layout.vue'
|
||||||
|
@ -62,7 +60,6 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
round
|
round
|
||||||
square-small
|
square-small
|
||||||
icon="bi-upload"
|
icon="bi-upload"
|
||||||
:class="[$style.button]"
|
|
||||||
ghost
|
ghost
|
||||||
@click="store.commit('ui/toggleModal', 'upload')"
|
@click="store.commit('ui/toggleModal', 'upload')"
|
||||||
:aria-pressed="store.state.ui.modalsOpen.has('upload') || undefined"
|
:aria-pressed="store.state.ui.modalsOpen.has('upload') || undefined"
|
||||||
|
@ -106,7 +103,9 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Sign up, Log in -->
|
<Spacer />
|
||||||
|
|
||||||
|
<!-- Sign up, Log in -->
|
||||||
<div style="display:contents;" v-if="!store.state.auth.authenticated">
|
<div style="display:contents;" v-if="!store.state.auth.authenticated">
|
||||||
<Layout flex grow style="--gap:16px;">
|
<Layout flex grow style="--gap:16px;">
|
||||||
<Link :to="{ name: 'login' }"
|
<Link :to="{ name: 'login' }"
|
||||||
|
@ -275,11 +274,6 @@ const logoUrl = computed(() => store.state.auth.authenticated ? 'library.index'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search {
|
|
||||||
padding: 0 4px;
|
|
||||||
margin-bottom: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> h3 {
|
> h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 32px 8px;
|
padding: 0 32px 8px;
|
||||||
|
|
|
@ -36,6 +36,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
const { report, getReportableObjects } = useReport()
|
const { report, getReportableObjects } = useReport()
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
|
|
||||||
|
// We are working either with an Actor or null
|
||||||
const object = ref<Actor | null>(null)
|
const object = ref<Actor | null>(null)
|
||||||
|
|
||||||
const displayName = computed(() => object.value?.name ?? object.value?.preferred_username)
|
const displayName = computed(() => object.value?.name ?? object.value?.preferred_username)
|
||||||
|
@ -79,7 +80,6 @@ watch(props, fetchData, { immediate: true })
|
||||||
<template>
|
<template>
|
||||||
<Layout stack main
|
<Layout stack main
|
||||||
v-title="labels.usernameProfile"
|
v-title="labels.usernameProfile"
|
||||||
class="page-profile"
|
|
||||||
>
|
>
|
||||||
<Layout flex>
|
<Layout flex>
|
||||||
<!-- Profile Picture -->
|
<!-- Profile Picture -->
|
||||||
|
@ -136,7 +136,7 @@ watch(props, fetchData, { immediate: true })
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<user-follow-button
|
<user-follow-button
|
||||||
v-if="$store.state.auth.authenticated && object && object.full_username !== $store.state.auth.fullUsername"
|
v-if="store.state.auth.authenticated && object && object.full_username !== store.state.auth.fullUsername"
|
||||||
:actor="object"
|
:actor="object"
|
||||||
/>
|
/>
|
||||||
<h1 class="ui center aligned icon header">
|
<h1 class="ui center aligned icon header">
|
||||||
|
@ -204,21 +204,11 @@ watch(props, fetchData, { immediate: true })
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
</Layout>
|
|
||||||
<Layout stack noGap style="flex-grow: 2;">
|
|
||||||
<Layout flex style="justify-content: space-between;">
|
|
||||||
<!-- <Section h1="{{ displayName }}" :action="{ text: 'Edit profile', to:'/settings' }" /> -->
|
|
||||||
<h1>{{ displayName }}</h1>
|
|
||||||
<Link ghost alignSelf="center" minContent forceUnderline primary style="color: var(--fw-primary);" to="/settings">Edit profile</Link>
|
|
||||||
</Layout>
|
|
||||||
<span>{{ object?.full_username }}<i class="bi bi-copy" style="margin-left: 8px;"/></span>
|
|
||||||
<rendered-description
|
|
||||||
>
|
|
||||||
<!-- Profile description -->
|
<!-- Profile description -->
|
||||||
<Section no-items
|
<Section no-items
|
||||||
:h1="store.state.auth.username"
|
:h1="store.state.auth.username"
|
||||||
:action="{ text:'Edit profile', to:'/settings' }"
|
:action="{ text:'Edit profile', to:'/settings' }"
|
||||||
style="flex-grow:1"
|
style="flex-grow: 1; margin-top: 58px;"
|
||||||
>
|
>
|
||||||
<span style="grid-column: 1 / -1">
|
<span style="grid-column: 1 / -1">
|
||||||
{{ object?.full_username }}
|
{{ object?.full_username }}
|
||||||
|
@ -226,12 +216,16 @@ watch(props, fetchData, { immediate: true })
|
||||||
</span>
|
</span>
|
||||||
<RenderedDescription
|
<RenderedDescription
|
||||||
style="grid-column: 1 / -1"
|
style="grid-column: 1 / -1"
|
||||||
:content="object?.summary"
|
:content="object?.summary? {text: object.summary} : null"
|
||||||
:field-name="'summary'"
|
:field-name="'summary'"
|
||||||
:update-url="`users/${store.state.auth.username}/`"
|
:update-url="`users/${store.state.auth.username}/`"
|
||||||
:can-update="store.state.auth.authenticated && object?.full_username === store.state.auth.fullUsername"
|
:can-update="store.state.auth.authenticated && object?.full_username === store.state.auth.fullUsername"
|
||||||
@updated="emit('updated', $event)"
|
@updated="emit('updated', $event)"
|
||||||
/>
|
/>
|
||||||
|
<UserFollowButton
|
||||||
|
v-if="store.state.auth.authenticated && object && object.full_username !== store.state.auth.fullUsername"
|
||||||
|
:actor="object"
|
||||||
|
/>
|
||||||
</Section>
|
</Section>
|
||||||
</Layout>
|
</Layout>
|
||||||
<!-- TODO: Make routerlinks work for tabs -->
|
<!-- TODO: Make routerlinks work for tabs -->
|
||||||
|
|
Loading…
Reference in New Issue