new choosing layout

This commit is contained in:
Kacper Donat 2018-10-05 22:23:29 +02:00
parent 12fb18d902
commit 4221fab3d1
11 changed files with 136 additions and 142 deletions

View File

@ -1,5 +1,5 @@
<div class="finder">
<input class="form-control" v-model="filter" />
<input class="form-control" v-model="filter" placeholder="Zacznij pisać nazwę aby szukać..."/>
<div v-if="state === 'fetching'">
<fa icon="spinner-third" pulse/>
@ -30,8 +30,4 @@
<fa :icon="['far', 'exclamation-triangle']"></fa>
Nie znaleziono więcej przystanków, spełniających te kryteria.
</div>
<div class="alert alert-info" v-else>
<fa :icon="['far', 'search']"></fa>
Wprowadź zapytanie powyżej, aby wyszukać przystanek.
</div>
</div>

View File

@ -1,12 +0,0 @@
<div class="picker">
<ul class="picker__stops list-underlined">
<li v-for="stop in stops" :key="stop.id" class="d-flex align-items-center">
<button @click="remove(stop)" class="btn btn-action">
<fa :icon="['fal', 'times']" />
</button>
<stop :stop="stop" class="flex-grow-1"></stop>
</li>
</ul>
<stop-finder @select="add" :blacklist="stops"/>
</div>

View File

@ -79,8 +79,7 @@
font-size: medium;
background: transparent;
padding-top: .5rem;
padding-bottom: .5rem;
padding: .5rem .75rem;
line-height: $btn-line-height;

View File

@ -25,103 +25,11 @@ Vue.use(Vuex);
import('bootstrap'),
]);
// here goes "public" API
window['czydojade'] = Object.assign({}, window['czydojade'], {
components
});
store.dispatch('messages/update');
store.dispatch('load', window['czydojade'].state);
let intervals = { messages: null, departures: null };
window['app'] = new Vue({
el: '#app',
store: store,
data: {
sections: {
messages: true
},
settings: {
messages: false,
departures: false
},
autorefresh: {
messages: {
active: true,
interval: 60
},
departures: {
active: true,
interval: 10
}
},
},
computed: {
messages(this: any) {
return {
count: this.$store.getters['messages/count'],
counts: this.$store.getters['messages/counts'],
state: this.$store.state.messages.state
};
},
departures(this: any) {
return {
state: this.$store.state.departures.state
};
},
stops: {
get(this: Vue) {
return this.$store.state.stops;
},
set(this: Vue, value) {
this.$store.commit('updateStops', value);
}
}
},
watch: {
stops(this: any, stops) {
this.updateDepartures({ stops });
},
autorefresh: {
immediate: true,
deep: true,
handler(this: any, settings) {
if (intervals.messages) {
clearInterval(intervals.messages);
intervals.messages = null;
}
if (intervals.departures) {
clearInterval(intervals.departures);
intervals.messages = null;
}
if (settings.messages.active) {
intervals.messages = setInterval(() => this.updateMessages(), Math.max(5, settings.messages.interval) * 1000);
}
if (settings.departures.active) {
intervals.departures = setInterval(() => this.updateDepartures({ stops: this.stops }), Math.max(5, settings.departures.interval) * 1000);
}
}
}
},
methods: {
...mapActions({
updateMessages: 'messages/update',
updateDepartures: 'departures/update'
}),
...mapMutations({
updateStops: 'updateStops'
}),
save(this: Vue) {
this.$store.dispatch('save').then(x => console.log(x));
}
},
mounted() {
this.$el.classList.remove('not-ready');
}
// here goes "public" API
window['czydojade'] = Object.assign({}, window['czydojade'], {
components, application: new components.Application({ el: '#app' })
});
})();

View File

@ -1,5 +1,94 @@
import Vue from 'vue'
import store from '../store'
import { Component, Watch } from "vue-property-decorator";
import { Mutation, Action } from 'vuex-class'
import { ObtainPayload } from "../store/departures";
import { Stop } from "../model";
@Component({ store })
export class Application extends Vue {
private messages: boolean = true;
private sections = {
messages: true
};
private settings = {
messages: false,
departures: false
};
private autorefresh = {
messages: {
active: true,
interval: 60
},
departures: {
active: true,
interval: 10
}
};
private intervals = { messages: null, departures: null };
get messages() {
return {
count: this.$store.getters['messages/count'],
counts: this.$store.getters['messages/counts'],
state: this.$store.state.messages.state
};
}
get departures() {
return {
state: this.$store.state.departures.state
};
}
get stops() {
return this.$store.state.stops;
}
set stops(value) {
this.$store.commit('updateStops', value);
}
mounted() {
this.$el.classList.remove('not-ready');
}
@Action('messages/update') updateMessages: () => void;
@Action('departures/update') updateDepartures: (payload: ObtainPayload) => void;
@Mutation add: (stops: Stop[]) => void;
@Mutation remove: (stop: Stop) => void;
@Mutation clear: () => void;
save() {
this.$store.dispatch('save').then(x => console.log(x));
}
@Watch('stops')
onStopUpdate(this: any, stops) {
this.updateDepartures({ stops });
}
@Watch('settings', { immediate: true, deep: true })
onAutorefreshUpdate(settings) {
if (this.intervals.messages) {
clearInterval(this.intervals.messages);
this.intervals.messages = null;
}
if (this.intervals.departures) {
clearInterval(this.intervals.departures);
this.intervals.messages = null;
}
if (settings.messages.active) {
this.intervals.messages = setInterval(() => this.updateMessages(), Math.max(5, settings.messages.interval) * 1000);
}
if (settings.departures.active) {
this.intervals.departures = setInterval(() => this.updateDepartures({ stops: this.stops }), Math.max(5, settings.departures.interval) * 1000);
}
}
}

View File

@ -5,3 +5,4 @@ export * from './departures'
export * from './stop'
export * from './messages'
export * from './map'
export * from './app'

View File

@ -6,20 +6,6 @@ import { ensureArray, FetchingState, filter, map } from "../utils";
import { debounce } from "../decorators";
import urls from '../urls';
@Component({ template: require("../../components/picker.html") })
export class PickerComponent extends Vue {
@Prop({ default: () => [], type: Array })
protected stops?: Stop[];
private remove(stop: Stop) {
this.$emit('update:stops', this.stops.filter(s => s != stop));
}
private add(stop: Stop|Stop[]) {
this.$emit('update:stops', [...this.stops, ...ensureArray(stop)]);
}
}
@Component({ template: require('../../components/finder.html') })
export class FinderComponent extends Vue {
protected found?: StopGroups = {};
@ -64,5 +50,4 @@ export class FinderComponent extends Vue {
}
}
Vue.component('StopPicker', PickerComponent);
Vue.component('StopFinder', FinderComponent);

View File

@ -33,13 +33,15 @@ Vue.directive('hover', {
el.addEventListener('focusout', deactivate);
},
unbind(el, binding) {
const { activate, deactivate, keyboard } = binding['events'];
if (typeof binding['events'] !== 'undefined') {
const { activate, deactivate, keyboard } = binding['events'];
el.removeEventListener('mouseenter', activate);
el.removeEventListener('click', activate);
el.removeEventListener('keydown', keyboard);
el.removeEventListener('mouseleave', deactivate);
el.removeEventListener('focusout', deactivate);
el.removeEventListener('mouseenter', activate);
el.removeEventListener('click', activate);
el.removeEventListener('keydown', keyboard);
el.removeEventListener('mouseleave', deactivate);
el.removeEventListener('focusout', deactivate);
}
}
});
@ -72,6 +74,8 @@ Vue.directive('responsive', {
}
},
unbind(el, binding) {
window.removeEventListener('resize', binding['resize']);
if (typeof binding['resize'] !== 'undefined') {
window.removeEventListener('resize', binding['resize']);
}
}
});

View File

@ -10,7 +10,7 @@ export interface DeparturesState extends CommonState {
departures: Departure[],
}
interface ObtainPayload {
export interface ObtainPayload {
stops: Stop[]
}

View File

@ -1,6 +1,7 @@
import { Stop } from "../model";
import { ActionTree, MutationTree } from "vuex";
import urls from "../urls";
import { ensureArray } from "../utils";
export interface RootState {
stops: Stop[],
@ -16,7 +17,9 @@ export const state: RootState = {
};
export const mutations: MutationTree<RootState> = {
updateStops: (state, stops) => state.stops = stops,
add: (state, stops) => state.stops = [...state.stops, ...ensureArray(stops)],
remove: (state, stop) => state.stops = state.stops.filter(s => s != stop),
clear: (state) => state.stops = [],
};
export const actions: ActionTree<RootState, undefined> = {

View File

@ -46,6 +46,7 @@
<fa :icon="['fal', 'clock']" fixed-width></fa>
<span class="text">Odjazdy</span>
</h2>
<button class="btn btn-action flex-space-left" ref="settings-departures" v-hover="settings.departures">
<fa :icon="['fal', 'cog']" fixed-width></fa>
</button>
@ -77,12 +78,32 @@
</section>
</div>
<div class="col-md-4 order-md-first">
<section class="section picker" v-if="stops.length > 0">
<header class="section__title flex">
<h2>
<fa :icon="['fal', 'sign']" fixed-width></fa>
<span class="text">Przystanki</span>
</h2>
<button class="btn btn-action flex-space-left" @click="clear">
<fa :icon="['fal', 'trash-alt']" fixed-width></fa>
</button>
</header>
<ul class="picker__stops list-underlined">
<li v-for="stop in stops" :key="stop.id" class="d-flex align-items-center">
<button @click="remove(stop)" class="btn btn-action">
<fa :icon="['fal', 'times']"></fa>
</button>
<stop :stop="stop" class="flex-grow-1"></stop>
</li>
</ul>
</section>
<section class="section picker">
<h2 class="section__title">
<fa :icon="['fal', 'sign']" fixed-width></fa>
Przystanki
<fa :icon="['fal', 'search']" fixed-width></fa>
Wybierz przystanki
</h2>
<stop-picker :stops.sync="stops"></stop-picker>
<stop-finder @select="add" :blacklist="stops"/>
</section>
</div>
</div>