dev merge #163
@ -9,7 +9,7 @@
|
||||
"build-client": "esbuild src/client/main.ts --outfile=public/main.js --tree-shaking=true --bundle --minify --sourcemap --tsconfig=tsconfig-client.json",
|
||||
"build-server": "esbuild src/server/**/*.ts --outdir=build --platform=node --format=cjs",
|
||||
"start": "node build/main.js",
|
||||
"demon": "nodemon -e ts,js --watch src --watch template --watch router --exec \"yarn build && yarn start\""
|
||||
"demon": "nodemon -e ts,js,css --watch src --watch template --watch router --exec \"yarn build && yarn start\""
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.7 KiB |
@ -1,4 +1,4 @@
|
||||
export const throttle = (func: () => void, wait: number) => {
|
||||
export const throttle = (func: (...args: any[]) => any, wait: number) => {
|
||||
var lastTime = 0;
|
||||
var timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||
var lastArgs: any[];
|
||||
@ -54,7 +54,7 @@ export const save = (id: string, v: journey) =>
|
||||
export const query_nominatim = (
|
||||
q: string,
|
||||
bb: any,
|
||||
f: (v: string) => Boolean = () => true
|
||||
f: (v: NominatimResult) => Boolean = () => true
|
||||
) => {
|
||||
if (q.length == 0) return Promise.resolve([])
|
||||
let url = new URL("/api/place/" + q, window.location.origin);
|
||||
@ -141,7 +141,7 @@ export const icon_type = (item: string | NominatimResult): string => {
|
||||
"nature_reserve",
|
||||
],
|
||||
"dice-five": ["water_park", "theme_park", "casino"],
|
||||
"": ["?", "neighbourhood", "quarter", "highway"],
|
||||
"": ["?", "neighbourhood", "quarter", "highway", "place"],
|
||||
};
|
||||
|
||||
for (let k in types) {
|
||||
@ -150,3 +150,13 @@ export const icon_type = (item: string | NominatimResult): string => {
|
||||
console.log(item.display_name, item.category, item.type);
|
||||
return "question";
|
||||
};
|
||||
|
||||
export const get_filter = function (f: string) {
|
||||
switch (f) {
|
||||
case "hotel": return is_hotel_type;
|
||||
case "restaurant": return is_restauration_type;
|
||||
case "place": return is_attraction_type;
|
||||
case "other":
|
||||
default: return () => true;
|
||||
}
|
||||
}
|
||||
|
61
src/client/helper/api.ts
Normal file
61
src/client/helper/api.ts
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
import { getGeoLine } from "../types/geom";
|
||||
import * as api from "../api";
|
||||
|
||||
const filter_existing = function (tpe: "nominatim" | "travel", leg: leg, r: geoloc[]) {
|
||||
switch (tpe) {
|
||||
case 'nominatim':
|
||||
return r.filter(e => {
|
||||
if (leg.hotel && leg.hotel.osm_id == e.osm_id) return false;
|
||||
if (leg.places.restaurants.find(i => i.osm_id == e.osm_id)) return false;
|
||||
if (leg.places.activities.find(i => i.osm_id == e.osm_id)) return false;
|
||||
return true
|
||||
})
|
||||
case 'travel':
|
||||
console.log(r)
|
||||
return r.filter(e => {
|
||||
if (leg.travel.find(i => `${(e as any).from}->${(e as any).to}` == `${(i as any).from}->${(i as any).to}`)) return false;
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const process_results = function (tpe: "nominatim" | "travel", r: geoloc[]) {
|
||||
switch (tpe) {
|
||||
case 'nominatim':
|
||||
return r.map((rr) => {
|
||||
rr.latlon = [parseFloat((rr as any).lat), parseFloat((rr as any).lon)];
|
||||
rr.title = (rr as any).display_name.split(",")[0];
|
||||
return rr;
|
||||
});
|
||||
case 'travel':
|
||||
console.log(r)
|
||||
return r.map(el => {
|
||||
(el as any).path = getGeoLine(
|
||||
{ lat: (el as any).from_geo.lat, lng: (el as any).from_geo.lon },
|
||||
{ lat: (el as any).to_geo.lat, lng: (el as any).to_geo.lon }, { dist: 2_500_000 }).map(v => [v.lat, v.lng]);
|
||||
(el as any).type = "flight";
|
||||
return el;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var _search_set_results: (...arg: any[]) => any;
|
||||
export const set_search_set_results = function (f: (...arg: any[]) => any) {
|
||||
_search_set_results = f;
|
||||
}
|
||||
export const search_nominatim = api.throttle(
|
||||
(f: string, q: string, bb: [[number, number], [number, number]], leg: leg) =>
|
||||
api.query_nominatim(q, bb, api.get_filter(f)).catch((_err) => console.log(_err)).then((r) => {
|
||||
r = process_results('nominatim', r)
|
||||
r = filter_existing('nominatim', leg, r)
|
||||
_search_set_results(r)
|
||||
}), 1000);
|
||||
|
||||
export const search_flight = api.throttle(
|
||||
(f: string, q: string, leg: leg) =>
|
||||
api.query_flight(q).then((r) => {
|
||||
r = process_results('travel', r)
|
||||
r = filter_existing('travel', leg, r)
|
||||
_search_set_results(r)
|
||||
}), 2000)
|
41
src/client/helper/journey.ts
Normal file
41
src/client/helper/journey.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import journey_wrapper from './types/wrapper';
|
||||
|
||||
/* LIST HELPERS */
|
||||
export const filter_selected = function (journey: journey_wrapper, list: geoloc[], step: boolean) {
|
||||
return list.filter((e) =>
|
||||
step ? e.step == journey.sel_day : e.step >= 0,
|
||||
);
|
||||
}
|
||||
|
||||
export const filter_unselected = function (list: geoloc[]) {
|
||||
return list.filter((e) => e.step == undefined || e.step < 0);
|
||||
}
|
||||
|
||||
export const remove_item = function (list: geoloc[], idx: number) {
|
||||
list[idx].step = -1;
|
||||
list.splice(idx, 1);
|
||||
}
|
||||
|
||||
|
||||
/* JOURNEY ADD/RM ITEM HELPER */
|
||||
export const journey_add_place = function (journey: journey_wrapper, tpe: String, item: geoloc) {
|
||||
switch (tpe) {
|
||||
case 'hotel': return journey.leg_get().hotel = item;
|
||||
case 'restaurant': return journey.leg_get().places.restaurants.push(item);
|
||||
case 'place': return journey.leg_get().places.activities.push(item);
|
||||
case 'other': return;
|
||||
case 'flight': return journey.leg_get().travel.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
export const journey_del_place = function (journey: journey_wrapper, tpe: String, idx: number) {
|
||||
console.log(tpe)
|
||||
switch (tpe) {
|
||||
case "hotel": return journey.leg_get().hotel = null;
|
||||
case "restaurants": return journey.leg_get().places.restaurants.splice(idx, 1);
|
||||
case "activities": return journey.leg_get().places.activities.splice(idx, 1);
|
||||
case "other": return;
|
||||
case "flight": return journey.leg_get().travel.splice(idx, 1);
|
||||
default: return true;
|
||||
}
|
||||
}
|
49
src/client/helper/nav.ts
Normal file
49
src/client/helper/nav.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import journey_wrapper from "../types/wrapper";
|
||||
|
||||
var nav = {
|
||||
scrollInterval: 0,
|
||||
scrollDir: 'none',
|
||||
};
|
||||
|
||||
|
||||
const sideScroll = function (element: Element, direction: 'left' | 'right' | 'none', speed: number, step: number) {
|
||||
nav.scrollDir = direction
|
||||
if (direction == 'none') return;
|
||||
nav.scrollInterval = setInterval(() => {
|
||||
element.scrollLeft += (direction == 'left') ? -step : step;
|
||||
}, speed);
|
||||
}
|
||||
|
||||
export const focus_leg = function (journey: journey_wrapper, idx: number | null = null) {
|
||||
const c = document.querySelector('.scroll-content.nav-leg')!!
|
||||
console.log(idx, c, journey)
|
||||
const item = c.children[(idx != null ? idx : journey.sel_leg) + 1];
|
||||
c.scrollLeft = (item as any).offsetLeft + ((item as any).offsetWidth / 2) - (c as any).offsetWidth / 2
|
||||
}
|
||||
|
||||
export const focus_day = function (journey: journey_wrapper, idx: number | null = null) {
|
||||
const c = document.querySelector('.scroll-content.nav-day')!!
|
||||
console.log(idx, c, journey)
|
||||
const item = c.children[(idx != null ? idx : journey.sel_day) + 1];
|
||||
c.scrollLeft = (item as any).offsetLeft + ((item as any).offsetWidth / 2) - (c as any).offsetWidth / 2;
|
||||
//focus_leg(journey) // We dont render both navs anymore
|
||||
}
|
||||
|
||||
export const nav_mousemove = function (e: PointerEvent) {
|
||||
if (e.pointerType != 'mouse') return;
|
||||
const c = (e.target as any).closest('.scroll-content') || (e.target as any).firstChild;
|
||||
const left = e.pageX - c.getBoundingClientRect().left;
|
||||
const newDir =
|
||||
left < c.offsetWidth * 0.1 ? 'left' :
|
||||
(left > c.offsetWidth * 0.9 ? 'right' : 'none')
|
||||
if (!nav.scrollInterval || nav.scrollDir != newDir) {
|
||||
if (nav.scrollInterval) clearInterval(nav.scrollInterval)
|
||||
sideScroll(c, newDir, 25, 10);
|
||||
}
|
||||
}
|
||||
export const nav_mouseleave = function (_e: PointerEvent) {
|
||||
clearInterval(nav.scrollInterval);
|
||||
nav.scrollDir = 'none'
|
||||
nav.scrollInterval = 0
|
||||
}
|
||||
|
@ -2,7 +2,10 @@
|
||||
import * as api from "./api";
|
||||
import journey_wrapper from "./types/wrapper";
|
||||
import { migrator } from "./types/migration";
|
||||
import { getGeoLine } from "./types/geom";
|
||||
import { journey_add_place, journey_del_place } from "./helper/journey";
|
||||
import { search_nominatim, search_flight } from "./helper/api";
|
||||
import { focus_day, focus_leg, nav_mouseleave, nav_mousemove } from "./helper/nav";
|
||||
import { set_search_set_results } from "./helper/api";
|
||||
|
||||
Vue.component("l-map", window.Vue2Leaflet.LMap);
|
||||
Vue.component("l-tile-layer", window.Vue2Leaflet.LTileLayer);
|
||||
@ -20,13 +23,18 @@ const app = new Vue({
|
||||
journey: new journey_wrapper(window.location.pathname.split("/").pop() || String.gen_id(16)),
|
||||
map_override: { active: false, elements: [] },
|
||||
query: {
|
||||
type: "", res: [], load: false, sub: false, note: false, drawer: false,
|
||||
type: "", query: "", res: [], load: false, sub: false, note: false, drawer: false, addmarker: false,
|
||||
},
|
||||
leg_nav: {
|
||||
scrollInterval: null,
|
||||
scrollDir: null
|
||||
useDay: false,
|
||||
toast: {
|
||||
show: false,
|
||||
title: '',
|
||||
desc: '',
|
||||
special: '',
|
||||
acceptText: '',
|
||||
cancelText: '',
|
||||
func: () => { },
|
||||
},
|
||||
impexp: "",
|
||||
lang: {
|
||||
format: "ddd D MMM",
|
||||
formatLocale: {
|
||||
@ -64,11 +72,10 @@ const app = new Vue({
|
||||
return `<i class="fa fa-${api.icon_type(item) || "star"} fa-2x ${classes}" style="${styling}; color:${fcolor || "white"}; text-align:center; align-content:center;"></i>`;
|
||||
},
|
||||
|
||||
|
||||
import_data: function () {
|
||||
import_data: function (v) {
|
||||
this.journey.data = Object.assign(
|
||||
{},
|
||||
JSON.parse(this.impexp.toDecoded()),
|
||||
JSON.parse(v.toDecoded()),
|
||||
);
|
||||
this.journey.data.main.forEach((e) => {
|
||||
if (e.date_range) {
|
||||
@ -77,77 +84,47 @@ const app = new Vue({
|
||||
}
|
||||
});
|
||||
},
|
||||
export_data: function () {
|
||||
this.impexp = JSON.stringify(this.journey.data).toEncoded();
|
||||
},
|
||||
filter_selected: function (list, step) {
|
||||
return list.filter((e) =>
|
||||
step ? e.step == this.journey.sel_day : e.step >= 0,
|
||||
);
|
||||
},
|
||||
filter_unselected: function (list) {
|
||||
return list.filter((e) => e.step == undefined || e.step < 0);
|
||||
},
|
||||
remove_item: function (list, idx) {
|
||||
list[idx].step = -1;
|
||||
list.splice(idx, 1);
|
||||
},
|
||||
log: function (e) {
|
||||
console.log(e);
|
||||
},
|
||||
place_delete: function (f, idx) {
|
||||
switch (f) {
|
||||
case "hotel": return this.journey.leg_get().hotel = null;
|
||||
case "restaurant": return this.journey.leg_get().places.restaurants.splice(idx, 1);
|
||||
case "activities": return this.journey.leg_get().places.activities.splice(idx, 1);
|
||||
case "other": return;
|
||||
case "flight": return this.journey.leg_get().travel.splice(idx, 1);
|
||||
default: return true;
|
||||
}
|
||||
},
|
||||
get_filter: function (f) {
|
||||
switch (f) {
|
||||
case "hotel": return api.is_hotel_type;
|
||||
case "restaurant": return api.is_restauration_type;
|
||||
case "place": return api.is_attraction_type;
|
||||
case "other":
|
||||
default: return () => true;
|
||||
}
|
||||
|
||||
toast_reset: function () {
|
||||
this.toast.show = false;
|
||||
this.toast.title = '';
|
||||
this.toast.desc = ''
|
||||
this.toast.special = '';
|
||||
this.toast.acceptText = ''
|
||||
this.toast.cancelText = ''
|
||||
this.toast.func = () => { }
|
||||
},
|
||||
|
||||
search_nominatim: function (f) {
|
||||
return (q) => api.query_nominatim(q, this.compute_bb(), this.get_filter(f)).catch((_err) => []).then((r) => {
|
||||
r.forEach((rr) => {
|
||||
rr.latlon = [parseFloat(rr.lat), parseFloat(rr.lon)];
|
||||
rr.sname = rr.display_name.split(",")[0];
|
||||
});
|
||||
r = r.filter(e => {
|
||||
if (this.journey.leg_get().hotel && this.journey.leg_get().hotel.osm_id == e.osm_id) return false;
|
||||
if (this.journey.leg_get().places.restaurants.find(i => i.osm_id == e.osm_id)) return false;
|
||||
if (this.journey.leg_get().places.activities.find(i => i.osm_id == e.osm_id)) return false;
|
||||
return true
|
||||
})
|
||||
toast_impexp: function (is_import) {
|
||||
this.toast.show = true;
|
||||
this.toast.title = is_import ? 'Import' : 'Export';
|
||||
this.toast.desc = ''
|
||||
this.toast.special = JSON.stringify(this.journey.data).toEncoded();
|
||||
this.toast.acceptText = is_import ? 'load' : ''
|
||||
this.toast.cancelText = 'cancel'
|
||||
this.toast.func = () => { this.import_data(this.toast.special); this.toast_reset(); }
|
||||
},
|
||||
|
||||
search_set_results(r) {
|
||||
this.query.load = false;
|
||||
this.query.res = r;
|
||||
return r
|
||||
});
|
||||
},
|
||||
search_travel: function (f) {
|
||||
return (q) => api.query_flight(q).then((r) => {
|
||||
r.forEach(el => {
|
||||
el.path = getGeoLine(
|
||||
{ lat: el.from_geo.lat, lng: el.from_geo.lon },
|
||||
{ lat: el.to_geo.lat, lng: el.to_geo.lon }, { dist: 2_500_000 }).map(v => [v.lat, v.lng])
|
||||
el.type = "flight";
|
||||
});
|
||||
r = r.filter(e => {
|
||||
if (this.journey.leg_get().travel.find(i => `${i.from}->${i.to}` == `${e.from}->${e.to}`)) return false;
|
||||
return true
|
||||
})
|
||||
this.query.load = false;
|
||||
this.query.res = r;
|
||||
return r;
|
||||
});
|
||||
search_set_clear(keep_drawer) {
|
||||
this.query.res = [];
|
||||
this.query.note = false;
|
||||
this.query.type = null;
|
||||
this.query.addmarker = false;
|
||||
this.query.sub = false;
|
||||
this.query.drawer = keep_drawer;
|
||||
setTimeout(() => this.$refs.map.mapObject.invalidateSize(), 500);
|
||||
},
|
||||
search_set_active: function (is_notes, tpe) {
|
||||
this.query.drawer = true;
|
||||
this.query.note = is_notes;
|
||||
this.query.type = !is_notes ? tpe : null;
|
||||
this.query.load = !is_notes;
|
||||
setTimeout(() => this.$refs.map.mapObject.invalidateSize(), 500);
|
||||
},
|
||||
|
||||
drawer_hover_item: function (item) {
|
||||
@ -164,112 +141,79 @@ const app = new Vue({
|
||||
},
|
||||
|
||||
drawer_click_item: function (item) {
|
||||
const tpe = this.query.type;
|
||||
this.query.res = [];
|
||||
this.query.note = false;
|
||||
this.query.type = null;
|
||||
this.query.drawer = item ? true : false;
|
||||
setTimeout(() => this.$refs.map.mapObject.invalidateSize(), 500);
|
||||
this.query.sub = false;
|
||||
this.drawer_hover_item()
|
||||
this.search_set_clear(item ? true : false);
|
||||
this.drawer_hover_item();
|
||||
if (item) {
|
||||
item.step = -1;
|
||||
switch (tpe) {
|
||||
case 'hotel': return this.journey.leg_get().hotel = item;
|
||||
case 'restaurant': return this.journey.leg_get().places.restaurants.push(item);
|
||||
case 'place': return this.journey.leg_get().places.activities.push(item);
|
||||
case 'other': return;
|
||||
case 'flight': return this.journey.leg_get().travel.push(item);
|
||||
}
|
||||
journey_add_place(this.journey, this.query.type, item)
|
||||
}
|
||||
},
|
||||
|
||||
search_active: function (q) {
|
||||
const txt = q.target.value
|
||||
this.query.load = true;
|
||||
switch (this.query.type) {
|
||||
case 'hotel': return this.search_hotel(txt);
|
||||
case 'restaurant': return this.search_restaurant(txt);
|
||||
case 'place': return this.search_place(txt);
|
||||
case 'other': return this.search_other(txt);
|
||||
case 'flight': return this.search_flight(txt);
|
||||
search_active: function (_e) {
|
||||
const tpe = this.query.type;
|
||||
const query = this.query.query;
|
||||
switch (tpe) {
|
||||
case 'hotel':
|
||||
case 'restaurant': ;
|
||||
case 'place':
|
||||
case 'other':
|
||||
return search_nominatim(tpe, query, this.compute_bb(), this.journey.leg_get())
|
||||
|
||||
case 'flight':
|
||||
return search_flight(tpe, query, this.journey.leg_get());
|
||||
}
|
||||
},
|
||||
|
||||
search_enable: function (f) {
|
||||
this.query.drawer = true;
|
||||
setTimeout(() => this.$refs.map.mapObject.invalidateSize(), 500);
|
||||
if (f == "notes") {
|
||||
this.query.note = true;
|
||||
this.query.type = null;
|
||||
const query_in = document.getElementById('query_note')
|
||||
setTimeout(() => query_in.focus(), 500);
|
||||
return;
|
||||
const is_notes = f == 'notes';
|
||||
this.search_set_active(is_notes, f)
|
||||
setTimeout(() => document.getElementById(is_notes ? 'query_note' : 'query_input').focus(), 500);
|
||||
if (!is_notes) this.search_active()
|
||||
},
|
||||
|
||||
refreshTextAreaHeight: function (e) {
|
||||
e.target.style['height'] = 'auto';
|
||||
e.target.style['height'] = e.target.scrollHeight + 'px';
|
||||
e.target.style['max-height'] = "100%";
|
||||
},
|
||||
|
||||
onMapClick(e) {
|
||||
if (this.query.addmarker) {
|
||||
const newMarker = {
|
||||
latlon: [e.latlng.lat, e.latlng.lng],
|
||||
sname: this.query.query,
|
||||
type: this.query.type,
|
||||
};
|
||||
this.drawer_click_item(newMarker)
|
||||
}
|
||||
this.query.note = false;
|
||||
this.query.type = f;
|
||||
const query_in = document.getElementById('query_input')
|
||||
setTimeout(() => query_in.focus(), 500);
|
||||
this.search_active({ target: query_in })
|
||||
},
|
||||
|
||||
|
||||
sideScroll: function (element, direction, speed, step) {
|
||||
this.leg_nav.scrollDir = direction
|
||||
if (direction == 'none') return;
|
||||
this.leg_nav.scrollInterval = setInterval(() => {
|
||||
element.scrollLeft += (direction == 'left') ? -step : step;
|
||||
}, speed);
|
||||
},
|
||||
|
||||
keyboardEvent(e) {
|
||||
if (e.which === 13) {
|
||||
}
|
||||
},
|
||||
nav_mousemove(e) {
|
||||
const c = document.querySelector('.scroll-content')
|
||||
const left = e.pageX - c.getBoundingClientRect().left;
|
||||
const newDir =
|
||||
left < c.offsetWidth * 0.1 ? 'left' :
|
||||
(left > c.offsetWidth * 0.9 ? 'right' : 'none')
|
||||
if (!this.leg_nav.scrollInterval || this.leg_nav.scrollDir != newDir) {
|
||||
if (this.leg_nav.scrollInterval) clearInterval(this.leg_nav.scrollInterval)
|
||||
this.sideScroll(c, newDir, 25, 10);
|
||||
}
|
||||
},
|
||||
nav_mouseleave(e) {
|
||||
clearInterval(this.leg_nav.scrollInterval);
|
||||
this.leg_nav.scrollDir = 'none'
|
||||
this.leg_nav.scrollInterval = null
|
||||
},
|
||||
|
||||
refreshTextAreaHeight(event) {
|
||||
console.log("AAA", event.target.scrollHeight, event.target)
|
||||
event.target.style['height'] = 'auto';
|
||||
event.target.style['height'] = event.target.scrollHeight + 'px';
|
||||
event.target.style['max-height'] = "100%";
|
||||
},
|
||||
},
|
||||
created: function () {
|
||||
this.search_hotel = api.throttle(this.search_nominatim("hotel"), 1000)
|
||||
this.search_restaurant = api.throttle(this.search_nominatim("restaurant"), 1000)
|
||||
this.search_place = api.throttle(this.search_nominatim("place"), 1000)
|
||||
set_search_set_results(this.search_set_results);
|
||||
this.nav_mouseleave = nav_mouseleave;
|
||||
this.nav_mousemove = nav_mousemove;
|
||||
this.focus_day = focus_day;
|
||||
this.focus_leg = focus_leg;
|
||||
this.place_delete = (tpe, idx) => journey_del_place(this.journey, tpe, idx);
|
||||
|
||||
this.save_data = api.throttle(() => {
|
||||
this.impexp = JSON.stringify(this.journey.data).toEncoded();
|
||||
api.save(this.journey.id, this.journey.data);
|
||||
}, 1000);
|
||||
this.search_flight = api.throttle(this.search_travel("flight"), 2000)
|
||||
|
||||
this.pressed_prev = api.throttle(() => {
|
||||
if (this.useDay) this.journey.day_prev();
|
||||
else this.journey.leg_prev();
|
||||
}, 250)
|
||||
this.pressed_next = api.throttle(() => {
|
||||
if (this.useDay) this.journey.day_next();
|
||||
else this.journey.leg_next();
|
||||
}, 250)
|
||||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
switch (e.key) {
|
||||
case "ArrowLeft":
|
||||
this.journey.day_prev();
|
||||
break;
|
||||
case "ArrowRight":
|
||||
this.journey.day_next();
|
||||
break;
|
||||
default:
|
||||
console.log(e.key);
|
||||
case "ArrowLeft": return this.pressed_prev()
|
||||
case "ArrowRight": return this.pressed_next()
|
||||
default: return console.log(e.key);
|
||||
}
|
||||
});
|
||||
|
||||
@ -280,12 +224,9 @@ const app = new Vue({
|
||||
watch: {
|
||||
journey: {
|
||||
handler: function (ndata, odata) {
|
||||
if (this.edit_active)
|
||||
this.save_data();
|
||||
if (this.edit_active) this.save_data();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
@ -6,6 +6,8 @@ declare global {
|
||||
lng: number
|
||||
}
|
||||
interface geoloc {
|
||||
title: string
|
||||
osm_id: number
|
||||
latlon: [number, number]
|
||||
notes: string
|
||||
step: -1
|
||||
@ -22,7 +24,7 @@ declare global {
|
||||
day_title: string[]
|
||||
date_range: [Date, Date] | null
|
||||
map: map
|
||||
travel: unknown[]
|
||||
travel: geoloc[]
|
||||
hotel: geoloc | null
|
||||
places: {
|
||||
restaurants: geoloc[]
|
||||
|
@ -8,6 +8,7 @@ function migrate_A_to_0(e: journey): journey {
|
||||
v.day_title = v.day_title || (v as any).step_title;
|
||||
v.places.activities = v.places.activities || (v as any).places.places;
|
||||
v.travel = v.travel || [];
|
||||
v.day_title = typeof (v.day_title) == "string" ? [v.day_title] : []
|
||||
})
|
||||
console.log(e)
|
||||
return e;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import './ext.ts'
|
||||
import { journey_template, leg_template } from "./format"
|
||||
|
||||
const date_day_diff = (d0: Date, d1: Date): number =>
|
||||
@ -56,6 +57,10 @@ class journey_wrapper {
|
||||
this.sel_leg = Math.max(this.sel_leg - 1, 0);
|
||||
this.sel_day = 0;
|
||||
}
|
||||
|
||||
day_sel(idx: number): void {
|
||||
this.sel_day = idx;
|
||||
}
|
||||
day_next() {
|
||||
this.sel_day += 1
|
||||
if (this.sel_day > this.leg_len() - 1) {
|
||||
@ -78,6 +83,13 @@ class journey_wrapper {
|
||||
}
|
||||
}
|
||||
}
|
||||
day_cycle() {
|
||||
if (this.sel_day >= this.leg_len() - 1) {
|
||||
this.sel_day = 0;
|
||||
} else {
|
||||
this.day_next()
|
||||
}
|
||||
}
|
||||
date_sel(): string {
|
||||
if (this.sel_day < 0) return "?";
|
||||
let leg = this.leg_get()
|
||||
|
@ -1,3 +1,15 @@
|
||||
body {
|
||||
background: var(--darkdark);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-popup-close-button {
|
||||
visibility: hidden;
|
||||
}
|
||||
@ -6,30 +18,6 @@
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
scrollbar-width: none;
|
||||
padding: 1rem 0rem;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
border: 1px solid var(--darkdark);
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
padding: 0.5rem 0.8rem;
|
||||
}
|
||||
|
||||
.list-group-item:hover {
|
||||
filter: brightness(85%);
|
||||
}
|
||||
|
||||
.leaflet-control-attribution {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.display-none {
|
||||
display: none;
|
||||
}
|
||||
@ -54,7 +42,7 @@
|
||||
height: 100%;
|
||||
right: 0;
|
||||
top: 0;
|
||||
overflow: scroll;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.travel-path-icon {
|
||||
@ -62,6 +50,9 @@
|
||||
margin-top: -32px;
|
||||
}
|
||||
|
||||
.input {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.ml-auto {
|
||||
margin-left: auto;
|
||||
@ -79,6 +70,20 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.h-0 {
|
||||
height: 0%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-0 {
|
||||
width: 0%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.map-menu {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
@ -113,7 +118,7 @@
|
||||
}
|
||||
|
||||
.map-menu-item:hover {
|
||||
filter: brightness(150%);
|
||||
background-color: var(--lightdark);
|
||||
}
|
||||
|
||||
.map-menu-sub {
|
||||
@ -141,14 +146,8 @@
|
||||
|
||||
.leaflet-popup-content {
|
||||
margin: 10px 20px !important;
|
||||
/* display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: auto !important;
|
||||
max-width: 100%; */
|
||||
}
|
||||
|
||||
|
||||
.leaflet-popup>.leaflet-popup-content-wrapper {
|
||||
border-radius: var(--border-radius);
|
||||
width: 350px;
|
||||
@ -188,7 +187,36 @@
|
||||
filter: brightness(85%);
|
||||
}
|
||||
|
||||
.scroll-content>div:first-child {
|
||||
.scroll-content.list-group>.list-group-item {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.list-group-item.placeholder-left.show.bg-dark,
|
||||
.list-group-item.placeholder-right.show.bg-dark {
|
||||
background: var(--darkdark);
|
||||
}
|
||||
|
||||
.list-group-item.placeholder-left.show {
|
||||
margin-left: auto;
|
||||
color: transparent;
|
||||
cursor: default;
|
||||
background: linear-gradient(to right, rgba(0, 0, 0, 0) 0%, var(--white) 50%);
|
||||
}
|
||||
|
||||
.list-group-item.placeholder-right.show {
|
||||
margin-right: auto;
|
||||
color: transparent;
|
||||
cursor: default;
|
||||
background: linear-gradient(to left, rgba(0, 0, 0, 0) 0%, var(--white) 50%);
|
||||
}
|
||||
|
||||
|
||||
.scroll-content>.list-group-item.active,
|
||||
.scroll-content>.list-group-item.show {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.scroll-content>div:nth-child(2) {
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-bottom-left-radius: var(--border-radius);
|
||||
}
|
||||
@ -202,6 +230,137 @@
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.list-group-item.add {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.scroll-content.list-group>.list-group-item {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.scroll-content>.list-group-item.placeholder-left,
|
||||
.scroll-content>.list-group-item.placeholder-right {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.list-group-item.add {
|
||||
position: relative;
|
||||
right: 0;
|
||||
margin-left: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.list-group {
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
scrollbar-width: none;
|
||||
padding: 1rem 0rem;
|
||||
}
|
||||
|
||||
.list-group-item>.text {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list-group-item.show {
|
||||
min-width: 24px;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
border: 1px solid var(--darkdark);
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
padding: .5rem .5rem;
|
||||
max-width: calc(100% - 48px);
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.list-group-item.bg-white:hover {
|
||||
background: var(--blue);
|
||||
/* filter: brightness(85%); */
|
||||
}
|
||||
|
||||
.mx-datepicker {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 5000;
|
||||
}
|
||||
|
||||
.popup {
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
z-index: 5001;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: var(--lightlight);
|
||||
border: 0;
|
||||
border-radius: var(--border-radius);
|
||||
color: var(--darkdark);
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
line-height: 1.2em;
|
||||
padding: 8px 16px;
|
||||
margin: 8px 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tooltip .tooltip-text {
|
||||
visibility: hidden;
|
||||
background-color: var(--white);
|
||||
color: var(--darkdark);
|
||||
text-align: center;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
bottom: 0%;
|
||||
left: 0%;
|
||||
margin-left: 0px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.tooltip:hover .tooltip-text {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.smallbar {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
padding: 8px;
|
||||
margin: 0 -12px;
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
body,
|
||||
|
@ -1,3 +1,4 @@
|
||||
switch,
|
||||
input,
|
||||
textarea {
|
||||
-webkit-appearance: none;
|
||||
@ -15,6 +16,7 @@ input:-webkit-autofill {
|
||||
box-shadow: 0 0 0 1000px #eceff1 inset;
|
||||
}
|
||||
|
||||
.switch,
|
||||
.textarea,
|
||||
.input,
|
||||
.select {
|
||||
@ -167,7 +169,7 @@ input:-webkit-autofill {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.checkbox input[type="checkbox"]:checked+label::after {
|
||||
.checkbox input[type="checkbox"]:checked::after {
|
||||
-webkit-animation: checkboxAndRadioAnimation 0.25s;
|
||||
animation: checkboxAndRadioAnimation 0.25s;
|
||||
content: "";
|
||||
@ -175,7 +177,7 @@ input:-webkit-autofill {
|
||||
transform: scale(1) rotate(45deg);
|
||||
}
|
||||
|
||||
.checkbox input[type="checkbox"]+label {
|
||||
.checkbox input[type="checkbox"] {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding-left: 30px;
|
||||
@ -183,7 +185,7 @@ input:-webkit-autofill {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.checkbox input[type="checkbox"]+label::before {
|
||||
.checkbox input[type="checkbox"]::before {
|
||||
background-color: #eceff1;
|
||||
border: 1px solid var(--white);
|
||||
border-radius: var(--border-radius);
|
||||
@ -197,7 +199,7 @@ input:-webkit-autofill {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.checkbox input[type="checkbox"]+label::after {
|
||||
.checkbox input[type="checkbox"]::after {
|
||||
border-bottom: 3px solid #03a9f4;
|
||||
border-right: 3px solid #03a9f4;
|
||||
display: block;
|
||||
@ -220,7 +222,7 @@ input:-webkit-autofill {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.radio input[type="radio"]:checked+label::after {
|
||||
.radio input[type="radio"]:checked::after {
|
||||
-webkit-animation: checkboxAndRadioAnimation 0.25s;
|
||||
animation: checkboxAndRadioAnimation 0.25s;
|
||||
content: "";
|
||||
@ -228,7 +230,7 @@ input:-webkit-autofill {
|
||||
transform: scale(1) rotate(45deg);
|
||||
}
|
||||
|
||||
.radio input[type="radio"]+label {
|
||||
.radio input[type="radio"] {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
padding-left: 30px;
|
||||
@ -236,7 +238,7 @@ input:-webkit-autofill {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.radio input[type="radio"]+label::before {
|
||||
.radio input[type="radio"]::before {
|
||||
background-color: #eceff1;
|
||||
border: 1px solid var(--white);
|
||||
border-radius: 20px;
|
||||
@ -250,7 +252,7 @@ input:-webkit-autofill {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.radio input[type="radio"]+label::after {
|
||||
.radio input[type="radio"]::after {
|
||||
background-color: #03a9f4;
|
||||
border-radius: 20px;
|
||||
display: block;
|
||||
@ -304,6 +306,7 @@ input:-webkit-autofill {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.switch,
|
||||
.input {
|
||||
background-color: var(--white);
|
||||
padding: 0;
|
||||
@ -316,6 +319,7 @@ input:-webkit-autofill {
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.switch .rocker,
|
||||
.input input,
|
||||
.input textarea {
|
||||
background: transparent;
|
||||
@ -360,3 +364,61 @@ input:-webkit-autofill {
|
||||
top: 50%;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.switch {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.switch input[type="checkbox"] {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.switch .rocker {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.switch .rocker-left,
|
||||
.switch .rocker-right {
|
||||
max-width: 50%;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
width: 50%;
|
||||
color: var(--darkdark);
|
||||
padding: 8px 16px;
|
||||
-webkit-transition: background-position .25s;
|
||||
-moz-transition: background-position .25s;
|
||||
transition: background-position .25s;
|
||||
background-size: 200% 100%;
|
||||
background-image: linear-gradient(to right, transparent 50%, var(--blue) 50%);
|
||||
}
|
||||
|
||||
.switch .rocker-left {
|
||||
background-position-x: 100%;
|
||||
}
|
||||
|
||||
.switch .rocker-bg {
|
||||
position: relative;
|
||||
border-radius: 50%;
|
||||
transition: 0.4s cubic-bezier(0.18, 0.89, 0.35, 1.15) all;
|
||||
left: 0;
|
||||
width: 50%;
|
||||
background-color: var(--blue);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.switch input:checked+.rocker .rocker-left {
|
||||
background-position-x: 0%;
|
||||
}
|
||||
|
||||
.switch input:checked+.rocker .rocker-right {
|
||||
background-position-x: -100%;
|
||||
}
|
@ -31,6 +31,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
max-width: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
max-width: 960px;
|
||||
@ -47,7 +53,6 @@
|
||||
.container {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
max-width: 720px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,6 @@ a:focus {
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.text-huge,
|
||||
.text-big,
|
||||
.text-medium {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.text-huge {
|
||||
font-size: 36px;
|
||||
|
@ -3,5 +3,6 @@ doctype html
|
||||
include module/head.pug
|
||||
|
||||
main#app(v-cloak)
|
||||
include module/view/toast.pug
|
||||
include module/journey/main.pug
|
||||
include module/foot.pug
|
||||
|
@ -1,13 +0,0 @@
|
||||
.impexp
|
||||
.container-medium.section
|
||||
.aligner
|
||||
.input.col-sm-4
|
||||
input(v-model="impexp", type="text")
|
||||
.col-sm-2
|
||||
button.button.button--primary.button--mobileFull(
|
||||
v-on:click="import_data"
|
||||
) Import
|
||||
.col-sm-2
|
||||
button.button.button--primary.button--mobileFull(
|
||||
v-on:click="export_data"
|
||||
) Export
|
@ -1,8 +1,9 @@
|
||||
.col-12.input.text-dark()
|
||||
.w-100.input()
|
||||
textarea.text-small#query_note(
|
||||
v-model="journey.leg_get().notes"
|
||||
rows="1"
|
||||
@input="refreshTextAreaHeight"
|
||||
@focus="refreshTextAreaHeight"
|
||||
rows="1"
|
||||
placeholder="...",
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
.col-12.input.text-dark
|
||||
.input.w-100.text-dark
|
||||
input#query_input(
|
||||
type="search"
|
||||
@input="search_active"
|
||||
@ -7,6 +7,7 @@
|
||||
placeholder="Search ... "
|
||||
style="width:85%;"
|
||||
:disabled="query.note"
|
||||
v-model="query.query"
|
||||
)
|
||||
.spinner(v-if="query.load")
|
||||
|
||||
@ -23,7 +24,8 @@ div(v-if="['hotel', 'restaurant', 'place','other', 'travel'].indexOf(query.type)
|
||||
.bg-dark.divider(
|
||||
:key="'qdiv'+idx" style="height:1px" )
|
||||
.query-result.col-12.bg-white.text-dark(
|
||||
v-if="query.load==false && query.res.length==0" )
|
||||
v-if="query.load==false && query.res.length>=0 && query.query!=''"
|
||||
@click="query.addmarker=true" )
|
||||
div( v-html="generate_icon('star', 'var(--dark)')")
|
||||
.col-10()
|
||||
| Add custom
|
||||
@ -40,7 +42,7 @@ div(v-else-if="['flight'].indexOf(query.type)>=0")
|
||||
div( v-html="generate_icon('plane', 'var(--dark)')")
|
||||
.col-10()
|
||||
| {{ item.from }} => {{item.to}}
|
||||
bg-dark.divider(
|
||||
.bg-dark.divider(
|
||||
:key="'qdiv'+idx" style="height:1px" )
|
||||
div(v-else)
|
||||
template()
|
||||
|
@ -1,34 +0,0 @@
|
||||
.scroll-handler.row(
|
||||
@mouseleave="nav_mouseleave"
|
||||
@mousemove="nav_mousemove")
|
||||
|
||||
.col-3.col-sm-2.col-md-1
|
||||
.list-group.text-dark.h-100
|
||||
.fleft.list-group-item.bg-white.text-small.rounded.h-100(v-on:click.prevent="journey.leg_prev()")
|
||||
i.fas.fa-angle-left
|
||||
.col-6.col-sm-8.col-md-10
|
||||
draggable.scroll-content.list-group.bg-dark(
|
||||
tag="div",
|
||||
:list="journey.data.main",
|
||||
handle=".handle"
|
||||
)
|
||||
.list-group-item.handle.text-dark(
|
||||
v-for="(element, idx) in journey.data.main",
|
||||
:key="idx",
|
||||
@click="journey.leg_sel(idx)",
|
||||
:class="journey.sel_leg == idx ? 'bg-primary' : 'bg-white'"
|
||||
)
|
||||
.text {{ element.title || "Leg "+idx}}
|
||||
i.fa.fa-times.close.fright(
|
||||
style="top: 2px; right: 2px; position: absolute",
|
||||
@click="journey.rm_leg(idx)"
|
||||
)
|
||||
.list-group-item.bg-dark
|
||||
.list-group-item.bg-white.text-dark(@click="journey.add_leg()")
|
||||
div
|
||||
i.fa.fa-plus.add()
|
||||
|
||||
.col-3.col-sm-2.col-md-1
|
||||
.list-group.text-dark.h-100
|
||||
a.fright.list-group-item.bg-white.text-small.rounded.h-100(v-on:click.prevent="journey.leg_next()")
|
||||
i.fas.fa-angle-right
|
@ -1,36 +0,0 @@
|
||||
.row.text-center.align
|
||||
.col-5.col-sm-4.col-md-2
|
||||
.input
|
||||
input(
|
||||
placeholder="Leg"
|
||||
v-model="journey.leg_get().title")
|
||||
|
||||
.col-5.col-sm-4.col-md-2.mr-auto
|
||||
.input
|
||||
input(
|
||||
placeholder="Day"
|
||||
v-model="journey.leg_get().day_title[journey.sel_day]"
|
||||
)
|
||||
.col-8.col-sm-6.col-md-4
|
||||
.input
|
||||
//- label Date Range ({{ journey.leg_len() }})
|
||||
date-picker(
|
||||
:lang="lang",
|
||||
v-model="journey.leg_get().date_range",
|
||||
range="",
|
||||
format="ddd D MMM",
|
||||
placeholder="Date Range",
|
||||
v-on:change="journey.date_update(journey.sel_leg)"
|
||||
)
|
||||
.col-4.col-sm-4.col-md-3.ml-auto
|
||||
.input
|
||||
input(
|
||||
disabled="",
|
||||
:value="journey.date_sel() + ' (' + journey.sel_day + ')'"
|
||||
)
|
||||
//- .col-6.list-group-item.align.center.bg-white(style="padding: 0.5rem 0;")
|
||||
//- i.fas.fa-angle-double-right(v-on:click.prevent="journey.day_next()")
|
||||
.col-sm-1.text-small
|
||||
|
||||
//- a(href="#prev", v-on:click.prevent="journey.day_prev()")
|
||||
i.fas.fa-angle-left
|
54
src/template/module/journey/leg/top_day.pug
Normal file
54
src/template/module/journey/leg/top_day.pug
Normal file
@ -0,0 +1,54 @@
|
||||
.row
|
||||
.mr-auto.col-auto
|
||||
.list-group.text-dark
|
||||
.list-group-item.show.bg-white.rounded(v-on:click.prevent="journey.day_prev(); focus_day(journey);")
|
||||
i.fas.fa-angle-left
|
||||
.col-8.col-sm-8.col-md-10.scroll-handler(
|
||||
@pointerleave="nav_mouseleave"
|
||||
@pointermove="nav_mousemove")
|
||||
|
||||
draggable.scroll-content.nav-day.list-group.bg-dark(
|
||||
tag="div",
|
||||
:list="journey.leg_get().day_title",
|
||||
handle=".handle"
|
||||
)
|
||||
.list-group-item.bg-white.text-white.show.placeholder-left(
|
||||
:class="journey.sel_day >0? '': 'bg-dark'"
|
||||
slot="header"
|
||||
)
|
||||
.text {{'⋅'}}
|
||||
.list-group-item.handle.text-dark(
|
||||
v-for="(element, idx) in journey.leg_len()",
|
||||
:key="idx",
|
||||
@click="journey.day_sel(idx)",
|
||||
:class="journey.sel_day == idx ? 'bg-primary active' : 'bg-white'"
|
||||
)
|
||||
.text {{ journey.leg_get().day_title[idx] || "Leg "+idx}}
|
||||
.list-group-item.bg-white.text-white.show.placeholder-right(
|
||||
:class="journey.sel_leg < journey.data.main.length-1? '': 'bg-dark'"
|
||||
slot="footer"
|
||||
)
|
||||
.text {{'⋅'}}
|
||||
.list-group-item.bg-dark.text-white(
|
||||
style="display:none"
|
||||
slot="footer"
|
||||
)
|
||||
.text {{'⋅'}}
|
||||
|
||||
.ml-auto.col-auto
|
||||
.list-group.text-dark
|
||||
.list-group-item.show.bg-white.rounded(v-on:click.prevent="journey.day_next(); focus_day(journey);")
|
||||
i.fas.fa-angle-right
|
||||
.row
|
||||
.col-8.col-sm-6.col-md-4
|
||||
.input.w-100
|
||||
input.col-8(
|
||||
placeholder="Day"
|
||||
v-model="journey.leg_get().day_title[journey.sel_day]"
|
||||
)
|
||||
.ml-auto.col-4.col-sm-4.col-md-3
|
||||
.input.w-100
|
||||
input.text-right(
|
||||
disabled="",
|
||||
:value="journey.date_sel() + ' (' + journey.sel_day + ')'"
|
||||
)
|
61
src/template/module/journey/leg/top_leg.pug
Normal file
61
src/template/module/journey/leg/top_leg.pug
Normal file
@ -0,0 +1,61 @@
|
||||
.row
|
||||
.mr-auto.col-auto
|
||||
.list-group.text-dark
|
||||
.list-group-item.show.bg-white.rounded(v-on:click.prevent="journey.leg_prev(); focus_leg(journey);")
|
||||
i.fas.fa-angle-left
|
||||
.col-8.col-sm-8.col-md-10.scroll-handler(
|
||||
@pointerleave="nav_mouseleave"
|
||||
@pointermove="nav_mousemove")
|
||||
|
||||
draggable.scroll-content.nav-leg.list-group.bg-dark(
|
||||
tag="div",
|
||||
:list="journey.data.main",
|
||||
handle=".handle"
|
||||
)
|
||||
.list-group-item.bg-white.text-white.show.placeholder-left(
|
||||
:class="journey.sel_leg >0? '': 'bg-dark'"
|
||||
slot="header"
|
||||
)
|
||||
.text {{'⋅'}}
|
||||
.list-group-item.handle.text-dark(
|
||||
v-for="(element, idx) in journey.data.main",
|
||||
:key="idx",
|
||||
@click="journey.leg_sel(idx)",
|
||||
:class="journey.sel_leg == idx ? 'bg-primary active' : 'bg-white'"
|
||||
)
|
||||
.text {{ element.title || "Leg "+idx}}
|
||||
i.fa.fa-times.text-small.fright(
|
||||
style="top: 2px; right: 2px; position: absolute",
|
||||
@click="journey.rm_leg(idx); focus_leg(journey);"
|
||||
)
|
||||
.list-group-item.bg-white.text-white.show.placeholder-right(
|
||||
:class="journey.sel_leg < journey.data.main.length-1? '': 'bg-dark'"
|
||||
slot="footer"
|
||||
)
|
||||
.text {{'⋅'}}
|
||||
.list-group-item.bg-white.text-dark.add(@click="journey.add_leg(); focus_leg(journey);"
|
||||
slot="footer"
|
||||
:class="journey.sel_leg >= journey.data.main.length-1? 'show': ''")
|
||||
div
|
||||
i.fa.fa-plus()
|
||||
|
||||
.ml-auto.col-auto
|
||||
.list-group.text-dark
|
||||
.list-group-item.show.bg-white.rounded(v-on:click.prevent="journey.leg_next(); focus_leg(journey);")
|
||||
i.fas.fa-angle-right
|
||||
.row.text-center
|
||||
.col-6.col-sm-6.col-md-5.mr-auto
|
||||
.input.w-100
|
||||
input(
|
||||
placeholder="Leg"
|
||||
v-model="journey.leg_get().title")
|
||||
.col-6.col-sm-6.col-md-4
|
||||
.input.w-100
|
||||
date-picker(
|
||||
:lang="lang",
|
||||
v-model="journey.leg_get().date_range",
|
||||
range="",
|
||||
format="ddd D MMM",
|
||||
placeholder="Date Range",
|
||||
v-on:change="journey.date_update(journey.sel_leg)"
|
||||
)
|
@ -1,31 +1,25 @@
|
||||
.row.fleft(style="position:absolute;right:0;")
|
||||
.col-1
|
||||
a(:href="'/short/' + journey.id")
|
||||
i.fas.fa-file-contract
|
||||
.col-1
|
||||
a(:href="'/view/' + journey.id")
|
||||
i.fas.fa-camera
|
||||
.col-1
|
||||
a(href="#", v-on:click.prevent="first_step")
|
||||
i.fas.fa-tools
|
||||
|
||||
include smallbar.pug
|
||||
|
||||
.bg-dark.text-white(v-if="journey && journey.leg_get()")
|
||||
.container
|
||||
.row.align(style="padding-top:45px;")
|
||||
.col-6.col-sm-4.col-md-3.input.text-big
|
||||
.row.align(style="padding-top:45px;position:relative")
|
||||
.col-6.col-sm-4.col-md-3
|
||||
.input.text-big
|
||||
input.text-center(v-model="journey.data.name" placeholder="My Journey" type="text")
|
||||
.col-6.col-sm-4.col-md-3( v-if="useDay" )
|
||||
.input.text-small
|
||||
input.text-center(v-model="journey.leg_get().title" placeholder="Leg" type="text")
|
||||
//- input.small(type="text", :placeholder="journey.date_tot() + ' (' + journey.tot_len() + ')'" )
|
||||
|
||||
include leg/nav.pug
|
||||
include leg/top.pug
|
||||
.row(style="aspect-ratio:1.25;")
|
||||
template(v-if="useDay")
|
||||
include leg/top_day.pug
|
||||
template(v-else)
|
||||
include leg/top_leg.pug
|
||||
.row(style="aspect-ratio:1.25;min-height:432px;max-height:calc(100vh - 125px);width:calc(100% + 24px);")
|
||||
.map-container(:class=" { 'col-2 col-sm-5 col-md-8': query.type, 'col-2 col-sm-5 col-md-6': query.note , 'col-12': (!query.type && !query.note) }" )
|
||||
include map.pug
|
||||
.row.drawer-container(:class="{ 'col-10 col-sm-7 col-md-4': query.type, 'col-10 col-sm-7 col-md-6': query.note, 'col-0': (!query.type && !query.note) }")
|
||||
.drawer-container(:class="{ 'col-12 ': query.type, 'col-0': !query.type }")
|
||||
.h-100(:class="{ 'w-100 ': query.type, 'w-0': !query.type }")
|
||||
include leg/drawer.pug
|
||||
.drawer-container(:class="{ 'col-12': query.note, 'col-0': !query.note }")
|
||||
.h-100(:class="{ 'w-100': query.note, 'w-0': !query.note }")
|
||||
include leg/drawer-notes.pug
|
||||
|
||||
//- include impexp.pug
|
@ -1,15 +1,17 @@
|
||||
l-map(
|
||||
:zoom.sync="journey.leg_get().map.zoom",
|
||||
:center.sync="journey.leg_get().map.center",
|
||||
:zoom.sync="journey.leg_get().map.zoom"
|
||||
:center.sync="journey.leg_get().map.center"
|
||||
@click="onMapClick"
|
||||
style="height:100%"
|
||||
no-blocking-animations=true
|
||||
:style="query.addmarker?'cursor:crosshair':''"
|
||||
ref="map"
|
||||
)
|
||||
l-tile-layer(
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
attribution="© <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors"
|
||||
)
|
||||
l-control-scale(position="bottomleft", :imperial="false", :metric="true")
|
||||
l-control-scale(position="bottomleft" :imperial="false" :metric="true")
|
||||
include map/override.pug
|
||||
|
||||
include map/hotel.pug
|
||||
|
@ -1,7 +1,7 @@
|
||||
l-marker(
|
||||
v-if="map_override.active",
|
||||
v-for="(el, idx) in map_override.elements"
|
||||
key="'ovr'+idx"
|
||||
:key="'ovr'+idx"
|
||||
:lat-lng="el"
|
||||
)
|
||||
l-icon(v-html="generate_marker('plus', 'darkgreen')")
|
||||
|
30
src/template/module/journey/smallbar.pug
Normal file
30
src/template/module/journey/smallbar.pug
Normal file
@ -0,0 +1,30 @@
|
||||
.smallbar
|
||||
.col-auto.mr-auto(style="display:flex; flex-flow: row")
|
||||
.col-1
|
||||
a.text-white.tooltip(:href="'/short/' + journey.id")
|
||||
i.fas.fa-file-contract
|
||||
.tooltip-text Summary
|
||||
.col-1
|
||||
a.text-white.tooltip(:href="'/view/' + journey.id")
|
||||
i.fas.fa-camera
|
||||
.tooltip-text Daily
|
||||
.col-1
|
||||
a.text-white.tooltip(href="#", v-on:click.prevent="first_step")
|
||||
i.fas.fa-tools
|
||||
.tooltip-text Editor
|
||||
.col-1
|
||||
.col-1
|
||||
a.text-white.tooltip(v-on:click.prevent="toast_impexp(true)")
|
||||
i.fas.fa-file-import
|
||||
.tooltip-text Import
|
||||
.col-1
|
||||
a.text-white.tooltip(v-on:click.prevent="toast_impexp(false)")
|
||||
i.fas.fa-file-export
|
||||
.tooltip-text Export
|
||||
|
||||
.col-auto.ml-auto
|
||||
.switch.legday-switch
|
||||
input(type="checkbox" v-model="useDay")
|
||||
.rocker
|
||||
.rocker-left LEG
|
||||
.rocker-right DAY
|
@ -11,7 +11,7 @@
|
||||
)
|
||||
.col-1.col-sm-2
|
||||
.input.col-5.col-sm-3.text-dark
|
||||
.text(disabled="" placeholder="No Hotel" :value="item.hotel?item.hotel.sname:''") {{item.hotel?item.hotel.sname:'No Hotel'}}
|
||||
.text(disabled="" placeholder="No Hotel" :value="item.hotel?item.hotel.sname:''") {{(item.hotel?item.hotel.sname:'') || 'No Hotel'}}
|
||||
//- .row.text-center
|
||||
.input.col-sm-3(v-if="item.travel")
|
||||
div(v-for="(item, idx) in item.travel")
|
||||
|
14
src/template/module/view/toast.pug
Normal file
14
src/template/module/view/toast.pug
Normal file
@ -0,0 +1,14 @@
|
||||
template
|
||||
.overlay.text-dark(v-if="toast.show" @click="")
|
||||
.popup.bg-white(@click.stop)
|
||||
.row
|
||||
.col-auto.text-huge {{ toast.title }}
|
||||
.row(v-if="toast.desc")
|
||||
.col-auto.text-medium {{ toast.desc }}
|
||||
.row(v-if="toast.special")
|
||||
.col-auto.text-medium
|
||||
.input
|
||||
input(v-model="toast.special")
|
||||
.row.align
|
||||
button.button.bg-white(@click="toast.func" v-if="toast.acceptText") {{ toast.acceptText }}
|
||||
button.button.bg-white(@click="toast.show=false;" v-if="toast.cancelText") {{ toast.cancelText }}
|
@ -5,7 +5,7 @@ main#app(v-cloak)
|
||||
|
||||
.bg-dark.text-white(v-if="journey && journey.leg_get()")
|
||||
.container
|
||||
.row.align(style="padding-top:45px;")
|
||||
.row.align(style="padding:45px;")
|
||||
.col-7.col-sm-5.col-md-4.input.text-big
|
||||
input.text-center(v-model="journey.data.name" placeholder="My Journey" type="text" disabled)
|
||||
div(
|
||||
|
Loading…
x
Reference in New Issue
Block a user