Compare commits

...

10 Commits

Author SHA1 Message Date
soraefir
07699b9843 fix yarnlock
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-02 01:03:10 +01:00
soraefir
f7fc822156 Merge branch 'dev' 2025-03-02 01:02:16 +01:00
soraefir
4b2db42a2d dockerfile
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-03-02 00:57:41 +01:00
soraefir
14e18a3e50 wip 2025-03-02 00:53:25 +01:00
soraefir
7efb63764c wip
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-02 00:27:49 +01:00
soraefir
52ee73a4ac wip
All checks were successful
continuous-integration/drone/push Build is passing
2025-03-01 23:40:45 +01:00
c98be7a4e6 Update template/module/journey/map/travel.pug
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-28 17:53:58 +01:00
48363040d3 Update template/module/journey/map/right_menu.pug
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-28 17:53:42 +01:00
6f3b005c5c Update template/module/journey/map/restaurants.pug
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-28 17:53:33 +01:00
832bfa485b Update template/module/journey/map/override.pug
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-28 17:53:26 +01:00
57 changed files with 1851 additions and 3806 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ db/
.yarn/ .yarn/
public/*.js public/*.js
public/*.map public/*.map
public/*.css
.yarnrc.yml .yarnrc.yml
.pnp* .pnp*
build/ build/

View File

@@ -7,6 +7,7 @@ WORKDIR /usr/src/app
# where available (npm@5+) # where available (npm@5+)
COPY package*.json ./ COPY package*.json ./
RUN yarn RUN yarn
RUN yarn build
# If you are building your code for production # If you are building your code for production
# RUN npm ci --only=production # RUN npm ci --only=production
# Bundle app source # Bundle app source

View File

@@ -4,11 +4,12 @@
"description": "Open Travel Mapper", "description": "Open Travel Mapper",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"build": "yarn build-server && yarn build-client", "build": "yarn build-server && yarn build-client && yarn build-style",
"build-style": "esbuild src/style/index.css --outfile=public/index.css --bundle --minify ",
"build-client": "esbuild src/client/main.ts --outfile=public/main.js --tree-shaking=true --bundle --minify --sourcemap --tsconfig=tsconfig-client.json", "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", "build-server": "esbuild src/server/**/*.ts --outdir=build --platform=node --format=cjs",
"start": "node build/main.js", "start": "node build/main.js",
"demon": "nodemon -e ts,js,pug --watch src --watch template --watch router --exec \"yarn build && yarn start\"" "demon": "nodemon -e ts,js --watch src --watch template --watch router --exec \"yarn build && yarn start\""
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -20,19 +21,13 @@
"@fastify/leveldb": "^6.0.0", "@fastify/leveldb": "^6.0.0",
"@fastify/static": "^8.0.0", "@fastify/static": "^8.0.0",
"@fastify/view": "^10.0.0", "@fastify/view": "^10.0.0",
"@prettier/plugin-pug": "^3.0.0",
"@types/node": "^22.13.5", "@types/node": "^22.13.5",
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fastify": "^5.2.1", "fastify": "^5.2.1",
"jsdom": "^26.0.0", "jsdom": "^26.0.0",
"leaflet": "^1.9.4",
"nodemon": "^3.0.1", "nodemon": "^3.0.1",
"prettier": "^3.5.2", "prettier": "^3.5.2",
"pug": "^3.0.2", "pug": "^3.0.2",
"undici": "^7.3.0", "undici": "^7.3.0"
"vue": "2",
"vue-multiselect": "2",
"vue-textarea-autosize": "^1.1.1",
"vue2-leaflet": "^2.7.1"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -124,7 +124,7 @@ export const icon_type = (item: string | NominatimResult): string => {
"place_of_worship", "place_of_worship",
"attraction", "attraction",
"information", "information",
"university", "theatre", "opera" "university", "science_park", "theatre", "opera"
], ],
mountain: ["peak", "viewpoint"], mountain: ["peak", "viewpoint"],
parking: ["parking"], parking: ["parking"],

View File

@@ -12,10 +12,6 @@ Vue.component("l-popup", window.Vue2Leaflet.LPopup);
Vue.component("l-tooltip", window.Vue2Leaflet.LTooltip); Vue.component("l-tooltip", window.Vue2Leaflet.LTooltip);
Vue.component("l-polyline", window.Vue2Leaflet.LPolyline); Vue.component("l-polyline", window.Vue2Leaflet.LPolyline);
Vue.component("l-control-scale", window.Vue2Leaflet.LControlScale); Vue.component("l-control-scale", window.Vue2Leaflet.LControlScale);
// Vue.component("multiselect", window.VueMultiselect.default);
Vue.use(window.VueTextareaAutosize);
var first_boot = true
const app = new Vue({ const app = new Vue({
el: "#app", el: "#app",
@@ -24,7 +20,7 @@ const app = new Vue({
journey: new journey_wrapper(window.location.pathname.split("/").pop() || String.gen_id(16)), journey: new journey_wrapper(window.location.pathname.split("/").pop() || String.gen_id(16)),
map_override: { active: false, elements: [] }, map_override: { active: false, elements: [] },
query: { query: {
type: "", res: [], load: false, sub: false, type: "", res: [], load: false, sub: false, note: false, drawer: false,
}, },
leg_nav: { leg_nav: {
scrollInterval: null, scrollInterval: null,
@@ -43,6 +39,7 @@ const app = new Vue({
start_journey: function () { window.location.href = "/" + this.journey.id }, start_journey: function () { window.location.href = "/" + this.journey.id },
compute_bb: function () { compute_bb: function () {
if (!this.$refs.map) return undefined
const bounds = this.$refs.map.mapObject.getBounds(); const bounds = this.$refs.map.mapObject.getBounds();
return [[bounds.getSouthWest().lng, bounds.getSouthWest().lat], return [[bounds.getSouthWest().lng, bounds.getSouthWest().lat],
[bounds.getNorthEast().lng, bounds.getNorthEast().lat]] [bounds.getNorthEast().lng, bounds.getNorthEast().lat]]
@@ -64,7 +61,7 @@ const app = new Vue({
<polygon points="4,12 20,12 12,36" fill="${fcolor || item.color || "blue"}" /></svg>` <polygon points="4,12 20,12 12,36" fill="${fcolor || item.color || "blue"}" /></svg>`
}, },
generate_icon: function (item, fcolor = "", styling = "", classes = "") { generate_icon: function (item, fcolor = "", styling = "", classes = "") {
return `<i class="fa fa-${api.icon_type(item) || "star"} fa-2x ${classes}" style="${styling}; color:${fcolor || "white"}; text-align:center; align-content:center; width:32px; height:32px;"></i>`; 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>`;
}, },
@@ -169,7 +166,10 @@ const app = new Vue({
drawer_click_item: function (item) { drawer_click_item: function (item) {
const tpe = this.query.type; const tpe = this.query.type;
this.query.res = []; this.query.res = [];
this.query.note = false;
this.query.type = null; this.query.type = null;
this.query.drawer = item ? true : false;
setTimeout(() => this.$refs.map.mapObject.invalidateSize(), 500);
this.query.sub = false; this.query.sub = false;
this.drawer_hover_item() this.drawer_hover_item()
if (item) { if (item) {
@@ -197,10 +197,19 @@ const app = new Vue({
}, },
search_enable: function (f) { 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;
}
this.query.note = false;
this.query.type = f; this.query.type = f;
const query_in = document.getElementById('query_input') const query_in = document.getElementById('query_input')
setTimeout(() => query_in.focus(), 500);
query_in.focus()
this.search_active({ target: query_in }) this.search_active({ target: query_in })
}, },
@@ -219,9 +228,10 @@ const app = new Vue({
}, },
nav_mousemove(e) { nav_mousemove(e) {
const c = document.querySelector('.scroll-content') const c = document.querySelector('.scroll-content')
const left = e.pageX - c.getBoundingClientRect().left;
const newDir = const newDir =
e.pageX < c.offsetWidth * 0.1 ? 'left' : left < c.offsetWidth * 0.1 ? 'left' :
(e.pageX > c.offsetWidth * 0.9 ? 'right' : 'none') (left > c.offsetWidth * 0.9 ? 'right' : 'none')
if (!this.leg_nav.scrollInterval || this.leg_nav.scrollDir != newDir) { if (!this.leg_nav.scrollInterval || this.leg_nav.scrollDir != newDir) {
if (this.leg_nav.scrollInterval) clearInterval(this.leg_nav.scrollInterval) if (this.leg_nav.scrollInterval) clearInterval(this.leg_nav.scrollInterval)
this.sideScroll(c, newDir, 25, 10); this.sideScroll(c, newDir, 25, 10);
@@ -232,6 +242,13 @@ const app = new Vue({
this.leg_nav.scrollDir = 'none' this.leg_nav.scrollDir = 'none'
this.leg_nav.scrollInterval = null 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 () { created: function () {
this.search_hotel = api.throttle(this.search_nominatim("hotel"), 1000) this.search_hotel = api.throttle(this.search_nominatim("hotel"), 1000)
@@ -263,6 +280,7 @@ const app = new Vue({
watch: { watch: {
journey: { journey: {
handler: function (ndata, odata) { handler: function (ndata, odata) {
if (this.edit_active)
this.save_data(); this.save_data();
}, },
deep: true, deep: true,

View File

@@ -38,14 +38,8 @@ declare global {
} }
} }
const journey_template: journey = {
fmt_ver: 1,
title: "New Journey",
main: [],
}
const leg_template: leg = { const leg_template: leg = {
title: "New Leg", title: "",
day_title: [], day_title: [],
map: { zoom: 2, center: { lng: 0, lat: 0 } }, map: { zoom: 2, center: { lng: 0, lat: 0 } },
travel: [], travel: [],
@@ -54,6 +48,12 @@ const leg_template: leg = {
notes: "", notes: "",
date_range: null date_range: null
} }
const journey_template: journey = {
fmt_ver: 1,
title: "New Journey",
main: [leg_template],
}
export { map, geoloc, leg, journey } export { map, geoloc, leg, journey }
export { journey_template, leg_template } export { journey_template, leg_template }

View File

@@ -29,6 +29,7 @@ class journey_wrapper {
rm_leg(idx: number): void { rm_leg(idx: number): void {
this.data.main.splice(idx, 1); this.data.main.splice(idx, 1);
if (this.sel_leg == idx) this.leg_prev(); if (this.sel_leg == idx) this.leg_prev();
if (this.sel_leg > this.data.main.length - 1) this.leg_next();
} }
tot_len(): number | "?" { tot_len(): number | "?" {
if (this.leg_count() == 0) return 0; if (this.leg_count() == 0) return 0;

View File

@@ -15,6 +15,7 @@ export function nominatim_get_data(id: string, bb: string[][] | null = null): Pr
const url = new URL("https://nominatim.openstreetmap.org/search"); const url = new URL("https://nominatim.openstreetmap.org/search");
url.searchParams.append('format', 'jsonv2') url.searchParams.append('format', 'jsonv2')
url.searchParams.append('q', id) url.searchParams.append('q', id)
url.searchParams.append('limit', '20')
if (bb) { if (bb) {
url.searchParams.append('viewbox', `${bb[0][0]},${bb[0][1]},${bb[1][0]},${bb[1][1]}`) url.searchParams.append('viewbox', `${bb[0][0]},${bb[0][1]},${bb[1][0]},${bb[1][1]}`)
url.searchParams.append('bounded', `1`) url.searchParams.append('bounded', `1`)

View File

@@ -25,10 +25,10 @@ server.register(fastify_view, {
server.register(api, { prefix: "/api" }); server.register(api, { prefix: "/api" });
server.get("/", (req, reply) => reply.view("/template/home.pug")); server.get("/", (req, reply) => reply.view("/src/template/home.pug"));
server.get("/:id", (req, reply) => reply.view("/template/journey.pug")); server.get("/:id", (req, reply) => reply.view("/src/template/journey.pug"));
server.get("/view/:id", (req, reply) => reply.view("/template/view.pug")); server.get("/view/:id", (req, reply) => reply.view("/src/template/view.pug"));
server.get("/short/:id", (req, reply) => reply.view("/template/short.pug")); server.get("/short/:id", (req, reply) => reply.view("/src/template/short.pug"));
server.listen({ port: 8080, host: "0.0.0.0" }, (err, address) => { server.listen({ port: 8080, host: "0.0.0.0" }, (err, address) => {
if (err) throw err; if (err) throw err;

207
src/style/custom.css Normal file
View File

@@ -0,0 +1,207 @@
.leaflet-popup-close-button {
visibility: hidden;
}
.p-abs {
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;
}
.col-0 {
flex: 0 0 0%;
max-width: 0%;
overflow: hidden;
}
.map-container,
.drawer-container {
transition: flex 0.5s ease-in-out, max-width 0.5s ease-in-out;
}
.map-container {
min-width: 52px;
height: 100%;
}
.drawer-container {
height: 100%;
right: 0;
top: 0;
overflow: scroll;
}
.travel-path-icon {
margin-left: -12px;
margin-top: -32px;
}
.ml-auto {
margin-left: auto;
}
.mr-auto {
margin-right: auto;
}
.input .mx-input {
height: 40px;
}
.h-100 {
height: 100%;
}
.map-menu {
position: absolute;
display: flex;
z-index: 1100;
right: 0;
flex-direction: column;
gap: 10px;
margin: 5px;
}
.map-menu-top {
top: 0;
}
.map-menu-bottom {
bottom: 0;
}
.map-menu-center {
top: 50%;
}
.padding-1 {
padding: 5px;
}
.map-menu-item {
background-color: var(--darkdark);
padding: 5px;
border-radius: 50%;
cursor: pointer;
}
.map-menu-item:hover {
filter: brightness(150%);
}
.map-menu-sub {
display: flex;
flex-direction: row-reverse;
gap: 5px;
}
.map-menu-item,
.map-menu-sub-item {
background-color: var(--darkdark);
padding: 5px;
border-radius: 50%;
cursor: pointer;
float: right;
width: 42px;
height: 42px;
align-content: center;
text-align: center;
}
.vue2leaflet-map {
border-radius: var(--border-radius);
}
.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;
}
.leaflet-popup-button-group {
position: absolute;
top: 0;
right: 0;
display: flex;
flex-direction: row;
gap: 5px;
margin: 2px 6px;
}
.leaflet-popup-button-group>a {
cursor: pointer;
}
.leaflet-popup-button-group>a:hover {
cursor: pointer;
filter: brightness(150%);
}
.leaflet-popup-button-group>a>i {
font-size: 1em;
}
.query-result {
display: flex;
align-items: center;
border-radius: var(--border-radius);
cursor: pointer;
}
.query-result:hover {
filter: brightness(85%);
}
.scroll-content>div:first-child {
border-top-left-radius: var(--border-radius);
border-bottom-left-radius: var(--border-radius);
}
.scroll-content>div:nth-last-child(3) {
border-top-right-radius: var(--border-radius);
border-bottom-right-radius: var(--border-radius);
}
.scroll-content>div:last-child {
border-radius: var(--border-radius);
}
.mx-datepicker {
width: 100% !important;
}

19
src/style/define.css Normal file
View File

@@ -0,0 +1,19 @@
:root {
--black: #030B12;
--darkdark: #0C1D2E;
--dark: #203A53;
--lightdark: #425F7C;
--light: #93A9BE;
--lightlight: #B6C5D5;
--white: #F0F3F7;
--orange: ##F5B97D;
--yellow: #F5F57D;
--green: #B9F57D;
--turquoise: #7DF5B9;
--blue: #7DB9F5;
--purple: #B97DF5;
--pink: #F57DB9;
--red: #F57D7D;
--border-radius: 3px;
}

13
src/style/index.css Normal file
View File

@@ -0,0 +1,13 @@
@import './define.css';
@import './module/input.css';
@import './module/load_n_spin.css';
@import './module/typography.css';
@import './module/layout.css';
@import './module/general.css';
@import './custom.css';
[v-cloak] {
display: none;
}

View File

@@ -0,0 +1,202 @@
html,
body,
body,
div,
span,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
abbr,
address,
cite,
code,
del,
dfn,
em,
ins,
kbd,
q,
samp,
small,
strong,
sub,
sup,
var,
b,
i,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
figure,
footer,
header,
hgroup,
menu,
nav,
section,
time,
mark,
audio,
video {
background: transparent;
border: 0;
font-size: 100%;
margin: 0;
outline: 0;
padding: 0;
vertical-align: baseline;
}
article,
aside,
figure,
footer,
header,
main,
nav,
section {
display: block;
}
*,
*:before,
*:after {
box-sizing: border-box;
}
*,
*::after,
*::before {
box-sizing: border-box;
outline: none;
}
body {
background-color: #fff;
min-height: 100%;
overflow-x: hidden;
position: relative;
}
p {
font-weight: normal;
margin-bottom: 1.5em;
}
img {
max-width: 100%;
}
strong {
font-weight: 600;
}
ul {
margin-bottom: 1em;
}
li {
list-style: none;
margin-bottom: 0.5em;
}
/**
* BACKGROUND
*/
.bg-primary {
background-color: var(--blue);
}
.bg-dark {
background-color: var(--darkdark);
}
.bg-secondary {
background-color: var(--pink);
}
.bg-white {
background-color: var(--white);
}
.bg-success {
background-color: var(--green);
}
.bg-info {
background-color: var(--yellow);
}
.bg-warning {
background-color: var(--orange);
}
.bg-error {
background-color: var(--red);
}
.bg-gray {
background-color: var(--lightdark);
}
.bg-gray-light {
background-color: var(--lightlight);
}
.align {
align-items: center;
justify-content: center;
}
.fleft {
float: left;
}
.fright {
float: right;
}
.clearfix ::after {
clear: both;
content: "";
display: table;
}
.no-wrap {
white-space: nowrap;
}
.overflow-hidden {
overflow: hidden;
}
.rounded {
border-radius: var(--border-radius);
}

362
src/style/module/input.css Normal file
View File

@@ -0,0 +1,362 @@
input,
textarea {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
resize: none;
}
label {
display: block;
font-weight: normal;
}
input:-webkit-autofill {
box-shadow: 0 0 0 1000px #eceff1 inset;
}
.textarea,
.input,
.select {
border: 1px solid var(--white);
border-radius: var(--border-radius);
box-shadow: none;
display: inline-block;
font-weight: normal;
overflow: hidden;
}
.textarea :focus,
.input :focus,
.select :focus {
outline: none;
}
.textarea.has-error,
.input.has-error,
.select.has-error {
background: #eceff1;
border: 1px solid #e74c3c;
margin-bottom: 0;
}
.select {
background-color: #eceff1;
display: inline-block;
margin-right: 16px;
position: relative;
}
.select:last-child {
margin-right: 0;
}
.select-fullWidth {
display: block;
margin-left: 0;
margin-right: 0;
width: 100%;
}
.select select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: transparent;
border: 0;
border-radius: 0;
color: #272727;
display: block;
font-size: 16px;
line-height: 1.5em;
margin: 0;
padding: 8px 16px;
padding-right: 30px;
transition: background-color 0.2s ease-in-out;
width: 100%;
}
.select select:active,
.select select:focus {
background-color: #fbfbfc;
border: 0;
outline: none;
}
.select select::-ms-expand {
display: none;
}
.select::after,
.select::before {
background: #03a9f4;
content: "";
display: block;
height: 2px;
margin-top: 2px;
position: absolute;
right: 5px;
top: 50%;
-webkit-transform-origin: 1px;
transform-origin: 1px;
width: 10px;
}
.select::after {
-webkit-transform: rotate(-135deg);
transform: rotate(-135deg);
}
.select::before {
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
.textarea {
background-color: #eceff1;
padding: 0;
}
.textarea-fullWidth {
display: block;
margin-left: 0;
margin-right: 0;
width: 100%;
}
.textarea textarea {
background: transparent;
border: 0;
color: #272727;
display: block;
font-family: "Lato", sans-serif;
font-size: 16px;
line-height: 1.5em;
margin: 0;
min-height: 120px;
padding: 8px 16px;
transition: background-color 0.2s ease-in-out;
width: 100%;
}
.textarea textarea::-webkit-input-placeholder {
color: #969da6;
}
.textarea textarea::-ms-input-placeholder {
color: #969da6;
}
.textarea textarea::placeholder {
color: #969da6;
}
.textarea textarea:focus,
.textarea textarea:active {
background-color: #fbfbfc;
border: 0;
outline: none;
}
.checkbox {
margin-bottom: 8px;
position: relative;
}
.checkbox input[type="checkbox"] {
display: none;
}
.checkbox input[type="checkbox"]:checked+label::after {
-webkit-animation: checkboxAndRadioAnimation 0.25s;
animation: checkboxAndRadioAnimation 0.25s;
content: "";
-webkit-transform: scale(1) rotate(45deg);
transform: scale(1) rotate(45deg);
}
.checkbox input[type="checkbox"]+label {
display: block;
overflow: hidden;
padding-left: 30px;
text-overflow: ellipsis;
white-space: nowrap;
}
.checkbox input[type="checkbox"]+label::before {
background-color: #eceff1;
border: 1px solid var(--white);
border-radius: var(--border-radius);
content: "";
display: inline-block;
height: 20px;
left: 0;
margin-top: -10px;
position: absolute;
top: 50%;
width: 20px;
}
.checkbox input[type="checkbox"]+label::after {
border-bottom: 3px solid #03a9f4;
border-right: 3px solid #03a9f4;
display: block;
height: 12px;
left: 11px;
margin-left: -4px;
margin-top: -7px;
position: absolute;
top: 50%;
width: 7px;
z-index: 1;
}
.radio {
margin-bottom: 8px;
position: relative;
}
.radio input[type="radio"] {
display: none;
}
.radio input[type="radio"]:checked+label::after {
-webkit-animation: checkboxAndRadioAnimation 0.25s;
animation: checkboxAndRadioAnimation 0.25s;
content: "";
-webkit-transform: scale(1) rotate(45deg);
transform: scale(1) rotate(45deg);
}
.radio input[type="radio"]+label {
display: block;
overflow: hidden;
padding-left: 30px;
text-overflow: ellipsis;
white-space: nowrap;
}
.radio input[type="radio"]+label::before {
background-color: #eceff1;
border: 1px solid var(--white);
border-radius: 20px;
content: "";
display: inline-block;
height: 20px;
left: 0;
margin-top: -10px;
position: absolute;
top: 50%;
width: 20px;
}
.radio input[type="radio"]+label::after {
background-color: #03a9f4;
border-radius: 20px;
display: block;
height: 10px;
left: 11px;
margin-left: -6px;
margin-top: -6px;
position: absolute;
top: 13px;
width: 10px;
z-index: 1;
}
@-webkit-keyframes checkboxAndRadioAnimation {
0% {
-webkit-transform: scale(0) rotate(45deg);
transform: scale(0) rotate(45deg);
}
50% {
-webkit-transform: scale(1.5) rotate(45deg);
transform: scale(1.5) rotate(45deg);
}
100% {
-webkit-transform: scale(1) rotate(45deg);
transform: scale(1) rotate(45deg);
}
}
@keyframes checkboxAndRadioAnimation {
0% {
-webkit-transform: scale(0) rotate(45deg);
transform: scale(0) rotate(45deg);
}
50% {
-webkit-transform: scale(1.5) rotate(45deg);
transform: scale(1.5) rotate(45deg);
}
100% {
-webkit-transform: scale(1) rotate(45deg);
transform: scale(1) rotate(45deg);
}
}
.input-invis {
background-color: transparent !important;
margin: auto !important;
border: 0 !important;
}
.input {
background-color: var(--white);
padding: 0;
position: relative;
}
.input :focus,
.input :active {
background-color: var(--white);
border-radius: var(--border-radius);
}
.input input,
.input textarea {
background: transparent;
border: 0;
box-shadow: none;
color: #272727;
font-size: 16px;
line-height: 1.5em;
margin: 0;
outline: none;
padding: 8px 16px;
width: 100%;
}
.input input::-webkit-input-placeholder {
color: #969da6;
}
.input input::-ms-input-placeholder {
color: #969da6;
}
.input input::placeholder {
color: #969da6;
}
.input input.small {
line-height: 1em;
padding: 0;
}
.input-withIcon input {
padding-right: 32px;
}
.input-icon {
fill: #969da6;
height: 16px;
margin-top: -8px;
position: absolute;
right: 16px;
top: 50%;
width: 16px;
}

354
src/style/module/layout.css Normal file
View File

@@ -0,0 +1,354 @@
/**
* LAYOUT
*/
.section {
padding-bottom: 36px;
padding-top: 36px;
}
@media (min-width: 768px) {
.section {
padding-bottom: 72px;
padding-top: 72px;
}
}
.section+.section {
padding-top: 0;
}
.container {
margin: 0 auto;
max-width: 1380px;
padding-left: 12px;
padding-right: 12px;
width: 100%;
}
@media (min-width: 576px) {
.container {
max-width: 540px;
}
}
@media (min-width: 992px) {
.container {
max-width: 960px;
}
}
@media (min-width: 1200px) {
.container {
max-width: 1140px;
}
}
@media (min-width: 768px) {
.container {
padding-left: 24px;
padding-right: 24px;
max-width: 720px;
}
}
.container-medium {
margin: 0 auto;
max-width: 944px;
padding-left: 12px;
padding-right: 12px;
}
@media (min-width: 768px) {
.container-medium {
padding-left: 24px;
padding-right: 24px;
}
}
.container {
width: 100%;
padding-right: 12px;
padding-left: 12px;
margin-right: auto;
margin-left: auto;
}
.container-fluid {
width: 100%;
padding-right: 12px;
padding-left: 12px;
margin-right: auto;
margin-left: auto;
}
.row {
display: flex;
flex-wrap: wrap;
margin-right: -12px;
margin-left: -12px;
}
.col-1,
.col-2,
.col-3,
.col-4,
.col-5,
.col-6,
.col-7,
.col-8,
.col-9,
.col-10,
.col-11,
.col-12,
.col,
.col-auto,
.col-sm-1,
.col-sm-2,
.col-sm-3,
.col-sm-4,
.col-sm-5,
.col-sm-6,
.col-sm-7,
.col-sm-8,
.col-sm-9,
.col-sm-10,
.col-sm-11,
.col-sm-12,
.col-md-1,
.col-md-2,
.col-md-3,
.col-md-4,
.col-md-5,
.col-md-6,
.col-md-7,
.col-md-8,
.col-md-9,
.col-md-10,
.col-md-11,
.col-md-12 {
position: relative;
width: 100%;
min-height: 1px;
padding-right: 12px;
padding-left: 12px;
}
.col {
flex-basis: 0;
flex-grow: 1;
max-width: 100%;
}
.col-auto {
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-1 {
flex: 0 0 8.33333%;
max-width: 8.33333%;
}
.col-2 {
flex: 0 0 16.66667%;
max-width: 16.66667%;
}
.col-3 {
flex: 0 0 25%;
max-width: 25%;
}
.col-4 {
flex: 0 0 33.33333%;
max-width: 33.33333%;
}
.col-5 {
flex: 0 0 41.66667%;
max-width: 41.66667%;
}
.col-6 {
flex: 0 0 50%;
max-width: 50%;
}
.col-7 {
flex: 0 0 58.33333%;
max-width: 58.33333%;
}
.col-8 {
flex: 0 0 66.66667%;
max-width: 66.66667%;
}
.col-9 {
flex: 0 0 75%;
max-width: 75%;
}
.col-10 {
flex: 0 0 83.33333%;
max-width: 83.33333%;
}
.col-11 {
flex: 0 0 91.66667%;
max-width: 91.66667%;
}
.col-12 {
flex: 0 0 100%;
max-width: 100%;
}
@media (min-width: 576px) {
.col-sm {
flex-basis: 0;
flex-grow: 1;
max-width: 100%;
}
.col-sm-auto {
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-sm-1 {
flex: 0 0 8.33333%;
max-width: 8.33333%;
}
.col-sm-2 {
flex: 0 0 16.66667%;
max-width: 16.66667%;
}
.col-sm-3 {
flex: 0 0 25%;
max-width: 25%;
}
.col-sm-4 {
flex: 0 0 33.33333%;
max-width: 33.33333%;
}
.col-sm-5 {
flex: 0 0 41.66667%;
max-width: 41.66667%;
}
.col-sm-6 {
flex: 0 0 50%;
max-width: 50%;
}
.col-sm-7 {
flex: 0 0 58.33333%;
max-width: 58.33333%;
}
.col-sm-8 {
flex: 0 0 66.66667%;
max-width: 66.66667%;
}
.col-sm-9 {
flex: 0 0 75%;
max-width: 75%;
}
.col-sm-10 {
flex: 0 0 83.33333%;
max-width: 83.33333%;
}
.col-sm-11 {
flex: 0 0 91.66667%;
max-width: 91.66667%;
}
.col-sm-12 {
flex: 0 0 100%;
max-width: 100%;
}
}
@media (min-width: 768px) {
.col-md {
flex-basis: 0;
flex-grow: 1;
max-width: 100%;
}
.col-md-auto {
flex: 0 0 auto;
width: auto;
max-width: none;
}
.col-md-1 {
flex: 0 0 8.33333%;
max-width: 8.33333%;
}
.col-md-2 {
flex: 0 0 16.66667%;
max-width: 16.66667%;
}
.col-md-3 {
flex: 0 0 25%;
max-width: 25%;
}
.col-md-4 {
flex: 0 0 33.33333%;
max-width: 33.33333%;
}
.col-md-5 {
flex: 0 0 41.66667%;
max-width: 41.66667%;
}
.col-md-6 {
flex: 0 0 50%;
max-width: 50%;
}
.col-md-7 {
flex: 0 0 58.33333%;
max-width: 58.33333%;
}
.col-md-8 {
flex: 0 0 66.66667%;
max-width: 66.66667%;
}
.col-md-9 {
flex: 0 0 75%;
max-width: 75%;
}
.col-md-10 {
flex: 0 0 83.33333%;
max-width: 83.33333%;
}
.col-md-11 {
flex: 0 0 91.66667%;
max-width: 91.66667%;
}
.col-md-12 {
flex: 0 0 100%;
max-width: 100%;
}
}

View File

@@ -0,0 +1,166 @@
/**
* LOADING BAR
*
* Markup:
* ---------
* <div class="loadingBar"></div>
*
*/
.loadingBar {
height: 6px;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
width: 100%;
z-index: 1000;
}
.loadingBar::before {
-webkit-animation: loading 2s linear infinite;
animation: loading 2s linear infinite;
background-color: #03a9f4;
content: "";
display: block;
height: 6px;
left: -300px;
position: absolute;
width: 300px;
}
@-webkit-keyframes loading {
from {
left: -300px;
width: 30%;
}
50% {
width: 30%;
}
70% {
width: 70%;
}
80% {
left: 50%;
}
95% {
left: 120%;
}
to {
left: 100%;
}
}
@keyframes loading {
from {
left: -300px;
width: 30%;
}
50% {
width: 30%;
}
70% {
width: 70%;
}
80% {
left: 50%;
}
95% {
left: 120%;
}
to {
left: 100%;
}
}
.spinner {
position: absolute;
right: 0;
top: 0;
width: 40px;
height: 40px;
display: block
}
.spinner:after,
.spinner:before {
position: absolute;
content: "";
top: 50%;
left: 50%;
margin: -12px 0 0 -12px;
width: 24px;
height: 24px;
border-radius: 100%;
border: 3px solid transparent;
border-top-color: var(--blue);
}
.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
}
@-webkit-keyframes spinning {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
25% {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
}
50% {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
75% {
-webkit-transform: rotate(270deg);
transform: rotate(270deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes spinning {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
}
50% {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}

View File

@@ -0,0 +1,148 @@
/**
* TYPOGRAPHY
*/
body {
color: #272727;
font-family: "Lato", sans-serif;
font-size: 16px;
font-weight: 400;
line-height: 1.5em;
}
a {
color: var(--blue);
text-decoration: none;
}
a:hover {
color: color-mix(in srgb, var(--color-primary), #FFF 15%);
}
a:focus {
color: var(--blue);
}
.text-huge,
.text-big,
.text-medium {
margin-bottom: 1em;
}
.text-huge {
font-size: 36px;
line-height: 1.3em;
}
.text-big {
font-size: 24px;
line-height: 1.3em;
}
.text-medium {
font-size: 16px;
line-height: 1.5em;
}
.text-small {
font-size: 12px;
line-height: 1.3em;
}
.text-body {
font-size: 16px;
line-height: 1.5em;
}
.text-primary {
color: #03a9f4;
}
.text-dark {
color: #18232f;
}
.text-secondary {
color: #e91e63;
}
.text-white {
color: #fff;
}
.text-success {
color: #4caf50;
}
.text-info {
color: #5bc0de;
}
.text-warning {
color: #f0ad4e;
}
.text-error {
color: #e74c3c;
}
.text-gray {
color: #969da6;
}
.text-gray-light {
color: #eceff1;
}
.text-light {
font-weight: 300;
}
.text-normal {
font-weight: 400;
}
.text-lineThrough {
text-decoration: line-through;
}
.text-italic {
font-style: italic;
}
.text-underline {
text-decoration: underline;
}
.text-uppercase {
text-transform: uppercase;
}
.text-withSubtitle {
margin-bottom: 0 !important;
}
.text-withSubtitle+.text-huge,
.text-withSubtitle+.text-big,
.text-withSubtitle+.text-medium,
.text-withSubtitle+.text-small {
margin-top: 0.5em;
}
h1,
h2,
h3,
h4 {
font-weight: 300;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.text-left {
text-align: left;
}

32
src/template/home.pug Normal file
View File

@@ -0,0 +1,32 @@
doctype html
include module/head.pug
main#app
.bg-white.section.text-dark
.container.mb-big
.text-center
div
h1.text-huge.text-withSubtitle Open Tourism Map
h2.text-big.text-gray Collaborative Holiday Planner
.spacer
.section.bg-dark.text-white
.container-medium
.row
.col-8
h2.text-big Your journey
p.text-gray
| Browse hotels, restaurants and attractions,....
br
|
| Select and plan the varying elements of your journey
.col-4
.row.align
.input
input#journey.id(v-model="journey.id", placeholder="ID", type="text")
p
.row.align
button.button.button--primary.button--mobileFull(
v-on:click="start_journey"
) Start the journey
include module/foot.pug

View File

@@ -3,6 +3,5 @@ doctype html
include module/head.pug include module/head.pug
main#app(v-cloak) main#app(v-cloak)
include module/nav.pug include module/journey/main.pug
include module/journey.pug
include module/foot.pug include module/foot.pug

View File

@@ -2,21 +2,12 @@ script(src="https://unpkg.com/leaflet")
script(src="https://unpkg.com/vue@2") script(src="https://unpkg.com/vue@2")
script(src="https://unpkg.com/vue2-datepicker") script(src="https://unpkg.com/vue2-datepicker")
script(src="https://unpkg.com/vue-textarea-autosize")
script(src="https://unpkg.com/vue2-leaflet") script(src="https://unpkg.com/vue2-leaflet")
script(src="https://unpkg.com/sortablejs") script(src="https://unpkg.com/sortablejs")
script(src="https://unpkg.com/vuedraggable") script(src="https://unpkg.com/vuedraggable")
script(src="/public/main.js", type="text/javascript", charset="utf-8") script(src="/public/main.js", type="text/javascript", charset="utf-8")
footer.bg-dark footer.bg-dark.section
.container .container.text-center.text-small.text-white
.section.text-center.text-small
p.text-white
img(src="/public/img/helcel.png", alt="helcel logo", width="100")
br
br
|
| Built with &nbsp; &#x2764; &nbsp; by Helcel | Built with &nbsp; &#x2764; &nbsp; by Helcel
br br
span.text-small.text-gray v0.0.1 span.text-small.text-gray v0.0.1
p.text-gray
a(href="https://git.helcel.net") Helcel Git

View File

@@ -8,7 +8,7 @@ head
href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,700,300", href="https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,700,300",
type="text/css" type="text/css"
) )
link(rel="stylesheet", href="/public/css/index.css") link(rel="stylesheet", href="/public/index.css")
link(rel="stylesheet", href="https://unpkg.com/vue2-datepicker/index.css") link(rel="stylesheet", href="https://unpkg.com/vue2-datepicker/index.css")
link(rel="stylesheet", href="https://unpkg.com/leaflet/dist/leaflet.css") link(rel="stylesheet", href="https://unpkg.com/leaflet/dist/leaflet.css")

View File

@@ -0,0 +1,8 @@
.col-12.input.text-dark()
textarea.text-small#query_note(
v-model="journey.leg_get().notes"
@input="refreshTextAreaHeight"
@focus="refreshTextAreaHeight"
rows="1"
placeholder="...",
)

View File

@@ -1,16 +1,18 @@
.input.text-dark(style="width: 100%")
.col-12.input.text-dark
input#query_input( input#query_input(
type="search" type="search"
@input="search_active" @input="search_active"
@focus="search_active"
placeholder="Search ... " placeholder="Search ... "
style="width:85%;" style="width:85%;"
:disabled="query.note"
) )
.spinner(v-if="query.load") .spinner(v-if="query.load")
div(style="width:100%"
v-if="['hotel', 'restaurant', 'place','other', 'travel'].indexOf(query.type)>=0") div(v-if="['hotel', 'restaurant', 'place','other', 'travel'].indexOf(query.type)>=0")
template(v-for="(item, idx) in query.res" ) template(v-for="(item, idx) in query.res" )
.col-12.bg-white.text-dark( .query-result.col-12.bg-white.text-dark(
style="display:flex;align-items:center; border-radius:3px;"
:key="'q'+idx" :key="'q'+idx"
@mouseover="drawer_hover_item(item)" @mouseover="drawer_hover_item(item)"
@mouseleave="drawer_hover_item()" @mouseleave="drawer_hover_item()"
@@ -20,20 +22,17 @@ div(style="width:100%"
| {{ item.name }} | {{ item.name }}
.bg-dark.divider( .bg-dark.divider(
:key="'qdiv'+idx" style="height:1px" ) :key="'qdiv'+idx" style="height:1px" )
.col-12.bg-white.text-dark( .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" )
style="display:flex;align-items:center; border-radius:3px;" )
div( v-html="generate_icon('star', 'var(--dark)')") div( v-html="generate_icon('star', 'var(--dark)')")
.col-10() .col-10()
| Add custom | Add custom
.col-12.text-white.text-center( .col-12.text-white.text-center(
) {{query.load? `Loading ...` : `Found ${query.res.length} results`}} ) {{query.load? `Loading ...` : `Found ${query.res.length} results`}}
div(style="width:100%" div(v-else-if="['flight'].indexOf(query.type)>=0")
v-else-if="['flight'].indexOf(query.type)>=0")
template(v-for="(item, idx) in query.res" ) template(v-for="(item, idx) in query.res" )
.col-12.bg-white.text-dark( .query-result.col-12.bg-white.text-dark(
style="display:flex;align-items:center; border-radius:3px;"
:key="'q'+idx" :key="'q'+idx"
@mouseover="drawer_hover_item(item)" @mouseover="drawer_hover_item(item)"
@mouseleave="drawer_hover_item()" @mouseleave="drawer_hover_item()"
@@ -41,10 +40,9 @@ div(style="width:100%"
div( v-html="generate_icon('plane', 'var(--dark)')") div( v-html="generate_icon('plane', 'var(--dark)')")
.col-10() .col-10()
| {{ item.from }} => {{item.to}} | {{ item.from }} => {{item.to}}
.bg-dark.divider( bg-dark.divider(
:key="'qdiv'+idx" style="height:1px" ) :key="'qdiv'+idx" style="height:1px" )
div(style="width:100%" v-else) div(v-else)
template() template()
.col-12.bg-white.text-dark( .query-result.col-12.bg-white.text-dark()
style="display:flex;align-items:center; border-radius:3px;")
| Unsuppored Query type {{query.type}} | Unsuppored Query type {{query.type}}

View File

@@ -0,0 +1,34 @@
.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

View File

@@ -0,0 +1,36 @@
.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

View File

@@ -0,0 +1,31 @@
.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
.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
input.text-center(v-model="journey.data.name" placeholder="My Journey" 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;")
.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 }")
include leg/drawer.pug
.drawer-container(:class="{ 'col-12': query.note, 'col-0': !query.note }")
include leg/drawer-notes.pug
//- include impexp.pug

View File

@@ -3,12 +3,13 @@ l-map(
:center.sync="journey.leg_get().map.center", :center.sync="journey.leg_get().map.center",
style="height:100%" style="height:100%"
no-blocking-animations=true no-blocking-animations=true
ref="map"
) )
l-tile-layer( l-tile-layer(
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution="© <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors" attribution="© <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors"
) )
l-control-scale(position="bottomright", :imperial="false", :metric="true") l-control-scale(position="bottomleft", :imperial="false", :metric="true")
include map/override.pug include map/override.pug
include map/hotel.pug include map/hotel.pug
@@ -16,5 +17,5 @@ l-map(
include map/restaurants.pug include map/restaurants.pug
include map/travel.pug include map/travel.pug
template(v-if="edit_active")
include map/right_menu.pug include map/right_menu.pug

View File

@@ -15,27 +15,23 @@ mixin map_marker(place, color_sel_c, color_sel_o, color_else)
v-else v-else
v-html="generate_marker(place, \""+color_else+"\")" v-html="generate_marker(place, \""+color_else+"\")"
) )
l-popup() l-popup(
:options="{maxWidth:400, minWidth:300}")
h1.row.text-medium.text-center {{ place.sname }} h1.row.text-medium.text-center {{ place.sname }}
span.row.text-small.text-gray {{ place.display_name }} span.row.text-small.text-gray {{ place.display_name }}
span(v-if="edit_active") span(v-if="edit_active")
.row.input(style="margin-bottom:0") .row.input()
textarea-autosize.col-12.col-sm-12.text-small( textarea.col-12.col-sm-12.text-small(
placeholder="Notes", placeholder="",
v-model="place.notes", v-model="place.notes",
:min-height="30",
:max-height="350"
) )
a.leaflet-popup-close-button.text-gray( .leaflet-popup-button-group(v-if="edit_active")
style="right: 4px; visibility: visible", a.text-gray(
href="#rm",
v-on:click.prevent="place_delete(\""+place+"\",index)"
v-html="generate_icon('trash', 'NA')"
)
a.leaflet-popup-close-button.text-gray(
style="right: 20px; visibility: visible",
href="#toggle_day",
v-on:click.prevent="place.step = ((place.step==journey.sel_day)?-1:journey.sel_day)" v-on:click.prevent="place.step = ((place.step==journey.sel_day)?-1:journey.sel_day)"
v-html="generate_icon(((place.step==journey.sel_day)?'calendar-xmark':'calendar-plus'), 'NA')" v-html="generate_icon(((place.step==journey.sel_day)?'calendar-xmark':'calendar-plus'), 'NA')"
) )
a.text-gray(
v-on:click.prevent="place_delete(\""+place+"\",index)"
v-html="generate_icon('trash', 'NA')"
)
span.row.text-small.text-dark(v-else) {{ place.notes }} span.row.text-small.text-dark(v-else) {{ place.notes }}

View File

@@ -0,0 +1,11 @@
l-marker(
v-if="map_override.active",
v-for="(el, idx) in map_override.elements"
key="'ovr'+idx"
:lat-lng="el"
)
l-icon(v-html="generate_marker('plus', 'darkgreen')")
l-polyline(
v-if="map_override.active && map_override.elements.length>1"
:lat-lngs="map_override.elements" :color="'darkgreen'"
)

View File

@@ -0,0 +1,6 @@
include mixin-marker.pug
div(
v-for="(place, index) in journey.leg_get().places.restaurants",
:key="'restaurants'+index",
)
+map_marker("restaurants", "var(--dark)", "var(--dark)", "var(--dark)")

View File

@@ -0,0 +1,21 @@
.map-menu.map-menu-top
div(v-if="query.type" @click="drawer_click_item()" )
.map-menu-item(v-html="generate_icon('close')")
div(v-if="!query.type" @click="search_enable('hotel')")
.map-menu-item( v-html="generate_icon('bed')")
div(v-if="!query.type" @click="search_enable('restaurant')")
.map-menu-item( v-html="generate_icon('utensils')")
div(v-if="!query.type" @click="search_enable('place')")
.map-menu-item( v-html="generate_icon('star')")
.map-menu-sub(v-if="!query.type" @mouseenter="query.sub=true" @mouseleave="query.sub=false" )
.map-menu-item(v-html="generate_icon('route')")
.map-menu-item(v-if="query.sub" @click="search_enable('flight')" v-html="generate_icon('plane')")
.map-menu-item(v-if="query.sub" @click="search_enable('train')" v-html="generate_icon('train')")
.map-menu-item(v-if="query.sub" @click="search_enable('car')" v-html="generate_icon('car')")
.map-menu-item(v-if="query.sub" @click="search_enable('other')" v-html="generate_icon('person-biking')")
.map-menu.map-menu-center
div(v-if="query.note" @click="drawer_click_item()" )
.map-menu-item(v-html="generate_icon('close')")
div(v-if="!query.note" @click="search_enable('notes')")
.map-menu-item( v-html="generate_icon('pencil')")

View File

@@ -0,0 +1,32 @@
mixin flight_popup()
l-popup(
:options="{maxWidth:400, minWidth:300}"
)
h1.row.text-medium.text-center.text-uppercase {{ travel.id }}
span.row.text-small.text-gray {{ travel.from }} - {{travel.to}}
span(v-if="edit_active")
.row.input(style="margin-bottom:0")
textarea.col-12.col-sm-12.text-small(
placeholder="",
v-model="travel.notes",
)
span.row.text-small.text-dark(v-else) {{ travel.notes }}
span(v-if="edit_active")
.leaflet-popup-button-group(v-if="edit_active")
a.text-gray(
v-on:click.prevent="place_delete('flight',idx)"
v-html="generate_icon('trash', 'NA')"
)
div(v-for= "(travel, idx) in journey.leg_get().travel")
l-polyline(:lat-lngs="travel.path" :color="travel.color || 'gray'")
+flight_popup()
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')"
)
+flight_popup()

View File

@@ -0,0 +1,10 @@
.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="'/' + journey.id" v-on:click.prevent="first_step")
//- i.fas.fa-tools

View File

@@ -0,0 +1,39 @@
.col-11.container.section
.row.text-center.align.padding-1
.input.col-5.col-sm-2
input(disabled="", placeholder="Unnamed" :value="item.title")
.col-sm-1
.input.col-6.col-sm-4
input(
disabled="",
placeholder="No Dates",
:value="item.date_range ? item.date_range[0].toLocal() + ' - ' + item.date_range[1].toLocal() : ''"
)
.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'}}
//- .row.text-center
.input.col-sm-3(v-if="item.travel")
div(v-for="(item, idx) in item.travel")
input(disabled="", placeholder="-" :value="item.map((v) => v.id).join(', ')")
.row.align.padding-1
.input.col-sm-10.text-dark
.text-small(
placeholder="No Restaurants",
:value="item.places.restaurants.map((v) => v.sname + (v.notes ? '(' + v.notes + ')' : '')).join(', ') || 'No Restaurants'",
disabled=""
) {{item.places.restaurants.map((v) => v.sname + (v.notes ? '(' + v.notes + ')' : '')).join(', ') || 'No Restaurants'}}
.row.align.padding-1
.input.col-sm-10.text-dark
.text-small(
placeholder="No Activities",
:value="item.places.activities.map((v) => v.sname + (v.notes ? '(' + v.notes + ')' : '')).join(', ') || 'No Activites'",
disabled=""
) {{item.places.activities.map((v) => v.sname + (v.notes ? '(' + v.notes + ')' : '')).join(', ') || 'No Activites'}}
.row.align.padding-1
.input.col-sm-10.text-dark
.text-small(
placeholder="No Notes",
:value="item.notes || 'No Notes'",
disabled=""
) {{item.notes || 'No Notes'}}

View File

@@ -0,0 +1,19 @@
div(v-for="(e, idx) in journey.data.main", :key="idx")
.bg-dark.text-white(v-if="journey.sel_leg == idx")
.container.section
.row
.col-3.fleft.text-center.text-white.text-huge
a(v-on:click.prevent="journey.day_prev()")
i.fas.fa-angle-left
.col-6.container.text-center.align
span.small {{ journey.data.main[idx].title }} {{ journey.sel_day }}
.text-big.text-gray {{ journey.data.main[idx].day_title[journey.sel_day] }}
.col-3.fright.text-center.text-white.text-huge
a(v-on:click.prevent="journey.day_next()")
i.fas.fa-angle-right
.row
.col-12.col-sm-12(style="aspect-ratio:1.25;")
include ../journey/map.pug
.row
.col-10
span.small.text-gray {{journey.data.main[idx].note || '...'}}

16
src/template/short.pug Normal file
View File

@@ -0,0 +1,16 @@
doctype html
include module/head.pug
main#app(v-cloak)
include module/view/nav.pug
.bg-dark.text-white(v-if="journey && journey.leg_get()")
.container
.row.align(style="padding-top: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(
v-for="(item, idx) in journey.data.main",
:class="idx % 2 === 0 ? 'bg-white text-dark' : 'bg-dark text-white'"
)
include module/view/short_leg.pug
include module/foot.pug

View File

@@ -1,6 +1,6 @@
doctype html doctype html
include module/head.pug include module/head.pug
main#app(v-cloak) main#app(v-cloak)
div(v-if="journey.data.main[journey.sel_leg] != undefined") div(v-if="journey.leg_get()")
include module/view/view_day.pug include module/view/view_day.pug
include module/foot.pug include module/foot.pug

View File

@@ -1,77 +0,0 @@
doctype html
include module/head.pug
main#app
.container
section.mb-big
.text-center
img.main-logo.mb-medium(
src="/public/img/helcel.png",
alt="Helcel logo"
)
div
h1.text-huge.text-withSubtitle Open Tourism Map
h2.text-big.text-gray Collaborative Holiday Planner
p#js-header-waypoint.m-none
a.button.button--primary.button--mobileFull(href="#go") Get started
.bg-dark
.container
.row.text-center
.col-12.col-sm-3
.section
img(
src="/public/img/lightweight.png",
alt="Lightweight",
width="118"
)
br
h2.text-withSubtitle.text-big.text-white
| Lightweight
br
span.text-medium.text-gray
| Powered By
br
| Fastify &amp; Sierra
.col-12.col-sm-4
.section
img(
src="/public/img/customizable.png",
alt="Customizable",
width="118"
)
br
h2.text-withSubtitle.text-big.text-white
| Customizable
br
span.text-medium.text-gray
| Many Templates
br
| to choose from
.col-12.col-sm-4
.section
h2.text-withSubtitle.text-big.text-white
img(
src="/public/img/opensource.png",
alt="Open Source",
width="118"
)
br
|
| FOSS
br
span.text-medium.text-gray :-)
#go.container-medium.section
h2.text-big Your journey
p
| Browse hotels, restaurants and attractions,....
br
|
| Select and plan the varying elements of your journey
.aligner.aligner--contentEnd
.input
input#journey.id(v-model="journey.id", placeholder="ID", type="text")
button.button.button--primary.button--mobileFull(
v-on:click="start_journey"
) Start the journey
include module/foot.pug

View File

@@ -1,3 +0,0 @@
.journey
include journey/leg.pug
include journey/impexp.pug

View File

@@ -1,11 +0,0 @@
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

View File

@@ -1,23 +0,0 @@
.scroll-handler(
@mouseleave="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")

View File

@@ -1,12 +0,0 @@
div
div
.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"
)

View File

@@ -1,29 +0,0 @@
.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-2
.right.col-sm-2
.input
input(
disabled="",
:value="journey.date_sel() + ' (' + journey.sel_day + ')'"
)

View File

@@ -1,5 +0,0 @@
l-marker(
v-if="map_override.active",
:lat-lng="map_override.center"
)
l-icon(v-html="generate_marker('plus', 'darkgreen')")

View File

@@ -1,18 +0,0 @@
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 }}

View File

@@ -1,6 +0,0 @@
.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')")

View File

@@ -1,9 +0,0 @@
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')"
)

View File

@@ -1,38 +0,0 @@
header.header
.header-inner.container
a.header-logo.text-dark(href="/")
img.header-logoImage(
src="/public/img/helcel.png",
alt="Helcel logo",
width="40"
)
span.hide-small OTM
.input.input-invis.row
input.col-6.small(v-model="journey.data.name", type="text")
input.col-6.small(
disabled,
type="text",
:placeholder="journey.date_tot() + ' (' + journey.tot_len() + ')'"
)
.row.header-nav.text-big(style="margin-bottom: 0")
.col-sm-2
a(:href="'/short/' + journey.id")
i.fas.fa-file-contract
.col-sm-2
a(:href="'/view/' + journey.id")
i.fas.fa-camera
.col-sm-2
a(href="#main", v-on:click.prevent="first_step")
i.fas.fa-tools
.col-sm-1.text-small
a(href="#prevprev", v-on:click.prevent="journey.leg_prev()")
i.fas.fa-angle-double-left
.col-sm-1
a(href="#prev", v-on:click.prevent="journey.day_prev()")
i.fas.fa-angle-left
.col-sm-1
a(href="#next", v-on:click.prevent="journey.day_next()")
i.fas.fa-angle-right
.col-sm-1.text-small
a(href="#nextnext", v-on:click.prevent="journey.leg_next()")
i.fas.fa-angle-double-right

View File

@@ -1,18 +0,0 @@
header.header
.header-inner.container
a.header-logo.text-dark(href="/")
img.header-logoImage(
src="/public/img/helcel.png",
alt="Helcel logo",
width="40"
)
span.hide-small HOTM
.input.input-invis
input.small(:value="journey.data.name", type="text", disabled="")
.row.header-nav.text-big(style="margin-bottom: 0")
.col-sm-3
a(:href="'/short/' + journey.id")
i.fas.fa-file-contract
.col-sm-3
a(:href="'/view/' + journey.id")
i.fas.fa-camera

View File

@@ -1,43 +0,0 @@
.container.section
.row.text-center
.input.col-sm-2
input(disabled="", :value="item.title")
.input.col-sm-4
input(
disabled="",
placeholder="No Dates",
:value="item.date_range ? format_date(item.date_range[0]) + ' - ' + format_date(item.date_range[1]) : ''"
)
.input.col-sm-2
input(disabled="", placeholder="No Hotel", :value="item.hotel.sname")
.row.text-center
.input.col-sm-3(v-if="item.transit")
div(v-for="(item, idx) in item.transit")
input(disabled="", :value="item.map((v) => v.id).join(', ')")
.row.text-center
.input.col-sm-8(v-if="item.places && item.places.restaurants")
textarea-autosize.text-small(
placeholder="No Restaurants",
:value="item.places.restaurants.map((v) => v.sname + (v.notes ? '(' + v.notes + ')' : '')).join(', ')",
:min-height="30",
:max-height="350",
disabled=""
)
.row.text-center
.input.col-sm-8(v-if="item.places && item.places.activities")
textarea-autosize.text-small(
placeholder="No Activities",
:value="item.places.activities.map((v) => v.sname + (v.notes ? '(' + v.notes + ')' : '')).join(', ')",
:min-height="30",
:max-height="350",
disabled=""
)
.row.text-center
.input.col-sm-8(v-if="item.notes")
textarea-autosize.text-small(
placeholder="No Notes",
:value="item.notes",
:min-height="30",
:max-height="350",
disabled=""
)

View File

@@ -1,19 +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
.aligner.text-center.text-white.text-huge(style="margin-bottom: 5px")
.aligner--itemTop.fleft
a(href="#prev", v-on:click.prevent="journey.day_prev()")
i.fas.fa-angle-left
span.container
span.small {{ journey.data.main[idx].title }} {{ journey.sel_day }}
.text-big.text-gray {{ journey.data.main[idx].day_title[journey.sel_day] }}
.aligner--itemEnd.fright
a(href="#next", v-on:click.prevent="journey.day_next()")
i.fas.fa-angle-right
.row
.col-12.col-sm-12
include map.pug
.row
.col-12.col-sm-12
.container

View File

@@ -1,10 +0,0 @@
doctype html
include module/head.pug
main#app(v-cloak)
include module/view/nav.pug
div(
v-for="(item, idx) in journey.data.main",
:class="idx % 2 === 0 ? 'bg-dark text-white' : ''"
)
include module/view/short_leg.pug
include module/foot.pug

142
yarn.lock
View File

@@ -32,7 +32,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/parser@npm:^7.23.5, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6": "@babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6":
version: 7.26.9 version: 7.26.9
resolution: "@babel/parser@npm:7.26.9" resolution: "@babel/parser@npm:7.26.9"
dependencies: dependencies:
@@ -442,17 +442,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@prettier/plugin-pug@npm:^3.0.0":
version: 3.2.1
resolution: "@prettier/plugin-pug@npm:3.2.1"
dependencies:
pug-lexer: "npm:^5.0.1"
peerDependencies:
prettier: ^3.0.0
checksum: 10c0/f361496e1669e308e1e74b3de2f524ba92364904142b23cf496bc26531f8cab3ccea965d0cb32b6272656c0415f0dbfe422aa6dc844f56f89cbdbdc815899390
languageName: node
linkType: hard
"@types/node@npm:^22.13.5": "@types/node@npm:^22.13.5":
version: 22.13.5 version: 22.13.5
resolution: "@types/node@npm:22.13.5" resolution: "@types/node@npm:22.13.5"
@@ -462,21 +451,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@vue/compiler-sfc@npm:2.7.16":
version: 2.7.16
resolution: "@vue/compiler-sfc@npm:2.7.16"
dependencies:
"@babel/parser": "npm:^7.23.5"
postcss: "npm:^8.4.14"
prettier: "npm:^1.18.2 || ^2.0.0"
source-map: "npm:^0.6.1"
dependenciesMeta:
prettier:
optional: true
checksum: 10c0/eaeeef054c939e6cd7591199e2b998ae33d0afd65dc1b5675b54361f0c657c08ae82945791a1a8ca76762e1c1f8e69a00595daf280b854cbc3370ed5c5a34bcd
languageName: node
linkType: hard
"abbrev@npm:^3.0.0": "abbrev@npm:^3.0.0":
version: 3.0.0 version: 3.0.0
resolution: "abbrev@npm:3.0.0" resolution: "abbrev@npm:3.0.0"
@@ -833,13 +807,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"core-js@npm:^2.6.5":
version: 2.6.12
resolution: "core-js@npm:2.6.12"
checksum: 10c0/00128efe427789120a06b819adc94cc72b96955acb331cb71d09287baf9bd37bebd191d91f1ee4939c893a050307ead4faea08876f09115112612b6a05684b63
languageName: node
linkType: hard
"cross-spawn@npm:^7.0.0": "cross-spawn@npm:^7.0.0":
version: 7.0.6 version: 7.0.6
resolution: "cross-spawn@npm:7.0.6" resolution: "cross-spawn@npm:7.0.6"
@@ -861,13 +828,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"csstype@npm:^3.1.0":
version: 3.1.3
resolution: "csstype@npm:3.1.3"
checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248
languageName: node
linkType: hard
"data-urls@npm:^5.0.0": "data-urls@npm:^5.0.0":
version: 5.0.0 version: 5.0.0
resolution: "data-urls@npm:5.0.0" resolution: "data-urls@npm:5.0.0"
@@ -1730,13 +1690,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"leaflet@npm:^1.9.4":
version: 1.9.4
resolution: "leaflet@npm:1.9.4"
checksum: 10c0/f639441dbb7eb9ae3fcd29ffd7d3508f6c6106892441634b0232fafb9ffb1588b05a8244ec7085de2c98b5ed703894df246898477836cfd0ce5b96d4717b5ca1
languageName: node
linkType: hard
"level-codec@npm:^10.0.0": "level-codec@npm:^10.0.0":
version: 10.0.0 version: 10.0.0
resolution: "level-codec@npm:10.0.0" resolution: "level-codec@npm:10.0.0"
@@ -2001,15 +1954,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"nanoid@npm:^3.3.8":
version: 3.3.8
resolution: "nanoid@npm:3.3.8"
bin:
nanoid: bin/nanoid.cjs
checksum: 10c0/4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120
languageName: node
linkType: hard
"napi-macros@npm:~2.0.0": "napi-macros@npm:~2.0.0":
version: 2.0.0 version: 2.0.0
resolution: "napi-macros@npm:2.0.0" resolution: "napi-macros@npm:2.0.0"
@@ -2171,13 +2115,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"picocolors@npm:^1.1.1":
version: 1.1.1
resolution: "picocolors@npm:1.1.1"
checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58
languageName: node
linkType: hard
"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1": "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1":
version: 2.3.1 version: 2.3.1
resolution: "picomatch@npm:2.3.1" resolution: "picomatch@npm:2.3.1"
@@ -2222,26 +2159,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"postcss@npm:^8.4.14":
version: 8.5.3
resolution: "postcss@npm:8.5.3"
dependencies:
nanoid: "npm:^3.3.8"
picocolors: "npm:^1.1.1"
source-map-js: "npm:^1.2.1"
checksum: 10c0/b75510d7b28c3ab728c8733dd01538314a18c52af426f199a3c9177e63eb08602a3938bfb66b62dc01350b9aed62087eabbf229af97a1659eb8d3513cec823b3
languageName: node
linkType: hard
"prettier@npm:^1.18.2 || ^2.0.0":
version: 2.8.8
resolution: "prettier@npm:2.8.8"
bin:
prettier: bin-prettier.js
checksum: 10c0/463ea8f9a0946cd5b828d8cf27bd8b567345cf02f56562d5ecde198b91f47a76b7ac9eae0facd247ace70e927143af6135e8cf411986b8cb8478784a4d6d724a
languageName: node
linkType: hard
"prettier@npm:^3.5.2": "prettier@npm:^3.5.2":
version: 3.5.2 version: 3.5.2
resolution: "prettier@npm:3.5.2" resolution: "prettier@npm:3.5.2"
@@ -2683,20 +2600,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"source-map-js@npm:^1.2.1":
version: 1.2.1
resolution: "source-map-js@npm:1.2.1"
checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf
languageName: node
linkType: hard
"source-map@npm:^0.6.1":
version: 0.6.1
resolution: "source-map@npm:0.6.1"
checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011
languageName: node
linkType: hard
"split2@npm:^4.0.0": "split2@npm:^4.0.0":
version: 4.2.0 version: 4.2.0
resolution: "split2@npm:4.2.0" resolution: "split2@npm:4.2.0"
@@ -2957,60 +2860,17 @@ __metadata:
"@fastify/leveldb": "npm:^6.0.0" "@fastify/leveldb": "npm:^6.0.0"
"@fastify/static": "npm:^8.0.0" "@fastify/static": "npm:^8.0.0"
"@fastify/view": "npm:^10.0.0" "@fastify/view": "npm:^10.0.0"
"@prettier/plugin-pug": "npm:^3.0.0"
"@types/node": "npm:^22.13.5" "@types/node": "npm:^22.13.5"
esbuild: "npm:^0.25.0" esbuild: "npm:^0.25.0"
fastify: "npm:^5.2.1" fastify: "npm:^5.2.1"
jsdom: "npm:^26.0.0" jsdom: "npm:^26.0.0"
leaflet: "npm:^1.9.4"
nodemon: "npm:^3.0.1" nodemon: "npm:^3.0.1"
prettier: "npm:^3.5.2" prettier: "npm:^3.5.2"
pug: "npm:^3.0.2" pug: "npm:^3.0.2"
undici: "npm:^7.3.0" undici: "npm:^7.3.0"
vue: "npm:2"
vue-multiselect: "npm:2"
vue-textarea-autosize: "npm:^1.1.1"
vue2-leaflet: "npm:^2.7.1"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
"vue-multiselect@npm:2":
version: 2.1.9
resolution: "vue-multiselect@npm:2.1.9"
checksum: 10c0/baecfbb97b4b225bd2e2054f2eed640917b47f448a76a43f084d344764c813a58e825ea2131f6803c125e6e8d4e0b4edb5712da49dd1b8a082f29ac845cc7c2b
languageName: node
linkType: hard
"vue-textarea-autosize@npm:^1.1.1":
version: 1.1.1
resolution: "vue-textarea-autosize@npm:1.1.1"
dependencies:
core-js: "npm:^2.6.5"
checksum: 10c0/22614d412b7e592b68c9b127cfc4257985058571d185ef1885acd3666b77381c87a2006b5084d5687b5e3729ad5b8c53ff962eaf43bbefa1dc5ae0e58cada9db
languageName: node
linkType: hard
"vue2-leaflet@npm:^2.7.1":
version: 2.7.1
resolution: "vue2-leaflet@npm:2.7.1"
peerDependencies:
"@types/leaflet": ^1.5.7
leaflet: ^1.3.4
vue: ^2.5.17
checksum: 10c0/34ae5cc4b78deaf3ee7f73a210b2e45f9d80b92860d5ac5d831d74fd8a94d06983845f01e6203b4e61bad7f6385715f0ea3cd23b2e39fb6c8ce912fe4d096af6
languageName: node
linkType: hard
"vue@npm:2":
version: 2.7.16
resolution: "vue@npm:2.7.16"
dependencies:
"@vue/compiler-sfc": "npm:2.7.16"
csstype: "npm:^3.1.0"
checksum: 10c0/15bf536c131a863d03c42386a4bbc82316262129421ef70e88d1758bcf951446ef51edeff42e3b27d026015330fe73d90155fca270eb5eadd30b0290735f2c3e
languageName: node
linkType: hard
"w3c-xmlserializer@npm:^5.0.0": "w3c-xmlserializer@npm:^5.0.0":
version: 5.0.0 version: 5.0.0
resolution: "w3c-xmlserializer@npm:5.0.0" resolution: "w3c-xmlserializer@npm:5.0.0"