tangram-core 0.2.0__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tangram_core/App.vue +335 -0
- tangram_core/__init__.py +5 -0
- tangram_core/__main__.py +141 -0
- tangram_core/_core.cp313-win_amd64.pyd +0 -0
- tangram_core/_core.pyi +38 -0
- tangram_core/api.ts +456 -0
- tangram_core/backend.py +335 -0
- tangram_core/colour.ts +71 -0
- tangram_core/config.py +122 -0
- tangram_core/dist-frontend/aggregation-layers.js +521 -0
- tangram_core/dist-frontend/aggregation-layers.js.map +1 -0
- tangram_core/dist-frontend/assets/_commonjsHelpers-CqkleIqs.js +2 -0
- tangram_core/dist-frontend/assets/_commonjsHelpers-CqkleIqs.js.map +1 -0
- tangram_core/dist-frontend/assets/array-utils-flat-wyE8tIYR.js +11 -0
- tangram_core/dist-frontend/assets/array-utils-flat-wyE8tIYR.js.map +1 -0
- tangram_core/dist-frontend/assets/assert-hrfsarFU.js +3 -0
- tangram_core/dist-frontend/assets/assert-hrfsarFU.js.map +1 -0
- tangram_core/dist-frontend/assets/b612-latin-400-italic-DePNXA0a.woff +0 -0
- tangram_core/dist-frontend/assets/b612-latin-400-italic-a-4GLPtl.woff2 +0 -0
- tangram_core/dist-frontend/assets/b612-latin-400-normal-CC98FVm_.woff2 +0 -0
- tangram_core/dist-frontend/assets/b612-latin-400-normal-JbZ7xwUX.woff +0 -0
- tangram_core/dist-frontend/assets/b612-latin-700-normal-B_Snq1wd.woff +0 -0
- tangram_core/dist-frontend/assets/b612-latin-700-normal-BinQrnoB.woff2 +0 -0
- tangram_core/dist-frontend/assets/clip-extension-DTCP51Ak.js +26 -0
- tangram_core/dist-frontend/assets/clip-extension-DTCP51Ak.js.map +1 -0
- tangram_core/dist-frontend/assets/color-CUNNsFV-.js +17 -0
- tangram_core/dist-frontend/assets/color-CUNNsFV-.js.map +1 -0
- tangram_core/dist-frontend/assets/cube-geometry-CzJ_uBWa.js +2 -0
- tangram_core/dist-frontend/assets/cube-geometry-CzJ_uBWa.js.map +1 -0
- tangram_core/dist-frontend/assets/deep-equal-uriyKJca.js +2 -0
- tangram_core/dist-frontend/assets/deep-equal-uriyKJca.js.map +1 -0
- tangram_core/dist-frontend/assets/fly-to-interpolator-DlKiy9_S.js +2 -0
- tangram_core/dist-frontend/assets/fly-to-interpolator-DlKiy9_S.js.map +1 -0
- tangram_core/dist-frontend/assets/geojson-layer-CLhXLxdI.js +1010 -0
- tangram_core/dist-frontend/assets/geojson-layer-CLhXLxdI.js.map +1 -0
- tangram_core/dist-frontend/assets/globe-view-DKhftlA1.js +94 -0
- tangram_core/dist-frontend/assets/globe-view-DKhftlA1.js.map +1 -0
- tangram_core/dist-frontend/assets/globe-viewport-CPES4D4P.js +2 -0
- tangram_core/dist-frontend/assets/globe-viewport-CPES4D4P.js.map +1 -0
- tangram_core/dist-frontend/assets/image-loader-ClbNCMXW.js +2 -0
- tangram_core/dist-frontend/assets/image-loader-ClbNCMXW.js.map +1 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-400-normal-DTZQ6lD6.woff2 +0 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-400-normal-HYADljCo.woff +0 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-700-normal-ByjKuJjN.woff2 +0 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-700-normal-DzgUY3Rl.woff +0 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-ext-400-normal-BaHVOdFB.woff2 +0 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-ext-400-normal-yvPjCxxx.woff +0 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-ext-700-normal-D0Kpgs_9.woff2 +0 -0
- tangram_core/dist-frontend/assets/inconsolata-latin-ext-700-normal-Dlt-daqV.woff +0 -0
- tangram_core/dist-frontend/assets/inconsolata-vietnamese-400-normal-ByiM2lek.woff +0 -0
- tangram_core/dist-frontend/assets/inconsolata-vietnamese-400-normal-DfC_iMic.woff2 +0 -0
- tangram_core/dist-frontend/assets/inconsolata-vietnamese-700-normal-DLCFFAUf.woff +0 -0
- tangram_core/dist-frontend/assets/inconsolata-vietnamese-700-normal-DuasYmn8.woff2 +0 -0
- tangram_core/dist-frontend/assets/index-UPPakSLR.css +1 -0
- tangram_core/dist-frontend/assets/index-r8T0kY2p.js +821 -0
- tangram_core/dist-frontend/assets/index-r8T0kY2p.js.map +1 -0
- tangram_core/dist-frontend/assets/layer-DO63TrsS.js +555 -0
- tangram_core/dist-frontend/assets/layer-DO63TrsS.js.map +1 -0
- tangram_core/dist-frontend/assets/layer-extension-CZ3zsHuN.js +2 -0
- tangram_core/dist-frontend/assets/layer-extension-CZ3zsHuN.js.map +1 -0
- tangram_core/dist-frontend/assets/mesh-layers-BSECKarm.js +1123 -0
- tangram_core/dist-frontend/assets/mesh-layers-BSECKarm.js.map +1 -0
- tangram_core/dist-frontend/assets/orthographic-viewport-CzZmHDEZ.js +2 -0
- tangram_core/dist-frontend/assets/orthographic-viewport-CzZmHDEZ.js.map +1 -0
- tangram_core/dist-frontend/assets/pick-layers-pass-xhWsgZtf.js +2 -0
- tangram_core/dist-frontend/assets/pick-layers-pass-xhWsgZtf.js.map +1 -0
- tangram_core/dist-frontend/assets/project-CrvReKGW.js +760 -0
- tangram_core/dist-frontend/assets/project-CrvReKGW.js.map +1 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-400-italic-4qS3_zkX.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-400-italic-CDK-EZBY.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-400-normal-Bgns473E.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-400-normal-_T2aQlWs.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-500-normal-CvEVpWxD.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-500-normal-s4PklZE0.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-700-normal-9RN-Z7cI.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-700-normal-BGMkBBYx.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-400-italic-C7erd-g8.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-400-italic-DR5R5TWx.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-400-normal-DGo1Ayjq.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-400-normal-WtM1l1qc.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-500-normal-C8FNIdXm.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-500-normal-TLDmfi3Q.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-700-normal-CTXjXnze.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-cyrillic-ext-700-normal-CWPRiRXS.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-400-italic-CR6qj4Z4.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-400-italic-DHRaIs10.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-400-normal-D5vBSIyg.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-400-normal-FabMgVmk.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-500-normal-BIN62cw9.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-500-normal-Hsn-wDIp.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-700-normal-89Up2Xly.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-greek-700-normal-DWMOA2VK.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-400-italic-D_BR-3LG.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-400-italic-om57GXsO.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-400-normal-BICmKrXV.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-400-normal-D2e7XwB1.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-500-normal-3p2daRJW.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-500-normal-Dc9bsamC.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-700-normal-BOl6B_hI.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-700-normal-DRbp0YnP.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-400-italic-BXrkWnoY.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-400-italic-Bhem1d5z.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-400-normal-DT8nEsYA.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-400-normal-OHaX69iP.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-500-normal-CcSTXKtO.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-500-normal-JgPl2bDS.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-700-normal-B004qtqu.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-latin-ext-700-normal-O6H_RRvN.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-400-italic-BwUYFJ2t.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-400-italic-DV8QogUk.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-400-normal-0o1laQ-g.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-400-normal-CPsdS8_S.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-500-normal-G9shSJ2z.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-500-normal-TFWhjk13.woff2 +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-700-normal-BtNeb9D6.woff +0 -0
- tangram_core/dist-frontend/assets/roboto-condensed-vietnamese-700-normal-D35V1G0s.woff2 +0 -0
- tangram_core/dist-frontend/assets/shader-BJmsOfPx.js +843 -0
- tangram_core/dist-frontend/assets/shader-BJmsOfPx.js.map +1 -0
- tangram_core/dist-frontend/assets/solid-polygon-layer-DiarVGxh.js +392 -0
- tangram_core/dist-frontend/assets/solid-polygon-layer-DiarVGxh.js.map +1 -0
- tangram_core/dist-frontend/assets/tesselator-49Dw9L5A.js +2 -0
- tangram_core/dist-frontend/assets/tesselator-49Dw9L5A.js.map +1 -0
- tangram_core/dist-frontend/assets/webgl-developer-tools-CZl8qVFg.js +7 -0
- tangram_core/dist-frontend/assets/webgl-developer-tools-CZl8qVFg.js.map +1 -0
- tangram_core/dist-frontend/assets/webgl-device-BY0-CUP6.js +3 -0
- tangram_core/dist-frontend/assets/webgl-device-BY0-CUP6.js.map +1 -0
- tangram_core/dist-frontend/assets/widget-BbOeHGj0.js +2 -0
- tangram_core/dist-frontend/assets/widget-BbOeHGj0.js.map +1 -0
- tangram_core/dist-frontend/core.js +60 -0
- tangram_core/dist-frontend/core.js.map +1 -0
- tangram_core/dist-frontend/extensions.js +609 -0
- tangram_core/dist-frontend/extensions.js.map +1 -0
- tangram_core/dist-frontend/favicon.ico +0 -0
- tangram_core/dist-frontend/favicon.png +0 -0
- tangram_core/dist-frontend/font-awesome.min.css +4 -0
- tangram_core/dist-frontend/fonts/FontAwesome.otf +0 -0
- tangram_core/dist-frontend/fonts/fontawesome-webfont.eot +0 -0
- tangram_core/dist-frontend/fonts/fontawesome-webfont.svg +2671 -0
- tangram_core/dist-frontend/fonts/fontawesome-webfont.ttf +0 -0
- tangram_core/dist-frontend/fonts/fontawesome-webfont.woff +0 -0
- tangram_core/dist-frontend/fonts/fontawesome-webfont.woff2 +0 -0
- tangram_core/dist-frontend/geo-layers.js +115 -0
- tangram_core/dist-frontend/geo-layers.js.map +1 -0
- tangram_core/dist-frontend/index.html +38 -0
- tangram_core/dist-frontend/json.js +3 -0
- tangram_core/dist-frontend/json.js.map +1 -0
- tangram_core/dist-frontend/layers.js +268 -0
- tangram_core/dist-frontend/layers.js.map +1 -0
- tangram_core/dist-frontend/lit-html.js +7 -0
- tangram_core/dist-frontend/lit-html.js.map +1 -0
- tangram_core/dist-frontend/mapbox.js +2 -0
- tangram_core/dist-frontend/mapbox.js.map +1 -0
- tangram_core/dist-frontend/maplibre-gl.js +59 -0
- tangram_core/dist-frontend/maplibre-gl.js.map +1 -0
- tangram_core/dist-frontend/mesh-layers.js +2 -0
- tangram_core/dist-frontend/mesh-layers.js.map +1 -0
- tangram_core/dist-frontend/rs1090_wasm.js +813 -0
- tangram_core/dist-frontend/rs1090_wasm_bg.wasm +0 -0
- tangram_core/dist-frontend/vue.esm-browser.prod.js +13 -0
- tangram_core/dist-frontend/widgets.js +3 -0
- tangram_core/dist-frontend/widgets.js.map +1 -0
- tangram_core/main.ts +16 -0
- tangram_core/plugin.py +70 -0
- tangram_core/plugin.ts +41 -0
- tangram_core/redis.py +89 -0
- tangram_core/user.css +114 -0
- tangram_core/vite-plugin-tangram.mjs +88 -0
- tangram_core-0.2.0.dist-info/METADATA +37 -0
- tangram_core-0.2.0.dist-info/RECORD +171 -0
- tangram_core-0.2.0.dist-info/WHEEL +4 -0
- tangram_core-0.2.0.dist-info/entry_points.txt +2 -0
tangram_core/App.vue
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<!-- NOTE: copied largely from v0.1. -->
|
|
3
|
+
<div v-if="apiState === 'loading'" class="loading-container">
|
|
4
|
+
<div>initialising tangram…</div>
|
|
5
|
+
<div v-if="loadingMessage" class="loading-detail">{{ loadingMessage }}</div>
|
|
6
|
+
</div>
|
|
7
|
+
<div v-else-if="apiState === 'error'">
|
|
8
|
+
error: could not connect to the tangram backend.
|
|
9
|
+
</div>
|
|
10
|
+
<div v-else-if="apiState === 'ready' && tangramApi" class="main-container">
|
|
11
|
+
<div class="navbar" role="navigation">
|
|
12
|
+
<div class="navbar-brand">
|
|
13
|
+
<img src="/favicon.png" alt="tangram" class="navbar-logo" />
|
|
14
|
+
<span class="navbar-title">tangram</span>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div class="navbar-spacer"></div>
|
|
18
|
+
|
|
19
|
+
<component
|
|
20
|
+
:is="widget.id"
|
|
21
|
+
v-for="widget in tangramApi.ui.widgets.TopBar"
|
|
22
|
+
:key="widget.id"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
id="sidebar"
|
|
28
|
+
class="sidebar"
|
|
29
|
+
:class="{
|
|
30
|
+
collapsed: !tangramApi.state.activeEntity || tangramApi.ui.isSidebarCollapsed
|
|
31
|
+
}"
|
|
32
|
+
>
|
|
33
|
+
<div class="sidebar-tabs">
|
|
34
|
+
<ul role="tablist">
|
|
35
|
+
<li>
|
|
36
|
+
<a role="tab" @click="tangramApi.ui.toggleSidebar()">
|
|
37
|
+
<span class="fa fa-plane"></span>
|
|
38
|
+
</a>
|
|
39
|
+
</li>
|
|
40
|
+
</ul>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="sidebar-content">
|
|
43
|
+
<component
|
|
44
|
+
:is="widget.id"
|
|
45
|
+
v-for="widget in tangramApi.ui.widgets.SideBar"
|
|
46
|
+
:key="widget.id"
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div ref="mapContainer" class="map-container">
|
|
52
|
+
<component
|
|
53
|
+
:is="widget.id"
|
|
54
|
+
v-for="widget in tangramApi.ui.widgets.MapOverlay"
|
|
55
|
+
:key="widget.id"
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<script setup lang="ts">
|
|
62
|
+
import { onMounted, onUnmounted, getCurrentInstance, ref, watch } from "vue";
|
|
63
|
+
import maplibregl from "maplibre-gl";
|
|
64
|
+
import { TangramApi } from "./api";
|
|
65
|
+
import { loadPlugins } from "./plugin";
|
|
66
|
+
import { layers, namedFlavor } from "@protomaps/basemaps";
|
|
67
|
+
import * as pmtiles from "pmtiles";
|
|
68
|
+
|
|
69
|
+
type ApiState = "loading" | "ready" | "error";
|
|
70
|
+
|
|
71
|
+
const app = getCurrentInstance()!.appContext.app;
|
|
72
|
+
const apiState = ref<ApiState>("loading");
|
|
73
|
+
const loadingMessage = ref<string>("");
|
|
74
|
+
const tangramApi = ref<TangramApi | null>(null);
|
|
75
|
+
const mapContainer = ref<HTMLElement | null>(null);
|
|
76
|
+
let mapInstance: maplibregl.Map | undefined = undefined;
|
|
77
|
+
|
|
78
|
+
onMounted(async () => {
|
|
79
|
+
try {
|
|
80
|
+
const api = await TangramApi.create(app);
|
|
81
|
+
app.provide("tangramApi", api);
|
|
82
|
+
await loadPlugins(api, progress => {
|
|
83
|
+
if (progress.stage === "manifest") {
|
|
84
|
+
loadingMessage.value = "fetching plugin manifest";
|
|
85
|
+
} else if (progress.stage === "plugin" && progress.pluginName) {
|
|
86
|
+
loadingMessage.value = `loading plugin: ${progress.pluginName}`;
|
|
87
|
+
} else if (progress.stage === "done") {
|
|
88
|
+
loadingMessage.value = "starting user interface";
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
tangramApi.value = api;
|
|
92
|
+
apiState.value = "ready";
|
|
93
|
+
} catch (e) {
|
|
94
|
+
console.error("failed to initialise tangram api:", e);
|
|
95
|
+
apiState.value = "error";
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
watch(
|
|
100
|
+
() => tangramApi.value?.state.activeEntity,
|
|
101
|
+
newEntity => {
|
|
102
|
+
if (newEntity) {
|
|
103
|
+
tangramApi.value?.ui.openSidebar();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
watch(mapContainer, newEl => {
|
|
109
|
+
if (newEl && tangramApi.value && !mapInstance) {
|
|
110
|
+
const mapConfig = tangramApi.value.config.map;
|
|
111
|
+
|
|
112
|
+
const protocol = new pmtiles.Protocol();
|
|
113
|
+
maplibregl.addProtocol("pmtiles", protocol.tile);
|
|
114
|
+
|
|
115
|
+
if (typeof mapConfig.style === "object") {
|
|
116
|
+
// If the style is an object, we need to ensure it has the correct structure
|
|
117
|
+
// First we need to remove all None/null values from the style object
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
119
|
+
const removeNulls = (obj: any): any => {
|
|
120
|
+
if (Array.isArray(obj)) {
|
|
121
|
+
return obj.map(removeNulls);
|
|
122
|
+
}
|
|
123
|
+
if (typeof obj === "string") {
|
|
124
|
+
// This is a special case if we don't want to hardcode the root URL
|
|
125
|
+
// of the application in the style JSON, we can use #ROOT# as a placeholder
|
|
126
|
+
if (obj.includes("#ROOT#")) {
|
|
127
|
+
const rootUrl =
|
|
128
|
+
window.location.origin +
|
|
129
|
+
window.location.pathname.replace(/\/[^\/]*$/, "/");
|
|
130
|
+
return obj.replace(/#ROOT#/g, rootUrl);
|
|
131
|
+
}
|
|
132
|
+
return obj;
|
|
133
|
+
}
|
|
134
|
+
if (obj !== null && typeof obj === "object") {
|
|
135
|
+
return Object.entries(obj).reduce((acc, [key, value]) => {
|
|
136
|
+
if (value !== null && value !== undefined) {
|
|
137
|
+
acc[key] = removeNulls(value);
|
|
138
|
+
}
|
|
139
|
+
return acc;
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
141
|
+
}, {} as any);
|
|
142
|
+
}
|
|
143
|
+
return obj;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const styleObject = removeNulls(mapConfig.style);
|
|
147
|
+
|
|
148
|
+
if (!styleObject.layers) {
|
|
149
|
+
styleObject.layers = layers("protomaps", namedFlavor("light"), {
|
|
150
|
+
lang: mapConfig.lang
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
mapConfig.style = styleObject;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// @ts-expect-error TS2589: Type instantiation is excessively deep and possibly infinite
|
|
157
|
+
mapInstance = new maplibregl.Map({
|
|
158
|
+
container: newEl,
|
|
159
|
+
style: mapConfig.style,
|
|
160
|
+
center: [mapConfig.center_lon, mapConfig.center_lat],
|
|
161
|
+
zoom: mapConfig.zoom,
|
|
162
|
+
pitch: mapConfig.pitch,
|
|
163
|
+
bearing: mapConfig.bearing,
|
|
164
|
+
attributionControl: false
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
tangramApi.value.map.initialize(mapInstance);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
onUnmounted(() => {
|
|
172
|
+
tangramApi.value?.map.dispose();
|
|
173
|
+
if (mapInstance) {
|
|
174
|
+
mapInstance.remove();
|
|
175
|
+
mapInstance = undefined;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
</script>
|
|
179
|
+
|
|
180
|
+
<style>
|
|
181
|
+
#app {
|
|
182
|
+
height: 100%;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* styles from v0.1 App.vue */
|
|
186
|
+
html {
|
|
187
|
+
width: 100%;
|
|
188
|
+
height: 100%;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
body {
|
|
192
|
+
font-family: "B612", sans-serif;
|
|
193
|
+
width: 100%;
|
|
194
|
+
height: 100%;
|
|
195
|
+
margin: 0;
|
|
196
|
+
padding: 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.main-container {
|
|
200
|
+
height: 100%;
|
|
201
|
+
width: 100%;
|
|
202
|
+
display: flex;
|
|
203
|
+
flex-direction: column;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.navbar {
|
|
207
|
+
min-height: 50px;
|
|
208
|
+
background: white;
|
|
209
|
+
z-index: 500;
|
|
210
|
+
width: 100%;
|
|
211
|
+
box-sizing: border-box;
|
|
212
|
+
padding: 0.5rem 1rem;
|
|
213
|
+
display: flex;
|
|
214
|
+
flex-wrap: wrap;
|
|
215
|
+
align-items: center;
|
|
216
|
+
gap: 1.5rem;
|
|
217
|
+
border-bottom: 1px solid #e7e7e7;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.navbar-brand {
|
|
221
|
+
display: flex;
|
|
222
|
+
align-items: center;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.navbar-logo {
|
|
226
|
+
height: 24px;
|
|
227
|
+
margin-right: 5px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.navbar-title {
|
|
231
|
+
padding-top: 0.3125rem;
|
|
232
|
+
padding-bottom: 0.3125rem;
|
|
233
|
+
font-size: 1.25rem;
|
|
234
|
+
margin-bottom: 0;
|
|
235
|
+
color: black;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.navbar-spacer {
|
|
239
|
+
margin-left: auto;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.sidebar {
|
|
243
|
+
position: absolute;
|
|
244
|
+
bottom: 15px;
|
|
245
|
+
left: 15px;
|
|
246
|
+
width: 21rem;
|
|
247
|
+
height: calc(100% - 95px);
|
|
248
|
+
transform: translate(2.5%, 0%);
|
|
249
|
+
overflow: hidden;
|
|
250
|
+
z-index: 1000;
|
|
251
|
+
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
|
|
252
|
+
border-radius: 4px;
|
|
253
|
+
display: flex;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.sidebar.collapsed {
|
|
257
|
+
width: 40px;
|
|
258
|
+
height: 40px;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.sidebar-tabs,
|
|
262
|
+
.sidebar-tabs > ul {
|
|
263
|
+
width: 40px;
|
|
264
|
+
margin: 0;
|
|
265
|
+
padding: 0;
|
|
266
|
+
list-style-type: none;
|
|
267
|
+
border-right: 1px solid #ddd;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.sidebar-tabs > li,
|
|
271
|
+
.sidebar-tabs > ul > li {
|
|
272
|
+
width: 40px;
|
|
273
|
+
height: 40px;
|
|
274
|
+
color: #333;
|
|
275
|
+
font-size: 12pt;
|
|
276
|
+
font-family: "B612", monospace;
|
|
277
|
+
overflow: hidden;
|
|
278
|
+
transition: all 80ms;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.sidebar-tabs > li > a,
|
|
282
|
+
.sidebar-tabs > ul > li > a {
|
|
283
|
+
display: block;
|
|
284
|
+
width: 40px;
|
|
285
|
+
height: 100%;
|
|
286
|
+
line-height: 40px;
|
|
287
|
+
color: inherit;
|
|
288
|
+
text-decoration: none;
|
|
289
|
+
text-align: center;
|
|
290
|
+
cursor: pointer;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.sidebar-content {
|
|
294
|
+
flex: 1;
|
|
295
|
+
background-color: rgba(255, 255, 255, 1);
|
|
296
|
+
overflow-x: hidden;
|
|
297
|
+
overflow-y: auto;
|
|
298
|
+
padding: 5px;
|
|
299
|
+
display: flex;
|
|
300
|
+
flex-direction: column;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.sidebar.collapsed > .sidebar-content {
|
|
304
|
+
overflow-y: hidden;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.control-container {
|
|
308
|
+
position: absolute;
|
|
309
|
+
right: 55px;
|
|
310
|
+
bottom: 90px;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.map-container {
|
|
314
|
+
flex: 1;
|
|
315
|
+
flex-grow: 1;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.control-attribution {
|
|
319
|
+
display: none !important;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.top,
|
|
323
|
+
.bottom {
|
|
324
|
+
z-index: 400;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.loading-container {
|
|
328
|
+
padding: 1.5rem;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.loading-detail {
|
|
332
|
+
margin-top: 0.5rem;
|
|
333
|
+
color: #555;
|
|
334
|
+
}
|
|
335
|
+
</style>
|
tangram_core/__init__.py
ADDED
tangram_core/__main__.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
from importlib.abc import Traversable
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Annotated
|
|
7
|
+
|
|
8
|
+
import platformdirs
|
|
9
|
+
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
|
|
13
|
+
from .backend import get_log_config_dict, resolve_frontend, start_tasks
|
|
14
|
+
from .config import Config
|
|
15
|
+
from .plugin import load_plugin, scan_plugins
|
|
16
|
+
|
|
17
|
+
app = typer.Typer(no_args_is_help=True, pretty_exceptions_enable=False)
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
stderr = Console(stderr=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def default_config_file() -> Path:
|
|
23
|
+
if (xdg_config := os.environ.get("XDG_CONFIG_HOME")) is not None:
|
|
24
|
+
config_dir = Path(xdg_config) / "tangram"
|
|
25
|
+
else:
|
|
26
|
+
config_dir = Path(platformdirs.user_config_dir(appname="tangram"))
|
|
27
|
+
if not config_dir.exists():
|
|
28
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
29
|
+
|
|
30
|
+
return Path(config_dir) / "tangram.toml"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@app.command()
|
|
34
|
+
def serve(
|
|
35
|
+
config: Annotated[
|
|
36
|
+
Path,
|
|
37
|
+
typer.Option(
|
|
38
|
+
help="Path to the tangram.toml config file.",
|
|
39
|
+
envvar="TANGRAM_CONFIG",
|
|
40
|
+
default_factory=default_config_file,
|
|
41
|
+
),
|
|
42
|
+
],
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Serves the core tangram frontend and backend services."""
|
|
45
|
+
if not config.is_file():
|
|
46
|
+
logger.error(f"config file not found: {config}")
|
|
47
|
+
raise typer.Exit()
|
|
48
|
+
|
|
49
|
+
cfg = Config.from_file(config)
|
|
50
|
+
logging.config.dictConfig(get_log_config_dict(cfg))
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
asyncio.run(start_tasks(cfg))
|
|
54
|
+
except KeyboardInterrupt:
|
|
55
|
+
logger.info("shutting down services.")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@app.command(name="list-plugins")
|
|
59
|
+
def list_plugins(
|
|
60
|
+
config_path: Annotated[
|
|
61
|
+
Path | None,
|
|
62
|
+
typer.Option("--config", help="Path to the tangram.toml config file."),
|
|
63
|
+
] = None,
|
|
64
|
+
all_plugins: Annotated[
|
|
65
|
+
bool, typer.Option("--all", help="Load all discovered plugins.")
|
|
66
|
+
] = False,
|
|
67
|
+
) -> None:
|
|
68
|
+
"""Lists discovered plugins and their components."""
|
|
69
|
+
table = Table()
|
|
70
|
+
table.add_column("plugin")
|
|
71
|
+
table.add_column("status")
|
|
72
|
+
table.add_column("frontend")
|
|
73
|
+
table.add_column("routers")
|
|
74
|
+
table.add_column("services")
|
|
75
|
+
|
|
76
|
+
enabled_plugins: list[str] | None = None
|
|
77
|
+
if config_path and config_path.is_file():
|
|
78
|
+
config = Config.from_file(config_path)
|
|
79
|
+
enabled_plugins = config.core.plugins
|
|
80
|
+
|
|
81
|
+
for entry_point in scan_plugins():
|
|
82
|
+
plugin_name = entry_point.name
|
|
83
|
+
load_this_plugin = all_plugins or (
|
|
84
|
+
enabled_plugins is not None and plugin_name in enabled_plugins
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if not load_this_plugin:
|
|
88
|
+
table.add_row(plugin_name, "available", "?", "?", "?")
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
if (p := load_plugin(entry_point)) is None:
|
|
92
|
+
status_str = "[red]load failed[/red]"
|
|
93
|
+
table.add_row(plugin_name, status_str, "!", "!", "!")
|
|
94
|
+
continue
|
|
95
|
+
name, plugin = p
|
|
96
|
+
status = (
|
|
97
|
+
"enabled"
|
|
98
|
+
if enabled_plugins and plugin_name in enabled_plugins
|
|
99
|
+
else "loaded"
|
|
100
|
+
)
|
|
101
|
+
frontend_str = ""
|
|
102
|
+
if plugin_path := plugin.frontend_path:
|
|
103
|
+
if resolved_path := resolve_frontend(path=name, dist_name=plugin_name):
|
|
104
|
+
size_kb = get_path_size(resolved_path) / 1024
|
|
105
|
+
frontend_str = f"{size_kb:.1f} B"
|
|
106
|
+
else:
|
|
107
|
+
frontend_str = f"[yellow]({plugin_path} not found)[/yellow]"
|
|
108
|
+
|
|
109
|
+
status_str = f"[green]{status}[/green]"
|
|
110
|
+
router_prefixes = [func.prefix for func in plugin.routers]
|
|
111
|
+
service_names = [func.__name__ for _, func in plugin.services]
|
|
112
|
+
|
|
113
|
+
table.add_row(
|
|
114
|
+
plugin_name,
|
|
115
|
+
status_str,
|
|
116
|
+
frontend_str,
|
|
117
|
+
"\n".join(router_prefixes),
|
|
118
|
+
"\n".join(service_names),
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
stderr.print(table)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def get_path_size(path: Path | Traversable) -> int:
|
|
125
|
+
total_size = 0
|
|
126
|
+
for item in path.iterdir():
|
|
127
|
+
if item.is_file():
|
|
128
|
+
with item.open("rb") as f:
|
|
129
|
+
total_size += len(f.read())
|
|
130
|
+
elif item.is_dir():
|
|
131
|
+
total_size += get_path_size(item)
|
|
132
|
+
return total_size
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@app.command()
|
|
136
|
+
def develop() -> None:
|
|
137
|
+
raise SystemExit
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
app()
|
|
Binary file
|
tangram_core/_core.pyi
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# This file is automatically generated by pyo3_stub_gen
|
|
2
|
+
# ruff: noqa: E501, F401
|
|
3
|
+
|
|
4
|
+
import builtins
|
|
5
|
+
import typing
|
|
6
|
+
|
|
7
|
+
@typing.final
|
|
8
|
+
class ChannelConfig:
|
|
9
|
+
@property
|
|
10
|
+
def host(self) -> builtins.str: ...
|
|
11
|
+
@host.setter
|
|
12
|
+
def host(self, value: builtins.str) -> None: ...
|
|
13
|
+
@property
|
|
14
|
+
def port(self) -> builtins.int: ...
|
|
15
|
+
@port.setter
|
|
16
|
+
def port(self, value: builtins.int) -> None: ...
|
|
17
|
+
@property
|
|
18
|
+
def redis_url(self) -> builtins.str: ...
|
|
19
|
+
@redis_url.setter
|
|
20
|
+
def redis_url(self, value: builtins.str) -> None: ...
|
|
21
|
+
@property
|
|
22
|
+
def jwt_secret(self) -> builtins.str: ...
|
|
23
|
+
@jwt_secret.setter
|
|
24
|
+
def jwt_secret(self, value: builtins.str) -> None: ...
|
|
25
|
+
@property
|
|
26
|
+
def jwt_expiration_secs(self) -> builtins.int: ...
|
|
27
|
+
@jwt_expiration_secs.setter
|
|
28
|
+
def jwt_expiration_secs(self, value: builtins.int) -> None: ...
|
|
29
|
+
@property
|
|
30
|
+
def id_length(self) -> builtins.int: ...
|
|
31
|
+
@id_length.setter
|
|
32
|
+
def id_length(self, value: builtins.int) -> None: ...
|
|
33
|
+
def __new__(cls, host: builtins.str, port: builtins.int, redis_url: builtins.str, jwt_secret: builtins.str, jwt_expiration_secs: builtins.int, id_length: builtins.int) -> ChannelConfig: ...
|
|
34
|
+
|
|
35
|
+
def init_tracing_stderr(filter_str: builtins.str) -> None: ...
|
|
36
|
+
|
|
37
|
+
def run(config: ChannelConfig) -> typing.Any: ...
|
|
38
|
+
|