Run prettier.

This commit is contained in:
2024-02-24 11:09:34 -05:00
parent 8e7e0ed490
commit d5267be38c
90 changed files with 5789 additions and 2265 deletions

View File

@ -46,7 +46,7 @@ tfrpc.register(async function query(sql, args) {
return result;
});
tfrpc.register(async function store_blob(blob) {
if (typeof(blob) == 'string') {
if (typeof blob == 'string') {
blob = utf8Encode(blob);
}
if (Array.isArray(blob)) {
@ -71,10 +71,15 @@ async function main() {
let shared_db = await shared_database('state');
attempt = await shared_db.get(core.user.credentials.session.name);
}
app.setDocument(utf8Decode(getFile('index.html')).replace('${data}', JSON.stringify({
attempt: attempt,
state: core.user?.credentials?.session?.name,
})));
app.setDocument(
utf8Decode(getFile('index.html')).replace(
'${data}',
JSON.stringify({
attempt: attempt,
state: core.user?.credentials?.session?.name,
})
)
);
}
main();
main();

View File

@ -17,7 +17,7 @@ function xml_parse(xml) {
let tag = xml.substring(tag_begin, i).trim();
if (tag.startsWith('?') && tag.endsWith('?')) {
/* Ignore directives. */
} else if (tag.startsWith('/')) {
} else if (tag.startsWith('/')) {
path.pop();
} else {
let parts = tag.split(' ');
@ -63,7 +63,10 @@ export function gpx_parse(xml) {
for (let trkseg of xml_each(trk, 'trkseg')) {
let segment = [];
for (let trkpt of xml_each(trkseg, 'trkpt')) {
segment.push({lat: parseFloat(trkpt.attributes.lat), lon: parseFloat(trkpt.attributes.lon)});
segment.push({
lat: parseFloat(trkpt.attributes.lat),
lon: parseFloat(trkpt.attributes.lon),
});
}
result.segments.push(segment);
}
@ -78,4 +81,4 @@ export function gpx_parse(xml) {
}
}
return result;
}
}

View File

@ -18,4 +18,4 @@ async function main() {
status_code: 307,
});
}
main();
main();

View File

@ -1,14 +1,26 @@
<!DOCTYPE html>
<!doctype html>
<html style="width: 100%; height: 100%; margin: 0; padding: 0">
<head>
<script>window.litDisableBundleWarning = true;</script>
<script>
window.litDisableBundleWarning = true;
</script>
<script>
let g_data = ${data};
</script>
<script src="script.js" type="module"></script>
<script src="leaflet.js"></script>
</head>
<body style="color: #fff; display: flex; flex-flow: column; height: 100%; width: 100%; margin: 0; padding: 0">
<body
style="
color: #fff;
display: flex;
flex-flow: column;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
"
>
<gg-app style="width: 100%; height: 100%" id="ggapp"></gg-app>
</body>
</html>
</html>

View File

@ -10,24 +10,24 @@
var polyline = {};
function py2_round(value) {
// Google's polyline algorithm uses the same rounding strategy as Python 2, which is different from JS for negative values
return Math.floor(Math.abs(value) + 0.5) * (value >= 0 ? 1 : -1);
// Google's polyline algorithm uses the same rounding strategy as Python 2, which is different from JS for negative values
return Math.floor(Math.abs(value) + 0.5) * (value >= 0 ? 1 : -1);
}
function encode(current, previous, factor) {
current = py2_round(current * factor);
previous = py2_round(previous * factor);
var coordinate = (current - previous) * 2;
if (coordinate < 0) {
coordinate = -coordinate - 1
}
var output = '';
while (coordinate >= 0x20) {
output += String.fromCharCode((0x20 | (coordinate & 0x1f)) + 63);
coordinate /= 32;
}
output += String.fromCharCode((coordinate | 0) + 63);
return output;
current = py2_round(current * factor);
previous = py2_round(previous * factor);
var coordinate = (current - previous) * 2;
if (coordinate < 0) {
coordinate = -coordinate - 1;
}
var output = '';
while (coordinate >= 0x20) {
output += String.fromCharCode((0x20 | (coordinate & 0x1f)) + 63);
coordinate /= 32;
}
output += String.fromCharCode((coordinate | 0) + 63);
return output;
}
/**
@ -41,54 +41,53 @@ function encode(current, previous, factor) {
*
* @see https://github.com/Project-OSRM/osrm-frontend/blob/master/WebContent/routing/OSRM.RoutingGeometry.js
*/
polyline.decode = function(str, precision) {
var index = 0,
lat = 0,
lng = 0,
coordinates = [],
shift = 0,
result = 0,
byte = null,
latitude_change,
longitude_change,
factor = Math.pow(10, Number.isInteger(precision) ? precision : 5);
polyline.decode = function (str, precision) {
var index = 0,
lat = 0,
lng = 0,
coordinates = [],
shift = 0,
result = 0,
byte = null,
latitude_change,
longitude_change,
factor = Math.pow(10, Number.isInteger(precision) ? precision : 5);
// Coordinates have variable length when encoded, so just keep
// track of whether we've hit the end of the string. In each
// loop iteration, a single coordinate is decoded.
while (index < str.length) {
// Coordinates have variable length when encoded, so just keep
// track of whether we've hit the end of the string. In each
// loop iteration, a single coordinate is decoded.
while (index < str.length) {
// Reset shift, result, and byte
byte = null;
shift = 1;
result = 0;
// Reset shift, result, and byte
byte = null;
shift = 1;
result = 0;
do {
byte = str.charCodeAt(index++) - 63;
result += (byte & 0x1f) * shift;
shift *= 32;
} while (byte >= 0x20);
do {
byte = str.charCodeAt(index++) - 63;
result += (byte & 0x1f) * shift;
shift *= 32;
} while (byte >= 0x20);
latitude_change = result & 1 ? (-result - 1) / 2 : result / 2;
latitude_change = (result & 1) ? ((-result - 1) / 2) : (result / 2);
shift = 1;
result = 0;
shift = 1;
result = 0;
do {
byte = str.charCodeAt(index++) - 63;
result += (byte & 0x1f) * shift;
shift *= 32;
} while (byte >= 0x20);
do {
byte = str.charCodeAt(index++) - 63;
result += (byte & 0x1f) * shift;
shift *= 32;
} while (byte >= 0x20);
longitude_change = result & 1 ? (-result - 1) / 2 : result / 2;
longitude_change = (result & 1) ? ((-result - 1) / 2) : (result / 2);
lat += latitude_change;
lng += longitude_change;
lat += latitude_change;
lng += longitude_change;
coordinates.push([lat / factor, lng / factor]);
}
coordinates.push([lat / factor, lng / factor]);
}
return coordinates;
return coordinates;
};
/**
@ -98,28 +97,33 @@ polyline.decode = function(str, precision) {
* @param {Number} precision
* @returns {String}
*/
polyline.encode = function(coordinates, precision) {
if (!coordinates.length) { return ''; }
polyline.encode = function (coordinates, precision) {
if (!coordinates.length) {
return '';
}
var factor = Math.pow(10, Number.isInteger(precision) ? precision : 5),
output = encode(coordinates[0][0], 0, factor) + encode(coordinates[0][1], 0, factor);
var factor = Math.pow(10, Number.isInteger(precision) ? precision : 5),
output =
encode(coordinates[0][0], 0, factor) +
encode(coordinates[0][1], 0, factor);
for (var i = 1; i < coordinates.length; i++) {
var a = coordinates[i], b = coordinates[i - 1];
output += encode(a[0], b[0], factor);
output += encode(a[1], b[1], factor);
}
for (var i = 1; i < coordinates.length; i++) {
var a = coordinates[i],
b = coordinates[i - 1];
output += encode(a[0], b[0], factor);
output += encode(a[1], b[1], factor);
}
return output;
return output;
};
function flipped(coords) {
var flipped = [];
for (var i = 0; i < coords.length; i++) {
var coord = coords[i].slice();
flipped.push([coord[1], coord[0]]);
}
return flipped;
var flipped = [];
for (var i = 0; i < coords.length; i++) {
var coord = coords[i].slice();
flipped.push([coord[1], coord[0]]);
}
return flipped;
}
/**
@ -129,14 +133,14 @@ function flipped(coords) {
* @param {Number} precision
* @returns {String}
*/
polyline.fromGeoJSON = function(geojson, precision) {
if (geojson && geojson.type === 'Feature') {
geojson = geojson.geometry;
}
if (!geojson || geojson.type !== 'LineString') {
throw new Error('Input must be a GeoJSON LineString');
}
return polyline.encode(flipped(geojson.coordinates), precision);
polyline.fromGeoJSON = function (geojson, precision) {
if (geojson && geojson.type === 'Feature') {
geojson = geojson.geometry;
}
if (!geojson || geojson.type !== 'LineString') {
throw new Error('Input must be a GeoJSON LineString');
}
return polyline.encode(flipped(geojson.coordinates), precision);
};
/**
@ -146,13 +150,13 @@ polyline.fromGeoJSON = function(geojson, precision) {
* @param {Number} precision
* @returns {Object}
*/
polyline.toGeoJSON = function(str, precision) {
var coords = polyline.decode(str, precision);
return {
type: 'LineString',
coordinates: flipped(coords)
};
polyline.toGeoJSON = function (str, precision) {
var coords = polyline.decode(str, precision);
return {
type: 'LineString',
coordinates: flipped(coords),
};
};
let polyline_decode = polyline.decode;
export { polyline_decode as decode };
export {polyline_decode as decode};

View File

@ -1,4 +1,11 @@
import {LitElement, html, unsafeHTML, css, guard, until} from './lit-all.min.js';
import {
LitElement,
html,
unsafeHTML,
css,
guard,
until,
} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
import * as polyline from './polyline.js';
import {gpx_parse} from './gpx.js';
@ -56,7 +63,7 @@ class GgAppElement extends LitElement {
this.focus = undefined;
this.status = undefined;
this.tab = 'map';
this.load().catch(function(e) {
this.load().catch(function (e) {
console.log('load error', e);
});
this.to_build = '🏠';
@ -65,9 +72,12 @@ class GgAppElement extends LitElement {
async load() {
console.log('load');
let emojis = await (await fetch('emojis.json')).json();
emojis = Object.values(emojis).map(x => Object.values(x)).flat();
emojis = Object.values(emojis)
.map((x) => Object.values(x))
.flat();
let today = new Date();
let date_index = today.getYear() * 356 + today.getMonth() * 31 + today.getDate();
let date_index =
today.getYear() * 356 + today.getMonth() * 31 + today.getDate();
this.emoji_of_the_day = emojis[(date_index * 123457) % emojis.length];
this.user = await tfrpc.rpc.getUser();
this.url = (await tfrpc.rpc.url()).split('?')[0];
@ -109,7 +119,8 @@ class GgAppElement extends LitElement {
async get_activities_from_ssb() {
this.status = {text: 'loading activities'};
this.loaded_activities = [];
let rows = await tfrpc.rpc.query(`
let rows = await tfrpc.rpc.query(
`
SELECT messages.author, json_extract(mention.value, '$.link') AS blob_id
FROM messages_fts('"gg-activity"')
JOIN messages ON messages.rowid = messages_fts.rowid,
@ -117,10 +128,15 @@ class GgAppElement extends LitElement {
WHERE json_extract(messages.content, '$.type') = 'gg-activity' AND
json_extract(mention.value, '$.name') = 'activity_data'
ORDER BY messages.timestamp DESC
`, []);
`,
[]
);
this.status = {text: 'loading activity data'};
let authors = rows.map(x => x.author);
let blobs = await this.promise_all(rows.map(x => tfrpc.rpc.get_blob(x.blob_id)), 8);
let authors = rows.map((x) => x.author);
let blobs = await this.promise_all(
rows.map((x) => tfrpc.rpc.get_blob(x.blob_id)),
8
);
this.status = {text: 'processing activity data'};
for (let [index, blob] of blobs.entries()) {
let activity;
@ -135,13 +151,19 @@ class GgAppElement extends LitElement {
}
}
this.status = {text: 'calculating balance'};
rows = await tfrpc.rpc.query(`
rows = await tfrpc.rpc.query(
`
SELECT count(*) AS currency FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'gg-activity'
`, [this.whoami]);
`,
[this.whoami]
);
let currency = rows[0].currency;
rows = await tfrpc.rpc.query(`
rows = await tfrpc.rpc.query(
`
SELECT SUM(json_extract(content, '$.cost')) AS cost FROM messages WHERE author = ? AND json_extract(content, '$.type') = 'gg-place'
`, [this.whoami]);
`,
[this.whoami]
);
let spent = rows[0].cost;
this.currency = currency - spent;
this.status = {text: 'getting placed emojis'};
@ -166,8 +188,11 @@ class GgAppElement extends LitElement {
}
async sync_activities() {
let ids = this.activities.map(x => `https://www.strava.com/activities/${x.id}`);
let missing = await tfrpc.rpc.query(`
let ids = this.activities.map(
(x) => `https://www.strava.com/activities/${x.id}`
);
let missing = await tfrpc.rpc.query(
`
WITH my_activities AS (
SELECT json_extract(mention.value, '$.link') AS url
FROM messages, json_each(messages.content, '$.mentions') AS mention
@ -178,17 +203,26 @@ class GgAppElement extends LitElement {
SELECT from_strava.value FROM json_each(?) AS from_strava
LEFT OUTER JOIN my_activities ON from_strava.value = my_activities.url
WHERE my_activities.url IS NULL
`, [this.whoami, JSON.stringify(ids)]);
`,
[this.whoami, JSON.stringify(ids)]
);
console.log('missing = ', missing);
for (let [index, row] of missing.entries()) {
this.status = {text: 'syncing from strava', value: index, max: missing.length};
this.status = {
text: 'syncing from strava',
value: index,
max: missing.length,
};
let url = row.value;
let id = url.match(/.*\/(\d+)/)[1];
let response = await fetch(`https://www.strava.com/api/v3/activities/${id}`, {
headers: {
'Authorization': `Bearer ${this.strava.access_token}`,
},
});
let response = await fetch(
`https://www.strava.com/api/v3/activities/${id}`,
{
headers: {
Authorization: `Bearer ${this.strava.access_token}`,
},
}
);
let activity = await response.json();
let blob_id = await tfrpc.rpc.store_blob(JSON.stringify(activity));
let message = {
@ -201,7 +235,7 @@ class GgAppElement extends LitElement {
{
link: blob_id,
name: 'activity_data',
}
},
],
};
await tfrpc.rpc.appendMessage(this.whoami, message);
@ -215,13 +249,20 @@ class GgAppElement extends LitElement {
return;
}
let ids = await tfrpc.rpc.getIdentities();
let players = ids.length ? (await tfrpc.rpc.query(`
let players = ids.length
? (
await tfrpc.rpc.query(
`
SELECT author FROM messages JOIN json_each(?) ON messages.author = json_each.value
WHERE
json_extract(messages.content, '$.type') = 'gg-player' AND
json_extract(messages.content, '$.active')
ORDER BY timestamp DESC limit 1
`, [JSON.stringify(ids)])).map(row => row.author) : [];
`,
[JSON.stringify(ids)]
)
).map((row) => row.author)
: [];
if (!players.length) {
this.whoami = await tfrpc.rpc.createIdentity();
if (this.whoami) {
@ -246,9 +287,14 @@ class GgAppElement extends LitElement {
await tfrpc.rpc.databaseSet('strava', shared);
await tfrpc.rpc.sharedDatabaseRemove(name);
}
this.strava = JSON.parse(await tfrpc.rpc.databaseGet('strava') || '{}');
this.strava = JSON.parse((await tfrpc.rpc.databaseGet('strava')) || '{}');
if (new Date().valueOf() / 1000 > this.strava.expires_at) {
console.log('this looks expired', new Date().valueOf() / 1000, '>', this.strava.expires_at);
console.log(
'this looks expired',
new Date().valueOf() / 1000,
'>',
this.strava.expires_at
);
let x = await tfrpc.rpc.refresh_token(this.strava);
if (x) {
this.strava = x;
@ -261,13 +307,16 @@ class GgAppElement extends LitElement {
async update_activities() {
if (this?.strava?.access_token) {
let response = await fetch('https://www.strava.com/api/v3/athlete/activities', {
headers: {
'Authorization': `Bearer ${this.strava.access_token}`,
},
});
let response = await fetch(
'https://www.strava.com/api/v3/athlete/activities',
{
headers: {
Authorization: `Bearer ${this.strava.access_token}`,
},
}
);
this.activities = await response.json();
this.activities.sort((a, b) => (a.id - b.id));
this.activities.sort((a, b) => a.id - b.id);
}
}
@ -282,10 +331,12 @@ class GgAppElement extends LitElement {
[k_color_default, '🟧'],
];
for (let m of k_map) {
if (m[0][0] == color[0] &&
if (
m[0][0] == color[0] &&
m[0][1] == color[1] &&
m[0][2] == color[2] &&
m[0][3] == color[3]) {
m[0][3] == color[3]
) {
return m[1];
}
}
@ -329,9 +380,11 @@ class GgAppElement extends LitElement {
on_click(event) {
let popup = L.popup()
.setLatLng(event.latlng)
.setContent(`
.setContent(
`
<div><a target="_top" href="https://www.google.com/maps/search/?api=1&query=${event.latlng.lat},${event.latlng.lng}">${event.latlng.lat}, ${event.latlng.lng}</a></div>
`)
`
)
.openOn(this.leaflet);
}
@ -368,31 +421,43 @@ class GgAppElement extends LitElement {
on_marker_click(event) {
this.popup = L.popup()
.setLatLng(event.latlng)
.setContent(`
.setContent(
`
${this.to_build} (-${k_store[this.to_build]}) <input type="button" value="Build" onclick="document.getElementById('ggapp').build()"></input>
`)
`
)
.openOn(this.leaflet);
}
snap_to_grid(latlng, fudge, zoom) {
let position = this.leaflet.options.crs.latLngToPoint(latlng, zoom ?? this.leaflet.getZoom());
let position = this.leaflet.options.crs.latLngToPoint(
latlng,
zoom ?? this.leaflet.getZoom()
);
position.x = Math.round(position.x / 16) * 16 + (fudge?.x ?? 0);
position.y = Math.round(position.y / 16) * 16 + (fudge?.y ?? 0);
position = this.leaflet.options.crs.pointToLatLng(position, zoom ?? this.leaflet.getZoom());
position = this.leaflet.options.crs.pointToLatLng(
position,
zoom ?? this.leaflet.getZoom()
);
return position;
}
on_marker_move(event) {
if (!this.no_snap && this.marker) {
this.no_snap = true;
this.marker.setLatLng(this.snap_to_grid(this.marker.getLatLng(), k_marker_snap));
this.marker.setLatLng(
this.snap_to_grid(this.marker.getLatLng(), k_marker_snap)
);
this.no_snap = false;
}
}
on_zoom(event) {
if (this.marker) {
this.marker.setLatLng(this.snap_to_grid(this.marker.getLatLng(), k_marker_snap));
this.marker.setLatLng(
this.snap_to_grid(this.marker.getLatLng(), k_marker_snap)
);
}
}
@ -403,7 +468,10 @@ class GgAppElement extends LitElement {
}
if (this.to_build) {
this.marker = L.marker(this.snap_to_grid(event.latlng, k_marker_snap), {icon: L.divIcon({className: 'build-icon'}), draggable: true}).addTo(this.leaflet);
this.marker = L.marker(this.snap_to_grid(event.latlng, k_marker_snap), {
icon: L.divIcon({className: 'build-icon'}),
draggable: true,
}).addTo(this.leaflet);
this.marker.on({click: this.on_marker_click.bind(this)});
this.marker.on({drag: this.on_marker_move.bind(this)});
}
@ -417,14 +485,18 @@ class GgAppElement extends LitElement {
return;
}
if (!this.leaflet) {
this.leaflet = L.map(map, {attributionControl: false, maxZoom: 16, bounceAtZoomLimits: false});
this.leaflet = L.map(map, {
attributionControl: false,
maxZoom: 16,
bounceAtZoomLimits: false,
});
this.leaflet.on({contextmenu: this.on_click.bind(this)});
this.leaflet.on({click: this.on_mouse_down.bind(this)});
this.leaflet.on({zoom: this.on_zoom.bind(this)});
}
let self = this;
let grid_layer = L.GridLayer.extend({
createTile: function(coords) {
createTile: function (coords) {
var tile = L.DomUtil.create('canvas', 'leaflet-tile');
var size = this.getTileSize();
tile.width = size.x;
@ -432,7 +504,7 @@ class GgAppElement extends LitElement {
var context = tile.getContext('2d');
context.font = '10pt sans';
let bounds = this._tileCoordsToBounds(coords);
let degrees = 360.0 / (2 ** coords.z);
let degrees = 360.0 / 2 ** coords.z;
let ul = bounds.getNorthWest();
let lr = bounds.getSouthEast();
@ -442,33 +514,53 @@ class GgAppElement extends LitElement {
let mini_context = mini.getContext('2d');
let image_data = context.getImageData(0, 0, mini.width, mini.height);
for (let activity of self.loaded_activities) {
self.draw_activity_to_tile(image_data, mini.width, mini.height, ul, lr, activity);
self.draw_activity_to_tile(
image_data,
mini.width,
mini.height,
ul,
lr,
activity
);
}
context.textAlign = 'left';
context.textBaseline = 'bottom';
for (let x = 0; x < mini.width; x++) {
for (let y = 0; y < mini.height; y++) {
let start = (y * mini.width + x) * 4;
let pixel = self.color_to_emoji(image_data.data.slice(start, start + 4));
let pixel = self.color_to_emoji(
image_data.data.slice(start, start + 4)
);
if (pixel) {
//context.fillRect(x * size.x / mini.width, y * size.y / mini.height, size.x / mini.width, size.y / mini.height);
context.fillText(pixel, x * size.x / mini.width, y * size.y / mini.height + mini.height);
context.fillText(
pixel,
(x * size.x) / mini.width,
(y * size.y) / mini.height + mini.height
);
}
}
}
for (let placed of self.placed_emojis) {
let position = self.leaflet.options.crs.latLngToPoint(self.snap_to_grid(placed.position, undefined, coords.z), coords.z);
let position = self.leaflet.options.crs.latLngToPoint(
self.snap_to_grid(placed.position, undefined, coords.z),
coords.z
);
let tile_x = Math.floor(position.x / size.x);
let tile_y = Math.floor(position.y / size.y);
position.x = position.x - tile_x * size.x;
position.y = position.y - tile_y * size.y;
if (tile_x == coords.x && tile_y == coords.y) {
//context.fillRect(position.x, position.y, size.x / mini.width, size.y / mini.height);
context.fillText(placed.emoji, position.x, position.y + mini.height);
context.fillText(
placed.emoji,
position.x,
position.y + mini.height
);
}
}
return tile;
}
},
});
if (this.grid_layer) {
this.grid_layer.redraw();
@ -484,10 +576,7 @@ class GgAppElement extends LitElement {
this.max_lon = Math.max(this.max_lon, bounds.max.lng);
}
if (this.focus) {
this.leaflet.fitBounds([
this.focus.min,
this.focus.max,
]);
this.leaflet.fitBounds([this.focus.min, this.focus.max]);
this.focus = undefined;
} else {
this.leaflet.fitBounds([
@ -588,7 +677,12 @@ class GgAppElement extends LitElement {
let sy = y0 < y1 ? 1 : -1;
let error = dx + dy;
while (true) {
if (x0 >= 0 && y0 >= 0 && x0 < image_data.width && y0 < image_data.height) {
if (
x0 >= 0 &&
y0 >= 0 &&
x0 < image_data.width &&
y0 < image_data.height
) {
let base = (y0 * image_data.width + x0) * 4;
image_data.data[base + 0] = value[0];
image_data.data[base + 1] = value[1];
@ -623,8 +717,8 @@ class GgAppElement extends LitElement {
let last;
for (let pt of polyline.decode(activity.map.polyline)) {
let px = [
Math.floor(width * (pt[1] - ul.lng) / (lr.lng - ul.lng)),
Math.floor(height * (pt[0] - ul.lat) / (lr.lat - ul.lat)),
Math.floor((width * (pt[1] - ul.lng)) / (lr.lng - ul.lng)),
Math.floor((height * (pt[0] - ul.lat)) / (lr.lat - ul.lat)),
];
if (last) {
this.line(image_data, last[0], last[1], px[0], px[1], color);
@ -637,8 +731,8 @@ class GgAppElement extends LitElement {
let last;
for (let pt of segment) {
let px = [
Math.floor(width * (pt.lon - ul.lng) / (lr.lng - ul.lng)),
Math.floor(height * (pt.lat - ul.lat) / (lr.lat - ul.lat)),
Math.floor((width * (pt.lon - ul.lng)) / (lr.lng - ul.lng)),
Math.floor((height * (pt.lat - ul.lat)) / (lr.lat - ul.lat)),
];
if (last) {
this.line(image_data, last[0], last[1], px[0], px[1], color);
@ -667,7 +761,7 @@ class GgAppElement extends LitElement {
{
link: blob_id,
name: 'activity_data',
}
},
],
};
console.log('id =', this.whoami, 'message = ', message);
@ -693,8 +787,7 @@ class GgAppElement extends LitElement {
focus_map(activity) {
let bounds = this.activity_bounds(activity);
if (bounds.min.lat < bounds.max.lat &&
bounds.min.lng < bounds.max.lng) {
if (bounds.min.lat < bounds.max.lat && bounds.min.lng < bounds.max.lng) {
this.tab = 'map';
this.focus = bounds;
}
@ -703,9 +796,13 @@ class GgAppElement extends LitElement {
render_news() {
return html`
<ul>
${this.loaded_activities.map(x => html`
<li style="cursor: pointer" @click=${() => this.focus_map(x)}>${x.author} ${x.name ?? x.time}</li>
`)}
${this.loaded_activities.map(
(x) => html`
<li style="cursor: pointer" @click=${() => this.focus_map(x)}>
${x.author} ${x.name ?? x.time}
</li>
`
)}
</ul>
`;
}
@ -714,7 +811,7 @@ class GgAppElement extends LitElement {
let [emoji, cost] = item;
return html`
<div>
<input type="button" value="${emoji}" @click=${() => this.to_build = emoji}></input> ${cost} ${emoji == this.to_build ? '<-- Will be built next' : undefined}
<input type="button" value="${emoji}" @click=${() => (this.to_build = emoji)}></input> ${cost} ${emoji == this.to_build ? '<-- Will be built next' : undefined}
</div>
`;
}
@ -732,7 +829,10 @@ class GgAppElement extends LitElement {
render() {
let header;
if (!this.user?.credentials?.session?.name) {
header = html`<div style="flex: 1 0">Please <a target="_top" href="/login?return=${this.url}">login</a> to Tilde Friends, first.</div>`;
header = html`<div style="flex: 1 0">
Please <a target="_top" href="/login?return=${this.url}">login</a> to
Tilde Friends, first.
</div>`;
} else if (!this.strava?.access_token) {
let strava_url = `https://www.strava.com/oauth/authorize?client_id=${k_client_id}&redirect_uri=${k_redirect_url}&response_type=code&approval_prompt=auto&scope=activity%3Aread&state=${g_data.state}`;
header = html`
@ -765,10 +865,10 @@ class GgAppElement extends LitElement {
}
</style>
<div id="navigation" style="display: flex; flex-direction: row">
<input type="button" id="button_map" @click=${() => this.tab = 'map'} value="🗺Map"></input>
<input type="button" id="button_news" @click=${() => this.tab = 'news'} value="🏃News"></input>
<input type="button" id="button_friends" @click=${() => this.tab = 'friends'} value="👫Friends"></input>
<input type="button" id="button_store" @click=${() => this.tab = 'store'} value="🏗Store"></input>
<input type="button" id="button_map" @click=${() => (this.tab = 'map')} value="🗺Map"></input>
<input type="button" id="button_news" @click=${() => (this.tab = 'news')} value="🏃News"></input>
<input type="button" id="button_friends" @click=${() => (this.tab = 'friends')} value="👫Friends"></input>
<input type="button" id="button_store" @click=${() => (this.tab = 'store')} value="🏗Store"></input>
</div>
`;
@ -790,13 +890,15 @@ class GgAppElement extends LitElement {
return html`
<style>
.build-icon::before {
content: '📍';
border: 2px solid red;
}
.build-icon::before {
content: '📍';
border: 2px solid red;
}
</style>
<link rel="stylesheet" href="leaflet.css"/>
<div style="width: 100%; height: 100%; display: flex; flex-direction: column">
<link rel="stylesheet" href="leaflet.css" />
<div
style="width: 100%; height: 100%; display: flex; flex-direction: column"
>
${header}
<div style="flex: 1 0; overflow: scroll">${content}</div>
${navigation}
@ -804,4 +906,4 @@ class GgAppElement extends LitElement {
`;
}
}
customElements.define('gg-app', GgAppElement);
customElements.define('gg-app', GgAppElement);

View File

@ -17,4 +17,4 @@ export async function authorization_code(code) {
method: 'POST',
body: `client_id=${k_client_id}&client_secret=${k_client_secret}&code=${code}&grant_type=authorization_code`,
});
}
}