autoupdate feature
This commit is contained in:
parent
82adf1139a
commit
1fe04718f9
@ -1,6 +1,6 @@
|
||||
<div class="popper" :class="{ 'has-arrow': arrow, 'd-none': !visible }">
|
||||
<div class="popper-arrow" ref="arrow" v-if="arrow"></div>
|
||||
<lazy v-if="lazy" :activate="visible">
|
||||
<div class="popper" :class="{ 'popper--arrow': arrow, 'd-none': !show }" v-hover="hovered">
|
||||
<div class="popper__arrow" ref="arrow" v-if="arrow"></div>
|
||||
<lazy v-if="lazy" :activate="show">
|
||||
<slot></slot>
|
||||
</lazy>
|
||||
<slot v-else></slot>
|
||||
|
@ -20,7 +20,7 @@
|
||||
<stop-details :stop="stop"></stop-details>
|
||||
</fold>
|
||||
|
||||
<popper reference="action-map" :visible="map" arrow>
|
||||
<popper reference="action-map" :visible="map" arrow class="popper--no-padding">
|
||||
<div style="height: 300px; width: 500px">
|
||||
<l-map :center="stop.location" :zoom=17 :options="{ zoomControl: false, dragging: false }">
|
||||
<l-tile-layer url="//{s}.tile.osm.org/{z}/{x}/{y}.png" attribution='© <a href="//osm.org/copyright">OpenStreetMap</a> contributors'></l-tile-layer>
|
||||
|
@ -44,6 +44,21 @@
|
||||
.flex {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> .text {
|
||||
margin-left: .2rem;
|
||||
margin-right: .2rem;
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
|
||||
&:last-child, & + .text {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section {
|
||||
@ -53,6 +68,15 @@
|
||||
@extend .alert;
|
||||
@extend .alert-dark;
|
||||
|
||||
> * {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
@include direct-headings {
|
||||
@extend .flex;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
font-size: medium;
|
||||
background: transparent;
|
||||
padding-top: .5rem;
|
||||
|
@ -55,11 +55,11 @@
|
||||
@mixin triangle-right($size, $color, $border: none) { @include triangle(right, $size, $color, $border); }
|
||||
|
||||
.popper {
|
||||
$arrow-base: 10px;
|
||||
$arrow-base: 8px;
|
||||
$arrow-color: white;
|
||||
$arrow-border: black;
|
||||
|
||||
$popper-padding: 2px;
|
||||
$popper-padding: .5rem;
|
||||
|
||||
padding: $popper-padding;
|
||||
background: white;
|
||||
@ -73,12 +73,22 @@
|
||||
|
||||
border-radius: 2px;
|
||||
|
||||
.popper-arrow {
|
||||
.popper__arrow {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&.popper--no-padding {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.popper__heading {
|
||||
font-size: $font-size-sm;
|
||||
font-weight: bold;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
@mixin placement($placement) {
|
||||
$opposite: (
|
||||
left: right,
|
||||
@ -90,14 +100,14 @@
|
||||
&[x-placement*="#{$placement}"] {
|
||||
margin-#{map-get($opposite, $placement)}: $arrow-base;
|
||||
|
||||
.popper-arrow {
|
||||
.popper__arrow {
|
||||
#{map-get($opposite, $placement)}: 0;
|
||||
@include triangle(map-get($opposite, $placement), $arrow-base, $arrow-color, $arrow-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.has-arrow {
|
||||
&.popper--arrow {
|
||||
@include placement("left");
|
||||
@include placement("right");
|
||||
@include placement("top");
|
||||
|
@ -1,6 +1,7 @@
|
||||
$border-radius: 0;
|
||||
$border-radius-lg: $border-radius;
|
||||
$border-radius-sm: $border-radius;
|
||||
|
||||
@import "~bootstrap/scss/functions";
|
||||
@import "~bootstrap/scss/variables";
|
||||
|
||||
@ -24,6 +25,18 @@ $container-max-widths: map-merge($container-max-widths, ( xl: 1320px ));
|
||||
|
||||
@import "~bootstrap/scss/bootstrap";
|
||||
|
||||
@mixin headings {
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
@content
|
||||
}
|
||||
}
|
||||
|
||||
@mixin direct-headings {
|
||||
> h1, > h2, > h3, > h4, > h5, > h6 {
|
||||
@content
|
||||
}
|
||||
}
|
||||
|
||||
@import "common";
|
||||
@import "stop";
|
||||
@import "departure";
|
||||
|
@ -32,6 +32,8 @@ Vue.use(Vuex);
|
||||
components
|
||||
};
|
||||
|
||||
let intervals = { messages: null, departures: null };
|
||||
|
||||
window['app'] = new Vue({
|
||||
el: '#app',
|
||||
store: store,
|
||||
@ -39,8 +41,23 @@ Vue.use(Vuex);
|
||||
stops: [],
|
||||
sections: {
|
||||
messages: true
|
||||
},
|
||||
settings: {
|
||||
messages: false,
|
||||
departures: false
|
||||
},
|
||||
autorefresh: {
|
||||
messages: {
|
||||
active: true,
|
||||
interval: 60
|
||||
},
|
||||
departures: {
|
||||
active: true,
|
||||
interval: 10
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
computed: {
|
||||
messages(this: any) {
|
||||
return {
|
||||
@ -58,7 +75,26 @@ Vue.use(Vuex);
|
||||
watch: {
|
||||
stops(this: any, stops) {
|
||||
this.updateDepartures({ stops });
|
||||
},
|
||||
autorefresh: { immediate: 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({
|
||||
|
@ -19,8 +19,14 @@ export class PopperComponent extends Vue {
|
||||
@Prop(Boolean)
|
||||
public lazy: boolean;
|
||||
|
||||
public hovered: boolean = false;
|
||||
|
||||
private _popper;
|
||||
|
||||
get show() {
|
||||
return this.visible || this.hovered;
|
||||
}
|
||||
|
||||
mounted() {
|
||||
const reference = this.$parent.$refs[this.reference] as HTMLElement;
|
||||
|
||||
@ -30,6 +36,12 @@ export class PopperComponent extends Vue {
|
||||
arrow: { enabled: this.arrow, element: this.$refs['arrow'] as Element }
|
||||
}
|
||||
});
|
||||
|
||||
this.$nextTick(() => this._popper.update())
|
||||
}
|
||||
|
||||
updated() {
|
||||
this._popper.update();
|
||||
}
|
||||
|
||||
@Watch('visible')
|
||||
@ -68,6 +80,7 @@ export class FoldComponent extends Vue {
|
||||
this.observer.disconnect();
|
||||
}
|
||||
|
||||
|
||||
@Watch('visible')
|
||||
private resize() {
|
||||
const inner = this.$refs['inner'] as HTMLDivElement;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { signed } from "./utils";
|
||||
import { set, signed } from "./utils";
|
||||
import Vue from 'vue';
|
||||
import { condition } from "./decorators";
|
||||
|
||||
@ -11,11 +11,11 @@ Vue.directive('hover', (el, binding, node) => {
|
||||
}
|
||||
|
||||
if (typeof binding.value === 'boolean') {
|
||||
node.context[binding.expression] = hovered;
|
||||
set(node.context, binding.expression, hovered);
|
||||
}
|
||||
|
||||
if (typeof binding.arg !== 'undefined') {
|
||||
node.context[binding.arg] = hovered;
|
||||
set(node.context, binding.arg, hovered);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -41,3 +41,21 @@ export function signed(number: number): string {
|
||||
export function ensureArray<T>(x: T[]|T): T[] {
|
||||
return x instanceof Array ? x : [ x ];
|
||||
}
|
||||
|
||||
export function set(object: any, path: string, value: any) {
|
||||
const segments = path.split('.');
|
||||
while (segments.length > 1) {
|
||||
object = object[segments.shift()];
|
||||
}
|
||||
|
||||
object[segments.shift()] = value;
|
||||
}
|
||||
|
||||
export function get(object: any, path: string): any {
|
||||
const segments = path.split('.');
|
||||
while (segments.length > 1) {
|
||||
object = object[segments.shift()];
|
||||
}
|
||||
|
||||
return object[segments.shift()];
|
||||
}
|
||||
|
@ -6,29 +6,67 @@
|
||||
<div class="row">
|
||||
<div class="col-md-8 order-md-last">
|
||||
<section class="section messages" v-show="messages.count > 0">
|
||||
<h2 class="section__title flex">
|
||||
<header class="section__title flex">
|
||||
<h2>
|
||||
<fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa>
|
||||
Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span>
|
||||
<button class="btn btn-action flex-space-left" @click="updateMessages">
|
||||
</h2>
|
||||
<button class="btn btn-action flex-space-left" ref="settings-messages" v-hover="settings.messages">
|
||||
<fa :icon="['fal', 'cog']"></fa>
|
||||
</button>
|
||||
<button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh">
|
||||
<fa :icon="['fal', 'sync']" :spin="messages.state === 'fetching'"></fa>
|
||||
</button>
|
||||
<button class="btn btn-action" @click="sections.messages = !sections.messages">
|
||||
<fa :icon="['fal', sections.messages ? 'chevron-up' : 'chevron-down']" fixed-width/>
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
<popper reference="settings-messages" :visible="settings.messages" arrow placement="left-start">
|
||||
<h3 class="popper__heading flex">
|
||||
<fa :icon="['far', 'cog']"></fa>
|
||||
<label class="text" for="messages-auto-refresh">autoodświeżanie</label>
|
||||
<input type="checkbox" class="flex-space-left" id="messages-auto-refresh" v-model="autorefresh.messages.active"/>
|
||||
</h3>
|
||||
<div class="flex" v-show="autorefresh.messages.active">
|
||||
<span class="text">co</span>
|
||||
<label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label>
|
||||
<input type="text" class="form-control form-control-sm" id="messages-auto-refresh-interval" v-model="autorefresh.messages.interval"/>
|
||||
<span class="text">s</span>
|
||||
</div>
|
||||
</popper>
|
||||
</header>
|
||||
<fold :visible="sections.messages">
|
||||
<messages></messages>
|
||||
</fold>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<h2 class="section__title flex">
|
||||
<fa :icon="['fal', 'clock']" fixed-width class="mr-1"></fa>
|
||||
Odjazdy
|
||||
<button class="btn btn-action flex-space-left" @click="updateDepartures({ stops })">
|
||||
<header class="section__title flex">
|
||||
<h2>
|
||||
<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']"></fa>
|
||||
</button>
|
||||
<button class="btn btn-action" @click="updateDepartures({ stops })">
|
||||
<fa :icon="['fal', 'sync']" :spin="departures.state === 'fetching'"></fa>
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
<popper reference="settings-departures" :visible="settings.departures" arrow placement="left-start">
|
||||
<h3 class="popper__heading flex">
|
||||
<fa :icon="['far', 'cog']"></fa>
|
||||
<label class="text" for="messages-auto-refresh">autoodświeżanie</label>
|
||||
<input type="checkbox" class="flex-space-left" id="messages-auto-refresh" v-model="autorefresh.departures.active"/>
|
||||
</h3>
|
||||
<div class="flex" v-show="autorefresh.messages.active">
|
||||
<span class="text">co</span>
|
||||
<label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label>
|
||||
<input type="text" class="form-control form-control-sm" id="messages-auto-refresh-interval" v-model="autorefresh.departures.interval"/>
|
||||
<span class="text">s</span>
|
||||
</div>
|
||||
</popper>
|
||||
</header>
|
||||
<departures :stops="stops"></departures>
|
||||
{% if provider.attribution %}
|
||||
<div class="attribution">
|
||||
|
Loading…
Reference in New Issue
Block a user