diff --git a/.gitignore b/.gitignore index b60d94f..fd98ac3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ db/ public/*.js public/*.map .yarnrc.yml +.pnp* build/ \ No newline at end of file diff --git a/public/css/index.css b/public/css/index.css index 73a2fcb..94c8fa1 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -3140,4 +3140,99 @@ li { border-left: 10px solid transparent; border-right: 10px solid transparent; background-color: 15px solid #ff5733; +} + +.leaflet-control-attribution { + display: none; +} + +.display-none { + display: none; +} + +.col-0 { + flex: 0 0 0%; + max-width: 100%; + overflow: hidden; +} + +.map-container, +.drawer-container { + transition: flex 0.5s ease-in-out, max-width 0.5s ease-in-out; +} + +.drawer-container { + right: 0; + top: 0; +} + +.map-menu { + position: absolute; + top: 0; + right: 0; + display: flex; + z-index: 500; + flex-direction: column; + gap: 10px; + margin: 5px; +} + +.map-menu-item { + background-color: darkslategrey; + padding: 5px; + border-radius: 50%; + cursor: pointer; +} + +.map-menu-item:hover { + filter: brightness(150%); +} + +.travel-path-icon { + margin-left: -12px; + margin-top: -32px; +} + +.spinner { + position: absolute; + right: 1px; + top: 1px; + width: 40px; + height: 38px; + background: #fff; + display: block +} + +.spinner:after, +.spinner:before { + position: absolute; + content: ""; + top: 50%; + left: 50%; + margin: -8px 0 0 -8px; + width: 16px; + height: 16px; + border-radius: 100%; + border: 2px solid transparent; + border-top-color: #41b883; + -webkit-box-shadow: 0 0 0 1px transparent; + box-shadow: 0 0 0 1px transparent +} + +.spinner:before { + -webkit-animation: spinning 2.4s cubic-bezier(.41, .26, .2, .62); + animation: spinning 2.4s cubic-bezier(.41, .26, .2, .62); + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite +} + +.spinner:after { + -webkit-animation: spinning 2.4s cubic-bezier(.51, .09, .21, .8); + animation: spinning 2.4s cubic-bezier(.51, .09, .21, .8); + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite +} + +.input .mx-input { + height: 40px; } \ No newline at end of file diff --git a/src/client/old.js b/src/client/old.js index a81823a..66f3eca 100644 --- a/src/client/old.js +++ b/src/client/old.js @@ -19,7 +19,6 @@ const app = new Vue({ el: "#app", data: { edit_active: ["view", "short"].indexOf(window.location.pathname.split("/")[1]) == -1, - drawer_active: "hotel", journey: new journey_wrapper(window.location.pathname.split("/").pop() || String.gen_id(16)), map_override: { active: false, center: [0, 0] }, @@ -37,13 +36,17 @@ const app = new Vue({ polyline: { latlngs: [], color: 'green' + }, + leg_nav: { + scrollInterval: null, + scrollDir: null } }, methods: { start_journey: function () { window.location.href = "/" + this.journey.id }, compute_bb: function () { - const bounds = this.$refs.map[0].mapObject.getBounds(); + const bounds = this.$refs.map.mapObject.getBounds(); return [[bounds.getSouthWest().lng, bounds.getSouthWest().lat], [bounds.getNorthEast().lng, bounds.getNorthEast().lat]] }, @@ -63,8 +66,8 @@ const app = new Vue({ ` }, - generate_icon: function (item, fcolor, styling = "") { - return ``; + generate_icon: function (item, fcolor = "", styling = "", classes = "") { + return ``; }, @@ -118,7 +121,6 @@ const app = new Vue({ rr.sname = rr.display_name.split(",")[0]; }); this.query.res = r; - this.query.type = null; return r }); } @@ -134,7 +136,6 @@ const app = new Vue({ el.type = "flight"; }); this.query.res = r; - this.query.type = null; return r; }); } @@ -150,12 +151,14 @@ const app = new Vue({ }, drawer_click_item: function (item) { - console.log(item) - console.log(this.journey.leg_get()) - switch (this.drawer_active) { + const tpe = this.query.type; + this.query.res = []; + this.query.type = null; + this.drawer_hover_item() + 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.places.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); } @@ -163,7 +166,7 @@ const app = new Vue({ search_active: function (q) { const txt = q.target.value - switch (this.drawer_active) { + 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); @@ -172,10 +175,32 @@ const app = new Vue({ } }, + + sideScroll: function (element, direction, speed, step) { + this.leg_nav.scrollDir = direction + 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 newDir = + e.pageX < c.offsetWidth * 0.2 ? 'left' : + (e.pageX > c.offsetWidth * 0.8 ? 'right' : this.leg_nav.scrollDir) + 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.scrollInterval = null + }, }, created: function () { this.search_hotel = api.throttle(this.search_nominatim("hotel"), 1000) @@ -186,7 +211,6 @@ const app = new Vue({ api.save(this.journey.id, this.journey.data); }, 1000); this.search_flight = api.throttle(this.search_travel("flight"), 2000) - this window.addEventListener("keydown", (e) => { switch (e.key) { @@ -219,25 +243,4 @@ const app = new Vue({ }, }); -var scrollInterval = null; -var scrollDir = null; -document.querySelector('.scroll-content').addEventListener('mousemove', (e) => { - const c = document.querySelector('.scroll-content') - const newDir = - e.pageX < c.offsetWidth * 0.2 ? 'left' : - (e.pageX > c.offsetWidth * 0.8 ? 'right' : scrollDir) - if (!scrollInterval || scrollDir != newDir) { - if (scrollInterval) clearInterval(scrollInterval) - sideScroll(c, newDir, 25, 10); - } -}); -document.querySelector('.scroll-content').addEventListener('mouseleave', () => { - clearInterval(scrollInterval); - scrollInterval = null -}); -function sideScroll(element, direction, speed, step) { - scrollDir = direction - scrollInterval = setInterval(() => { - element.scrollLeft += (direction == 'left') ? -step : step; - }, speed); -} + diff --git a/src/client/types/wrapper.ts b/src/client/types/wrapper.ts index 66f84b3..db9923c 100644 --- a/src/client/types/wrapper.ts +++ b/src/client/types/wrapper.ts @@ -42,7 +42,7 @@ class journey_wrapper { } leg_sel(idx: number): void { this.sel_leg = idx; - this.sel_day = 1; + this.sel_day = 0; } leg_get(idx?: number): leg { return this.data.main[idx != undefined ? idx : this.sel_leg] diff --git a/src/client/vue.ts b/src/client/vue.ts deleted file mode 100644 index 731f8fe..0000000 --- a/src/client/vue.ts +++ /dev/null @@ -1,192 +0,0 @@ - -import * as api from "./api"; -import journey_wrapper from "./types/wrapper"; -import { migrator } from "./types/migration"; -import { getGeoLine } from "./types/geom"; - -import Vue from "vue"; -import { LMap, LTileLayer, LMarker, LIcon, LPopup, LTooltip, LPolyline, LControlScale } from "vue2-leaflet"; -import Multiselect from 'vue-multiselect' -import TextareaAutosize from 'vue-textarea-autosize' - -Vue.component("l-map", LMap); -Vue.component("l-tile-layer", LTileLayer); -Vue.component("l-marker", LMarker); -Vue.component("l-icon", LIcon); -Vue.component("l-popup", LPopup); -Vue.component("l-tooltip", LTooltip); -Vue.component("l-polyline", LPolyline); -Vue.component("l-control-scale", LControlScale); -Vue.component("multiselect", Multiselect); -Vue.use(TextareaAutosize); - -const app = new Vue({ - el: "#app", - data: { - journey_edit: - ["view", "short"].indexOf(window.location.pathname.split("/")[1]) == -1, - journey: new journey_wrapper(window.location.pathname.split("/").pop() || String.gen_id(16)), - - query: { - type: "", - act: false, - res: [], - }, - impexp: "", - lang: { - format: "ddd D MMM", - formatLocale: { - firstDayOfWeek: 1, - }, - monthBeforeYear: true, - }, - polyline: { - latlngs: [], - color: 'green' - } - }, - methods: { - start_journey: function () { window.location.href = "/" + this.journey.id }, - - compute_bb: function () { - const bounds = this.$refs.map[0].mapObject.getBounds(); - return [[bounds.getSouthWest().lng, bounds.getSouthWest().lat], - [bounds.getNorthEast().lng, bounds.getNorthEast().lat]] - }, - generate_rotation: function (index, list) { - if (index < 0 || index >= list.length) return 0; - const c0 = list[(index == 0) ? index : (index - 1)] - const c1 = list[(index == list.length - 1) ? index : (index + 1)] - const brng = Math.atan2(c1[1] - c0[1], c1[0] - c0[0]); - return `rotate:${brng - Math.PI / 2}rad`; - - }, - generate_marker: function (item, fcolor) { - return ` -
- - - - ` - }, - generate_icon: function (item, fcolor, styling = "") { - return ``; - }, - - - import_data: function () { - this.journey.data = Object.assign( - {}, - JSON.parse(this.impexp.toDecoded()), - ); - this.journey.data.main.forEach((e) => { - if (e.date_range) { - e.date_range[0] = new Date(e.date_range[0]); - e.date_range[1] = new Date(e.date_range[1]); - } - }); - }, - 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); - }, - - 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; - } - }, - - search_nominatim: function (f) { - return (q) => { - this.query.act = true; - this.query.type = f; - return 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]; - }); - this.query.res = r; - this.query.act = false; - return r - }); - } - }, - search_travel: function (f) { - return (q) => { - this.query.act = true; - this.query.type = f; - return api.query_flight(q).then((r) => { - r.forEach(el => el.path = getGeoLine( - new L.LatLng(el.from_geo.lat, el.from_geo.lon), - new L.LatLng(el.to_geo.lat, el.to_geo.lon), { dist: 5_000_000 }).map(v => [v.lat, v.lng])); - this.query.res = r; - this.query.act = false; - return r; - }); - } - }, - - keyboardEvent(e) { - if (e.which === 13) { - } - }, - }, - 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) - 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) - - 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); - } - }); - - api.load(this.journey.id).then((r) => (app.journey.data = migrator(r))); - - this.search_travel("flight")("qf1").then(r => { - this.polyline.latlngs = r.map(e => e.path) - }); - - }, - watch: { - journey: { - handler: function (ndata, odata) { - this.save_data(); - }, - deep: true, - }, - }, -}); diff --git a/template/journey.pug b/template/journey.pug index 7cdd77a..0ca849f 100644 --- a/template/journey.pug +++ b/template/journey.pug @@ -4,7 +4,5 @@ include module/head.pug main#app(v-cloak) include module/nav.pug - include module/journey_nav.pug - include module/journey_leg.pug - include module/importexport.pug + include module/journey.pug include module/foot.pug diff --git a/template/module/foot.pug b/template/module/foot.pug index 39e7a65..0ee055f 100644 --- a/template/module/foot.pug +++ b/template/module/foot.pug @@ -1,11 +1,11 @@ script(src="https://unpkg.com/leaflet") -script(src="https://unpkg.com/sortablejs") script(src="https://unpkg.com/vue@2") script(src="https://unpkg.com/vue2-datepicker") script(src="https://unpkg.com/vue-textarea-autosize") script(src="https://unpkg.com/vue-multiselect@2") script(src="https://unpkg.com/vue2-leaflet") +script(src="https://unpkg.com/sortablejs") script(src="https://unpkg.com/vuedraggable") script(src="/public/main.js", type="text/javascript", charset="utf-8") footer.bg-dark diff --git a/template/module/journey.pug b/template/module/journey.pug new file mode 100644 index 0000000..ed370b3 --- /dev/null +++ b/template/module/journey.pug @@ -0,0 +1,3 @@ +.journey + include journey/leg.pug +include journey/impexp.pug \ No newline at end of file diff --git a/template/module/importexport.pug b/template/module/journey/impexp.pug similarity index 93% rename from template/module/importexport.pug rename to template/module/journey/impexp.pug index b66f61e..6e0c3a5 100644 --- a/template/module/importexport.pug +++ b/template/module/journey/impexp.pug @@ -1,4 +1,4 @@ -div +.impexp .container-medium.section .aligner .input.col-sm-4 @@ -10,4 +10,4 @@ div .col-sm-2 button.button.button--primary.button--mobileFull( v-on:click="export_data" - ) Export + ) Export \ No newline at end of file diff --git a/template/module/journey/leg.pug b/template/module/journey/leg.pug new file mode 100644 index 0000000..58eb20f --- /dev/null +++ b/template/module/journey/leg.pug @@ -0,0 +1,11 @@ +include leg/nav.pug +.bg-dark.text-white(v-if="journey && journey.leg_get()") + .container.section + include leg/top.pug + .row(style="aspect-ratio:1.25;") + .map-container(:class="{ 'col-9': query.type, 'col-12': !query.type }" ) + include map.pug + .drawer-container(:class="{ 'col-3': query.type, 'col-0': !query.type }") + include leg/drawer.pug + + include leg/old_cfg.pug \ No newline at end of file diff --git a/template/module/journey/leg/drawer.pug b/template/module/journey/leg/drawer.pug new file mode 100644 index 0000000..76b4b99 --- /dev/null +++ b/template/module/journey/leg/drawer.pug @@ -0,0 +1,15 @@ +.row.text-center + .input.text-dark(style="width: 100%") + input( + type="search" + @input="search_active" + placeholder="Search ... " + ) + ul + li( + v-for="item in query.res" + :key="item.id" + @mouseover="drawer_hover_item(item)" + @mouseleave="drawer_hover_item()" + @click="drawer_click_item(item)" ) + | {{ item.name }} \ No newline at end of file diff --git a/template/module/journey/leg/nav.pug b/template/module/journey/leg/nav.pug new file mode 100644 index 0000000..42fdebc --- /dev/null +++ b/template/module/journey/leg/nav.pug @@ -0,0 +1,23 @@ +.scroll-handler( + @mouveleave="nav_mouseleave" + @mousemove="nav_mousemove") + draggable.scroll-content.list-group.bg-dark( + tag="div", + :list="journey.data.main", + handle=".handle" + ) + .list-group-item.handle( + 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 }} + i.fa.fa-times.close.fright( + style="top: 2px; right: 2px; position: absolute", + @click="journey.rm_leg(idx)" + ) + + .list-group-item.bg-white(@click="journey.add_leg()") + .text Add Leg + i.fa.fa-plus.add(style="top: 12px; right: 5px; position: absolute") diff --git a/template/module/journey/leg/old_cfg.pug b/template/module/journey/leg/old_cfg.pug new file mode 100644 index 0000000..027df9c --- /dev/null +++ b/template/module/journey/leg/old_cfg.pug @@ -0,0 +1,71 @@ +div + div + .row.text-center + div + label Hotel + multiselect#ajax( + v-model="journey.leg_get().hotel", + label="sname", + track-by="place_id", + placeholder="Type to search", + open-direction="bottom", + :options="query.res", + :searchable="true", + :loading="query.type=='hotel'", + :internal-search="false", + :clear-on-select="false", + :options-limit="50", + :limit="1", + :max-height="600", + @search-change="search_hotel" + ) + .row.text-center + div + label Restoration + multiselect#ajax( + v-model="journey.leg_get().places.restaurants", + label="sname", + track-by="place_id", + placeholder="Type to search", + open-direction="bottom", + :multiple="true", + :options="query.res", + :searchable="true", + :loading="query.type == 'restaurant'", + :internal-search="false", + :clear-on-select="false", + :options-limit="50", + :limit="10", + :max-height="600", + @search-change="search_restaurant" + ) + .row.text-center + div + label Activities + multiselect#ajax( + v-model="journey.leg_get().places.activities", + label="sname", + track-by="place_id", + placeholder="Type to search", + open-direction="bottom", + :multiple="true", + :options="query.res", + :searchable="true", + :loading="query.type=='place'", + :internal-search="false", + :clear-on-select="false", + :options-limit="50", + :limit="10", + :max-height="600", + @search-change="search_place" + ) + .row.text-center + div + label Notes + .input.text-dark(style="width: 100%") + textarea-autosize.text-small( + v-model="journey.leg_get().notes", + placeholder="Notes", + :min-height="30", + :max-height="350" + ) diff --git a/template/module/journey/leg/top.pug b/template/module/journey/leg/top.pug new file mode 100644 index 0000000..434f6af --- /dev/null +++ b/template/module/journey/leg/top.pug @@ -0,0 +1,29 @@ +.row.text-center + .col-sm-2 + .input + input(v-model="journey.leg_get().title") + .col-sm-2 + .input + input( + placeholder="Day title", + v-model="journey.leg_get().day_title[journey.sel_day]" + ) + + .col-sm-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-sm-1 + .right.col-sm-2 + .input + input( + disabled="", + :value="journey.date_sel() + ' (' + journey.sel_day + ')'" + ) \ No newline at end of file diff --git a/template/module/journey/map.pug b/template/module/journey/map.pug new file mode 100644 index 0000000..6acc613 --- /dev/null +++ b/template/module/journey/map.pug @@ -0,0 +1,20 @@ +l-map( + :zoom.sync="journey.leg_get().map.zoom", + :center.sync="journey.leg_get().map.center", + style="height:100%" + ref="map" +) + l-tile-layer( + url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + attribution="© OpenStreetMap contributors" + ) + l-control-scale(position="bottomright", :imperial="false", :metric="true") + include map/override.pug + + include map/hotel.pug + include map/activities.pug + include map/restaurants.pug + + include map/travel.pug + + include map/right_menu.pug \ No newline at end of file diff --git a/template/module/journey/map/activities.pug b/template/module/journey/map/activities.pug new file mode 100644 index 0000000..e7d9f0d --- /dev/null +++ b/template/module/journey/map/activities.pug @@ -0,0 +1,37 @@ +l-marker( + v-for="(place, index) in journey.leg_get().places.activities", + :key="'activities'+index", + :lat-lng="place.latlon" + ) + l-icon( + v-if="place.step == journey.sel_day", + v-html="generate_marker(place)" + ) + l-icon( + v-else-if="place.step == -1 || place.step == undefined", + v-html="generate_marker(place, 'gray')" + ) + l-icon(v-else-if="edit_active", v-html="generate_marker(place, 'lightgray')") + l-icon(v-else) + l-popup + h1.row.text-medium.text-center {{ place.sname }} + span.row.text-small.text-gray {{ place.display_name }} + span(v-if="edit_active") + .row.input(style="margin-bottom:0") + textarea-autosize.col-12.col-sm-12.text-small( + placeholder="Notes", + v-model="place.notes", + :min-height="30", + :max-height="350" + ) + a.leaflet-popup-close-button.text-gray( + style="right: 0px; visibility: visible", + href="#rm", + v-on:click.prevent="place.step = -1" + ) - + a.leaflet-popup-close-button.text-gray( + style="right: 16px; visibility: visible", + href="#ad", + v-on:click.prevent="place.step = journey.sel_day" + ) + + span.row.text-small.text-dark(v-else) {{ place.notes }} diff --git a/template/module/journey/map/hotel.pug b/template/module/journey/map/hotel.pug new file mode 100644 index 0000000..d19bea4 --- /dev/null +++ b/template/module/journey/map/hotel.pug @@ -0,0 +1,18 @@ +l-marker( + v-if="journey.leg_get().hotel", + :lat-lng="journey.leg_get().hotel.latlon" + ) + l-icon(v-html="generate_marker(journey.leg_get().hotel, 'darkblue')") + l-popup + h1.row.text-medium.text-center {{ journey.leg_get().hotel.sname }} + span.row.text-small.text-gray {{ journey.leg_get().hotel.display_name }} + span(v-if="edit_active") + .row.input(style="margin-bottom:0;") + textarea-autosize.col-12.col-sm-12.text-small( + placeholder="Notes", + v-model="journey.leg_get().hotel.notes", + :min-height="30", + :max-height="350" + ) + span.row.text-small.text-white(v-else) {{ journey.leg_get().hotel.notes }} + \ No newline at end of file diff --git a/template/module/journey/map/override.pug b/template/module/journey/map/override.pug new file mode 100644 index 0000000..c03d5e7 --- /dev/null +++ b/template/module/journey/map/override.pug @@ -0,0 +1,5 @@ +l-marker( + v-if="map_override.active", + :lat-lng="map_override.center" + ) + l-icon(v-html="generate_marker('plus', 'darkgreen')") \ No newline at end of file diff --git a/template/module/journey/map/restaurants.pug b/template/module/journey/map/restaurants.pug new file mode 100644 index 0000000..02a9cfe --- /dev/null +++ b/template/module/journey/map/restaurants.pug @@ -0,0 +1,18 @@ +l-marker( + v-for="(place, index) in journey.leg_get().places.restaurants", + :key="'restaurants'+index" + :lat-lng="place.latlon" + ) + l-icon(v-html="generate_marker(place, 'cadetblue')") + l-popup + h1.row.text-medium.text-center {{ place.sname }} + span.row.text-small.text-gray {{ place.display_name }} + span(v-if="edit_active") + .row.input(style="margin-bottom:0") + textarea-autosize.col-12.col-sm-12.text-small( + placeholder="Notes" + v-model="place.notes" + :min-height="30" + :max-height="350" + ) + span.row.text-small.text-dark(v-else) {{ place.notes }} diff --git a/template/module/journey/map/right_menu.pug b/template/module/journey/map/right_menu.pug new file mode 100644 index 0000000..3601232 --- /dev/null +++ b/template/module/journey/map/right_menu.pug @@ -0,0 +1,6 @@ +.map-menu + .map-menu-item( v-if="query.type" @click="query.type=''" v-html="generate_icon('close')") + .map-menu-item(v-if="!query.type" @click="query.type='hotel'" v-html="generate_icon('bed')") + .map-menu-item(v-if="!query.type" @click="query.type='restaurant'" v-html="generate_icon('utensils')") + .map-menu-item(v-if="!query.type" @click="query.type='place'" v-html="generate_icon('star')") + .map-menu-item(v-if="!query.type" @click="query.type='flight'" v-html="generate_icon('plane')") \ No newline at end of file diff --git a/template/module/journey/map/travel.pug b/template/module/journey/map/travel.pug new file mode 100644 index 0000000..e3ee144 --- /dev/null +++ b/template/module/journey/map/travel.pug @@ -0,0 +1,9 @@ +div(v-for= "travel in journey.leg_get().travel") + l-polyline(:lat-lngs="travel.path" :color="travel.color || 'gray'") + l-marker( + v-for="(place, index) in travel.path" + :key="'plane'+index" + :lat-lng="place" + ) + l-icon(v-html="generate_icon('plane', travel.color || 'gray', generate_rotation(index,travel.path), 'travel-path-icon')" + ) \ No newline at end of file diff --git a/template/module/journey_leg.pug b/template/module/journey_leg.pug deleted file mode 100644 index aee7a18..0000000 --- a/template/module/journey_leg.pug +++ /dev/null @@ -1,119 +0,0 @@ -div(v-for="(e, idx) in journey.data.main", :key="idx") - .bg-dark.text-white(v-if="journey.sel_leg == idx") - .container.section - .row.text-center - .input.col-sm-2 - input(v-model="journey.leg_get(idx).title") - .input.col-sm-2 - input( - placeholder="Day title", - v-model="journey.leg_get(idx).day_title[journey.sel_day]" - ) - .col-sm-3 - .right.input.col-sm-2 - input( - disabled="", - :value="journey.date_sel() + ' (' + journey.sel_day + ')'" - ) - .row - .map-container(:class="{ 'col-9': !drawer_active, 'col-7': drawer_active }") - include map.pug - .drawer-container(:class="{ 'col-3': drawer_active, 'col-0': !drawer_active }") - .row.text-center - .input.text-dark(style="width: 100%") - input( - type="search" - @input="search_active" - placeholder="Search ... " - ) - ul - li( - v-for="item in query.res" - :key="item.id" - @mouseover="drawer_hover_item(item)" - @mouseleave="drawer_hover_item()" - @click="drawer_click_item(item)" ) - | {{ item.name }} - - .col-3.col-ssm-12 - .row.text-center - div - label Date Range ({{ journey.leg_len(idx) }}) - .input.text-dark - date-picker( - :lang="lang", - v-model="journey.data.main[idx].date_range", - range="", - format="ddd D MMM", - placeholder="Date Range", - v-on:change="journey.date_update(idx)" - ) - .row.text-center - div - label Hotel - multiselect#ajax( - v-model="journey.data.main[idx].hotel", - label="sname", - track-by="place_id", - placeholder="Type to search", - open-direction="bottom", - :options="query.res", - :searchable="true", - :loading="query.type=='hotel'", - :internal-search="false", - :clear-on-select="false", - :options-limit="50", - :limit="1", - :max-height="600", - @search-change="search_hotel" - ) - .row.text-center - div - label Restoration - multiselect#ajax( - v-model="journey.data.main[idx].places.restaurants", - label="sname", - track-by="place_id", - placeholder="Type to search", - open-direction="bottom", - :multiple="true", - :options="query.res", - :searchable="true", - :loading="query.type == 'restaurant'", - :internal-search="false", - :clear-on-select="false", - :options-limit="50", - :limit="10", - :max-height="600", - @search-change="search_restaurant" - ) - .row.text-center - div - label Activities - multiselect#ajax( - v-model="journey.data.main[idx].places.activities", - label="sname", - track-by="place_id", - placeholder="Type to search", - open-direction="bottom", - :multiple="true", - :options="query.res", - :searchable="true", - :loading="query.type=='place'", - :internal-search="false", - :clear-on-select="false", - :options-limit="50", - :limit="10", - :max-height="600", - @search-change="search_place" - ) - .row.text-center - div - label Notes - .input.text-dark(style="width: 100%") - textarea-autosize.text-small( - v-model="journey.data.main[idx].notes", - placeholder="Notes", - :min-height="30", - :max-height="350" - ) diff --git a/template/module/journey_nav.pug b/template/module/journey_nav.pug deleted file mode 100644 index 3a2ed78..0000000 --- a/template/module/journey_nav.pug +++ /dev/null @@ -1,20 +0,0 @@ -draggable.scroll-content.list-group.bg-dark( - tag="div", - :list="journey.data.main", - handle=".handle" -) - .list-group-item.handle( - 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 }} - i.fa.fa-times.close.fright( - style="top: 2px; right: 2px; position: absolute", - @click="journey.rm_leg(idx)" - ) - - .list-group-item.bg-white(@click="journey.add_leg()") - .text Add Leg - i.fa.fa-plus.add(style="top: 12px; right: 5px; position: absolute") diff --git a/template/module/map.pug b/template/module/map.pug deleted file mode 100644 index 19e4da8..0000000 --- a/template/module/map.pug +++ /dev/null @@ -1,99 +0,0 @@ -l-map( - - :zoom.sync="journey.leg_get().map.zoom", - :center.sync="journey.leg_get().map.center", - style="padding-top: 100%" - ref="map" -) - l-tile-layer( - url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", - attribution="© OpenStreetMap contributors" - ) - l-control-scale(position="topright", :imperial="false", :metric="true") - l-marker( - v-if="map_override.active", - :lat-lng="map_override.center" - ) - l-icon(v-html="generate_marker('plus', 'darkgreen')") - - l-marker( - v-if="journey.data.main[idx].hotel", - :lat-lng="journey.data.main[idx].hotel.latlon" - ) - l-icon(v-html="generate_marker(journey.data.main[idx].hotel, 'darkblue')") - l-popup - h1.row.text-medium.text-center {{ journey.data.main[idx].hotel.sname }} - span.row.text-small.text-gray {{ journey.data.main[idx].hotel.display_name }} - span(v-if="edit_active") - .row.input(style="margin-bottom:0;") - textarea-autosize.col-12.col-sm-12.text-small( - placeholder="Notes", - v-model="journey.data.main[idx].hotel.notes", - :min-height="30", - :max-height="350" - ) - span.row.text-small.text-white(v-else) {{ journey.data.main[idx].hotel.notes }} - l-marker( - v-for="(place, index) in journey.data.main[idx].places.activities", - :key="'activities'+index", - :lat-lng="place.latlon" - ) - l-icon( - v-if="place.step == journey.sel_day", - v-html="generate_marker(place)" - ) - l-icon( - v-else-if="place.step == -1 || place.step == undefined", - v-html="generate_marker(place, 'gray')" - ) - l-icon(v-else-if="edit_active", v-html="generate_marker(place, 'lightgray')") - l-icon(v-else) - l-popup - h1.row.text-medium.text-center {{ place.sname }} - span.row.text-small.text-gray {{ place.display_name }} - span(v-if="edit_active") - .row.input - textarea-autosize.col-12.col-sm-12.text-small( - placeholder="Notes", - v-model="place.notes", - :min-height="30", - :max-height="350" - ) - a.leaflet-popup-close-button.text-gray( - style="right: 0px; visibility: visible", - href="#rm", - v-on:click.prevent="place.step = -1" - ) - - a.leaflet-popup-close-button.text-gray( - style="right: 16px; visibility: visible", - href="#ad", - v-on:click.prevent="place.step = journey.sel_day" - ) + - span.row.text-small.text-dark(v-else) {{ place.notes }} - l-marker( - v-for="(place, index) in journey.data.main[idx].places.restaurants", - :key="'restaurants'+index" - :lat-lng="place.latlon" - ) - l-icon(v-html="generate_marker(place, 'cadetblue')") - l-popup - h1.row.text-medium.text-center {{ place.sname }} - span.row.text-small.text-gray {{ place.display_name }} - span(v-if="edit_active") - .row.input - textarea-autosize.col-12.col-sm-12.text-small( - placeholder="Notes" - v-model="place.notes" - :min-height="30" - :max-height="350" - ) - span.row.text-small.text-dark(v-else) {{ place.notes }} - - div(v-for= "travel in journey.data.main[idx].travel") - l-polyline(:lat-lngs="travel.path" :color="travel.color || 'gray'") - l-marker( - v-for="(place, index) in travel.path" - :key="'plane'+index" - :lat-lng="place" - ) - l-icon(v-html="generate_icon('plane', travel.color || 'gray', generate_rotation(index,travel.path))") \ No newline at end of file diff --git a/template/module/nav_pub.pug b/template/module/view/nav.pug similarity index 100% rename from template/module/nav_pub.pug rename to template/module/view/nav.pug diff --git a/template/module/short_sec.pug b/template/module/view/short_leg.pug similarity index 100% rename from template/module/short_sec.pug rename to template/module/view/short_leg.pug diff --git a/template/module/view_step.pug b/template/module/view/view_day.pug similarity index 100% rename from template/module/view_step.pug rename to template/module/view/view_day.pug diff --git a/template/short.pug b/template/short.pug index f4fdd09..90390db 100644 --- a/template/short.pug +++ b/template/short.pug @@ -1,10 +1,10 @@ doctype html include module/head.pug main#app(v-cloak) - include module/nav_pub.pug + include module/view/nav.pug div( v-for="(item, idx) in journey.data.main", :class="idx % 2 === 0 ? 'bg-dark text-white' : ''" ) - include module/short_sec.pug + include module/view/short_leg.pug include module/foot.pug diff --git a/template/view.pug b/template/view.pug index 7230689..96c486d 100644 --- a/template/view.pug +++ b/template/view.pug @@ -2,5 +2,5 @@ doctype html include module/head.pug main#app(v-cloak) div(v-if="journey.data.main[journey.sel_leg] != undefined") - include module/view_step.pug + include module/view/view_day.pug include module/foot.pug