mirror of
https://framagit.org/les/gancio.git
synced 2025-01-31 16:42:22 +01:00
keep migrating to vuetify
This commit is contained in:
parent
539c0fa933
commit
3abb39f62b
24 changed files with 1382 additions and 1389 deletions
|
@ -1,6 +1,7 @@
|
||||||
html, body {
|
html, body {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: orange;
|
scrollbar-color: orange;
|
||||||
|
overflow: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
v-calendar(
|
v-calendar(
|
||||||
title-position='left'
|
title-position='left'
|
||||||
:is-dark="settings['theme.is_dark']"
|
:is-dark="settings['theme.is_dark']"
|
||||||
:columns="$screens({ default: 1, md: 2 })"
|
:columns="2"
|
||||||
@update:from-page='updatePage'
|
@update:from-page='updatePage'
|
||||||
:locale='$i18n.locale'
|
:locale='$i18n.locale'
|
||||||
:attributes='attributes'
|
:attributes='attributes'
|
||||||
|
@ -21,7 +21,7 @@ import { take, get } from 'lodash'
|
||||||
export default {
|
export default {
|
||||||
name: 'Calendar',
|
name: 'Calendar',
|
||||||
props: {
|
props: {
|
||||||
events: { type: Array, default: [] }
|
events: { type: Array, default: () => [] }
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
const month = dayjs().month() + 1
|
const month = dayjs().month() + 1
|
||||||
|
@ -35,13 +35,14 @@ export default {
|
||||||
|
|
||||||
// TODO: could be better
|
// TODO: could be better
|
||||||
attributes () {
|
attributes () {
|
||||||
|
return []
|
||||||
const colors = ['blue', 'orange', 'yellow', 'teal', 'indigo', 'green', 'red', 'purple', 'pink', 'gray']
|
const colors = ['blue', 'orange', 'yellow', 'teal', 'indigo', 'green', 'red', 'purple', 'pink', 'gray']
|
||||||
const tags = take(this.tags, 10).map(t => t.tag)
|
const tags = take(this.tags, 10).map(t => t.tag)
|
||||||
let attributes = []
|
let attributes = []
|
||||||
attributes.push({ key: 'today', dates: new Date(), highlight: { color: 'green', fillMode: 'outline' } })
|
attributes.push({ key: 'today', dates: new Date(), highlight: { color: 'green', fillMode: 'outline' } })
|
||||||
|
|
||||||
function getColor (event) {
|
function getColor (event) {
|
||||||
const color = { class: 'vc-rounded-full', color: 'blue', fillMode: 'outline' }
|
const color = { class: 'vc-rounded-full', color: 'blue', fillMode: 'normal' }
|
||||||
const tag = get(event, 'tags[0]')
|
const tag = get(event, 'tags[0]')
|
||||||
if (!tag) { return color }
|
if (!tag) { return color }
|
||||||
const idx = tags.indexOf(tag)
|
const idx = tags.indexOf(tag)
|
||||||
|
|
|
@ -1,78 +1,83 @@
|
||||||
<template lang="pug">
|
<template lang="pug" functional>
|
||||||
v-card.h-event.event.mt-1
|
v-card.h-event.event.mt-1
|
||||||
nuxt-link(:to='`/event/${event.id}`')
|
template(v-if='props.show')
|
||||||
v-img.align-end.white--text(:src="`/media/thumb/${event.image_path}`"
|
nuxt-link(:to='`/event/${props.event.id}`')
|
||||||
gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.7), rgba(0,0,0,.9)"
|
v-img.align-end.white--text(:src="`/media/thumb/${props.event.image_path}`"
|
||||||
height="250" position="top top")
|
gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.7), rgba(0,0,0,.9)"
|
||||||
v-card-title.text-h5 {{event.title}}
|
height="250" position="top top")
|
||||||
|
v-card-title.text-h5.p-name {{props.event.title}}
|
||||||
|
|
||||||
v-card-text
|
v-card-text
|
||||||
|
v-icon.float-right(v-if='props.event.parentId' color='success') mdi-repeat
|
||||||
|
//- time.text-h6.dt-start(:datetime='props.event.start_datetime|unixFormat("YYYY-MM-DD HH:mm")') <v-icon>mdi-event</v-icon> {{ event|when }}
|
||||||
|
.d-none.dt-end {{props.event.end_datetime|unixFormat('YYYY-MM-DD HH:mm')}}
|
||||||
|
v-btn.d-block.text-h6.p-location(text color='primary' big @click="$emit('placeclick', props.event.place.id)") <v-icon>mdi-map-marker</v-icon> {{props.event.place.name}}
|
||||||
|
|
||||||
time.text-h6(:datetime='event.start_datetime|unixFormat("YYYY-MM-DD HH:mm")') <v-icon>mdi-event</v-icon> {{ event|when }}
|
v-card-actions
|
||||||
v-btn.d-block.text-h6(text color='primary' big @click="$emit('placeclick', event.place.id)") <v-icon>mdi-map-marker</v-icon> {{event.place.name}}
|
v-chip.ml-1(v-for='tag in props.event.tags' link
|
||||||
|
:key='tag' outlined color='primary' @click="$emit('tagclick',tag)") {{tag}}
|
||||||
|
v-spacer
|
||||||
|
|
||||||
v-card-actions
|
v-menu(offset-y)
|
||||||
v-chip.ml-1(v-for='tag in event.tags' link
|
template(v-slot:activator="{on}")
|
||||||
:key='tag' outlined color='primary' @click="$emit('tagclick',tag)") {{tag}}
|
v-btn(icon v-on='on' color='primary')
|
||||||
v-spacer
|
v-icon mdi-dots-vertical
|
||||||
|
v-list(dense)
|
||||||
|
v-list-item-group
|
||||||
|
v-list-item(v-clipboard:success='copyLink'
|
||||||
|
v-clipboard:copy='`${parent.settings.baseurl}/event/${props.event.id}`')
|
||||||
|
v-list-item-icon
|
||||||
|
v-icon mdi-content-copy
|
||||||
|
v-list-item-content
|
||||||
|
v-list-item-title {{parent.$t('common.copy_link')}}
|
||||||
|
v-list-item(:href='`/api/event/${props.event.id}.ics`')
|
||||||
|
v-list-item-icon
|
||||||
|
v-icon mdi-calendar-export
|
||||||
|
v-list-item-content
|
||||||
|
v-list-item-title {{parent.$t('common.add_to_calendar')}}
|
||||||
|
|
||||||
v-menu(offset-y)
|
|
||||||
template(v-slot:activator="{on}")
|
|
||||||
v-btn(icon v-on='on' color='primary')
|
|
||||||
v-icon mdi-dots-vertical
|
|
||||||
v-list(dense)
|
|
||||||
v-list-item-group
|
|
||||||
v-list-item(v-clipboard:success='copyLink'
|
|
||||||
v-clipboard:copy='`${settings.baseurl}/event/${event.id}`')
|
|
||||||
v-list-item-icon
|
|
||||||
v-icon mdi-content-copy
|
|
||||||
v-list-item-content
|
|
||||||
v-list-item-title {{$t('common.copy_link')}}
|
|
||||||
v-list-item(:href='`/api/event/${event.id}.ics`')
|
|
||||||
v-list-item-icon
|
|
||||||
v-icon mdi-calendar-export
|
|
||||||
v-list-item-content
|
|
||||||
v-list-item-title {{$t('common.add_to_calendar')}}
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapActions } from 'vuex'
|
// import { mapState, mapActions } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
event: { type: Object, default: () => ({}) }
|
event: { type: Object, default: () => ({}) },
|
||||||
},
|
show: { type: Boolean }
|
||||||
computed: {
|
|
||||||
...mapState(['settings']),
|
|
||||||
show_footer () {
|
|
||||||
return (this.event.tags.length || this.event.resources.length)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions(['setSearchTags', 'setSearchPlaces']),
|
|
||||||
copyLink () {
|
|
||||||
this.$root.$message('common.copied', { color: 'success' })
|
|
||||||
},
|
|
||||||
addTag (tag) {
|
|
||||||
if (this.filters.tags.includes(tag)) {
|
|
||||||
this.setSearchTags(this.filters.tags.filter(t => t !== tag))
|
|
||||||
} else {
|
|
||||||
this.setSearchTags(this.filters.tags.concat([tag]))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addPlace () {
|
|
||||||
const place = this.event.place.id
|
|
||||||
if (this.filters.places.includes(place)) {
|
|
||||||
this.setSearchPlaces(this.filters.places.filter(p => p !== place))
|
|
||||||
} else {
|
|
||||||
this.setSearchPlaces(this.filters.places.concat(place))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// computed: {
|
||||||
|
// ...mapState(['settings']),
|
||||||
|
// show_footer () {
|
||||||
|
// return (this.event.tags.length || this.event.resources.length)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// methods: {
|
||||||
|
// ...mapActions(['setSearchTags', 'setSearchPlaces']),
|
||||||
|
// copyLink () {
|
||||||
|
// this.$root.$message('common.copied', { color: 'success' })
|
||||||
|
// },
|
||||||
|
// addTag (tag) {
|
||||||
|
// if (this.filters.tags.includes(tag)) {
|
||||||
|
// this.setSearchTags(this.filters.tags.filter(t => t !== tag))
|
||||||
|
// } else {
|
||||||
|
// this.setSearchTags(this.filters.tags.concat([tag]))
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// addPlace () {
|
||||||
|
// const place = this.event.place.id
|
||||||
|
// if (this.filters.places.includes(place)) {
|
||||||
|
// this.setSearchPlaces(this.filters.places.filter(p => p !== place))
|
||||||
|
// } else {
|
||||||
|
// this.setSearchPlaces(this.filters.places.concat(place))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less">
|
||||||
.event {
|
.event {
|
||||||
width: 330px;
|
width: 330px;
|
||||||
|
height: 370px;
|
||||||
max-width: 450px;
|
max-width: 450px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
margin: .2em;
|
margin: .2em;
|
||||||
|
|
|
@ -22,24 +22,10 @@
|
||||||
v-btn(icon nuxt to='/export' v-on='on')
|
v-btn(icon nuxt to='/export' v-on='on')
|
||||||
v-icon mdi-share-variant
|
v-icon mdi-share-variant
|
||||||
|
|
||||||
//- v-menu(v-if='settings.enable_trusted_instances && settings.trusted_instances && settings.trusted_instances.length'
|
v-tooltip(v-if='!$auth.loggedIn' bottom) {{$t('common.login')}}
|
||||||
offset-y bottom open-on-hover transition="slide-y-transition")
|
template(v-slot:activator='{ on }')
|
||||||
template(v-slot:activator="{ on, attrs }")
|
v-btn(icon nuxt to='/login' v-on='on')
|
||||||
v-btn(icon v-bind='attrs' v-on='on')
|
v-icon mdi-login
|
||||||
v-icon mdi-map-marker-path
|
|
||||||
v-list
|
|
||||||
v-list-item(v-for='instance in settings.trusted_instances'
|
|
||||||
:key='instance.name'
|
|
||||||
:href='instance.url'
|
|
||||||
two-line)
|
|
||||||
v-list-item-avatar
|
|
||||||
v-img(:src='`${instance.url}/favicon.ico`')
|
|
||||||
v-list-item-content
|
|
||||||
v-list-item-title {{instance.name}}
|
|
||||||
v-list-item-subtitle {{instance.label}}
|
|
||||||
|
|
||||||
v-btn(v-if='!$auth.loggedIn' icon nuxt to='/login')
|
|
||||||
v-icon mdi-login
|
|
||||||
|
|
||||||
v-menu(v-else
|
v-menu(v-else
|
||||||
offset-y bottom open-on-hover transition="slide-y-transition")
|
offset-y bottom open-on-hover transition="slide-y-transition")
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
v-container
|
v-container
|
||||||
v-switch.mt-0(
|
v-switch.mt-0(
|
||||||
v-if='recurrentFilter && settings.allow_recurrent_event'
|
v-if='recurrentFilter && settings.allow_recurrent_event'
|
||||||
|
v-model='filters.show_recurrent'
|
||||||
inset color='primary'
|
inset color='primary'
|
||||||
:label="$t('event.show_recurrent')"
|
:label="$t('event.show_recurrent')"
|
||||||
@change="v => $emit('showrecurrent', v)")
|
@change="toggleShowRecurrent")
|
||||||
|
|
||||||
v-autocomplete.mt-0(
|
v-autocomplete.mt-0(
|
||||||
:label='$t("common.search")'
|
:label='$t("common.search")'
|
||||||
|
@ -37,7 +38,6 @@ import { mapState } from 'vuex'
|
||||||
export default {
|
export default {
|
||||||
name: 'Search',
|
name: 'Search',
|
||||||
props: {
|
props: {
|
||||||
pastFilter: { type: Boolean, default: true },
|
|
||||||
recurrentFilter: { type: Boolean, default: true },
|
recurrentFilter: { type: Boolean, default: true },
|
||||||
filters: { type: Object, default: () => {} }
|
filters: { type: Object, default: () => {} }
|
||||||
},
|
},
|
||||||
|
@ -67,14 +67,24 @@ export default {
|
||||||
remove (item) {
|
remove (item) {
|
||||||
const filters = {
|
const filters = {
|
||||||
tags: item.type === 'tag' ? this.filters.tags.filter(f => f !== item.id) : this.filters.tags,
|
tags: item.type === 'tag' ? this.filters.tags.filter(f => f !== item.id) : this.filters.tags,
|
||||||
places: item.type === 'place' ? this.filters.places.filter(f => f !== item.id) : this.filters.places
|
places: item.type === 'place' ? this.filters.places.filter(f => f !== item.id) : this.filters.places,
|
||||||
|
show_recurrent: this.filters.show_recurrent
|
||||||
|
}
|
||||||
|
this.$emit('update', filters)
|
||||||
|
},
|
||||||
|
toggleShowRecurrent (v) {
|
||||||
|
const filters = {
|
||||||
|
tags: this.filters.tags,
|
||||||
|
places: this.filters.places,
|
||||||
|
show_recurrent: v
|
||||||
}
|
}
|
||||||
this.$emit('update', filters)
|
this.$emit('update', filters)
|
||||||
},
|
},
|
||||||
change (filters) {
|
change (filters) {
|
||||||
filters = {
|
filters = {
|
||||||
tags: filters.filter(t => t.type === 'tag').map(t => t.id),
|
tags: filters.filter(t => t.type === 'tag').map(t => t.id),
|
||||||
places: filters.filter(p => p.type === 'place').map(p => p.id)
|
places: filters.filter(p => p.type === 'place').map(p => p.id),
|
||||||
|
show_recurrent: this.filters.show_recurrent
|
||||||
}
|
}
|
||||||
this.$emit('update', filters)
|
this.$emit('update', filters)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ export default {
|
||||||
ca: 'Català',
|
ca: 'Català',
|
||||||
pl: 'Polski',
|
pl: 'Polski',
|
||||||
eu: 'Euskara',
|
eu: 'Euskara',
|
||||||
nb_NO: 'Norwegian Bokmål',
|
no: 'Norwegian Bokmål',
|
||||||
fr: 'Francais',
|
fr: 'Francais',
|
||||||
de: 'Deutsch'
|
de: 'Deutsch'
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ module.exports = {
|
||||||
ca: 'Català',
|
ca: 'Català',
|
||||||
pl: 'Polski',
|
pl: 'Polski',
|
||||||
eu: 'Euskara',
|
eu: 'Euskara',
|
||||||
nb_NO: 'Norwegian Bokmål',
|
no: 'Norwegian Bokmål',
|
||||||
fr: 'Francais',
|
fr: 'Francais',
|
||||||
de: 'Deutsch'
|
de: 'Deutsch'
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,8 @@
|
||||||
"embed": "Incorpora",
|
"embed": "Incorpora",
|
||||||
"embed_title": "Mostra questo evento sul tuo sito web",
|
"embed_title": "Mostra questo evento sul tuo sito web",
|
||||||
"embed_help": "Copiando il seguente codice sul tuo sito web l'evento verrà incluso come qui di lato",
|
"embed_help": "Copiando il seguente codice sul tuo sito web l'evento verrà incluso come qui di lato",
|
||||||
"feed": "Flusso RSS",
|
"feed": "Feed RSS",
|
||||||
"feed_url_copied": "URL copiato, incollalo nel tuo lettore di flusso RSS",
|
"feed_url_copied": "URL copiato, incollalo nel tuo lettore di Feed RSS",
|
||||||
"follow_me_title": "Segui gli aggiornamenti dal fediverso",
|
"follow_me_title": "Segui gli aggiornamenti dal fediverso",
|
||||||
"follow": "Segui",
|
"follow": "Segui",
|
||||||
"n_resources": "nessuna risorsa|una risorsa|{n} risorse",
|
"n_resources": "nessuna risorsa|una risorsa|{n} risorse",
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
"media_description": "Puoi aggiungere un volantino (opzionale)",
|
"media_description": "Puoi aggiungere un volantino (opzionale)",
|
||||||
"added": "Evento aggiunto",
|
"added": "Evento aggiunto",
|
||||||
"added_anon": "Evento aggiunto, verrà confermato quanto prima.",
|
"added_anon": "Evento aggiunto, verrà confermato quanto prima.",
|
||||||
"where_description": "Dov'è il gancio? Se il posto non è presente, scrivilo e <b>premi invio</b>. ",
|
"where_description": "Dov'è il gancio? Se il posto non è presente potrai crearlo. ",
|
||||||
"confirmed": "Evento confermato",
|
"confirmed": "Evento confermato",
|
||||||
"not_found": "Evento non trovato",
|
"not_found": "Evento non trovato",
|
||||||
"remove_confirmation": "Sei sicuro/a di voler eliminare questo evento?",
|
"remove_confirmation": "Sei sicuro/a di voler eliminare questo evento?",
|
||||||
|
@ -153,7 +153,8 @@
|
||||||
"interact_with_me_at": "Seguimi nel fediverso su",
|
"interact_with_me_at": "Seguimi nel fediverso su",
|
||||||
"import_ICS": "Importa da ICS",
|
"import_ICS": "Importa da ICS",
|
||||||
"import_URL": "Importa da URL",
|
"import_URL": "Importa da URL",
|
||||||
"ics": "ICS"
|
"ics": "ICS",
|
||||||
|
"import_description": "Puoi importare eventi da altre piattaforme e da altre istanze attraverso i formati standard (ics e h-event)"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"place_description": "Nel caso in cui un luogo sia errato o cambi indirizzo, puoi modificarlo.<br/>Considera che tutti gli eventi associati a questo luogo cambieranno indirizzo (anche quelli passati).",
|
"place_description": "Nel caso in cui un luogo sia errato o cambi indirizzo, puoi modificarlo.<br/>Considera che tutti gli eventi associati a questo luogo cambieranno indirizzo (anche quelli passati).",
|
||||||
|
|
34
package.json
34
package.json
|
@ -28,9 +28,9 @@
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/auth": "^4.9.1",
|
"@nuxtjs/auth": "^4.9.1",
|
||||||
"@nuxtjs/axios": "^5.12.3",
|
"@nuxtjs/axios": "^5.12.4",
|
||||||
"accept-language": "^3.0.18",
|
"accept-language": "^3.0.18",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"body-parser": "^1.18.3",
|
"body-parser": "^1.18.3",
|
||||||
"config": "^3.3.3",
|
"config": "^3.3.3",
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"date-fns": "^2.16.1",
|
"date-fns": "^2.16.1",
|
||||||
"dayjs": "^1.9.6",
|
"dayjs": "^1.9.6",
|
||||||
"dompurify": "^2.2.2",
|
"dompurify": "^2.2.6",
|
||||||
"email-templates": "^8.0.2",
|
"email-templates": "^8.0.2",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-oauth-server": "^2.0.0",
|
"express-oauth-server": "^2.0.0",
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
"inquirer": "^7.3.3",
|
"inquirer": "^7.3.3",
|
||||||
"jsdom": "^16.4.0",
|
"jsdom": "^16.4.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"less": "^3.12.2",
|
"less": "^4.0.0",
|
||||||
"linkifyjs": "^2.1.9",
|
"linkifyjs": "^2.1.9",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"microformat-node": "^2.0.1",
|
"microformat-node": "^2.0.1",
|
||||||
|
@ -59,18 +59,18 @@
|
||||||
"moment-timezone": "^0.5.32",
|
"moment-timezone": "^0.5.32",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.2",
|
"multer": "^1.4.2",
|
||||||
"nuxt": "^2.14.9",
|
"nuxt": "^2.14.12",
|
||||||
"nuxt-express-module": "^0.0.11",
|
"nuxt-express-module": "^0.0.11",
|
||||||
"pg": "^8.5.1",
|
"pg": "^8.5.1",
|
||||||
"sequelize": "^6.3.5",
|
"sequelize": "^6.3.5",
|
||||||
"sequelize-cli": "^6.2.0",
|
"sequelize-cli": "^6.2.0",
|
||||||
"sharp": "^0.26.3",
|
"sharp": "^0.27.0",
|
||||||
"sqlite3": "^5.0.0",
|
"sqlite3": "^5.0.0",
|
||||||
"tiptap": "^1.30.0",
|
"tiptap": "^1.30.0",
|
||||||
"tiptap-extensions": "^1.33.2",
|
"tiptap-extensions": "^1.33.2",
|
||||||
"to-ico": "^1.1.5",
|
"to-ico": "^1.1.5",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"v-calendar": "^2.1.1",
|
"v-calendar": "^2.1.3",
|
||||||
"vue-clipboard2": "^0.3.1",
|
"vue-clipboard2": "^0.3.1",
|
||||||
"vue-i18n": "^8.22.2",
|
"vue-i18n": "^8.22.2",
|
||||||
"yargs": "^16.1.1"
|
"yargs": "^16.1.1"
|
||||||
|
@ -80,29 +80,29 @@
|
||||||
"@nuxtjs/eslint-config": "^5.0.0",
|
"@nuxtjs/eslint-config": "^5.0.0",
|
||||||
"@nuxtjs/vuetify": "^1.11.2",
|
"@nuxtjs/vuetify": "^1.11.2",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
"eslint": "^7.14.0",
|
"eslint": "^7.16.0",
|
||||||
"eslint-config-prettier": "^6.15.0",
|
"eslint-config-prettier": "^7.1.0",
|
||||||
"eslint-config-standard": "^16.0.2",
|
"eslint-config-standard": "^16.0.2",
|
||||||
"eslint-loader": "^4.0.2",
|
"eslint-loader": "^4.0.2",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.22.1",
|
||||||
"eslint-plugin-node": ">=11.1.0",
|
"eslint-plugin-node": ">=11.1.0",
|
||||||
"eslint-plugin-nuxt": "^2.0.0",
|
"eslint-plugin-nuxt": "^2.0.0",
|
||||||
"eslint-plugin-prettier": "^3.2.0",
|
"eslint-plugin-prettier": "^3.3.0",
|
||||||
"eslint-plugin-promise": ">=4.0.1",
|
"eslint-plugin-promise": ">=4.0.1",
|
||||||
"eslint-plugin-standard": "^5.0.0",
|
"eslint-plugin-standard": "^5.0.0",
|
||||||
"eslint-plugin-vue": "^7.2.0",
|
"eslint-plugin-vue": "^7.3.0",
|
||||||
"less-loader": "^7.1.0",
|
"less-loader": "^7.2.0",
|
||||||
"nodemon": "^2.0.6",
|
"nodemon": "^2.0.6",
|
||||||
"prettier": "^2.2.1",
|
"prettier": "^2.2.1",
|
||||||
"pug-plain-loader": "^1.0.0",
|
"pug-plain-loader": "^1.1.0",
|
||||||
"sass": "^1.29.0",
|
"sass": "^1.30.0",
|
||||||
"sass-loader": "^10.1.0",
|
"sass-loader": "^10.1.0",
|
||||||
"vue-cli-plugin-vuetify": "~2.0.8",
|
"vue-cli-plugin-vuetify": "~2.0.8",
|
||||||
"vuetify-loader": "^1.3.0",
|
"vuetify-loader": "^1.3.0",
|
||||||
"webpack-cli": "^4.2.0"
|
"webpack-cli": "^4.3.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"prosemirror-model": "1.12.0"
|
"prosemirror-model": "1.13.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"gancio": "server/cli.js"
|
"gancio": "server/cli.js"
|
||||||
|
@ -112,7 +112,7 @@
|
||||||
"url": "https://framagit.org/les/gancio/issues"
|
"url": "https://framagit.org/les/gancio/issues"
|
||||||
},
|
},
|
||||||
"homepage": "https://gancio.org",
|
"homepage": "https://gancio.org",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"AP",
|
"AP",
|
||||||
"gancio",
|
"gancio",
|
||||||
"events",
|
"events",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
v-container
|
v-container
|
||||||
v-card
|
v-card
|
||||||
v-tabs
|
v-tabs(v-model='selectedTab')
|
||||||
|
|
||||||
//- SETTINGS
|
//- SETTINGS
|
||||||
v-tab {{$t('common.settings')}}
|
v-tab {{$t('common.settings')}}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
v-row
|
v-row
|
||||||
v-date-picker.col-md-6(
|
v-date-picker.col-md-6(
|
||||||
mode='dateTime'
|
mode='dateTime'
|
||||||
|
is24hr
|
||||||
:input-debounce="200"
|
:input-debounce="200"
|
||||||
:min='today'
|
:min='today'
|
||||||
:minute-increment="5"
|
:minute-increment="5"
|
||||||
|
@ -15,7 +16,6 @@ v-row
|
||||||
:value='inputValue'
|
:value='inputValue'
|
||||||
:label="$t('event.from')"
|
:label="$t('event.from')"
|
||||||
:rules="[$validators.required('common.when')]"
|
:rules="[$validators.required('common.when')]"
|
||||||
:hint="$t(`event.description`)"
|
|
||||||
ref='date'
|
ref='date'
|
||||||
prepend-icon='mdi-calendar'
|
prepend-icon='mdi-calendar'
|
||||||
persistent-hint
|
persistent-hint
|
||||||
|
@ -24,6 +24,7 @@ v-row
|
||||||
|
|
||||||
v-date-picker.col-md-4(
|
v-date-picker.col-md-4(
|
||||||
mode='dateTime'
|
mode='dateTime'
|
||||||
|
is24hr
|
||||||
:minute-increment="5"
|
:minute-increment="5"
|
||||||
:input-debounce="200"
|
:input-debounce="200"
|
||||||
:min='today'
|
:min='today'
|
||||||
|
@ -35,8 +36,7 @@ v-row
|
||||||
template(v-slot="{ inputValue, inputEvents }")
|
template(v-slot="{ inputValue, inputEvents }")
|
||||||
v-text-field(
|
v-text-field(
|
||||||
:value='inputValue'
|
:value='inputValue'
|
||||||
:label="$t('event.from')"
|
:label="$t('event.due')"
|
||||||
:hint="$t(`event.description`)"
|
|
||||||
ref='date'
|
ref='date'
|
||||||
prepend-icon='mdi-calendar'
|
prepend-icon='mdi-calendar'
|
||||||
persistent-hint
|
persistent-hint
|
||||||
|
@ -60,20 +60,19 @@ v-row
|
||||||
//- v-btn-toggle.col-md-4(@change='changeType' color='primary' :value='value.type')
|
//- v-btn-toggle.col-md-4(@change='changeType' color='primary' :value='value.type')
|
||||||
//- v-btn(value='normal') {{$t('event.normal')}}
|
//- v-btn(value='normal') {{$t('event.normal')}}
|
||||||
//- v-btn(value='multidate') {{$t('event.multidate')}}
|
//- v-btn(value='multidate') {{$t('event.multidate')}}
|
||||||
v-switch.col-md-2(v-model='is_recurrent' :label="$t('event.recurrent')" inset)
|
v-switch.col-md-2(:input-value='isRecurrent' :label="$t('event.recurrent')" inset @change='updateRecurrent')
|
||||||
v-menu(v-if='settings.allow_recurrent_event && is_recurrent' offset-y open-on-hover)
|
//- v-menu(v-if='settings.allow_recurrent_event && isRecurrent' offset-y open-on-hover)
|
||||||
template(v-slot:activator="{ on, attrs }")
|
//- template(v-slot:activator="{ on, attrs }")
|
||||||
v-btn.col-md-2.mt-2(color='primary' value='recurrent' v-on='on') {{$t('event.recurrent')}}
|
//- v-btn.col-md-2.mt-2(color='primary' value='recurrent' v-on='on') {{$t('event.recurrent')}}
|
||||||
v-list
|
//- v-btn-group(v-if='settings.allow_recurrent_event && isRecurrent')
|
||||||
v-list-item-group(color='primary' v-model='frequency')
|
v-btn-toggle.col-md-12(dense group text link v-if='isRecurrent' color='primary' v-model='value.recurrent.frequency')
|
||||||
v-list-item(v-for='f in frequencies' :key='f.value'
|
v-btn(text link v-for='f in frequencies' :key='f.value' :value='f.value'
|
||||||
@click='selectFrequency(f.value)') {{f.text}}
|
@click='selectFrequency(f.value)') {{f.text}}
|
||||||
|
|
||||||
//- div.text-center.mb-2(v-if='value.type === "recurrent"')
|
div.col-md-12(v-if='isRecurrent')
|
||||||
//- span(v-if='value.recurrent.frequency !== "1m" && value.recurrent.frequency !== "2m"') {{whenPatterns}}
|
p(v-if='value.recurrent.frequency !== "1m" && value.recurrent.frequency !== "2m"') 🡲 {{whenPatterns}}
|
||||||
//- v-btn-toggle.mt-1(v-else v-model='value.recurrent.type' color='primary')
|
v-btn-toggle(v-else dense group v-model='value.recurrent.type' color='primary')
|
||||||
//- v-btn(v-for='whenPattern in whenPatterns' :value='whenPattern.key' :key='whenPatterns.key' small)
|
v-btn(text link v-for='whenPattern in whenPatterns' :value='whenPattern.key' :key='whenPatterns.key') {{whenPattern.label}}
|
||||||
//- span {{whenPattern.label}}
|
|
||||||
|
|
||||||
//- List(v-if='type==="normal" && todayEvents.length' :events='todayEvents' :title='$t("event.same_day")')
|
//- List(v-if='type==="normal" && todayEvents.length' :events='todayEvents' :title='$t("event.same_day")')
|
||||||
|
|
||||||
|
@ -91,7 +90,6 @@ export default {
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
is_recurrent: false,
|
|
||||||
today: dayjs().format('YYYY-MM-DD'),
|
today: dayjs().format('YYYY-MM-DD'),
|
||||||
frequency: '',
|
frequency: '',
|
||||||
frequencies: [
|
frequencies: [
|
||||||
|
@ -103,17 +101,19 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['settings', 'events']),
|
...mapState(['settings', 'events']),
|
||||||
|
isRecurrent () {
|
||||||
|
return !!this.value.recurrent
|
||||||
|
},
|
||||||
whenPatterns () {
|
whenPatterns () {
|
||||||
if (!this.value.date) { return }
|
if (!this.value.from) { return }
|
||||||
const date = dayjs(this.value.date)
|
const date = dayjs(this.value.from)
|
||||||
|
|
||||||
const freq = this.value.recurrent.frequency
|
const freq = this.value.recurrent.frequency
|
||||||
const weekDay = date.format('dddd')
|
const weekDay = date.format('dddd')
|
||||||
if (freq === '1w' || freq === '2w') {
|
if (freq === '1w' || freq === '2w') {
|
||||||
return this.$t(`event.recurrent_${freq}_days`, { days: weekDay })
|
return this.$t(`event.recurrent_${freq}_days`, { days: weekDay }).toUpperCase()
|
||||||
} else if (freq === '1m' || freq === '2m') {
|
} else if (freq === '1m' || freq === '2m') {
|
||||||
const monthDay = date.format('D')
|
const monthDay = date.format('D')
|
||||||
|
|
||||||
const n = Math.floor((monthDay - 1) / 7) + 1
|
const n = Math.floor((monthDay - 1) / 7) + 1
|
||||||
|
|
||||||
const patterns = [
|
const patterns = [
|
||||||
|
@ -150,19 +150,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
updateRecurrent (value) {
|
||||||
|
this.$emit('input', { ...this.value, recurrent: value ? {} : null })
|
||||||
|
},
|
||||||
change (what, date) {
|
change (what, date) {
|
||||||
const v = this.value
|
const v = this.value
|
||||||
v[what] = date
|
v[what] = date
|
||||||
this.$emit('input', v)
|
this.$emit('input', v)
|
||||||
},
|
},
|
||||||
changeType (type) {
|
|
||||||
this.$emit('input', { date: null, recurrent: {} })
|
|
||||||
if (type !== 'recurrent') {
|
|
||||||
this.frequency = ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectFrequency (f) {
|
selectFrequency (f) {
|
||||||
this.$emit('input', { recurrent: { frequency: f }, date: null })
|
this.$emit('input', { recurrent: { frequency: f }, from: this.value.from, due: this.value.due })
|
||||||
}
|
}
|
||||||
// pick (date) {
|
// pick (date) {
|
||||||
// if (this.value.type === 'normal' || this.value.type === 'recurrent' || (this.value.date && this.value.date.length === 2)) {
|
// if (this.value.type === 'normal' || this.value.type === 'recurrent' || (this.value.date && this.value.date.length === 2)) {
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
v-card(color='secondary')
|
v-card(color='secondary')
|
||||||
v-card-title {{$t('common.import')}}
|
v-card-title {{$t('common.import')}}
|
||||||
v-card-text
|
v-card-text
|
||||||
v-form(v-model='valid' ref='form' lazy-validation)
|
p(v-html="$t('event.import_description')")
|
||||||
|
v-form(v-model='valid' ref='form' lazy-validation @submit.prevent='importGeneric')
|
||||||
v-text-field(v-model='URL'
|
v-text-field(v-model='URL'
|
||||||
:label="$t('common.url')"
|
:label="$t('common.url')"
|
||||||
:hint="$t('event.import_URL')"
|
:hint="$t('event.import_URL')"
|
||||||
|
@ -18,7 +19,7 @@
|
||||||
persistent-hint
|
persistent-hint
|
||||||
)
|
)
|
||||||
|
|
||||||
p {{event}}
|
p {{events}}
|
||||||
v-card-actions
|
v-card-actions
|
||||||
v-spacer
|
v-spacer
|
||||||
v-btn(@click='$emit("close")' color='warning') {{$t('common.cancel')}}
|
v-btn(@click='$emit("close")' color='warning') {{$t('common.cancel')}}
|
||||||
|
@ -39,7 +40,7 @@ export default {
|
||||||
loading: false,
|
loading: false,
|
||||||
valid: false,
|
valid: false,
|
||||||
URL: '',
|
URL: '',
|
||||||
event: {}
|
events: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -54,8 +55,7 @@ export default {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.readAsText(this.file)
|
reader.readAsText(this.file)
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
const data = reader.result
|
const event = ical.parse(reader.result)
|
||||||
const event = ical.parse(data)
|
|
||||||
this.event = {
|
this.event = {
|
||||||
title: event.name
|
title: event.name
|
||||||
}
|
}
|
||||||
|
@ -73,9 +73,9 @@ export default {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ret = await this.$axios.$get('/event/import', { params: { URL: this.URL } })
|
const ret = await this.$axios.$get('/event/import', { params: { URL: this.URL } })
|
||||||
this.event = ret
|
this.events = ret
|
||||||
// check if contain an h-event
|
// check if contain an h-event
|
||||||
this.$emit('imported', ret)
|
// this.$emit('imported', ret)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
this.error = true
|
this.error = true
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
@change='v => event.title = v'
|
@change='v => event.title = v'
|
||||||
:value = 'event.title'
|
:value = 'event.title'
|
||||||
:rules="[$validators.required('common.title')]"
|
:rules="[$validators.required('common.title')]"
|
||||||
:hint="$t('event.what_description')"
|
|
||||||
prepend-icon='mdi-format-title'
|
prepend-icon='mdi-format-title'
|
||||||
:label="$t('common.title')"
|
:label="$t('common.title')"
|
||||||
autofocus
|
autofocus
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
v-container
|
v-container
|
||||||
//- EVENT PAGE
|
//- EVENT PAGE
|
||||||
//- gancio supports microformats (http://microformats.org/wiki/h-event)
|
//- gancio supports microformats (http://microformats.org/wiki/h-event)
|
||||||
v-card.h-event(v-on:keyup="$router.push(`/event/${event.next}`)")
|
v-card.h-event
|
||||||
v-card-text
|
v-card-text
|
||||||
|
|
||||||
//- admin controls
|
//- admin controls
|
||||||
|
@ -32,7 +32,8 @@ v-container
|
||||||
time.dt-start.text-h5(:datetime='event.start_datetime|unixFormat("YYYY-MM-DD HH:mm")')
|
time.dt-start.text-h5(:datetime='event.start_datetime|unixFormat("YYYY-MM-DD HH:mm")')
|
||||||
v-icon mdi-calendar
|
v-icon mdi-calendar
|
||||||
b.ml-2 {{event|when}}
|
b.ml-2 {{event|when}}
|
||||||
p.subtitle-1 {{event.start_datetime|from}}
|
div.subtitle-1 {{event.start_datetime|from}}
|
||||||
|
small(v-if='event.parentId') ({{event|recurrentDetail}})
|
||||||
|
|
||||||
.text-h5.p-location
|
.text-h5.p-location
|
||||||
v-icon mdi-map-marker
|
v-icon mdi-map-marker
|
||||||
|
|
|
@ -2,11 +2,16 @@
|
||||||
v-card(color='secondary')
|
v-card(color='secondary')
|
||||||
v-card-title(v-text="$t('common.embed_title')")
|
v-card-title(v-text="$t('common.embed_title')")
|
||||||
v-card-text
|
v-card-text
|
||||||
v-row(:gutter='10')
|
v-row
|
||||||
v-col(:span='12' :xs='24')
|
v-col.col-12
|
||||||
v-alert.mb-1.mt-1(type='info' show-icon) {{$t('common.embed_help')}}
|
v-alert.mb-1.mt-1(type='info' show-icon) {{$t('common.embed_help')}}
|
||||||
v-text-field(v-model='code')
|
v-text-field(v-model='code')
|
||||||
v-col.mt-2(:span='12' :xs='24' v-html='code')
|
v-btn(slot='prepend' plain text color='primary'
|
||||||
|
v-clipboard:copy='code'
|
||||||
|
v-clipboard:success='copyLink') {{$t("common.copy")}}
|
||||||
|
v-icon.ml-1 mdi-content-copy
|
||||||
|
|
||||||
|
v-col.mt-2(v-html='code')
|
||||||
v-card-actions
|
v-card-actions
|
||||||
v-spacer
|
v-spacer
|
||||||
v-btn(color='warning' @click="$emit('close')") {{$t("common.cancel")}}
|
v-btn(color='warning' @click="$emit('close')") {{$t("common.cancel")}}
|
||||||
|
|
|
@ -6,10 +6,7 @@ div
|
||||||
v-btn(text color='primary' v-if='!event.parentId' @click='remove(false)') {{$t('common.remove')}}
|
v-btn(text color='primary' v-if='!event.parentId' @click='remove(false)') {{$t('common.remove')}}
|
||||||
|
|
||||||
template(v-if='event.parentId')
|
template(v-if='event.parentId')
|
||||||
v-divider {{$t('event.recurrent')}}
|
//- v-divider {{$t('event.recurrent')}}
|
||||||
p.text-secondary
|
|
||||||
i.el-icon-refresh
|
|
||||||
small {{event|recurrentDetail}}
|
|
||||||
v-btn(text color='primary' v-if='event.parent.is_visible' @click='toggle(true)') {{$t('common.pause')}}
|
v-btn(text color='primary' v-if='event.parent.is_visible' @click='toggle(true)') {{$t('common.pause')}}
|
||||||
v-btn(text color='primary' v-else @click='toggle(true)') {{$t('common.start')}}
|
v-btn(text color='primary' v-else @click='toggle(true)') {{$t('common.start')}}
|
||||||
v-btn(text color='primary' @click='$router.push(`/add/${event.parentId}`)') {{$t('common.edit')}}
|
v-btn(text color='primary' @click='$router.push(`/add/${event.parentId}`)') {{$t('common.edit')}}
|
||||||
|
|
|
@ -29,10 +29,6 @@
|
||||||
v-clipboard:success='copyLink') {{$t("common.copy")}}
|
v-clipboard:success='copyLink') {{$t("common.copy")}}
|
||||||
v-icon.ml-1 mdi-content-copy
|
v-icon.ml-1 mdi-content-copy
|
||||||
|
|
||||||
v-tab(v-if='settings.enable_federation') {{$t('common.fediverse')}}
|
|
||||||
v-tab-item
|
|
||||||
FollowMe
|
|
||||||
|
|
||||||
v-tab ics/ical
|
v-tab ics/ical
|
||||||
v-tab-item
|
v-tab-item
|
||||||
v-card
|
v-card
|
||||||
|
@ -62,6 +58,9 @@
|
||||||
color='primary' v-clipboard:copy='listScript' v-clipboard:success='copyLink') {{$t('common.copy')}}
|
color='primary' v-clipboard:copy='listScript' v-clipboard:success='copyLink') {{$t('common.copy')}}
|
||||||
v-icon.ml-1 mdi-content-copy
|
v-icon.ml-1 mdi-content-copy
|
||||||
|
|
||||||
|
v-tab(v-if='settings.enable_federation') {{$t('common.fediverse')}}
|
||||||
|
v-tab-item(v-if='settings.enable_federation')
|
||||||
|
FollowMe
|
||||||
//- TOFIX
|
//- TOFIX
|
||||||
//- v-tab.pt-1(label='calendar' name='calendar')
|
//- v-tab.pt-1(label='calendar' name='calendar')
|
||||||
//- v-tab-item
|
//- v-tab-item
|
||||||
|
@ -125,6 +124,7 @@ export default {
|
||||||
return `<iframe style='border: 0px; width: 100%;' src="${this.settings.baseurl}/embed/list?${params.join('&')}"></iframe>`
|
return `<iframe style='border: 0px; width: 100%;' src="${this.settings.baseurl}/embed/list?${params.join('&')}"></iframe>`
|
||||||
},
|
},
|
||||||
link () {
|
link () {
|
||||||
|
const typeMap = ['rss', 'ics', 'list']
|
||||||
const tags = this.filters.tags.join(',')
|
const tags = this.filters.tags.join(',')
|
||||||
const places = this.filters.places.join(',')
|
const places = this.filters.places.join(',')
|
||||||
let query = ''
|
let query = ''
|
||||||
|
@ -138,7 +138,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${this.settings.baseurl}/feed/${this.type}${query}`
|
return `${this.settings.baseurl}/feed/${typeMap[this.type]}${query}`
|
||||||
},
|
},
|
||||||
showLink () {
|
showLink () {
|
||||||
return (['rss', 'ics'].includes(this.type))
|
return (['rss', 'ics'].includes(this.type))
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
//- Calendar and search bar
|
//- Calendar and search bar
|
||||||
v-row#calbarmb-2
|
v-row#calbarmb-2
|
||||||
.col-xl-5.col-lg-5.col-md-6.col-sm-12.col-xs-12
|
.col-xl-5.col-lg-5.col-md-7.col-sm-12.col-xs-12
|
||||||
//- this is needed as v-calendar does not support SSR
|
//- this is needed as v-calendar does not support SSR
|
||||||
//- https://github.com/nathanreyes/v-calendar/issues/336
|
//- https://github.com/nathanreyes/v-calendar/issues/336
|
||||||
client-only
|
client-only
|
||||||
|
@ -14,12 +14,11 @@
|
||||||
|
|
||||||
.col
|
.col
|
||||||
Search(:filters='filters' @update='updateFilters')
|
Search(:filters='filters' @update='updateFilters')
|
||||||
v-chip(v-if='selectedDay' close @click:close='dayChange(selectedDay)') {{selectedDay}}
|
v-chip(v-if='selectedDay' close @click:close='dayChange({ date: selectedDay})') {{selectedDay}}
|
||||||
|
|
||||||
//- Events
|
//- Events
|
||||||
#events
|
#events
|
||||||
Event(v-for='event in events'
|
Event(v-for='(event, idx) in events' :key='event.id' :event='event' :show='idx>=firstVisibleItem && idx<=lastVisibleItem'
|
||||||
:key='event.id' :event='event'
|
|
||||||
@tagclick='tagClick' @placeclick='placeClick')
|
@tagclick='tagClick' @placeclick='placeClick')
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
@ -35,33 +34,68 @@ import Calendar from '@/components/Calendar'
|
||||||
export default {
|
export default {
|
||||||
name: 'Index',
|
name: 'Index',
|
||||||
components: { Event, Search, Announcement, Calendar },
|
components: { Event, Search, Announcement, Calendar },
|
||||||
async asyncData ({ params, $api }) {
|
async asyncData ({ params, $api, store }) {
|
||||||
const events = await $api.getEvents({
|
const events = await $api.getEvents({
|
||||||
start: dayjs().unix()
|
start: dayjs().unix(),
|
||||||
|
end: null,
|
||||||
|
filters: { show_recurrent: store.state.settings.allow_recurrent_event && store.state.settings.recurrent_event_visible }
|
||||||
})
|
})
|
||||||
return { events }
|
return { events }
|
||||||
},
|
},
|
||||||
data () {
|
data ({ $store }) {
|
||||||
return {
|
return {
|
||||||
date: dayjs().format('YYYY-MM-DD'),
|
date: dayjs().format('YYYY-MM-DD'),
|
||||||
events: [],
|
events: [],
|
||||||
start: dayjs().unix(),
|
start: dayjs().unix(),
|
||||||
end: null,
|
end: null,
|
||||||
filters: { tags: [], places: [] },
|
filters: { tags: [], places: [], show_recurrent: $store.state.settings.allow_recurrent_event && $store.state.settings.recurrent_event_visible },
|
||||||
selectedDay: null
|
selectedDay: null,
|
||||||
|
firstVisibleItem: 0,
|
||||||
|
lastVisibleItem: 20
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['settings', 'announcements']),
|
...mapState(['settings', 'announcements'])
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
let last_known_scroll_position = 0
|
||||||
|
let ticking = false
|
||||||
|
|
||||||
|
document.addEventListener('scroll', e => {
|
||||||
|
last_known_scroll_position = window.scrollY
|
||||||
|
|
||||||
|
if (!ticking) {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
this.scroll(last_known_scroll_position)
|
||||||
|
ticking = false
|
||||||
|
})
|
||||||
|
|
||||||
|
ticking = true
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(['setFilters']),
|
...mapActions(['setFilters']),
|
||||||
|
scroll (y) {
|
||||||
|
const rowHeight = 370
|
||||||
|
const nItems = this.events.length
|
||||||
|
const fullHeight = document.getElementById('events').offsetHeight
|
||||||
|
const nRows = fullHeight / rowHeight
|
||||||
|
const itemPerRow = nItems / nRows
|
||||||
|
const visibleRows = 10
|
||||||
|
this.firstVisibleItem = Math.trunc(((y - 370) / rowHeight) * itemPerRow) - (5 * itemPerRow)
|
||||||
|
this.lastVisibleItem = this.firstVisibleItem + (visibleRows * itemPerRow)
|
||||||
|
|
||||||
|
console.error('Scrolled to ', y, ' nItems', nItems, 'fullHeight', fullHeight, ' itemPerRow', itemPerRow, ' nRow', nRows)
|
||||||
|
console.error('mostro dal ', this.firstVisibleItem, this.lastVisibleItem)
|
||||||
|
},
|
||||||
async updateEvents () {
|
async updateEvents () {
|
||||||
this.events = await this.$api.getEvents({
|
this.events = await this.$api.getEvents({
|
||||||
start: this.start,
|
start: this.start,
|
||||||
end: this.end,
|
end: this.end,
|
||||||
places: this.filters.places,
|
places: this.filters.places,
|
||||||
tags: this.filters.tags
|
tags: this.filters.tags,
|
||||||
|
show_recurrent: this.filters.show_recurrent
|
||||||
})
|
})
|
||||||
this.setFilters(this.filters)
|
this.setFilters(this.filters)
|
||||||
},
|
},
|
||||||
|
@ -101,18 +135,17 @@ export default {
|
||||||
this.updateEvents()
|
this.updateEvents()
|
||||||
},
|
},
|
||||||
dayChange (day) {
|
dayChange (day) {
|
||||||
if (this.selectedDay === day) {
|
const date = dayjs(day.date).format('YYYY-MM-DD')
|
||||||
|
if (this.selectedDay === date) {
|
||||||
this.selectedDay = null
|
this.selectedDay = null
|
||||||
this.date = dayjs().format('YYYY-MM-DD')
|
|
||||||
this.start = dayjs().unix() // .startOf('week').unix()
|
this.start = dayjs().unix() // .startOf('week').unix()
|
||||||
this.end = null
|
this.end = null
|
||||||
this.updateEvents()
|
this.updateEvents()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.start = dayjs(day).unix()
|
this.start = dayjs(date).startOf('day').unix()
|
||||||
this.end = dayjs(day).endOf('day').unix()
|
this.end = dayjs(day).endOf('day').unix()
|
||||||
this.date = dayjs(day).format('YYYY-MM-DD')
|
this.selectedDay = date
|
||||||
this.selectedDay = day
|
|
||||||
this.updateEvents()
|
this.updateEvents()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,10 +21,11 @@ export default ({ $axios, store }, inject) => {
|
||||||
start: params.start,
|
start: params.start,
|
||||||
end: params.end,
|
end: params.end,
|
||||||
places: params.places && params.places.join(','),
|
places: params.places && params.places.join(','),
|
||||||
tags: params.tags && params.tags.join(',')
|
tags: params.tags && params.tags.join(','),
|
||||||
|
show_recurrent: params.show_recurrent
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return events
|
return events.map(e => Object.freeze(e))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
return []
|
return []
|
||||||
|
|
|
@ -38,13 +38,13 @@ export default ({ app, store }) => {
|
||||||
|
|
||||||
Vue.filter('recurrentDetail', event => {
|
Vue.filter('recurrentDetail', event => {
|
||||||
const parent = event.parent
|
const parent = event.parent
|
||||||
const { frequency, days, type } = parent.recurrent
|
const { frequency, type } = parent.recurrent
|
||||||
let recurrent
|
let recurrent
|
||||||
if (frequency === '1w' || frequency === '2w') {
|
if (frequency === '1w' || frequency === '2w') {
|
||||||
recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: dayjs.unix(parent.start_datetime).format('dddd') })
|
recurrent = app.i18n.t(`event.recurrent_${frequency}_days`, { days: dayjs.unix(parent.start_datetime).format('dddd') })
|
||||||
} else if (frequency === '1m' || frequency === '2m') {
|
} else if (frequency === '1m' || frequency === '2m') {
|
||||||
const d = type === 'ordinal' ? days : days.map(d => dayjs().day(d - 1).format('dddd'))
|
const d = type === 'ordinal' ? dayjs.unix(parent.start_datetime).date() : dayjs.unix(parent.start_datetime).format('dddd')
|
||||||
recurrent = app.i18n.tc(`event.recurrent_${frequency}_${type}`, days.length, { days: d })
|
recurrent = app.i18n.tc(`event.recurrent_${frequency}_${type}`, d)
|
||||||
}
|
}
|
||||||
return recurrent
|
return recurrent
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,10 +4,11 @@ const config = require('config')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const { Op } = require('sequelize')
|
const { Op } = require('sequelize')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const helpers = require('../../helpers')
|
|
||||||
const linkifyHtml = require('linkifyjs/html')
|
const linkifyHtml = require('linkifyjs/html')
|
||||||
const Sequelize = require('sequelize')
|
const Sequelize = require('sequelize')
|
||||||
const dayjs = require('dayjs')
|
const dayjs = require('dayjs')
|
||||||
|
const helpers = require('../../helpers')
|
||||||
|
const settingsController = require('./settings')
|
||||||
|
|
||||||
const Event = require('../models/event')
|
const Event = require('../models/event')
|
||||||
const Resource = require('../models/resource')
|
const Resource = require('../models/resource')
|
||||||
|
@ -417,19 +418,25 @@ const eventController = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async _select ({ start, end, tags, places }) {
|
async _select ({ start, end, tags, places, show_recurrent }) {
|
||||||
const where = {
|
const where = {
|
||||||
|
// do not include parent recurrent event
|
||||||
recurrent: null,
|
recurrent: null,
|
||||||
|
|
||||||
// confirmed event only
|
// confirmed event only
|
||||||
is_visible: true,
|
is_visible: true,
|
||||||
|
|
||||||
[Op.or]: {
|
[Op.or]: {
|
||||||
start_datetime: { [Op.gt]: start },
|
start_datetime: { [Op.gte]: start },
|
||||||
end_datetime: { [Op.gt]: start }
|
end_datetime: { [Op.gte]: start }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!show_recurrent) {
|
||||||
|
where.parentId = null
|
||||||
|
}
|
||||||
if (end) {
|
if (end) {
|
||||||
where.start_datetime = { [Op.lt]: end }
|
where.start_datetime = { [Op.lte]: end }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (places) {
|
if (places) {
|
||||||
|
@ -470,9 +477,11 @@ const eventController = {
|
||||||
const end = req.query.end
|
const end = req.query.end
|
||||||
const tags = req.query.tags
|
const tags = req.query.tags
|
||||||
const places = req.query.places
|
const places = req.query.places
|
||||||
|
const show_recurrent = settingsController.settings.allow_recurrent_event &&
|
||||||
|
(typeof req.query.show_recurrent !== 'undefined' ? req.query.show_recurrent === 'true' : settingsController.settings.recurrent_event_visible)
|
||||||
|
|
||||||
res.json(await eventController._select({
|
res.json(await eventController._select({
|
||||||
start, end, places, tags
|
start, end, places, tags, show_recurrent
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -497,20 +506,37 @@ const eventController = {
|
||||||
const frequency = recurrent.frequency
|
const frequency = recurrent.frequency
|
||||||
const type = recurrent.type
|
const type = recurrent.type
|
||||||
|
|
||||||
|
debug(`NOW IS ${cursor} while event is at ${start_date} (freq: ${frequency})`)
|
||||||
|
|
||||||
cursor = cursor.hour(start_date.hour()).minute(start_date.minute()).second(0)
|
cursor = cursor.hour(start_date.hour()).minute(start_date.minute()).second(0)
|
||||||
|
debug(`set cursor to correct date and hour => ${cursor}`)
|
||||||
|
|
||||||
// each week or 2
|
// each week or 2
|
||||||
if (frequency[1] === 'w') {
|
if (frequency[1] === 'w') {
|
||||||
cursor = cursor.day(start_date.day())
|
cursor = cursor.day(start_date.day())
|
||||||
|
debug(`Imposto il giorno della settimana ${cursor}`)
|
||||||
if (cursor.isBefore(dayjs())) {
|
if (cursor.isBefore(dayjs())) {
|
||||||
cursor = cursor.add(7, 'day')
|
cursor = cursor.add(7, 'day')
|
||||||
}
|
}
|
||||||
if (frequency[0] === 2) {
|
if (frequency[0] === '2') {
|
||||||
cursor = cursor.add(7, 'day')
|
cursor = cursor.add(7, 'day')
|
||||||
}
|
}
|
||||||
} else if (frequency === '1m') {
|
} else if (frequency === '1m') {
|
||||||
if (type === 'ordinal') {
|
if (type === 'ordinal') {
|
||||||
cursor = cursor.date(start_date.date())
|
cursor = cursor.date(start_date.date())
|
||||||
|
|
||||||
|
if (cursor.isBefore(dayjs())) {
|
||||||
|
cursor = cursor.add(1, 'month')
|
||||||
|
}
|
||||||
|
} else { // weekday
|
||||||
|
const monthDay = start_date.format('D')
|
||||||
|
const n = Math.floor((monthDay - 1) / 7) + 1
|
||||||
|
cursor = cursor.startOf('month')
|
||||||
|
cursor = cursor.add(n, 'week')
|
||||||
|
cursor = cursor.day(start_date.day())
|
||||||
|
if (cursor.isBefore(dayjs())) {
|
||||||
|
cursor = cursor.add(1, 'month')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,7 +555,6 @@ const eventController = {
|
||||||
include: [{ model: Event, as: 'child', required: false, where: { start_datetime: { [Op.gte]: start_datetime } } }],
|
include: [{ model: Event, as: 'child', required: false, where: { start_datetime: { [Op.gte]: start_datetime } } }],
|
||||||
order: ['start_datetime']
|
order: ['start_datetime']
|
||||||
})
|
})
|
||||||
|
|
||||||
// filter events that as no instance in future yet
|
// filter events that as no instance in future yet
|
||||||
const creations = events
|
const creations = events
|
||||||
.filter(e => e.child.length === 0)
|
.filter(e => e.child.length === 0)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const ical = require('ical.js')
|
||||||
const settingsController = require('./api/controller/settings')
|
const settingsController = require('./api/controller/settings')
|
||||||
const acceptLanguage = require('accept-language')
|
const acceptLanguage = require('accept-language')
|
||||||
|
|
||||||
|
@ -114,31 +115,56 @@ module.exports = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import events from url
|
||||||
|
* It does supports ICS and H-EVENT
|
||||||
|
*/
|
||||||
async importURL (req, res) {
|
async importURL (req, res) {
|
||||||
const URL = req.query.URL
|
const URL = req.query.URL
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(URL)
|
const response = await axios.get(URL)
|
||||||
Microformats.get({ html: response.data, filter: ['h-event'] }, (err, data) => {
|
const contentType = response.headers['content-type']
|
||||||
if (err || !data.items.length || !data.items[0].properties) {
|
|
||||||
return res.sendStatus(404)
|
if (contentType.includes('text/html')) {
|
||||||
}
|
Microformats.get({ html: response.data, filter: ['h-event'] }, (err, data) => {
|
||||||
const event = data.items[0].properties
|
if (err || !data.items.length || !data.items[0].properties) {
|
||||||
return res.json({
|
return res.sendStatus(404)
|
||||||
title: get(event, 'name[0]', ''),
|
}
|
||||||
description: get(event, 'content[0]', ''),
|
const events = data.items.map(e => {
|
||||||
place: get(event, 'location[0].properties.name', ''),
|
const props = e.properties
|
||||||
address: get(event, 'location[0].properties.street-address'),
|
return {
|
||||||
start: get(event, 'start[0]', ''),
|
title: get(props, 'name[0]', ''),
|
||||||
end: get(event, 'end[0]', ''),
|
description: get(props, 'description[0]', ''),
|
||||||
tags: get(event, 'category', []),
|
place: get(props, 'location[0].properties.name', ''),
|
||||||
image: get(event, 'featured[0]')
|
address: get(props, 'location[0].properties.street-address'),
|
||||||
|
start: get(props, 'start[0]', ''),
|
||||||
|
end: get(props, 'end[0]', ''),
|
||||||
|
tags: get(props, 'category', []),
|
||||||
|
image: get(props, 'featured[0]')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res.json(events)
|
||||||
})
|
})
|
||||||
})
|
} else if (contentType.includes('text/calendar')) {
|
||||||
|
const ret = ical.parse(response.data)
|
||||||
|
const component = new ical.Component(ret)
|
||||||
|
const events = component.getAllSubcomponents('vevent')
|
||||||
|
return res.json(events.map(e => {
|
||||||
|
const event = new ical.Event(e)
|
||||||
|
return {
|
||||||
|
title: get(event, 'summary', ''),
|
||||||
|
description: get(event, 'description', ''),
|
||||||
|
place: get(event, 'location', ''),
|
||||||
|
start: get(event, 'dtstart', ''),
|
||||||
|
end: get(event, 'dtend', '')
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
// const event = dom.window.document.querySelected(".h-event")
|
// const event = dom.window.document.querySelected(".h-event")
|
||||||
// console.error(event)
|
// console.error(event)
|
||||||
// console.error(response)
|
// console.error(response)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
debug(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// res.json('ok')
|
// res.json('ok')
|
||||||
|
|
|
@ -41,7 +41,6 @@ class Task {
|
||||||
|
|
||||||
class TaskManager {
|
class TaskManager {
|
||||||
constructor () {
|
constructor () {
|
||||||
this.interval = 60 * 1000
|
|
||||||
this.tasks = []
|
this.tasks = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +89,7 @@ const TS = new TaskManager()
|
||||||
TS.add(new Task({
|
TS.add(new Task({
|
||||||
name: 'RECURRENT_EVENT',
|
name: 'RECURRENT_EVENT',
|
||||||
method: eventController._createRecurrent,
|
method: eventController._createRecurrent,
|
||||||
repeatEach: 10 // check each 10 minutes
|
repeatEach: 1 // check each 10 minutes
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// daily morning notification
|
// daily morning notification
|
||||||
|
|
Loading…
Reference in a new issue