This commit is contained in:
lesion
2019-05-30 12:04:14 +02:00
parent 69792b518e
commit 6099d538c0
47 changed files with 1220 additions and 998 deletions

View File

@@ -1,37 +1,29 @@
<template lang="pug">
v-calendar#calendar.card(
#calendar
v-calendar(
title-position='left'
locale='it'
is-dark
show-caps
:attributes='attributes'
:from-page.sync='page'
is-expanded is-inline)
div(slot='popover', slot-scope='{ customData, attributes }')
p {{attributes}}
//- router-link(:to="`/event/${customData.id}`") {{customData.start_datetime|hour}} - {{customData.title}}
//- div(v-if='customData.days && customData.days[selectedEvent]')
p {{customData.days[customData.selectedEvent].title}}
p {{customData.days[customData.selectedEvent].tags}}
el-button(@click='customData.selectedEvent=customData.selectedEvent+1') {{customData.selectedEvent}}/{{customData.days.length}}
v-icon(name='clock' @click='customData.selectedEvent=customData.selectedEvent+1')
//- @{{customData.place.name}}
is-expanded
show-clear-margin
is-inline
@dayclick='click')
</template>
<script>
import { mapState, mapActions } from 'vuex'
import { mapState, mapActions, mapGetters } from 'vuex'
import moment from 'dayjs'
import { intersection } from 'lodash'
export default {
name: 'Calendar',
// filters,
data () {
const month = moment().month()+1
const year = moment().year()
return {
page: { month, year},
selectedEvent: {},
daysWithEvents: {}
}
},
@@ -42,8 +34,9 @@ export default {
},
methods: {
...mapActions(['updateEvents']),
nextEvent () {
click (day) {
const element = document.getElementById(day.day)
if (element) element.scrollIntoView(); //Even IE6 supports this
},
eventToAttribute(event) {
let e = {
@@ -52,18 +45,6 @@ export default {
order: event.start_datetime,
}
const day = moment(event.start_datetime).date()
if (!this.daysWithEvents[day]) {
this.daysWithEvents[day] = []
e.popover = {
slot: 'popover',
visibility: 'hover',
isInteractive: true,
hideIndicator: true,
}
e.customData.days = this.daysWithEvents[day]
}
this.daysWithEvents[day].push({title: event.title, when: event.start_datetime, tags: event.tags })
let color = event.tags && event.tags.length && event.tags[0].color ? event.tags[0].color : 'rgba(170,170,250,0.7)'
if (event.past) color = 'rgba(200,200,200,0.5)'
if (event.multidate) {
@@ -71,7 +52,7 @@ export default {
start: event.start_datetime, end: event.end_datetime
}
e.highlight = { backgroundColor: color,
borderColor: 'transparent',
// borderColor: 'transparent',
borderWidth: '4px' }
} else {
e.dates = event.start_datetime
@@ -81,17 +62,13 @@ export default {
}
},
computed: {
filteredEvents () {
return this.$store.getters.filteredEvents
},
...mapState(['events', 'filters']),
...mapGetters(['filteredEvents']),
attributes () {
return [
{ key: 'today', dates: new Date(),
highlight: {
backgroundColor: '#aaffaa'
},
popover: {label: this.$t('common.today')}
},
...this.filteredEvents.map(this.eventToAttribute)
]
@@ -102,11 +79,9 @@ export default {
<style>
#calendar {
margin-bottom: 0em;
margin-top: 0.3em;
margin: 0 auto;
max-width: 500px;
align-self: center;
}
#calendar a {
color: blue;
}
</style>

View File

@@ -1,65 +1,139 @@
<template lang="pug">
nuxt-link(:to='`/event/${event.id}`')
//- @click='$router.push("/event/" + event.id)'
b-card(bg-variant='dark' text-variant='white' :class="{ withImg: event.image_path ? true : false }"
:img-src='imgPath')
strong {{event.title}}
div <v-icon name='clock'/> {{event.start_datetime|datetime}}
span <v-icon name='map-marker-alt'/> {{event.place.name}}
br
el-tag.mr-1(:color='tag.color' v-for='tag in event.tags' :key='tag.tag'
size='small' @click.stop='addSearchTag(tag)') {{tag.tag}}
nuxt-link.event(:to='`event/${event.id}`' :class='{ withImg: event.image_path }')
//- image
img(v-if='showImage && event.image_path' :src='`/media/thumb/${event.image_path}`')
.event-info
.content-info
//- title
h2 {{event.title}}
//- date / place
.date
div {{event|event_when}}
div {{event.place.name}}
//- p(v-if='showDescription') {{event.description}}
//- div(v-if='event.comments && event.comments.length')
//- v-icon(name='comments' color='dark')
//- span {{event.comments.length}} {{$t('common.comments')}}
ul.tags(v-if='showTags && event.tags')
li(v-for='tag in event.tags' :key='tag.tag') {{tag.tag}}
</template>
<script>
import { mapState, mapActions } from 'vuex'
// import api from '@/server/api'
// import filters from '@/filters'
export default {
props: ['event'],
computed: {
...mapState(['user']),
imgPath() {
return this.event.image_path && '/media/thumb/' + this.event.image_path
props: {
event: Object,
showTags: {
type: Boolean,
default: true
},
mine() {
return this.event.userId === this.user.id
showImage: {
type: Boolean,
default: true
},
showDescription: {
type: Boolean,
default: true
},
selected: {
type: Boolean,
default: false
}
},
// filters: {
// datetime: this.datetime
// },
methods: {
...mapActions(['delEvent', 'addSearchTag']),
async remove() {
// await api.delEvent(this.event.id)
// this.delEvent(this.event.id)
computed: {
date () {
return new Date(this.event.start_datetime).getDate()
}
}
}
</script>
<style scoped>
/* .card::before {
border-top: 4px solid black;
content: ''
} */
<style lang='less'>
.el-card {
border: none;
@media only screen and (min-width: 574px) {
.event {
height: 100%;
}
}
.event {
padding: 3px;
display: flex;
flex-direction: column;
// height: 100%;
&:hover {
text-decoration: none;
}
img {
width: 100%;
max-height: 200px;
object-fit: cover;
object-position: top;
}
.event-info {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
background-color: #222;
}
.content-info {
font-size: 12px;
font-size: 0.8em;
padding: 0.8em 1em;
max-height: 200px;
color: rgb(255, 122, 204);
h2 {
color: yellow;
font-size: 16px;
font-size: 1.1rem;
margin: 0px;
}
p {
max-height: 92px;
overflow: hidden;
color: white;
margin: 0px;
}
.date {
font-weight: 800;
font-size: 16px;
font-size: 1rem;
}
}
.tags {
font-size: 12px;
padding: 1px;
margin-bottom: 0;
display:flex;
flex-wrap: wrap;
justify-content: center;
li {
background: #40484D;
display: inline-block;
padding: 2px 10px;
color: rgba(255,255,255,0.7);
margin: 1px;
text-align: center;
flex-grow: 1;
}
}
}
.el-card img {
width: 100%;
}
.card-columns .card {
margin-top: 0.2em;
margin-bottom: 0em;
}
.card-img {
height: 180px;
object-fit: cover;
}
</style>

View File

@@ -1,108 +1,40 @@
<template lang="pug">
div(v-loading='loading')
magic-grid(:animate="true" useMin :gap=5 :maxCols=4
:maxColWidth='400' ref='magicgrid')
div.mt-1.item
//- Search#search
no-ssr
Calendar
Event.item.mt-1(v-for='event in events'
:key='event.id'
:event='event')
section
.row.m-0
no-ssr
Calendar.col-sm-12.col-lg-8.col-xl-6
.p-0.col-sm-6.col-lg-4.col-xl-3(v-for='event in filteredEvents')
a(:id='event.newDay' v-if='event.newDay')
.d-block.d-sm-none
el-divider {{event.start_datetime|day}}
Event(
:id='event.start_datetime'
:key='event.id'
:event='event'
)
</template>
<script>
import { mapState, mapActions } from 'vuex'
import axios from 'axios'
// import filters from '@/filters.js'
import { mapGetters } from 'vuex'
import Event from '@/components/Event'
import Calendar from '@/components/Calendar'
// import { intersection } from 'lodash'
// import moment from 'dayjs'
// import Search from '@/components/Search'
import Search from '@/components/Search'
export default {
name: 'Home',
data () {
return { loading: true }
return { }
},
// created () {
// const now = new Date()
// const page = { month: now.getMonth() - 1, year: now.getFullYear() }
// this.updateEvents(page)
// },
components: { Event, Calendar }, // , Calendar, Search },
computed: {
...mapState(['events', 'filters']),
filteredEvents() {
return this.events
// return this.$store.getters.filteredEvents
.filter(e => !e.past)
.sort((a, b) => a.start_datetime > b.start_datetime)
}
},
mounted () {
this.loading = false
},
methods: mapActions(['updateEvents']),
watch: {
filteredEvents() {
this.$nextTick(this.$refs.magicgrid.positionItems)
this.loading = false
}
}
components: { Calendar, Event, Search },
computed: mapGetters(['filteredEvents']),
}
</script>
<style>
#search {
display: inline-flex;
}
.item {
<style lang="less">
section {
width: 100%;
max-width: 400px;
margin-top: 4px;
position: absolute;
cursor: pointer;
max-width: 1500px;
margin: 0 auto;
}
.card-columns {
column-count: 1;
column-gap: 0.2em;
}
@media (min-width: 576px) {
.container {
max-width: none;
}
.card-columns {
column-count: 2;
}
}
@media (min-width: 950px) {
.container {
max-width: 1400px;
}
.card-columns {
column-count: 3;
}
}
/* .item {
transition: all .2s;
display: inline-block;
width: 100%;
} */
/* .list-enter, .list-leave-to {
opacity: 0;
transform: translateY(30px);
}
.list-leave-active {
position: absolute;
top: 0px;
width: 0px;
left: 0px;
height: 0px;
z-index: -10;
} */
</style>

View File

@@ -1,34 +1,83 @@
<template lang="pug">
div#gancio-widget
//- el-card.mb-1(no-body header='Eventi')
//- b-list-group#list(flush)
p minimal {{minimal}}
ul
li.flex-column.align-items-start(v-for="event in events" :key='event.id'
:to='`/event/${event.id}`' target='_parent')
img(v-if='event.image_path' slot="aside" :src="`http://localhost:3000/media/${event.image_path}`" alt="Meia Aside" style='max-height: 60px')
strong.mb-1 {{event.title}}
br
small.float-right {{event.place.name}}
//- el-tag.mr-1(v-if='showtags' :color='tag.color || "rgba(64,158,255,.1)"' size='mini' v-for='tag in event.tags' :key='tag.tag') {{tag.tag}}
div#list
el-divider {{title}}
el-timeline
el-timeline-item(
v-for='event in events'
:key='event.id'
:timestamp='event|event_when'
placement='top' icon='el-icon-arrow-down' size='large'
)
div.float-right
small @{{event.place.name}}
a(:href='"/event/" + event.id' target='_blank') {{event.title}}
hr
</template>
<script>
import axios from 'axios'
import { mapGetters } from 'vuex'
const { SHARED_CONF } = require('@/config')
export default {
name: 'List',
data () {
return {
events: []
}
return { SHARED_CONF }
},
props: {
title: {
type: String,
default: SHARED_CONF.title
},
events: {
type: Array,
default: () => {
return []
}
},
maxEvents: {
type: Number,
default: 0
},
minimal: {
type: Boolean,
default: false
},
showTags: {
type: Boolean,
default: true,
},
showImage: {
type: Boolean,
default: true,
},
showDescription: {
type: Boolean,
default: true
}
},
async mounted () {
this.events = (await axios.get('http://localhost:3000/api/export/json')).data
}
}
</script>
</script>
<style lang='less'>
#list {
max-width: 500px;
.el-timeline {
padding-left: 5px;
hr {
margin-top: 4px;
margin-bottom: 4px;
}
}
.el-timeline-item {
padding-bottom: 1px;
}
.el-timeline-item__timestamp {
margin: 0px;
padding: 0px;
}
}
</style>

View File

@@ -1,51 +1,59 @@
<template lang="pug">
b-navbar(type="dark" variant="dark" toggleable='md')
b-navbar-toggle(target='nav_collapse')
b-navbar-brand(to='/') <img id='logo' src='gancio_logo.svg'/>
b-collapse#nav_collapse(is-nav)
b-navbar-nav
b-nav-item(v-if='!$auth.loggedIn' to='/login' v-b-tooltip :title='$t("common.login")') <v-icon color='lightgreen' name='lock' />
span.d-md-none {{$t('common.login')}}
b-nav-item(to='/add' v-b-tooltip :title='$t("common.add_event")' ) <v-icon color='lightgreen' name='plus'/>
span.d-md-none {{$t('common.add_event')}}
b-nav-item(v-if='$auth.loggedIn' to='/settings' v-b-tooltip :title='$t("common.settings")') <v-icon color='orange' name='cog'/>
span.d-md-none {{$t('common.settings')}}
b-nav-item(v-if='$auth.user && $auth.user.is_admin' to='/admin' v-b-tooltip :title='$t("common.admin")') <v-icon color='lightblue' name='tools'/>
span.d-md-none {{$t('common.admin')}}
b-nav-item(to='/export' v-b-tooltip :title='$t("common.export")') <v-icon name='file-export' color='yellow'/>
span.d-md-none {{$t('common.export')}}
b-nav-item(v-if='$auth.loggedIn' @click='logout' v-b-tooltip :title='$t("common.logout")') <v-icon color='red' name='sign-out-alt'/>
span.d-md-none {{$t('common.logout')}}
b-nav-item
b-navbar-nav.ml-auto
b-nav-item(to='/about')
span {{$t('common.info')}} <v-icon color='#ff9fc4' name='question-circle'/>
el-menu.d-grid.nav(mode='horizontal' router background-color="#222C32")
el-menu-item(v-if='!$auth.loggedIn' index='/login' :title="$t('common.login')")
v-icon(color='lightgreen' name='user')
el-menu-item(index='/add' :title="$t('common.add_event')")
v-icon(color='lightgreen' name='plus')
el-menu-item(v-if='$auth.loggedIn' index='/settings' :title="$t('common.settings')")
v-icon(color='orange' name='cog')
el-menu-item(v-if='$auth.user && $auth.user.is_admin' index='/admin' :title="$t('common.admin')")
v-icon(color='lightblue' name='tools')
el-menu-item(index='/export' :title="$t('common.share')")
v-icon(name='share' color='yellow')
el-menu-item(v-if='$auth.loggedIn' @click='logout' :title="$t('common.logout')")
v-icon(color='red' name='sign-out-alt')
el-popover(
placement="bottom"
trigger="click")
Search
el-menu-item(slot='reference')
v-icon(color='lightblue' name='search')
el-menu-item.float-right(index='/about' :title="$t('common.info')")
img#logo(src='/favicon.ico')
</template>
<script>
import {mapState, mapActions} from 'vuex'
import { Message } from 'element-ui'
import Search from '@/components/Search'
export default {
name: 'Nav',
computed: {
...mapState(['filters']),
filters_tags: {
set (value) {
this.setSearchTags(value)
},
get () {
return this.filters.tags
}
},
filters_places: {
set (value) {
this.setSearchPlaces(value)
},
get () {
return this.filters.places
}
},
},
methods: mapActions(['logout']),
components: { Search },
methods: {
logout () {
Message({
message: this.$t('common.logout_ok'),
type: 'success'
})
this.$auth.logout()
}
}
}
</script>
<style>
.el-menu.el-menu--horizontal {
border-bottom: none;
}
</style>

View File

@@ -1,23 +1,64 @@
<template lang="pug">
div
el-select.mr-1(v-model='filters_places' multiple filterable collapse-tags
default-first-option :placeholder='$t("Where")')
el-option(v-for='place in places' :value='place.name'
:label='place.name' :key='place.id')
el-select(v-model='filters_tags' multiple filterable collapse-tags
default-first-option :placeholder='$t("Tags")')
el-option(v-for='tag in tags' :key='tag.tag'
:label='tag.tag' :value='tag.tag')
div.ml-2.mt-1
el-switch.mb-1(v-if='$auth.loggedIn'
active-text='solo miei'
inactive-text='tutti'
inactive-color='lightgreen'
v-model='onlyMine'
)
el-switch.mt-1.mb-1.ml-2.d-block(
inactive-text='futuri'
active-text='anche passati'
inactive-color='lightgreen'
v-model='showPast'
)
el-select.search(v-model='filter' multiple
filterable collapse-tags default-first-option
:placeholder='$t("common.search")')
el-option(v-for='(keyword, id) in keywords' :key='keyword.value'
:label='keyword.label' :value='keyword.value')
</template>
<script>
import {mapState, mapActions} from 'vuex'
export default {
data () {
return {
onlyMine: false,
withPast: true,
}
},
name :'Search',
methods: mapActions(['setSearchPlaces', 'setSearchTags']),
methods: mapActions(['setSearchPlaces', 'setSearchTags', 'showPastEvents']),
computed: {
...mapState(['tags', 'places', 'filters']),
...mapState(['tags', 'places', 'filters', 'show_past_events']),
keywords () {
const tags = this.tags.map( t => ({ value: 't' + t.tag, label: t.tag, count: +t.eventsCount }))
const places = this.places.map( p => ({ value: 'p' + p.id, label: p.name, count: +p.eventsCount }))
return tags.concat(places)
},
showPast : {
set (value) {
this.showPastEvents(value)
},
get () {
return this.show_past_events
}
},
filter: {
set (filters) {
const tags = filters.filter(f => f[0] === 't').map(t => t.slice(1))
this.setSearchTags(tags)
const places = filters.filter(f => f[0] === 'p').map(p => +p.slice(1))
this.setSearchPlaces(places)
},
get () {
return this.filters.tags.map(t => 't' + t).concat(this.filters.places.map(p => 'p' + p))
}
},
filters_tags: {
set (value) {
this.setSearchTags(value)
@@ -37,3 +78,5 @@ export default {
}
}
</script>
<style lang="less">
</style>