new navbar

This commit is contained in:
lesion
2022-11-24 01:00:30 +01:00
parent 5622ed8995
commit 9ad0277d11
8 changed files with 222 additions and 261 deletions

View File

@@ -9,10 +9,6 @@ li {
margin-left: 10px;
}
.v-main {
padding-top: 176px !important;
}
.v-dialog .theme--dark.v-card {
background-color: #434343;
}

View File

@@ -1,251 +1,43 @@
<template>
<v-app-bar prominent absolute app src="/headerimage.png">
<template v-slot:img="{ props }">
<v-img
v-bind="props"
:gradient="gradient"></v-img>
</template>
<nav>
<v-app-bar-nav-icon to='/'>
<img src='/logo.png' height='40' />
</v-app-bar-nav-icon>
<NavHeader/>
<!-- <v-text-field name='search' :label='$t("common.search")' dense outlined rounded hide-details :append-icon='mdiMagnify'/> -->
<!-- title -->
<div class='text-center'>
<nuxt-link class='text-h3 text-decoration-none' v-text='settings.title' to='/' />
<div class='text-body-1 font-weight-light' v-text='settings.description' />
</div>
<v-list-item class='align-self-end' two-line>
<v-list-item-content>
<h4 v-text='settings.title'></h4>
<v-list-item-subtitle v-text='settings.description'></v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<NavSearch/>
<NavBar />
</nav>
<client-only>
<v-menu offset-y transition="slide-y-transition">
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind='attrs' v-on='on' aria-label='Language' v-text="$i18n.locale" />
</template>
<v-list>
<v-list-item v-for='locale in $i18n.locales' @click.prevent.stop="$i18n.setLocale(locale.code)" :key='locale.code'>
<v-list-item-content>
<v-list-item-title v-text='locale.name' />
</v-list-item-content>
</v-list-item>
<v-list-item nuxt target='_blank' href='https://hosted.weblate.org/engage/gancio/'>
<v-list-item-content>
<v-list-item-subtitle v-text='$t("common.help_translate")' />
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
<v-btn slot='placeholder' icon arial-label='Language'>{{$i18n.locale}}</v-btn>
</client-only>
<client-only>
<v-menu v-if='loggedIn' offset-y transition="slide-y-transition">
<template v-slot:activator="{ on, attrs }">
<v-btn class='mr-0' icon v-bind='attrs' v-on='on' title='Menu' aria-label='Menu'>
<v-icon v-text='mdiDotsVertical' />
</v-btn>
</template>
<v-list>
<v-list-item nuxt to='/settings'>
<v-list-item-icon><v-icon v-text='mdiCog'></v-icon></v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="$t('common.settings')"/>
</v-list-item-content>
</v-list-item>
<v-list-item v-if='$auth.user.is_admin' nuxt to='/admin'>
<v-list-item-icon>
<v-icon v-text='mdiAccount' />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="$t('common.admin')" />
</v-list-item-content>
</v-list-item>
<v-list-item @click='logout'>
<v-list-item-icon>
<v-icon v-text='mdiLogout' />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="$t('common.logout')" />
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
<template #placeholder>
<v-btn v-if='loggedIn' icon aria-label='Menu' title='Menu'>
<v-icon v-text='mdiDotsVertical' />
</v-btn>
</template>
</client-only>
<!-- login button -->
<v-btn class='mr-0' v-if='!loggedIn' icon nuxt to='/login' :title='$t("common.login")' :aria-label='$t("common.login")'>
<v-icon v-text='mdiLogin' />
</v-btn>
<!-- <nuxt-link v-if='loggedIn || settings.allow_anon_event' link text nuxt to='/add' :aria-label='$t("common.add_event")' :title='$t("common.add_event")'>
<v-icon large v-text='mdiPlus' />
<small v-text="$t('common.add_event')" />
</nuxt-link> -->
<!-- //- v-btn(icon nuxt to='/export' :title='$t("common.share")' :aria-label='$t("common.share")')
//- v-icon(v-text='mdiShareVariant')
//- v-btn(v-if='!loggedIn' icon nuxt to='/login' :title='$t("common.login")' :aria-label='$t("common.login")')
//- v-icon(v-text='mdiLogin')
//- client-only
//- v-menu(offset-y transition="slide-y-transition" min-width='200px' max-height='400px')
//- template(v-slot:activator="{ on, attrs }")
//- v-btn(icon v-bind='attrs' v-on='on' aria-label='Language') {{$i18n.locale}}
//- v-list
//- v-list-item(v-for='locale in $i18n.locales' @click.prevent.stop="$i18n.setLocale(locale.code)" :key='locale.code')
//- v-list-item-content
//- v-list-item-title {{locale.name}}
//- v-list-item(nuxt target='_blank' href='https://hosted.weblate.org/engage/gancio/')
//- v-list-item-content
//- v-list-item-subtitle(v-text='$t("common.help_translate")')
//- template(#placeholder)
//- v-btn(icon aria-label='Language') {{$i18n.locale}}
//- v-btn(icon target='_blank' :href='`${settings.baseurl}/feed/rss`' title='RSS' aria-label='RSS')
//- v-icon(color='orange' v-text='mdiRss') -->
<!--
<v-menu left bottom>
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on">
<v-icon>mdi-dots-vertical</v-icon>
</v-btn>
</template>
</v-menu> -->
<!-- .v-application--is-ltr .v-tabs--align-with-title > .v-tabs-bar:not(.v-tabs-bar--show-arrows):not(.v-slide-group--is-overflowing) > .v-slide-group__wrapper > .v-tabs-bar__content > .v-tab:first-child,
.v-application--is-ltr .v-tabs--align-with-title > .v-tabs-bar:not(.v-tabs-bar--show-arrows):not(.v-slide-group--is-overflowing) > .v-slide-group__wrapper > .v-tabs-bar__content > .v-tabs-slider-wrapper + .v-tab -->
<template v-slot:extension>
<v-tabs v-model='tab' optional dense icons-and-text>
<v-tab to='/'>
<span class='d-none d-sm-flex'>Home</span>
<v-icon v-text='mdiHome' />
</v-tab>
<v-tab v-if='loggedIn || settings.allow_anon_event' to='/add'>
<span class='d-none d-sm-flex'>{{$t('common.add_event')}}</span>
<v-icon color='primary' v-text='mdiPlus' />
</v-tab>
<v-tab to='/export' >
<span class='d-none d-sm-flex'>{{$t('common.share')}}</span>
<v-icon v-text='mdiShareVariant' />
</v-tab>
<v-tab to='/about'>
<span class='d-none d-sm-flex'>About</span>
<v-icon v-text='mdiInformation' />
</v-tab>
</v-tabs>
</template>
</v-app-bar>
<!-- //- v-app-bar(app aria-label='Menu' height=64)
//- //- logo, title and description
//- v-list-item(:to='$route.name==="index"?"/about":"/"')
//- v-list-item-avatar.ma-xs-1(tile)
//- img(src='/logo.png' height='40')
//- v-list-item-content
//- v-list-item-title.d-flex
//- h2 {{settings.title}}
//- v-list-item-subtitle.d-none.d-sm-flex {{settings.description}}
//- v-spacer
//- v-btn(v-if='loggedIn || settings.allow_anon_event' icon nuxt to='/add' :aria-label='$t("common.add_event")' :title='$t("common.add_event")')
//- v-icon(large color='primary' v-text='mdiPlus')
//- v-btn(icon nuxt to='/export' :title='$t("common.share")' :aria-label='$t("common.share")')
//- v-icon(v-text='mdiShareVariant')
//- v-btn(v-if='!loggedIn' icon nuxt to='/login' :title='$t("common.login")' :aria-label='$t("common.login")')
//- v-icon(v-text='mdiLogin')
//- client-only
//- v-menu(v-if='loggedIn' offset-y transition="slide-y-transition")
//- template(v-slot:activator="{ on, attrs }")
//- v-btn(icon v-bind='attrs' v-on='on' title='Menu' aria-label='Menu')
//- v-icon(v-text='mdiDotsVertical')
//- v-list
//- v-list-item(nuxt to='/settings')
//- v-list-item-icon
//- v-icon(v-text='mdiCog')
//- v-list-item-content
//- v-list-item-title {{$t('common.settings')}}
//- v-list-item(v-if='$auth.user.is_admin' nuxt to='/admin')
//- v-list-item-icon
//- v-icon(v-text='mdiAccount')
//- v-list-item-content
//- v-list-item-title {{$t('common.admin')}}
//- v-list-item(@click='logout')
//- v-list-item-icon
//- v-icon(v-text='mdiLogout')
//- v-list-item-content
//- v-list-item-title {{$t('common.logout')}}
//- template(#placeholder)
//- v-btn(v-if='loggedIn' icon aria-label='Menu' title='Menu')
//- v-icon(v-text='mdiDotsVertical')
//- client-only
//- v-menu(offset-y transition="slide-y-transition" min-width='200px' max-height='400px')
//- template(v-slot:activator="{ on, attrs }")
//- v-btn(icon v-bind='attrs' v-on='on' aria-label='Language') {{$i18n.locale}}
//- v-list
//- v-list-item(v-for='locale in $i18n.locales' @click.prevent.stop="$i18n.setLocale(locale.code)" :key='locale.code')
//- v-list-item-content
//- v-list-item-title {{locale.name}}
//- v-list-item(nuxt target='_blank' href='https://hosted.weblate.org/engage/gancio/')
//- v-list-item-content
//- v-list-item-subtitle(v-text='$t("common.help_translate")')
//- template(#placeholder)
//- v-btn(icon aria-label='Language') {{$i18n.locale}}
//- v-btn(icon target='_blank' :href='`${settings.baseurl}/feed/rss`' title='RSS' aria-label='RSS')
//- v-icon(color='orange' v-text='mdiRss') -->
</template>
<script>
const locales = require('../locales/index')
import { mapState } from 'vuex'
import clipboard from '../assets/clipboard'
import { mdiPlus, mdiShareVariant, mdiLogin, mdiDotsVertical, mdiLogout, mdiAccount, mdiCog, mdiRss, mdiHome, mdiInformation } from '@mdi/js'
import NavHeader from './NavHeader.vue'
import NavBar from './NavBar.vue'
import NavSearch from './NavSearch.vue'
export default {
name: 'Appbar',
data () {
return { mdiPlus, mdiShareVariant, mdiLogout, mdiLogin, mdiDotsVertical, mdiAccount, mdiCog, mdiRss, mdiHome, mdiInformation, locales, tab: '' }
},
mixins: [clipboard],
computed: {
loggedIn () {
return this.$auth.loggedIn
},
gradient () {
if (this.$vuetify.theme.dark) {
return 'to bottom, rgba(59,0,0,.9), rgba(0,0,0,.9)'
} else {
return 'to bottom, rgba(255,230,230,.95), rgba(250,250,250,.95)'
}
},
...mapState(['settings']),
},
methods: {
logout () {
this.$root.$message('common.logout_ok')
this.$auth.logout()
}
}
components: { NavHeader, NavBar, NavSearch },
computed: mapState(['settings'])
}
</script>
<style>
nav {
background-image: linear-gradient(rgba(59, 0, 0, 0.4), rgba(0, 0, 0, 0.4)), url(/headerimage.png);
background-position: center center;
background-size: cover;
}
.theme--light nav {
background-image: linear-gradient(to bottom, rgba(255,230,230,.95), rgba(250,250,250,.95)), url(/headerimage.png);
}
</style>

View File

@@ -1,6 +1,7 @@
<template lang="pug">
#calendar
client-only
vc-date-picker(
ref='cal'
v-model='selectedDate'
title-position='left'
:is-dark="settings['theme.is_dark']"
@@ -13,28 +14,37 @@
aria-label='Calendar'
is-expanded
is-inline)
template(v-slot="{ inputValue, inputEvents }")
v-btn#calendarButton(v-on='inputEvents' text tile :color='selectedDate ? "primary" : "" ') {{inputValue || $t('common.calendar')}}
v-icon(v-if='selectedDate' v-text='mdiClose' right small icon @click='selectedDate = null')
v-icon(v-else v-text='mdiChevronDown' right small icon)
template(v-slot:placeholder)
v-btn#calendarButton(text tile :color='selectedDate ? "primary" : "" ') {{selectedDate || $t('common.calendar')}}
v-icon(v-if='selectedDate' v-text='mdiClose' right small icon @click='selectedDate = null')
v-icon(v-else v-text='mdiChevronDown' right small icon)
</template>
</template>
<script>
import { mapState } from 'vuex'
import dayjs from 'dayjs'
import { mdiChevronDown, mdiClose } from '@mdi/js'
import { attributesFromEvents } from '../assets/helper'
export default {
name: 'Calendar',
props: {
events: { type: Array, default: () => [] }
},
data () {
const month = dayjs.tz().month() + 1
const year = dayjs.tz().year()
return {
mdiChevronDown, mdiClose,
selectedDate: null,
page: { month, year }
page: { month, year },
}
},
computed: {
...mapState(['settings']),
...mapState(['settings', 'events']),
attributes () {
return attributesFromEvents(this.events)
}
@@ -62,4 +72,9 @@ export default {
.past-event {
opacity: 0.3;
}
#calendarButton {
margin-top: -6px;
margin-left: -10px;
}
</style>

View File

@@ -4,7 +4,6 @@ v-footer(aria-label='Footer')
v-dialog(v-model='showFollowMe' destroy-on-close max-width='700px' :fullscreen='$vuetify.breakpoint.xsOnly')
FollowMe(@close='showFollowMe=false' is-dialog)
v-btn(color='primary' text href='https://gancio.org' target='_blank' rel="noopener") Gancio <small>{{settings.version}}</small>
v-btn.ml-1(v-for='link in footerLinks'
:key='link.label' color='primary' text
:href='link.href' :to='link.to' :target="link.href && '_blank'") {{link.label}}
@@ -26,6 +25,9 @@ v-footer(aria-label='Footer')
v-list-item-subtitle {{instance.label}}
v-btn.ml-1(v-if='settings.enable_federation' color='primary' text rel='me' @click.prevent='showFollowMe=true') {{$t('event.interact_with_me')}}
v-spacer
v-btn(color='primary' text href='https://gancio.org' target='_blank' rel="noopener") Gancio <small>{{settings.version}}</small>
</template>
<script>
import { mapState } from 'vuex'

29
components/NavBar.vue Normal file
View File

@@ -0,0 +1,29 @@
<template>
<v-tabs centered background-color='transparent' optional dense icons-and-text class='mt-4'>
<v-tab to='/'>
<span class='d-none d-sm-flex'>Home</span>
<v-icon v-text='mdiHome' />
</v-tab>
<v-tab v-if='$auth.loggedIn || settings.allow_anon_event' to='/add'>
<span class='d-none d-sm-flex'>{{$t('common.add_event')}}</span>
<v-icon color='primary' v-text='mdiPlus' />
</v-tab>
<v-tab to='/export' >
<span class='d-none d-sm-flex'>{{$t('common.share')}}</span>
<v-icon v-text='mdiShareVariant' />
</v-tab>
</v-tabs>
</template>
<script>
import { mdiPlus, mdiShareVariant, mdiHome, mdiInformation } from '@mdi/js'
import { mapState } from 'vuex'
export default {
name: 'Navbar',
data () {
return { mdiPlus, mdiShareVariant, mdiHome, mdiInformation }
},
computed: mapState(['settings'])
}
</script>

97
components/NavHeader.vue Normal file
View File

@@ -0,0 +1,97 @@
<template>
<div class='d-flex pa-4'>
<img src='/logo.png' height='40' />
<v-spacer/>
<div class='d-flex'>
<v-btn class='mr-0' icon to='/about' :title='$t("common.about")' :aria-label='$t("common.about")'>
<v-icon v-text='mdiInformation' />
</v-btn>
<client-only>
<v-menu offset-y transition="slide-y-transition">
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind='attrs' v-on='on' aria-label='Language' v-text="$i18n.locale" />
</template>
<v-list>
<v-list-item v-for='locale in $i18n.locales' @click.prevent.stop="$i18n.setLocale(locale.code)" :key='locale.code'>
<v-list-item-content>
<v-list-item-title v-text='locale.name' />
</v-list-item-content>
</v-list-item>
<v-list-item nuxt target='_blank' href='https://hosted.weblate.org/engage/gancio/'>
<v-list-item-content>
<v-list-item-subtitle v-text='$t("common.help_translate")' />
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
<v-btn slot='placeholder' icon arial-label='Language'>{{$i18n.locale}}</v-btn>
</client-only>
<client-only>
<v-menu v-if='$auth.loggedIn' offset-y transition="slide-y-transition">
<template v-slot:activator="{ on, attrs }">
<v-btn class='mr-0' icon v-bind='attrs' v-on='on' title='Menu' aria-label='Menu'>
<v-icon v-text='mdiDotsVertical' />
</v-btn>
</template>
<v-list>
<v-list-item nuxt to='/settings'>
<v-list-item-icon><v-icon v-text='mdiCog'></v-icon></v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="$t('common.settings')"/>
</v-list-item-content>
</v-list-item>
<v-list-item v-if='$auth.user.is_admin' nuxt to='/admin'>
<v-list-item-icon>
<v-icon v-text='mdiAccount' />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="$t('common.admin')" />
</v-list-item-content>
</v-list-item>
<v-list-item @click='logout'>
<v-list-item-icon>
<v-icon v-text='mdiLogout' />
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title v-text="$t('common.logout')" />
</v-list-item-content>
</v-list-item>
</v-list>
</v-menu>
<template #placeholder>
<v-btn v-if='$auth.loggedIn' icon aria-label='Menu' title='Menu'>
<v-icon v-text='mdiDotsVertical' />
</v-btn>
</template>
</client-only>
<!-- login button -->
<v-btn class='mr-0' v-if='!$auth.loggedIn' icon nuxt to='/login' :title='$t("common.login")' :aria-label='$t("common.login")'>
<v-icon v-text='mdiLogin' />
</v-btn>
</div>
</div>
</template>
<script>
import { mdiLogin, mdiDotsVertical, mdiLogout, mdiAccount, mdiCog, mdiInformation } from '@mdi/js'
export default {
data () {
return { mdiLogin, mdiDotsVertical, mdiLogout, mdiAccount, mdiCog, mdiInformation }
},
methods: {
logout () {
this.$root.$message('common.logout_ok')
this.$auth.logout()
}
}
}
</script>

30
components/NavSearch.vue Normal file
View File

@@ -0,0 +1,30 @@
<template lang="pug">
#navsearch.mt-2.mt-sm-4
v-text-field.mx-2(outlined dense hide-details :placeholder='$t("common.search")' :append-icon='mdiMagnify')
template(v-slot:prepend-inner)
Calendar(v-if='!settings.hide_calendar')
v-btn.ml-2.mt-2.gap-2(small outlined v-for='collection in collections' color='primary' :key='collection.id' :to='`/collection/${encodeURIComponent(collection.name)}`') {{collection.name}}
</template>
<script>
import { mapState } from 'vuex'
import Calendar from '@/components/Calendar'
import { mdiMagnify } from '@mdi/js'
export default {
data: () => ({
mdiMagnify,
collections: []
}),
async fetch () {
this.collections = await this.$axios.$get('collections').catch(_e => [])
},
components: { Calendar },
computed: mapState(['settings'])
}
</script>
<style>
#navsearch {
margin: 0 auto;
max-width: 800px;
}
</style>

View File

@@ -6,7 +6,7 @@ v-container
v-card-text(v-else v-html='about')
v-card-actions(v-if='$auth.user && $auth.user.is_admin')
v-spacer
v-btn(color='primary' text
v-btn(color='primary' outlined
@click='save') {{$t('common.save')}}
</template>
<script>