Verified Commit 5c3e1e2a authored by les's avatar les
Browse files

Merge branch 'dev'

parents 6f838d12 d354eeaf
......@@ -63,7 +63,7 @@ typings/
.node_repl_history
# Output of 'npm pack'
*.tgz
#*.tgz
# Yarn Integrity file
.yarn-integrity
......
All notable changes to this project will be documented in this file.
### Unreleased
### 1.0 (beta)
This release is a complete rewrite of frontend UI and many internals, main changes are:
- Switch UI framework from [element](https://element.eleme.io/) to [vuetify](https://vuetifyjs.com/)
- Distribute package directly from site instead of using npm registry
- Improve docker setup (run as user, fix some data export)
- New logging system (based on [winston](https://github.com/winstonjs/winston))
- Slugify event URL (keeping old one valid)
- Import events from ics and external website using h-event (microformat) improving [`h-event`](https://microformats.org/wiki/h-event) export
- Hide unconfirmed tags and places
- Clean unused places and tags
- Fix tons of issues
### 0.24.0
- New Euskara language from Basque Country, thanks @hacklabkelo
- fix feed with filters
......
export default function (to, from, savedPosition) {
return { x: 0, y: 0 }
}
.event {
width: 320px;
max-width: 450px;
flex-grow: 1;
margin: .2em;
background-color: #202020;
overflow: hidden;
// .event {
// width: 320px;
// max-width: 450px;
// flex-grow: 1;
// margin: .2em;
// background-color: #202020;
// overflow: hidden;
a:hover {
text-decoration: none;
.title {
border-bottom: 1px solid #888;
color: white;
}
}
// a:hover {
// text-decoration: none;
// .title {
// border-bottom: 1px solid #888;
// color: white;
// }
// }
.title {
margin-left: 1rem;
margin-top: 1rem;
margin-right: 1rem;
border-bottom: 1px solid #333;
transition: border-color .5s;
font-size: 1.2em;
max-height: 3em;
overflow: hidden;
color: white;
font-weight: bold;
}
// .title {
// margin-left: 1rem;
// margin-top: 1rem;
// margin-right: 1rem;
// border-bottom: 1px solid #333;
// transition: border-color .5s;
// font-size: 1.2em;
// max-height: 3em;
// overflow: hidden;
// color: white;
// font-weight: bold;
// }
.card-footer {
max-height: 4.5em;
overflow: hidden;
padding: .25rem 0.5rem;
line-height: 1.8rem;
min-height: 2.2rem;
}
// .card-footer {
// max-height: 4.5em;
// overflow: hidden;
// padding: .25rem 0.5rem;
// line-height: 1.8rem;
// min-height: 2.2rem;
// }
.card-body {
overflow: hidden;
}
// .card-body {
// overflow: hidden;
// }
.description {
color: #999;
font-size: 0.8em;
overflow: hidden;
max-height: 100%;
}
// .description {
// color: #999;
// font-size: 0.8em;
// overflow: hidden;
// max-height: 100%;
// }
.el-image { width: 100% }
img {
width: 100%;
max-height: 250px;
object-fit: cover;
object-position: top;
}
}
// .el-image { width: 100% }
// img {
// width: 100%;
// max-height: 250px;
// object-fit: cover;
// object-position: top;
// }
// }
import take from 'lodash/take'
import get from 'lodash/get'
import dayjs from 'dayjs'
export function attributesFromEvents (_events, _tags) {
const colors = ['blue', 'orange', 'yellow', 'teal', 'indigo', 'green', 'red', 'purple', 'pink', 'gray']
const tags = take(_tags, 10).map(t => t.tag)
let attributes = []
attributes.push({ key: 'today', dates: new Date(), bar: { color: 'green', fillMode: 'outline' } })
const now = dayjs().unix()
function getColor (event, where) {
const color = { class: 'vc-rounded-full', color: 'blue', fillMode: where === 'base' ? 'light' : 'solid' }
const tag = get(event, 'tags[0]')
if (event.start_datetime < now) {
if (event.multidate) {
color.fillMode = where === 'base' ? 'light' : 'outline'
if (where === 'base') {
color.class += ' vc-past'
}
} else {
color.class += ' vc-past'
}
}
if (!tag) { return color }
const idx = tags.indexOf(tag)
if (idx < 0) { return color }
color.color = colors[idx]
// if (event.start_datetime < now) { color.class += ' vc-past' }
return color
}
attributes = attributes.concat(_events
.filter(e => !e.multidate)
.map(e => {
return {
key: e.id,
dot: getColor(e),
dates: new Date(e.start_datetime * 1000)
}
}))
attributes = attributes.concat(_events
.filter(e => e.multidate)
.map(e => ({
key: e.id,
highlight: {
start: getColor(e),
base: getColor(e, 'base'),
end: getColor(e)
},
dates: { start: new Date(e.start_datetime * 1000), end: new Date(e.end_datetime * 1000) }
})))
return attributes
}
:focus {outline:none;}
::-moz-focus-inner {border:0;}
blockquote {
border-left: 3px solid grey;
font-style: italic;
color: #666;
padding-left: 1em;
html, body {
scrollbar-width: thin;
overflow: auto !important;
scrollbar-color: #FF4511 #111;
font-family: sans-serif;
}
code {
font-family: sans-serif;
display: inline-block;
padding: 0 .4rem;
border-radius: 5px;
font-size: .8rem;
font-weight: 700;
background: rgba(0,0,0,.1);
color: #888;
li {
margin-left: 10px;
}
html, body {
font-family: sans-serif;
scroll-behavior: smooth;
text-rendering: optimizeSpeed;
background-color: #111;
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: #555 #111;
padding: 0 !important;
.v-dialog .theme--dark.v-card {
background-color: #434343;
}
#__nuxt, #__layout {
min-height: 100vh;
display: flex;
flex-direction: column;
.v-application .p-description.text-body-1 {
letter-spacing: normal !important;
}
#main {
min-height: 200px;
#home {
max-width: 1400px;
padding: 0px;
overflow: hidden;
scrollbar-width: thin;
transition: background-color .5s, opacity .5s; //, color 1s;
background-color: white;
&.dark {
background-color: #111;
}
}
#content {
max-width: 1400px;
flex-grow: 1;
width: 100%;
#events {
margin: 0 auto;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
#header, #footer {
color: white;
background-color: #222;
font-size: 18px;
padding: 0 15px;
.container {
max-width: 1400px;
}
#footer {
a {
color: orangered;
transition: color .4s;
&:hover {
text-decoration: none;
color: orange;
}
}
#links a {
margin-left: 15px;
}
min-height: 6em;
padding-top: 2em;
font-size: 1em;
.v-dialog {
width: 600px;
max-width: 800px;
}
#header .el-menu--horizontal {
background-color: #222;
color: white;
.el-menu-item, .el-submenu__title {
color: white;
}
.el-submenu .el-submenu__icon-arrow {
margin-left: 0px;
}
.el-submenu .el-submenu__title {
padding: 0 15px;
}
.el-menu-item:not(.is-disabled):focus,
.el-menu-item.is-active,
.el-menu-item:not(.is-disabled):hover,
.el-submenu:focus > .el-submenu__title,
.el-submenu:hover > .el-submenu__title,
.el-submenu.is-active > .el-submenu__title,
.el-submenu.is-opened {
color: white;
background-color: #111;
}
.theme--dark.v-list {
background-color: #333;
}
.page-enter-active {
transition: opacity .05s;
}
.page-enter, .page-leave-active {
transition: opacity .3s; //, transform .3s;
opacity: 0;
// transform: translateX(30px);
.v-autocomplete__content.v-menu__content {
scrollbar-width: thin;
scrollbar-color: #FF4511 #111;
}
.el-card {
max-width: 700px;
margin: 0 auto;
}
// EVENT
.event {
display: flex;
position: relative;
flex-direction: column;
width: 330px;
max-width: 500px !important;
flex-grow: 1;
margin-top: .4em;
margin-right: .4em;
transition: all .5s;
overflow: hidden;
.el-menu-item {
height: 40px;
line-height: 40px;
a {
color: #303133;
.title {
transition: all .5s;
display: block;
text-decoration: none;
text-overflow: ellipsis;
max-height: 3em;
color: white;
overflow: hidden;
margin: 0.5rem 1rem 0.5rem 1rem;
font-size: 1.1em !important;
line-height: 1em !important;
}
}
.el-message-box {
max-width: 90%;
}
//TODO: refactoring
.el-button.is-plain,
.el-button.is-plain:focus,
.el-button.is-plain {
border-color: #ff450075;
background-color: transparent;
color: orangered;
&:hover {
border-color: #ff450075;
background-color: transparent;
color: orange;
.body {
flex: 1 1 auto;
}
}
// TODO: this should be a link
.event .p-location {
transition: color .2s;
&:hover {
cursor: pointer;
color: orangered !important;
.img {
width: 100%;
max-height: 250px;
min-height: 160px;
background-color: #222;
object-fit: cover;
object-position: top;
}
}
.el-button--text {
color: orangered !important;
&:hover {
color: orange !important;
.place {
max-width: 100%;
span {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
a {
text-decoration: none;
}
}
.el-button--success.is-plain {
color: #2c8600;
border-color: #9de27b;
background-color: #f9fff6;
}
.el-button--mini, .el-button--mini.is-round {
padding: 6px 12px;
font-size: 0.8rem;
}
.bg-dark {
background-color: #292929 !important;
.v-list {
background-color: #333 !important;
}
.el-dialog {
min-height: 300px;
max-width: 600px;
width: 100%;
.el-dialog__body {
word-break: normal !important;
}
.vc-past {
opacity: 0.4;
}
.el-switch__label span {
position: absolute;
#event {
max-width: 1200px;
}
// .el-input {
// max-width: 350px;
// }
// @media only screen and (max-width: 768px) {
// .el-card {
// padding: 0px !important;
// border-radius: 0px;
// }
// }
@import './event.less';
@import './editor.less';
\ No newline at end of file
.tags .v-chip .v-chip__content {
max-width: 120px;
white-space: nowrap;
overflow: hidden;
display: block;
}
\ No newline at end of file
<template lang="pug">
.announcement.announcement.text-white(body-style='padding: 0px;')
nuxt-link(:to='`/announcement/${announcement.id}`')
.title <i class='el-icon-info'/> {{announcement.title}}
//- .card-body
//- .description(v-html='description')
nuxt-link(:to='`/announcement/${announcement.id}`')
v-alert.mb-1(border='left' type='info' color="primary" show-icon) {{announcement.title}}
</template>
<script>
......@@ -14,32 +10,6 @@ export default {
props: {
announcement: { type: Object, default: () => ({}) }
},
computed: {
...mapState(['announcements']),
description () {
return this.announcement.announcement.replace(/(<br>)+/g, '<br>')
}
}
computed: mapState(['announcements'])
}
</script>
<style lang='less'>
.announcement {
padding: 2%;
background-color: #511;
margin: 1rem 0;
border-radius: 5px;
a:hover {
text-decoration: none;
}
.title {
font-size: 1.2em;
color: white;
transition: color .2s;
&:hover {
color: #fbd6b5;
}
}
border: 2px solid #ff4500ba;
// box-shadow: inset 0px 0px 10px 0px orangered;
}
</style>
<template lang="pug">
#calendar
v-calendar(
vc-calendar(
title-position='left'
is-dark
:is-dark="settings['theme.is_dark']"
:columns="$screens({ sm: 2 }, 1)"
@update:from-page='updatePage'
:columns="$screens({ default: 1, lg: 2 })"
:locale='$i18n.locale'
:attributes='attributes'
transition='fade'
......@@ -14,77 +14,43 @@
</template>
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
import moment from 'moment-timezone'
import { take, get } from 'lodash'
import { mapState, mapActions } from 'vuex'
import dayjs from 'dayjs'
import { attributesFromEvents } from '../assets/helper'
export default {
name: 'Calendar',
props: {
events: { type: Array, default: () => [] }
},
data () {
const month = moment().month() + 1
const year = moment().year()
const month = dayjs().month() + 1
const year = dayjs().year()
return {
page: { month, year }
}
},
computed: {
...mapGetters(['filteredEventsWithPast']),
...mapState(['tags', 'filters', 'in_past']),
// TODO: could be better
...mapState(['tags', 'filters', 'in_past', 'settings']),
attributes () {
const colors = ['green', 'orange', 'yellow', 'teal', 'indigo', 'blue', 'red', 'purple', 'pink', 'gray']
const tags = take(this.tags, 10).map(t => t.tag)
let attributes = []
attributes.push({ key: 'today', dates: new Date(), highlight: { color: 'green' } })
const that = this
function getColor (event) {
const color = { class: event.past && !that.filters.show_past_events && !that.in_past ? 'past-event vc-rounded-full' : 'vc-rounded-full', color: 'blue' }
const tag = get(event, 'tags[0]')
if (!tag) { return color }
const idx = tags.indexOf(tag)
if (idx < 0) { return color }
color.color = colors[idx]
return color
}
attributes = attributes.concat(this.filteredEventsWithPast
.filter(e => !e.multidate)
.map(e => {
return {
key: e.id,
dot: getColor(e),
dates: new Date(e.start_datetime * 1000)
}
}))
attributes = attributes.concat(this.filteredEventsWithPast
.filter(e => e.multidate)
.map(e => ({
key: e.id,
highlight: getColor(e),
dates: { start: new Date(e.start_datetime * 1000), end: new Date(e.end_datetime * 1000) }
})))
return attributes
return attributesFromEvents(this.events, this.tags)
}
},
methods: {
...mapActions(['updateEvents', 'showPastEvents']),
updatePage (page) {
this.updateEvents(page)
return new Promise((resolve, reject) => {
this.$emit('monthchange', page)
})
},
click (day) {
const element = document.getElementById(day.day)
if (element) { element.scrollIntoView() } // Even IE6 supports this
this.$emit('dayclick', day)
}
}
}