1+ {\rtf1\ansi\ansicpg1252\cocoartf2818
2+ \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 HelveticaNeue;\f1\fnil\fcharset77 ZapfDingbatsITC;}
3+ {\colortbl;\red255\green255\blue255;}
4+ {\*\expandedcolortbl;;}
5+ \margl1440\margr1440\vieww11520\viewh8400\viewkind0
6+ \deftab560
7+ \pard\pardeftab560\slleading20\partightenfactor0
8+
9+ \f0\fs26 \cf0 \
10+ <!doctype html> \
11+ < html lang ="en "> \
12+ \
13+ < head > \
14+ < meta charset ="utf-8 " /> \
15+ < title > MeshCore Wardrive (Ottawa)</ title > \
16+ < meta name ="viewport " content ="width=device-width, initial-scale=1 " /> \
17+ < meta name ="description " content ="Minimal MeshCore Wardrive \'97 BLE companion "> \
18+ < meta name ="keywords " content ="MeshCore,coverage,wardrive,cascadia,ottawamesh,ottawa "> \
19+ < meta name ="Original author " content ="Kyle Reed "> \
20+ < meta name ="Modified by " content ="MrAlders0n "> \
21+ < link rel ="manifest " href ="content/wardrive.json "> \
22+ < link rel ="icon " href ="content/wardrive.png "> \
23+ < link rel ="stylesheet " href ="content/tailwind.css "> \
24+ \
25+ <!-- Leaflet --> \
26+ < link rel ="stylesheet " href ="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css "\
27+ integrity ="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY= " crossorigin ="" /> \
28+ < script src ="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js "\
29+ integrity ="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo= " crossorigin =""> </ script > \
30+ \
31+ <!-- AES-JS for AES-ECB decryption support --> \
32+ < script src ="https://cdn.jsdelivr.net/npm/aes-js@3.1.2/index.min.js "> </ script > \
33+ \
34+ < style > \
35+ .leaflet-interactive .marker-shadow \{ \
36+ filter: url(# marker-shadow );\
37+ \}\
38+ </ style > \
39+ </ head > \
40+ \
41+ < body class ="bg-slate-900 text-slate-100 "> \
42+ < main class ="min-h-screen flex items-start justify-center p-4 "> \
43+ < div class ="w-full max-w-xl space-y-4 "> \
44+ \
45+ <!-- App Title --> \
46+ < header class ="flex items-center justify-between "> \
47+ < h1 class ="flex items-center gap-2 text-xl font-semibold "> \
48+ < img class ="h-8 w-8 " src ="content/wardrive.png " alt ="MeshCore " /> \
49+ MeshCore Wardrive\
50+ </ h1 > \
51+ < span id ="appVersion " class ="text-xs text-slate-400 "> v1.0</ span > \
52+ </ header > \
53+ \
54+ <!-- Status Bar --> \
55+ < div class ="bg-slate-800/80 border border-slate-700 rounded-xl px-4 py-2 flex items-center justify-between "> \
56+ < div class ="flex items-center gap-2 "> \
57+ < span id ="statusIndicator " class ="text-xl "> \uc0\u9679 </ span > \
58+ < span id ="statusText " class ="text-sm font-medium "> Disconnected</ span > \
59+ </ div > \
60+ < button id ="settingsGearBtn " class ="text-2xl text-slate-400 hover:text-slate-200 p-1 " aria-label ="Toggle settings "> \
61+ \uc0\u9881 \u65039 \
62+ </ button > \
63+ </ div > \
64+ \
65+ <!-- Status Messages Box --> \
66+ < section id ="statusMessageBox " class ="hidden bg-slate-800/80 border border-slate-700 rounded-xl p-3 "> \
67+ < div class ="text-xs text-slate-400 "> \
68+ < span class ="font-medium text-slate-300 "> Status:</ span > \
69+ < span id ="statusMessage " class ="ml-2 "> <!-- Status messages will appear here --> </ span > \
70+ </ div > \
71+ </ section > \
72+ \
73+ <!-- Settings Panel --> \
74+ < section id ="settingsPanel " class ="hidden bg-slate-800/80 border border-slate-700 rounded-xl p-4 space-y-4 "> \
75+ < div class ="flex items-center justify-between "> \
76+ < h2 class ="text-sm font-medium text-slate-300 uppercase tracking-wide "> Settings</ h2 > \
77+ < button id ="settingsCloseBtn " class ="hidden text-slate-400 hover:text-slate-200 text-xl leading-none " aria-label ="Close settings "> \
78+
79+ \f1 \uc0\u10005
80+ \f0 \
81+ </ button > \
82+ </ div > \
83+ \
84+ <!-- Auto Ping Interval --> \
85+ < div class ="space-y-2 "> \
86+ < label class ="block text-xs font-medium text-slate-400 uppercase tracking-wide "> Auto Ping Interval</ label > \
87+ < div style ="display: flex; gap: 0.5rem; "> \
88+ < label style ="flex: 1; display: flex; align-items: center; justify-content: center; padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #475569; cursor: pointer; " class ="hover:bg-slate-700 has-[:checked]:bg-emerald-600 has-[:checked]:border-emerald-600 "> \
89+ < input type ="radio " name ="interval " value ="15 " class ="sr-only "> \
90+ < span class ="text-sm font-medium "> 15s</ span > \
91+ </ label > \
92+ < label style ="flex: 1; display: flex; align-items: center; justify-content: center; padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #475569; cursor: pointer; " class ="hover:bg-slate-700 has-[:checked]:bg-emerald-600 has-[:checked]:border-emerald-600 "> \
93+ < input type ="radio " name ="interval " value ="30 " checked class ="sr-only "> \
94+ < span class ="text-sm font-medium "> 30s</ span > \
95+ </ label > \
96+ < label style ="flex: 1; display: flex; align-items: center; justify-content: center; padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #475569; cursor: pointer; " class ="hover:bg-slate-700 has-[:checked]:bg-emerald-600 has-[:checked]:border-emerald-600 "> \
97+ < input type ="radio " name ="interval " value ="60 " class ="sr-only "> \
98+ < span class ="text-sm font-medium "> 60s</ span > \
99+ </ label > \
100+ </ div > \
101+ </ div > \
102+ \
103+ <!-- Radio Power --> \
104+ < div class ="space-y-2 "> \
105+ < label class ="block text-xs font-medium text-slate-400 uppercase tracking-wide "> \
106+ Radio Power < span class ="text-amber-400 "> \uc0\u9888 \u65039 Required</ span > \
107+ </ label > \
108+ < div style ="display: flex; gap: 0.5rem; "> \
109+ < label style ="flex: 1; display: flex; align-items: center; justify-content: center; padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #475569; cursor: pointer; " class ="hover:bg-slate-700 has-[:checked]:bg-emerald-600 has-[:checked]:border-emerald-600 "> \
110+ < input type ="radio " name ="power " value ="0.3w " class ="sr-only "> \
111+ < span class ="text-sm font-medium "> 0.3w</ span > \
112+ </ label > \
113+ < label style ="flex: 1; display: flex; align-items: center; justify-content: center; padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #475569; cursor: pointer; " class ="hover:bg-slate-700 has-[:checked]:bg-emerald-600 has-[:checked]:border-emerald-600 "> \
114+ < input type ="radio " name ="power " value ="0.6w " class ="sr-only "> \
115+ < span class ="text-sm font-medium "> 0.6w</ span > \
116+ </ label > \
117+ < label style ="flex: 1; display: flex; align-items: center; justify-content: center; padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #475569; cursor: pointer; " class ="hover:bg-slate-700 has-[:checked]:bg-emerald-600 has-[:checked]:border-emerald-600 "> \
118+ < input type ="radio " name ="power " value ="1.0w " class ="sr-only "> \
119+ < span class ="text-sm font-medium "> 1.0w</ span > \
120+ </ label > \
121+ </ div > \
122+ </ div > \
123+ \
124+ <!-- Permissions & Status --> \
125+ < div class ="space-y-2 "> \
126+ < label class ="block text-xs font-medium text-slate-400 uppercase tracking-wide "> Permissions & Status</ label > \
127+ < div class ="flex flex-wrap gap-4 text-sm "> \
128+ < div class ="flex items-center gap-2 "> \
129+ < span class ="text-slate-300 "> Bluetooth:</ span > \
130+ < span id ="permBluetooth " class ="font-medium "> -</ span > \
131+ </ div > \
132+ < div class ="flex items-center gap-2 "> \
133+ < span class ="text-slate-300 "> Location:</ span > \
134+ < span id ="permLocation " class ="font-medium "> -</ span > \
135+ </ div > \
136+ < div class ="flex items-center gap-2 "> \
137+ < span class ="text-slate-300 "> Channel:</ span > \
138+ < span id ="channelInfo " class ="font-medium "> -</ span > \
139+ </ div > \
140+ </ div > \
141+ </ div > \
142+ </ section > \
143+ \
144+ <!-- Map Section with Overlays --> \
145+ < section class ="relative bg-slate-800/80 border border-slate-700 rounded-xl overflow-hidden "> \
146+ < iframe \
147+ id ="coverageFrame "\
148+ title ="MeshMapper Coverage Zone "\
149+ style ="width: 100%; height: 400px; border: 0; "\
150+ loading ="lazy "\
151+ referrerpolicy ="no-referrer "\
152+ src ="https://yow.meshmapper.net/embed.php?cov_grid=1&fail_grid=1&pings=0&repeaters=1&rep_coverage=0&grid_lines=0&lat=45.42150&lon=-75.69720&meters=10000 "> \
153+ </ iframe > \
154+ \
155+ <!-- Map Overlays - Horizontal Layout --> \
156+ < div class ="absolute bottom-2 left-2 right-2 flex gap-2 justify-between items-end "> \
157+ <!-- GPS Accuracy - Left --> \
158+ < div class ="bg-slate-900/80 backdrop-blur-sm border border-slate-700 rounded-lg px-3 py-2 text-xs text-slate-300 whitespace-nowrap "> \
159+ < span id ="mapAccuracy "> \'b1-</ span > \
160+ </ div > \
161+ \
162+ <!-- GPS Coordinates - Center (flexible) --> \
163+ < div class ="bg-slate-900/80 backdrop-blur-sm border border-slate-700 rounded-lg px-3 py-2 text-xs text-slate-300 text-center flex-1 "> \
164+ < div id ="mapCoordinates "> -</ div > \
165+ < div id ="mapGpsAge " class ="text-slate-500 mt-0.5 "> -</ div > \
166+ </ div > \
167+ \
168+ <!-- Distance from Last Ping - Right --> \
169+ < div class ="bg-slate-900/80 backdrop-blur-sm border border-slate-700 rounded-lg px-3 py-2 text-xs text-slate-300 whitespace-nowrap "> \
170+ < span id ="mapDistance "> -</ span > \
171+ </ div > \
172+ </ div > \
173+ </ section > \
174+ \
175+ <!-- Control Buttons --> \
176+ < section class ="bg-slate-800/80 border border-slate-700 rounded-xl p-4 space-y-2 "> \
177+ < p id ="connectHelperText " class ="text-xs text-slate-400 text-center "> \
178+ Select radio power to connect\
179+ </ p > \
180+ \
181+ <!-- Ping controls (visible when connected) --> \
182+ < div id ="pingControls " class ="grid grid-cols-2 gap-2 hidden "> \
183+ < button id ="sendPingBtn "\
184+ class ="px-3 py-2 rounded-lg bg-sky-600 hover:bg-sky-500 text-sm font-medium text-white disabled:opacity-40 "> \
185+ Ping\
186+ </ button > \
187+ < button id ="autoToggleBtn "\
188+ class ="px-3 py-2 rounded-lg bg-indigo-600 hover:bg-indigo-500 text-sm font-medium text-white disabled:opacity-40 "> \
189+ Start Auto\
190+ </ button > \
191+ </ div > \
192+ \
193+ <!-- Connect/Disconnect button (always visible, changes text/color) --> \
194+ < button id ="connectBtn "\
195+ class ="w-full px-3 py-2 rounded-lg bg-emerald-600 hover:bg-emerald-500 text-sm font-medium text-white disabled:opacity-40 "> \
196+ Connect\
197+ </ button > \
198+ </ section > \
199+ \
200+ <!-- Session ping log (separate section, placed above footer) --> \
201+ < section class ="bg-slate-800/80 border border-slate-700 rounded-xl p-4 space-y-2 " aria-labelledby ="sessionPingsHeading "> \
202+ < div class ="flex items-center justify-between "> \
203+ < h2 id ="sessionPingsHeading " class ="text-sm font-medium "> Session Pings</ h2 > \
204+ </ div > \
205+ < ul id ="sessionPings "\
206+ class ="text-xs text-slate-400 font-mono leading-5 max-h-48 overflow-y-auto border border-slate-700/70 rounded-lg p-2 bg-slate-900/50 list-none mt-2 "> \
207+ <!-- each ping will be appended as an <li> --> \
208+ </ ul > \
209+ </ section > \
210+ \
211+ <!-- Notes Section --> \
212+ < section class ="bg-slate-800/80 border border-slate-700 rounded-xl p-4 space-y-2 "> \
213+ < h2 class ="text-sm font-medium text-slate-300 "> Notes</ h2 > \
214+ < ul class ="text-xs text-slate-400 space-y-1 list-disc list-inside "> \
215+ < li > Requires Bluetooth and Location permissions</ li > \
216+ < li > Keep app in foreground with screen on & unlocked</ li > \
217+ < li > YOW region only</ li > \
218+ < li > Sends location to < code class ="bg-slate-900 px-1 py-0.5 rounded "> #wardriving</ code > for coverage map</ li > \
219+ < li class ="text-amber-400 font-medium "> \uc0\u9888 \u65039 Not supported in Safari \'97 Use Bluefy on iOS</ li > \
220+ </ ul > \
221+ < p class ="text-xs italic text-slate-500 pt-2 border-t border-slate-700 "> \
222+ Fork of < a class ="underline " target ="_blank " href ="https://github.com/kallanreed/mesh-map "> kallanreed/mesh-map</ a > ,\
223+ modified for < a class ="underline " target ="_blank " href ="https://meshmapper.net "> meshmapper.net</ a > \
224+ </ p > \
225+ </ section > \
226+ \
227+ </ div > \
228+ </ main > \
229+ \
230+ <!-- Load main script --> \
231+ < script type ="module " src ="content/wardrive.js "> </ script > \
232+ < script type ="module "> \
233+ import \{ onLoad \} from './content/wardrive.js' ; \
234+ onLoad ( ) ; \
235+ </ script > \
236+ </ body > \
237+ </ html > }
0 commit comments