Compare commits

...

12 Commits

Author SHA1 Message Date
BuckarooBanzay
27d12c20bc wal mode 2022-07-05 09:54:40 +02:00
BuckarooBanzay
6a62d14102 sqlite open mode adjustements 2022-03-23 08:39:45 +01:00
BuckarooBanzay
2abe4f567b world stats 2022-03-21 19:21:06 +01:00
BuckarooBanzay
dbd13415df coord display 2022-03-21 18:51:06 +01:00
BuckarooBanzay
bb4da68ef5 layer service 2022-03-21 18:47:54 +01:00
BuckarooBanzay
3735dbd242 persistent hash route 2022-03-20 19:44:17 +01:00
BuckarooBanzay
c701170a07 realtime layer stub 2022-03-20 19:35:57 +01:00
BuckarooBanzay
8e29829e96 map element setup 2022-03-20 10:54:53 +01:00
BuckarooBanzay
0fb4f8fed6 full screen map page 2022-03-20 10:19:15 +01:00
BuckarooBanzay
eaa8cb5fc0 fix indents 2022-03-19 17:48:22 +01:00
BuckarooBanzay
92ecab7c44 update go versions 2022-03-19 17:45:37 +01:00
BuckarooBanzay
9371e1efb7 vuejs stuff 2022-03-19 17:40:45 +01:00
117 changed files with 1019 additions and 249 deletions

View File

@ -20,7 +20,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3.0.0
with:
go-version: 1.16
go-version: 1.17
- name: Set up nodejs
uses: actions/setup-node@v3

View File

@ -11,10 +11,12 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3.0.0
with:
go-version: '1.16'
go-version: '1.17'
- name: test
run: go test ./... -coverprofile=profile.cov
run: |
cd public && npm ci && cd ..
go test ./... -coverprofile=profile.cov
- uses: shogo82148/actions-goveralls@v1.6.0
with:

View File

@ -2,6 +2,7 @@ package sqlite
import (
"database/sql"
"errors"
"mapserver/coords"
"mapserver/db"
"mapserver/public"
@ -24,7 +25,7 @@ type Sqlite3Accessor struct {
func (db *Sqlite3Accessor) Migrate() error {
//RW connection
rwdb, err := sql.Open("sqlite", db.filename+"?mode=rw")
rwdb, err := sql.Open("sqlite", "file:"+db.filename+"?mode=rw")
if err != nil {
return err
}
@ -164,18 +165,21 @@ func (db *Sqlite3Accessor) GetBlock(pos *coords.MapBlockCoords) (*db.Block, erro
}
func New(filename string) (*Sqlite3Accessor, error) {
db, err := sql.Open("sqlite", filename+"?mode=ro")
db, err := sql.Open("sqlite", "file:"+filename)
if err != nil {
return nil, err
}
// limit connection and set a busy-timeout to prevent errors if the db should be locked sometimes
db.SetMaxOpenConns(1)
_, err = db.Exec("pragma busy_timeout = 5000;")
if err != nil {
return nil, err
}
_, err = db.Exec("pragma journal_mode = wal;")
if err != nil {
return nil, errors.New("could not set db to wal-mode, please stop the minetest-server to allow this one-time fixup")
}
sq := &Sqlite3Accessor{db: db, filename: filename}
return sq, nil
}

View File

@ -1,32 +1,13 @@
html {
height: 100%;
margin: 0;
height: 100%;
margin: 0;
}
body {
height: 100%;
margin: 0;
height: 100%;
margin: 0;
}
#app {
height: 100%;
}
#title {
text-align: center;
}
.full-screen {
width: 100%;
height: 100%;
}
.leaflet-custom-display {
background: #fff;
padding: 5px;
}
.mapserver-label-icon {
margin-left: -100px !important;
margin-top: -100px !important;
}
height: 100%;
}

View File

@ -2,12 +2,16 @@ package public
import "embed"
//go:embed js/* css/* pics/* index.html
//go:embed node_modules/vue/dist/vue.global.prod.js
//go:embed node_modules/vue-router/dist/vue-router.global.prod.js
//go:embed node_modules/@fortawesome/fontawesome-free/css/all.min.css
//go:embed node_modules/@fortawesome/fontawesome-free/webfonts/*
//go:embed node_modules/leaflet/dist/leaflet.js
//go:embed node_modules/leaflet/dist/leaflet.css
//go:embed node_modules/leaflet/dist/images
//go:embed node_modules/leaflet.awesome-markers/dist/leaflet.awesome-markers.css
//go:embed colors/*
//go:embed css/*
//go:embed pics/*
//go:embed sql/*
//go:embed webfonts/*
//go:embed *.html
//go:embed *.txt
//go:embed js/*
var Files embed.FS

View File

@ -6,10 +6,10 @@
<meta name="theme-color" content="#000">
<!-- styles -->
<link rel="stylesheet" href="css/bootstrap.min.css"/>
<link rel="stylesheet" href="css/fontawesome.min.css"/>
<link rel="stylesheet" href="css/leaflet.css"/>
<link rel="stylesheet" href="css/leaflet.awesome-markers.css"/>
<link rel="stylesheet" href="node_modules/bootswatch/dist/cyborg/bootstrap.min.css"/>
<link rel="stylesheet" href="node_modules/@fortawesome/fontawesome-free/css/all.min.css"/>
<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css"/>
<link rel="stylesheet" href="node_modules/leaflet.awesome-markers/dist/leaflet.awesome-markers.css"/>
<link rel="stylesheet" href="css/custom.css"/>
<title>Minetest Mapserver</title>
@ -21,10 +21,9 @@
</div>
<!-- libraries -->
<script src="js/lib/mithril.min.js"></script>
<script src="js/lib/leaflet.js"></script>
<script src="js/lib/leaflet.awesome-markers.js"></script>
<script src="js/lib/moment.min.js"></script>
<script src="node_modules/vue/dist/vue.global.prod.js"></script>
<script src="node_modules/vue-router/dist/vue-router.global.prod.js"></script>
<script src="node_modules/leaflet/dist/leaflet.js"></script>
<!-- main script -->
<script src="js/bundle.js" onerror="import('./js/main.js')"></script>

View File

@ -1,3 +1 @@
bundle.js
bundle-stats.js
lib/*

View File

@ -4,9 +4,9 @@
"esversion": 6,
"browser": true,
"globals": {
"L": true,
"m": true,
"THREE": true,
"console": true
"Vue": true,
"VueRouter": true,
"console": true,
"L": true
}
}

2
public/js/api/config.js Normal file
View File

@ -0,0 +1,2 @@
export const get = () => fetch("api/config").then(r => r.json());

2
public/js/api/stats.js Normal file
View File

@ -0,0 +1,2 @@
export const get = () => fetch("api/stats").then(r => r.json());

5
public/js/app.js Normal file
View File

@ -0,0 +1,5 @@
export default {
template: /*html*/`
<router-view></router-view>
`
};

View File

@ -1,61 +1,73 @@
import layerManager from '../LayerManager.js';
import { createMap } from '../map/MapFactory.js';
function setupMap(vnode, id){
const map = createMap(
id,
layerManager.getCurrentLayer().id,
+vnode.attrs.zoom,
+vnode.attrs.lat,
+vnode.attrs.lon
);
vnode.state.map = map;
function updateHash(){
const center = map.getCenter();
const layerId = layerManager.getCurrentLayer().id;
m.route.set(`/map/${layerId}/${map.getZoom()}/` +
`${Math.floor(center.lng)}/${Math.floor(center.lat)}`);
}
map.on('zoomend', updateHash);
map.on('moveend', updateHash);
return map;
}
import SimpleCRS from "../utils/SimpleCRS.js";
import RealtimeTileLayer from '../utils/RealtimeTileLayer.js';
import ws from '../service/ws.js';
import { getLayerById } from "../service/layer.js";
import CoordinatesDisplay from "../../old/js/map/CoordinatesDisplay.js";
import WorldInfoDisplay from "../utils/WorldInfoDisplay.js";
export default {
props: ["lat", "lon", "zoom", "layerId"],
mounted: function() {
const layer = getLayerById(this.layerId);
console.log("Map::mounted", this.lat, this.lon, this.zoom, this.layerId, layer);
oninit(){
this.id = "map_" + Math.floor(Math.random() * 10000);
},
const map = L.map(this.$refs.target, {
minZoom: 2,
maxZoom: 12,
center: [this.lat, this.lon],
zoom: this.zoom,
crs: SimpleCRS,
maxBounds: L.latLngBounds(
L.latLng(-31000, -31000),
L.latLng(31000, 31000)
)
});
view(){
return m("div", { class: "full-screen", id: this.id });
},
oncreate(vnode){
this.map = setupMap(vnode, this.id);
},
const updateLink = () => {
const center = map.getCenter();
const lon = Math.floor(center.lng);
const lat = Math.floor(center.lat);
console.log("Map::updateLink", map.getZoom(), lon, lat);
// change hash route
this.$router.push({
name: "map",
params: {
lat: lat,
lon: lon,
zoom: map.getZoom(),
layerId: this.layerId
}
});
};
onupdate(vnode){
if (vnode.attrs.layerId != layerManager.getCurrentLayer().id){
//layer changed, recreate map
this.map.remove();
layerManager.setLayerId(vnode.attrs.layerId);
this.map = setupMap(vnode, this.id);
// listen for route change
map.on('zoomend', updateLink);
map.on('moveend', updateLink);
} else {
//position/zoom change
//this.map.setView([+vnode.attrs.lat, +vnode.attrs.lon], +vnode.attrs.zoom);
// add attribution
map.attributionControl.addAttribution('<a href="https://github.com/minetest-mapserver/mapserver">Minetest Mapserver</a>');
}
return false;
},
// TODO: all layers
var tileLayer = new RealtimeTileLayer(ws, this.layerId, map);
tileLayer.addTo(map);
// various map tools
new CoordinatesDisplay({ position: 'bottomleft' }).addTo(map);
new WorldInfoDisplay(ws, { position: 'bottomright' }).addTo(map);
onremove(){
this.map.remove();
}
};
console.log(map);
},
methods: {
updateMap: function() {
const layer = getLayerById(this.layerId);
console.log("Map::updateMap", this.lat, this.lon, this.zoom, this.layerId, layer);
}
},
watch: {
"$route": "updateMap"
},
template: /*html*/`
<div ref="target" style="height: 100%"></div>
`
};

View File

@ -1,49 +1,47 @@
import ws from '../service/ws.js';
export default function(info){
var timeIcon = m("span", { class: "fa fa-sun", style: "color: orange;" });
if (info.time < 5500 || info.time > 19000) //0 - 24'000
timeIcon = m("span", { class: "fa fa-moon", style: "color: blue;" });
function getHour(){
return Math.floor(info.time/1000);
}
function getMinute(){
var min = Math.floor((info.time % 1000) / 1000 * 60);
return min >= 10 ? min : "0" + min;
}
function getLag(){
var color = "green";
if (info.max_lag > 0.8)
color = "orange";
else if (info.max_lag > 1.2)
color = "red";
return [
m("span", { class: "fa fa-wifi", style: "color: " + color }),
parseInt(info.max_lag*1000),
" ms"
];
}
function getPlayers(){
return [
m("span", { class: "fa fa-users" }),
info.players ? info.players.length : "0"
];
}
return m("div", [
getPlayers(),
" ",
getLag(),
" ",
m("span", { class: "fa fa-clock" }),
timeIcon,
getHour(), ":", getMinute()
]);
}
export default {
data: function(){
return {
info: null
};
},
methods: {
infoListener: function(info){
this.info = info;
}
},
computed: {
lagColor: function(){
if (this.info.max_lag > 0.8)
return "orange";
else if (this.info.max_lag > 1.2)
return "red";
else
return "green";
},
time: function() {
const min = Math.floor((this.info.time % 1000) / 1000 * 60);
return Math.floor(this.info.time/1000) + ":" + (min >= 10 ? min : "0" + min);
}
},
created: function() {
// bind infoListener to this
this.infoListener = this.infoListener.bind(this);
ws.addListener("minetest-info", this.infoListener);
},
beforeUnmount: function() {
ws.removeListener("minetest-info", this.infoListener);
},
template: /*html*/`
<div v-if="info">
<span v-if="info.players">
<span class="fa fa-users"></span> {{ info.players.length }}
</span>
<span class="fa fa-wifi" v-bind:style="{ 'color': lagColor }"></span> {{ parseInt(info.max_lag*1000) }} ms
<span class="fa fa-clock"></span> {{ time }}
<span v-if="info.time < 5500 || info.time > 19000" class="fa fa-moon" style="color: blue;"></span>
<span v-else class="fa fa-sun" style="color: orange;"></span>
</div>
`
};

View File

@ -1,21 +1,30 @@
import { getConfig } from './api.js';
import App from './app.js';
import routes from './routes.js';
import wsChannel from './WebSocketChannel.js';
import config from './config.js';
import { hashCompat } from './compat.js';
import layerManager from './LayerManager.js';
import { get as getConfig } from './api/config.js';
import configStore from './store/config.js';
import ws from './service/ws.js';
// hash route compat
hashCompat();
function start() {
// create router instance
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes: routes
});
getConfig()
.then(cfg => {
layerManager.setup(cfg.layers);
config.set(cfg);
wsChannel.connect();
m.route(document.getElementById("app"), "/map/0/12/0/0", routes);
})
.catch(e => {
document.getElementById("app").innerHTML = e;
});
// start vue
const app = Vue.createApp(App);
app.use(router);
app.mount("#app");
}
// fetch config from server first
getConfig().then(cfg => {
// copy config to store
Object.keys(cfg).forEach(k => configStore[k] = cfg[k]);
// start websocket/polling
ws.connect();
// start app
start();
});

View File

@ -0,0 +1,15 @@
import Map from "../components/Map.js";
export default {
components: {
"map-component": Map
},
template: /*html*/`
<map-component
:lat="$route.params.lat"
:lon="$route.params.lon"
:zoom="$route.params.zoom"
:layerId="$route.params.layerId"
/>
`
};

View File

@ -1,5 +1,5 @@
export default {
export default [{
input: 'main.js',
output: {
file :'bundle.js',
@ -7,4 +7,4 @@ export default {
sourcemap: true,
compact: true
}
};
}];

View File

@ -1,8 +1,8 @@
import MapPage from "./pages/MapPage.js";
import Map from './components/Map.js';
import Search from './components/Search.js';
export default {
"/map/:layerId/:zoom/:lon/:lat": Map,
"/search/:query": Search
};
export default [{
path: "/map/:layerId/:zoom/:lon/:lat", name: "map", component: MapPage
},{
path: "/", redirect: "/map/0/13/0/0"
}];

View File

@ -0,0 +1,4 @@
import store from '../store/config.js';
export const getLayerById = id => store.layers.find(l => l.id == id);

72
public/js/service/ws.js Normal file
View File

@ -0,0 +1,72 @@
import { get } from '../api/stats.js';
class WebSocketChannel {
constructor(){
this.wsUrl = window.location.protocol.replace("http", "ws") +
"//" + window.location.host +
window.location.pathname.substring(0, window.location.pathname.lastIndexOf("/")) +
"/api/ws";
this.listenerMap = {/* type -> [listeners] */};
}
addListener(type, listener){
var list = this.listenerMap[type];
if (!list){
list = [];
this.listenerMap[type] = list;
}
list.push(listener);
}
removeListener(type, listener){
var list = this.listenerMap[type];
if (!list){
return;
}
this.listenerMap[type] = list.filter(l => l != listener);
}
connect(){
var ws = new WebSocket(this.wsUrl);
var self = this;
ws.onmessage = function(e){
var event = JSON.parse(e.data);
//rendered-tile, mapobject-created, mapobjects-cleared
var listeners = self.listenerMap[event.type];
if (listeners){
listeners.forEach(function(listener){
listener(event.data);
});
}
};
function fallbackPolling(){
get().then(function(stats){
if (!stats){
// no stats (yet)
return;
}
var listeners = self.listenerMap["minetest-info"];
if (listeners){
listeners.forEach(function(listener){
listener(stats);
});
}
});
}
ws.onerror = function(){
//fallback to polling stats
setInterval(fallbackPolling, 2000);
};
}
}
export default new WebSocketChannel();

View File

@ -0,0 +1,2 @@
export default Vue.reactive({});

View File

@ -0,0 +1,34 @@
export default L.Control.extend({
onAdd: function(map) {
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-custom-display');
var hoverCoord, clickCoord;
function updateHover(ev){
hoverCoord = ev.latlng;
update();
}
function updateClick(ev){
clickCoord = ev.latlng;
update();
}
function update(){
var html = "";
if (hoverCoord)
html = html + "X=" + parseInt(hoverCoord.lng) + " Z=" + parseInt(hoverCoord.lat);
if (clickCoord)
html = html + " (marked: X=" + parseInt(clickCoord.lng) + " Z=" + parseInt(clickCoord.lat) + ")";
div.innerHTML = html;
}
map.on('mousemove', updateHover);
map.on('click', updateClick);
map.on('touch', updateClick);
return div;
}
});

View File

@ -0,0 +1,15 @@
import WorldStats from '../components/WorldStats.js';
export default L.Control.extend({
initialize: function(wsChannel, opts) {
L.Control.prototype.initialize.call(this, opts);
this.wsChannel = wsChannel;
},
onAdd: function() {
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-custom-display');
const app = Vue.createApp(WorldStats);
app.mount(div);
return div;
}
});

32
public/old/css/custom.css Normal file
View File

@ -0,0 +1,32 @@
html {
height: 100%;
margin: 0;
}
body {
height: 100%;
margin: 0;
}
#app {
height: 100%;
}
#title {
text-align: center;
}
.full-screen {
width: 100%;
height: 100%;
}
.leaflet-custom-display {
background: #fff;
padding: 5px;
}
.mapserver-label-icon {
margin-left: -100px !important;
margin-top: -100px !important;
}

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 696 B

After

Width:  |  Height:  |  Size: 696 B

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 618 B

After

Width:  |  Height:  |  Size: 618 B

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

Before

Width:  |  Height:  |  Size: 535 B

After

Width:  |  Height:  |  Size: 535 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -0,0 +1,3 @@
bundle.js
bundle-stats.js
lib/*

12
public/old/js/.jshintrc Normal file
View File

@ -0,0 +1,12 @@
{
"undef": true,
"unused": true,
"esversion": 6,
"browser": true,
"globals": {
"L": true,
"m": true,
"THREE": true,
"console": true
}
}

View File

@ -0,0 +1,61 @@
import layerManager from '../LayerManager.js';
import { createMap } from '../map/MapFactory.js';
function setupMap(vnode, id){
const map = createMap(
id,
layerManager.getCurrentLayer().id,
+vnode.attrs.zoom,
+vnode.attrs.lat,
+vnode.attrs.lon
);
vnode.state.map = map;
function updateHash(){
const center = map.getCenter();
const layerId = layerManager.getCurrentLayer().id;
m.route.set(`/map/${layerId}/${map.getZoom()}/` +
`${Math.floor(center.lng)}/${Math.floor(center.lat)}`);
}
map.on('zoomend', updateHash);
map.on('moveend', updateHash);
return map;
}
export default {
oninit(){
this.id = "map_" + Math.floor(Math.random() * 10000);
},
view(){
return m("div", { class: "full-screen", id: this.id });
},
oncreate(vnode){
this.map = setupMap(vnode, this.id);
},
onupdate(vnode){
if (vnode.attrs.layerId != layerManager.getCurrentLayer().id){
//layer changed, recreate map
this.map.remove();
layerManager.setLayerId(vnode.attrs.layerId);
this.map = setupMap(vnode, this.id);
} else {
//position/zoom change
//this.map.setView([+vnode.attrs.lat, +vnode.attrs.lon], +vnode.attrs.zoom);
}
return false;
},
onremove(){
this.map.remove();
}
};

View File

@ -0,0 +1,49 @@
export default function(info){
var timeIcon = m("span", { class: "fa fa-sun", style: "color: orange;" });
if (info.time < 5500 || info.time > 19000) //0 - 24'000
timeIcon = m("span", { class: "fa fa-moon", style: "color: blue;" });
function getHour(){
return Math.floor(info.time/1000);
}
function getMinute(){
var min = Math.floor((info.time % 1000) / 1000 * 60);
return min >= 10 ? min : "0" + min;
}
function getLag(){
var color = "green";
if (info.max_lag > 0.8)
color = "orange";
else if (info.max_lag > 1.2)
color = "red";
return [
m("span", { class: "fa fa-wifi", style: "color: " + color }),
parseInt(info.max_lag*1000),
" ms"
];
}
function getPlayers(){
return [
m("span", { class: "fa fa-users" }),
info.players ? info.players.length : "0"
];
}
return m("div", [
getPlayers(),
" ",
getLag(),
" ",
m("span", { class: "fa fa-clock" }),
timeIcon,
getHour(), ":", getMinute()
]);
}

21
public/old/js/main.js Normal file
View File

@ -0,0 +1,21 @@
import { getConfig } from './api.js';
import routes from './routes.js';
import wsChannel from './WebSocketChannel.js';
import config from './config.js';
import { hashCompat } from './compat.js';
import layerManager from './LayerManager.js';
// hash route compat
hashCompat();
getConfig()
.then(cfg => {
layerManager.setup(cfg.layers);
config.set(cfg);
wsChannel.connect();
m.route(document.getElementById("app"), "/map/0/12/0/0", routes);
})
.catch(e => {
document.getElementById("app").innerHTML = e;
});

View File

@ -0,0 +1,50 @@
export default L.TileLayer.extend({
initialize: function(wsChannel, layerId, map) {
L.TileLayer.prototype.initialize.call(this);
var self = this;
this.layerId = layerId;
wsChannel.addListener("rendered-tile", function(tc){
if (tc.layerid != self.layerId){
//ignore other layers
return;
}
if (tc.zoom != map.getZoom()){
//ignore other zoom levels
return;
}
var id = self.getImageId(tc.x, tc.y, tc.zoom);
var el = document.getElementById(id);
if (el){
//Update src attribute if img found
el.src = self.getTileSource(tc.x, tc.y, tc.zoom, true);
}
});
},
getTileSource: function(x,y,zoom,cacheBust){
return "api/tile/" + this.layerId + "/" + x + "/" + y + "/" + zoom + (cacheBust ? "?_=" + Date.now() : "");
},
getImageId: function(x, y, zoom){
return "tile-" + this.layerId + "/" + x + "/" + y + "/" + zoom;
},
createTile: function(coords, done){
var tile = document.createElement('img');
tile.src = this.getTileSource(coords.x, coords.y, coords.z, true);
tile.id = this.getImageId(coords.x, coords.y, coords.z);
// trigger callbacks
tile.onload = () => done(null, tile);
tile.onerror = e => done(e, tile);
return tile;
}
});

View File

@ -0,0 +1,6 @@
export default L.Util.extend({}, L.CRS.Simple, {
scale: function (zoom) {
return Math.pow(2, zoom-9);
}
});

View File

@ -0,0 +1,10 @@
export default {
input: 'main.js',
output: {
file :'bundle.js',
format: 'iife',
sourcemap: true,
compact: true
}
};

8
public/old/js/routes.js Normal file
View File

@ -0,0 +1,8 @@
import Map from './components/Map.js';
import Search from './components/Search.js';
export default {
"/map/:layerId/:zoom/:lon/:lat": Map,
"/search/:query": Search
};

Some files were not shown because too many files have changed in this diff Show More