refactor: remove stale code
This commit is contained in:
parent
5097f70d90
commit
9e798f1b15
|
@ -20,20 +20,15 @@
|
||||||
"@radix-ui/react-label": "^2.1.0",
|
"@radix-ui/react-label": "^2.1.0",
|
||||||
"@radix-ui/react-separator": "^1.1.0",
|
"@radix-ui/react-separator": "^1.1.0",
|
||||||
"@radix-ui/react-slot": "^1.1.0",
|
"@radix-ui/react-slot": "^1.1.0",
|
||||||
"@types/leaflet": "^1.9.12",
|
|
||||||
"@types/react": "^18.3.3",
|
|
||||||
"@types/react-dom": "^18.3.0",
|
|
||||||
"astro": "^4.11.6",
|
"astro": "^4.11.6",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dayjs": "^1.11.11",
|
"dayjs": "^1.11.11",
|
||||||
"htmx.org": "^1.9.12",
|
"htmx.org": "^1.9.12",
|
||||||
"hyperscript.org": "^0.9.12",
|
|
||||||
"kysely": "^0.26.3",
|
"kysely": "^0.26.3",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
"lit": "^3.1.4",
|
"lit": "^3.1.4",
|
||||||
"lucide-react": "^0.309.0",
|
"lucide-react": "^0.309.0",
|
||||||
"nanoid": "^5.0.7",
|
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"tailwind-merge": "^2.4.0",
|
"tailwind-merge": "^2.4.0",
|
||||||
|
@ -43,6 +38,9 @@
|
||||||
"typescript": "^5.5.3"
|
"typescript": "^5.5.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/leaflet": "^1.9.12",
|
||||||
|
"@types/react": "^18.3.3",
|
||||||
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/bun": "^1.1.6",
|
"@types/bun": "^1.1.6",
|
||||||
"@types/google.maps": "^3.55.11",
|
"@types/google.maps": "^3.55.11",
|
||||||
"@types/toastify-js": "^1.12.3"
|
"@types/toastify-js": "^1.12.3"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 320 KiB |
|
@ -1,59 +0,0 @@
|
||||||
import L, { type LatLngTuple } from "leaflet";
|
|
||||||
|
|
||||||
const GoToTargetControl = L.Control.extend({
|
|
||||||
_targetLocation: null as LatLngTuple | null,
|
|
||||||
setTargetLocation: function (latlng: LatLngTuple) {
|
|
||||||
this._targetLocation = latlng;
|
|
||||||
},
|
|
||||||
onAdd: function (map: L.Map) {
|
|
||||||
const locationButton = document.createElement("button");
|
|
||||||
|
|
||||||
locationButton.id = "go-to-target-control-button";
|
|
||||||
|
|
||||||
locationButton.textContent = "Hedefe Git";
|
|
||||||
|
|
||||||
locationButton.classList.add("custom-map-control-button");
|
|
||||||
|
|
||||||
L.DomEvent.on(locationButton, "click", () => {
|
|
||||||
if (!this._targetLocation) return;
|
|
||||||
map.setView(this._targetLocation, 18);
|
|
||||||
});
|
|
||||||
|
|
||||||
return locationButton;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const GeolocationControl = L.Control.extend({
|
|
||||||
_containerEl: null as HTMLButtonElement | null,
|
|
||||||
_currentLocationMarker: null as L.Marker | null,
|
|
||||||
setCurrentLocationMarker: function (marker?: L.Marker) {
|
|
||||||
if (marker) this._currentLocationMarker = marker;
|
|
||||||
},
|
|
||||||
onAdd: function (map: L.Map) {
|
|
||||||
const locationButton = document.createElement("button");
|
|
||||||
|
|
||||||
this._containerEl = locationButton;
|
|
||||||
|
|
||||||
locationButton.id = "ask-permission-control-button";
|
|
||||||
|
|
||||||
locationButton.textContent = "Konumuma Git";
|
|
||||||
|
|
||||||
locationButton.classList.add("custom-map-control-button");
|
|
||||||
|
|
||||||
locationButton.type = "button";
|
|
||||||
|
|
||||||
L.DomEvent.on(locationButton, "click", () => {
|
|
||||||
console.log(this._currentLocationMarker);
|
|
||||||
if (this._currentLocationMarker) {
|
|
||||||
map.setView(this._currentLocationMarker.getLatLng(), 12);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return locationButton;
|
|
||||||
},
|
|
||||||
onRemove: function () {
|
|
||||||
L.DomEvent.off(this._containerEl!);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export { GoToTargetControl, GeolocationControl };
|
|
|
@ -1,63 +0,0 @@
|
||||||
import Toastify from "toastify-js";
|
|
||||||
import L from "leaflet";
|
|
||||||
import { currentLocationIcon } from "./icons";
|
|
||||||
|
|
||||||
function onLocationError(err: L.ErrorEvent) {
|
|
||||||
let errorMessage;
|
|
||||||
switch (err.code) {
|
|
||||||
case 1:
|
|
||||||
errorMessage =
|
|
||||||
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin.";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
errorMessage =
|
|
||||||
"Konumunuz tespit edilemedi, lütfen biraz sonra tekrar deneyiniz.";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
errorMessage =
|
|
||||||
"Konum isteği zaman aşımına uğradı, lütfen sayfayı yenileyip tekrar deneyiniz.";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
errorMessage =
|
|
||||||
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Toastify({
|
|
||||||
text: errorMessage,
|
|
||||||
duration: 3000,
|
|
||||||
gravity: "top", // `top` or `bottom`
|
|
||||||
position: "center", // `left`, `center` or `right`
|
|
||||||
stopOnFocus: true, // Prevents dismissing of toast on hover
|
|
||||||
style: {
|
|
||||||
background: "black",
|
|
||||||
borderRadius: "6px",
|
|
||||||
margin: "16px",
|
|
||||||
},
|
|
||||||
onClick: function () {}, // Callback after click
|
|
||||||
}).showToast();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLocationSuccess(
|
|
||||||
locationEvent: L.LocationEvent,
|
|
||||||
map: L.Map,
|
|
||||||
currentLocationMarker: L.Marker | undefined
|
|
||||||
) {
|
|
||||||
const position = locationEvent.latlng;
|
|
||||||
|
|
||||||
const currentPos = {
|
|
||||||
lat: position.lat,
|
|
||||||
lng: position.lng,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (currentLocationMarker) {
|
|
||||||
currentLocationMarker.setLatLng(currentPos);
|
|
||||||
} else {
|
|
||||||
currentLocationMarker = L.marker(currentPos, {
|
|
||||||
icon: currentLocationIcon,
|
|
||||||
});
|
|
||||||
currentLocationMarker.addTo(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { onLocationError, onLocationSuccess };
|
|
|
@ -1,13 +0,0 @@
|
||||||
import L from "leaflet";
|
|
||||||
|
|
||||||
var targetLocationIcon = L.icon({
|
|
||||||
iconUrl: "goal.svg",
|
|
||||||
iconSize: [32, 32],
|
|
||||||
});
|
|
||||||
|
|
||||||
var currentLocationIcon = L.icon({
|
|
||||||
iconUrl: "blue-dot.png",
|
|
||||||
iconSize: [32, 32],
|
|
||||||
});
|
|
||||||
|
|
||||||
export { targetLocationIcon, currentLocationIcon };
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { html } from "lit";
|
|
||||||
|
|
||||||
// Locked lock icon
|
|
||||||
const lockSVG = html`<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
fill="#ffffff"
|
|
||||||
viewBox="0 0 256 256"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M208,80H176V56a48,48,0,0,0-96,0V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80ZM96,56a32,32,0,0,1,64,0V80H96ZM208,208H48V96H208V208Zm-68-56a12,12,0,1,1-12-12A12,12,0,0,1,140,152Z"
|
|
||||||
></path>
|
|
||||||
</svg>`;
|
|
||||||
|
|
||||||
// Unlocked lock icon
|
|
||||||
const unlockSVG = html`
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="24"
|
|
||||||
height="24"
|
|
||||||
fill="#ffffff"
|
|
||||||
viewBox="0 0 256 256"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M208,80H96V56a32,32,0,0,1,32-32c15.37,0,29.2,11,32.16,25.59a8,8,0,0,0,15.68-3.18C171.32,24.15,151.2,8,128,8A48.05,48.05,0,0,0,80,56V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80Zm0,128H48V96H208V208Zm-68-56a12,12,0,1,1-12-12A12,12,0,0,1,140,152Z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
`;
|
|
||||||
|
|
||||||
export { lockSVG, unlockSVG };
|
|
|
@ -1,95 +0,0 @@
|
||||||
import { html } from "lit";
|
|
||||||
import { lockSVG, unlockSVG } from "./icons";
|
|
||||||
|
|
||||||
// This template is shown when user hasn't give geolocation permission yet
|
|
||||||
// When user click the button user is asked for geolocation permission
|
|
||||||
function permissionButtonTemplate(onClickHandler: () => void) {
|
|
||||||
return html`
|
|
||||||
<div class="flex flex-col justify-center gap-4 overlay">
|
|
||||||
<button
|
|
||||||
id="unlock-content-button"
|
|
||||||
class="inline-flex items-center justify-center whitespace-nowrap font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-11 rounded-md text-lg p-6 text-md">
|
|
||||||
İçerik Kilitli
|
|
||||||
</button>
|
|
||||||
<div class="rounded-lg border bg-card text-card-foreground shadow-sm p-2">
|
|
||||||
<div class="pb-0 text-center flex flex-col gap-4">
|
|
||||||
<p id="locked-content-description">
|
|
||||||
Ne kadar yaklaştığını görmek için aşağıdaki butona bas.
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
@click="${onClickHandler}"
|
|
||||||
class="inline-flex items-center justify-center whitespace-nowrap font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 text-primary-foreground h-9 rounded-md px-3 bg-green-700 hover:bg-green-600 text-md">
|
|
||||||
Konum İzni Ver
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This template is shown when user has not given permission
|
|
||||||
function permissionDeniedButtonTemplate() {
|
|
||||||
return html`<div class="flex flex-col justify-center gap-4 overlay">
|
|
||||||
<button
|
|
||||||
id="unlock-content-button"
|
|
||||||
class="inline-flex gap-2 items-center justify-center whitespace-nowrap font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-11 rounded-md text-lg p-6 text-md">
|
|
||||||
${lockSVG}
|
|
||||||
<p>İçerik Kilitli</p>
|
|
||||||
</button>
|
|
||||||
<div class="rounded-lg border bg-card text-card-foreground shadow-sm p-2">
|
|
||||||
<div class="pb-0 px-4 text-center">
|
|
||||||
<p id="locked-content-description">
|
|
||||||
Konumuna erişim izni vermediğin için hedefe ne kadar <br />
|
|
||||||
yakın olduğun tespit edilemiyor.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This template is shown when user has given permission but has not arrived yet
|
|
||||||
function lockedButtonTemplate(proximityText: string | undefined) {
|
|
||||||
return html`<div class="flex flex-col justify-center gap-4 overlay">
|
|
||||||
<button
|
|
||||||
id="unlock-content-button"
|
|
||||||
class="inline-flex gap-2 items-center justify-center whitespace-nowrap font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-11 rounded-md text-lg p-6 text-md">
|
|
||||||
${lockSVG}
|
|
||||||
<p>İçerik Kilitli</p>
|
|
||||||
</button>
|
|
||||||
<div class="rounded-lg border bg-card text-card-foreground shadow-sm p-2">
|
|
||||||
<div class="pb-0 px-4 text-center">
|
|
||||||
<p id="locked-content-description">
|
|
||||||
İçeriği görmek için konuma gitmelisin! Kalan mesafe: ${proximityText}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This template is shown when user has arrived to the target location
|
|
||||||
// When user click the button counter at the bottom of the page is incremented
|
|
||||||
// and image is revealed
|
|
||||||
function unlockedButtonTemplate(onClickHandler: () => void) {
|
|
||||||
return html` <div class="flex flex-col justify-center gap-4 overlay">
|
|
||||||
<button
|
|
||||||
@click="${onClickHandler}"
|
|
||||||
id="unlock-content-button"
|
|
||||||
class="inline-flex gap-2 items-center justify-center whitespace-nowrap font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 text-primary-foreground h-11 rounded-md text-lg p-6 animate-pulse bg-indigo-600 hover:bg-indigo-700 hover:animate-none border-2 border-indigo-800 transition-1000">
|
|
||||||
${unlockSVG}
|
|
||||||
<p>İçeriğin Kilidi Açıldı</p>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="rounded-lg border bg-card text-card-foreground shadow-sm p-2">
|
|
||||||
<div class="pb-0 px-4 text-center">
|
|
||||||
<p id="locked-content-description">İçeriği görmek için butona bas!</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
lockedButtonTemplate,
|
|
||||||
unlockedButtonTemplate,
|
|
||||||
permissionButtonTemplate,
|
|
||||||
permissionDeniedButtonTemplate,
|
|
||||||
};
|
|
|
@ -1,100 +0,0 @@
|
||||||
// Lit
|
|
||||||
import {
|
|
||||||
html,
|
|
||||||
LitElement,
|
|
||||||
unsafeCSS,
|
|
||||||
type CSSResultGroup,
|
|
||||||
type PropertyValues,
|
|
||||||
} from "lit";
|
|
||||||
import { customElement, property, query, state } from "lit/decorators.js";
|
|
||||||
|
|
||||||
// Leaflet
|
|
||||||
import L, { Map } from "leaflet";
|
|
||||||
import type { LatLngTuple } from "leaflet";
|
|
||||||
import { currentLocationIcon, targetLocationIcon } from "./LeafletMap/icons";
|
|
||||||
import { GeolocationControl, GoToTargetControl } from "./LeafletMap/controls";
|
|
||||||
|
|
||||||
// Styles
|
|
||||||
import leafletStyles from "leaflet/dist/leaflet.css?inline";
|
|
||||||
import globalStyles from "@/styles/globals.css?inline";
|
|
||||||
import mapStyles from "@/styles/locked-page.css?inline";
|
|
||||||
|
|
||||||
@customElement("leaflet-map")
|
|
||||||
export class LeafletMap extends LitElement {
|
|
||||||
// Styles
|
|
||||||
static styles?: CSSResultGroup | undefined = [
|
|
||||||
unsafeCSS(leafletStyles),
|
|
||||||
unsafeCSS(globalStyles),
|
|
||||||
unsafeCSS(mapStyles),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Div element to initialize Leaflet in
|
|
||||||
@query("#mapid")
|
|
||||||
_mapElement!: HTMLDivElement;
|
|
||||||
|
|
||||||
// Properties and states
|
|
||||||
@property({ type: Object, noAccessor: true }) targetPosition?: LatLngTuple;
|
|
||||||
@property({ type: Object })
|
|
||||||
currentPosition?: LatLngTuple;
|
|
||||||
|
|
||||||
protected _map?: L.Map;
|
|
||||||
protected _currentLocationMarker?: L.Marker;
|
|
||||||
|
|
||||||
firstUpdated(): void {
|
|
||||||
if (!this._mapElement || !this.targetPosition) return;
|
|
||||||
this._map = new Map(this._mapElement).setView(this.targetPosition, 13);
|
|
||||||
|
|
||||||
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
|
||||||
maxZoom: 19,
|
|
||||||
attribution:
|
|
||||||
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
|
||||||
}).addTo(this._map);
|
|
||||||
|
|
||||||
// Add target location icon marker
|
|
||||||
L.marker(this.targetPosition, { icon: targetLocationIcon }).addTo(
|
|
||||||
this._map
|
|
||||||
);
|
|
||||||
|
|
||||||
L.circle(this.targetPosition, {
|
|
||||||
color: "blue",
|
|
||||||
fillColor: "#30f",
|
|
||||||
fillOpacity: 0.2,
|
|
||||||
radius: 50,
|
|
||||||
}).addTo(this._map);
|
|
||||||
|
|
||||||
// Add target location control
|
|
||||||
const targetLocationControl = new GoToTargetControl({
|
|
||||||
position: "bottomleft",
|
|
||||||
});
|
|
||||||
|
|
||||||
targetLocationControl.setTargetLocation(this.targetPosition);
|
|
||||||
targetLocationControl.addTo(this._map);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected update(changedProperties: PropertyValues): void {
|
|
||||||
super.update(changedProperties);
|
|
||||||
if (changedProperties.get("currentPosition")) {
|
|
||||||
if (!this._currentLocationMarker && this._map) {
|
|
||||||
this._currentLocationMarker = L.marker(this.currentPosition!, {
|
|
||||||
icon: currentLocationIcon,
|
|
||||||
});
|
|
||||||
this._currentLocationMarker.addTo(this._map);
|
|
||||||
|
|
||||||
const geolocationControl = new GeolocationControl({
|
|
||||||
position: "bottomleft",
|
|
||||||
});
|
|
||||||
|
|
||||||
geolocationControl.setCurrentLocationMarker(
|
|
||||||
this._currentLocationMarker
|
|
||||||
);
|
|
||||||
geolocationControl.addTo(this._map);
|
|
||||||
} else if (this._currentLocationMarker) {
|
|
||||||
this._currentLocationMarker.setLatLng(this.currentPosition!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`<div id="mapid" class="w-full h-[450px] rounded"></div>`;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
// Lit imports
|
|
||||||
import { LitElement, html, nothing, unsafeCSS, type CSSResultGroup } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators.js";
|
|
||||||
|
|
||||||
// Leaflet
|
|
||||||
import { type LatLngTuple } from "leaflet";
|
|
||||||
|
|
||||||
// Styles
|
|
||||||
import globalStyles from "@/styles/globals.css?inline";
|
|
||||||
import lockedContentStyles from "../styles/locked-content.css?inline";
|
|
||||||
|
|
||||||
// Templates
|
|
||||||
import {
|
|
||||||
lockedButtonTemplate,
|
|
||||||
permissionButtonTemplate,
|
|
||||||
permissionDeniedButtonTemplate,
|
|
||||||
unlockedButtonTemplate,
|
|
||||||
} from "./LockedContent/templates";
|
|
||||||
|
|
||||||
// Geolocation utils
|
|
||||||
import { calculateDistance } from "./LockedContent/geolocation";
|
|
||||||
import { incrementUnlockCounter } from "./LockedContent/serverUtils";
|
|
||||||
|
|
||||||
// LockedContent is a custom element watching user location and blurring
|
|
||||||
// given image until user has arrived a certain position
|
|
||||||
@customElement("locked-content")
|
|
||||||
export class LockedContent extends LitElement {
|
|
||||||
// Constants
|
|
||||||
geolocationOptions = {
|
|
||||||
enableHighAccuracy: true,
|
|
||||||
timeout: 15000,
|
|
||||||
maximumAge: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tailwind and custom styles
|
|
||||||
static styles: CSSResultGroup | undefined = [
|
|
||||||
unsafeCSS(globalStyles),
|
|
||||||
unsafeCSS(lockedContentStyles),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Components properties/attributes, no accessor attribute disables detecting
|
|
||||||
// changes as these are readonly attributes there is no need to attach setters
|
|
||||||
@property({ noAccessor: true }) readonly imageId?: string;
|
|
||||||
@property({ noAccessor: true }) readonly imageURL?: string;
|
|
||||||
@property({ type: Object, noAccessor: true })
|
|
||||||
readonly targetPosition?: LatLngTuple;
|
|
||||||
@property({ type: Object })
|
|
||||||
currentPosition?: LatLngTuple;
|
|
||||||
|
|
||||||
// Reactive states, template is rendered according to this states
|
|
||||||
@state()
|
|
||||||
protected _unlocked = false;
|
|
||||||
@state()
|
|
||||||
protected _arrived = false;
|
|
||||||
@state()
|
|
||||||
protected _distanceText?: string;
|
|
||||||
|
|
||||||
private _updateDistanceText(distance: number) {
|
|
||||||
// Update the proximity text according to the distance remaining
|
|
||||||
if (distance > 1000) {
|
|
||||||
this._distanceText = `${(distance / 1000).toFixed()} KM`;
|
|
||||||
} else if (distance > 100) {
|
|
||||||
this._distanceText = `${distance.toFixed(0)} M`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _checkArrived(distance: number) {
|
|
||||||
// If target is close less then 100 meters user has arrived to target location
|
|
||||||
if (distance < 100) {
|
|
||||||
// Update state to reveal the image
|
|
||||||
this._arrived = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dispatchAskPermissionEvent() {
|
|
||||||
const event = new Event("askpermission", { bubbles: true, composed: true });
|
|
||||||
this.dispatchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This template is shown when user hasn't give geolocation permission yet
|
|
||||||
// When user click the button user is asked for geolocation permission
|
|
||||||
private _permissionButtonTemplate = () =>
|
|
||||||
permissionButtonTemplate(this._dispatchAskPermissionEvent);
|
|
||||||
|
|
||||||
// This template is shown when user has given permission but has not arrived yet
|
|
||||||
private _lockedButtonTemplate = () => {
|
|
||||||
// Target position must be set
|
|
||||||
if (!this.targetPosition || !this.currentPosition) return;
|
|
||||||
|
|
||||||
// Calculate the distance between target and current position in meters
|
|
||||||
const distance = calculateDistance(
|
|
||||||
this.currentPosition,
|
|
||||||
this.targetPosition
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the text based on the distance
|
|
||||||
this._updateDistanceText(distance);
|
|
||||||
|
|
||||||
this._checkArrived(distance);
|
|
||||||
|
|
||||||
return lockedButtonTemplate(this._distanceText);
|
|
||||||
};
|
|
||||||
|
|
||||||
// This template is shown when user has arrived to the target location
|
|
||||||
// When user click the button counter at the bottom of the page is incremented
|
|
||||||
// and image is revealed
|
|
||||||
private _unlockedButtonTemplate = () =>
|
|
||||||
unlockedButtonTemplate(() => {
|
|
||||||
incrementUnlockCounter(this.imageId);
|
|
||||||
this._unlocked = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
connectedCallback(): void {
|
|
||||||
super.connectedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let buttonTemplate;
|
|
||||||
|
|
||||||
// Determine which template to show, there are 3 states:
|
|
||||||
// 1 - No current location provided
|
|
||||||
// 2 - Current location given but has no arrived to target position yet
|
|
||||||
// 3 - Arrived to target position
|
|
||||||
// 4 - User did not give geolocation permission
|
|
||||||
if (this._arrived) {
|
|
||||||
buttonTemplate = this._unlockedButtonTemplate;
|
|
||||||
} else if (this.currentPosition) {
|
|
||||||
buttonTemplate = this._lockedButtonTemplate;
|
|
||||||
} else if (!this.currentPosition) {
|
|
||||||
buttonTemplate = this._permissionButtonTemplate;
|
|
||||||
} else {
|
|
||||||
buttonTemplate = permissionDeniedButtonTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<div
|
|
||||||
class="w-full h-[475px] overflow-hidden border border-zinc-200 shadow-sm p-4 rounded"
|
|
||||||
>
|
|
||||||
<div class="flex flex-col justify-center items-center image-wrapper">
|
|
||||||
<img
|
|
||||||
id="content"
|
|
||||||
src="${this.imageURL}"
|
|
||||||
class="h-[450px] ${this._unlocked ? "" : "blur-2xl"}"
|
|
||||||
/>
|
|
||||||
|
|
||||||
${this._unlocked ? nothing : buttonTemplate()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,6 @@
|
||||||
import { type ClassValue, clsx } from "clsx"
|
import { type ClassValue, clsx } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge"
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs))
|
return twMerge(clsx(inputs));
|
||||||
}
|
|
||||||
|
|
||||||
export function remoteLog(data: any) {
|
|
||||||
fetch("/api/debug", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) })
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user