Skip to content

Commit

Permalink
Merge pull request #98 from koddsson/update
Browse files Browse the repository at this point in the history
Update
  • Loading branch information
koddsson authored May 1, 2024
2 parents 8a71cd5 + 11e2973 commit 34284dd
Show file tree
Hide file tree
Showing 9 changed files with 877 additions and 1,525 deletions.
5 changes: 5 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import config from '@koddsson/eslint-config';

export default [
...config
];
Binary file added favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2,156 changes: 741 additions & 1,415 deletions package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,25 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/koddsson/web-dev.git"
"url": "git+https://github.com/koddsson/geopedia.git"
},
"keywords": [],
"author": "Kristján Oddsson <[email protected]>",
"license": "ISC",
"bugs": {
"url": "https://github.com/koddsson/web-dev/issues"
"url": "https://github.com/koddsson/geopedia/issues"
},
"prettier": "@github/prettier-config",
"homepage": "https://github.com/koddsson/web-dev#readme",
"prettier": "@koddsson/prettier-config",
"homepage": "https://github.com/koddsson/geopedia#readme",
"devDependencies": {
"@github/prettier-config": "^0.0.6",
"@koddsson/eslint-config": "^1.1.0",
"@koddsson/prettier-config": "^2.0.0",
"@open-wc/testing": "^4.0.0",
"@web/dev-server": "^0.4.4",
"@web/dev-server-esbuild": "^1.0.2",
"@web/rollup-plugin-html": "^2.3.0",
"@web/test-runner": "^0.18.1",
"eslint": "^8.57.0",
"eslint-plugin-github": "^4.10.2",
"open-props": "^1.7.4",
"postcss": "^8.4.38",
"postcss-cli": "^11.0.0",
Expand Down
31 changes: 31 additions & 0 deletions src/js/database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
interface DatabaseEntry {
id: string;
}

type DatabaseEntryId = string;

export class Database<T extends DatabaseEntry> {
constructor(public key: string) {}

save(datum: T) {
const existingData = this.getAll();
existingData.push(datum);

localStorage.setItem(this.key, JSON.stringify(existingData));
}

remove(id: DatabaseEntryId) {
const data = this.getAll().filter((item) => item.id !== id);

localStorage.setItem(this.key, JSON.stringify(data));
}

get(id: DatabaseEntryId): T | undefined {
const all = this.getAll();
return all.find((item) => item.id === id);
}

getAll(): T[] {
return JSON.parse(localStorage.getItem(this.key) || '[]');
}
}
32 changes: 0 additions & 32 deletions src/js/db.ts

This file was deleted.

16 changes: 8 additions & 8 deletions src/js/error-handler.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
function handleError(event: ErrorEvent | PromiseRejectionEvent) {
const searchParams = new URLSearchParams(window.location.search)
if (!searchParams.has('debug')) {
return
const searchParameters = new URLSearchParams(window.location.search);
if (!searchParameters.has('debug')) {
return;
}

if (event instanceof ErrorEvent) {
alert(event.message)
alert(event.message);
} else if (event instanceof PromiseRejectionEvent) {
alert(event.reason)
alert(event.reason);
} else {
alert(JSON.stringify(event, null, 4))
alert(JSON.stringify(event, undefined, 4));
}
}

window.addEventListener("error", handleError)
window.addEventListener('unhandledrejection', handleError)
window.addEventListener('error', handleError);
window.addEventListener('unhandledrejection', handleError);
125 changes: 69 additions & 56 deletions src/js/index.ts
Original file line number Diff line number Diff line change
@@ -1,111 +1,124 @@
import {Database} from './db'
import {ready, html} from './utils'
import { Database } from './database';
import { ready, html } from './utils';

interface Location {
title: string
pageid: number
primary: string
ns: number
lat: number
lon: number
dist: number
title: string;
pageid: number;
primary: string;
ns: number;
lat: number;
lon: number;
dist: number;
}

interface LocationEntry {
id: string
location: Location
id: string;
location: Location;
}

const db = new Database<LocationEntry>('locations')
const database = new Database<LocationEntry>('locations');

function getCurrentPosition(): Promise<{coords: {latitude: number, longitude: number}}> {
function getCurrentPosition(): Promise<{
coords: { latitude: number; longitude: number };
}> {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, {
enableHighAccuracy: false,
timeout: 5000,
maximumAge: 60000,
maximumAge: 60_000,
});
})
});
}

async function findPagesNear(latitude: number, longitude: number): Promise<Location[]> {
const url = new URL('https://en.wikipedia.org/w/api.php')
async function findPagesNear(
latitude: number,
longitude: number,
): Promise<Location[]> {
const url = new URL('https://en.wikipedia.org/w/api.php');
url.search = new URLSearchParams({
action: 'query',
list: 'geosearch',
origin: '*',
gscoord: `${latitude}|${longitude}`,
gsradius: '10000',
gslimit: '1',
format: 'json'
}).toString()
format: 'json',
}).toString();

const headers = new Headers({Accept: 'application/json'})
const response = await fetch(url, {headers})
const json = await response.json()
const headers = new Headers({ Accept: 'application/json' });
const response = await fetch(url, { headers });
const json = await response.json();

return json.query.geosearch
return json.query.geosearch;
}

const pageTextCache = new Database<{id: string, extract: string}>('page-text-cache')
const pageTextCache = new Database<{ id: string; extract: string }>(
'page-text-cache',
);

async function getPageText(pageid: string) {
const cacheHit = pageTextCache.get(pageid)
const cacheHit = pageTextCache.get(pageid);
if (cacheHit) {
return cacheHit.extract
return cacheHit.extract;
}
const url = new URL('https://en.wikipedia.org/w/api.php')
const url = new URL('https://en.wikipedia.org/w/api.php');
url.search = new URLSearchParams({
action: 'query',
prop: 'extracts',
exintro: 'true',
explaintext: 'true',
pageids: pageid,
origin: '*',
format: 'json'
}).toString()
const headers = new Headers({Accept: 'application/json'})
const response = await fetch(url, {headers})
const json = await response.json()
const extract = json.query.pages[pageid].extract
pageTextCache.save({id: pageid, extract})
return extract
format: 'json',
}).toString();

const headers = new Headers({ Accept: 'application/json' });
const response = await fetch(url, { headers });
const json = await response.json();
const extract = json.query.pages[pageid].extract;
pageTextCache.save({ id: pageid, extract });
return extract;
}

async function generatePlace() {
const {coords: {latitude, longitude}} = await getCurrentPosition()
const locations = await findPagesNear(latitude, longitude)
const location = locations[0]
const {
coords: { latitude, longitude },
} = await getCurrentPosition();
const locations = await findPagesNear(latitude, longitude);
const location = locations[0];

db.save({id: location.pageid.toString(), location})
database.save({ id: location.pageid.toString(), location });

renderLocation(location)
renderLocation(location);
}

async function renderLocation(location: Location) {
const text = await getPageText(location.pageid.toString())
const text = await getPageText(location.pageid.toString());

document.querySelector('#locations')?.prepend(...html`<article><h2>${location.title}</h2><div>${text}</div><div class="location-actions"><button data-remove-location="${location.pageid}">Remove</button><div></article>`)
document
.querySelector('#locations')
?.prepend(
...html`<article><h2>${location.title}</h2><div>${text}</div><div class="location-actions"><button data-remove-location="${location.pageid}">Remove</button><div></article>`,
);
}

await ready()
const entries = db.getAll().sort()
for (const {location} of entries) {
await renderLocation(location)
await ready();
const entries = database.getAll().sort();
for (const { location } of entries) {
await renderLocation(location);
}

document.querySelector('#find-nearest-place')?.addEventListener('click', () => {
generatePlace()
})
generatePlace();
});

document.addEventListener('click', function(event) {
const target = event.target as HTMLElement
document.addEventListener('click', function (event) {
const target = event.target as HTMLElement;
if (target.matches('button[data-remove-location]')) {
const id = target.getAttribute('data-remove-location')!
db.remove(id)
target.closest('article')?.remove()
const id = target.dataset.removeLocation!;
database.remove(id);
target.closest('article')?.remove();
}
})
});

export {}
export {};
25 changes: 17 additions & 8 deletions src/js/utils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
export function ready(): Promise<void> {
return new Promise(resolve => {
if (document.readyState === 'interactive' || document.readyState === 'complete') {
resolve()
return new Promise((resolve) => {
if (
document.readyState === 'interactive' ||
document.readyState === 'complete'
) {
resolve();
} else {
document.addEventListener('DOMContentLoaded', () => resolve())
document.addEventListener('DOMContentLoaded', () => resolve());
}
})
});
}

const parser = new DOMParser()
const parser = new DOMParser();

export function html(strings: TemplateStringsArray, ...values: unknown[]): HTMLCollection {
return parser.parseFromString(String.raw({raw: strings}, ...values), 'text/html').body.children
export function html(
strings: TemplateStringsArray,
...values: unknown[]
): HTMLCollection {
return parser.parseFromString(
String.raw({ raw: strings }, ...values),
'text/html',
).body.children;
}

0 comments on commit 34284dd

Please sign in to comment.