feat: add templates and geolocation callbacks to lit component

This commit is contained in:
log101 2024-07-17 13:02:51 +03:00
parent 873e127251
commit 5ea7471678
3 changed files with 175 additions and 6 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -106,12 +106,14 @@ const { contentId = "", imageUrl = "#", location = "" } = Astro.props;
</style> </style>
</template> </template>
<!--
<locked-content <locked-content
contentId={contentId} contentId={contentId}
imageURL={imageUrl} imageURL={imageUrl}
targetPos={location} targetPos={location}
id="locked-content"></locked-content> id="locked-content"></locked-content>
<locked-content-lit imageId="sample" targetPosition="[1,1]" -->
<locked-content-lit imageId="sample" imageURL={imageUrl} targetPosition="[1,1]"
></locked-content-lit> ></locked-content-lit>
<script src="../components/locked-content.ts"></script> <script src="../components/locked-content.ts"></script>

View File

@ -1,13 +1,32 @@
import { LitElement, html } from "lit"; import { LitElement, html, unsafeCSS, type CSSResultGroup } from "lit";
import { customElement, property, state } from "lit/decorators.js"; import { customElement, property, state } from "lit/decorators.js";
import L, { type LatLngTuple } from "leaflet";
import Toastify from "toastify-js";
import globalStyles from "@/styles/globals.css?inline";
import lockedContentStyles from "../styles/locked-content.css?inline";
@customElement("locked-content-lit") @customElement("locked-content-lit")
export class LockedContent extends LitElement { export class LockedContent extends LitElement {
// Constants
geolocationOptions = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0,
};
// Styling
static styles: CSSResultGroup | undefined = [
unsafeCSS(globalStyles),
unsafeCSS(lockedContentStyles),
];
// Static properties // Static properties
@property() readonly imageId?: string; @property() readonly imageId?: string;
@property() readonly imageURL?: string; @property() readonly imageURL?: string;
@property({ type: Object }) @property({ type: Object })
readonly targetPosition?: [lat: number, lng: number]; readonly targetPosition?: LatLngTuple;
// Reactive state // Reactive state
@state() @state()
@ -16,12 +35,160 @@ export class LockedContent extends LitElement {
protected _unlocked = false; protected _unlocked = false;
@state() @state()
protected _targetProximity?: number; protected _targetProximity?: number;
@state()
protected _watchId?: number;
// This callback will be fired when geolocation info is available
successCallback(position: GeolocationPosition) {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
if (!this.targetPosition) return;
const targetLatLng = L.latLng(this.targetPosition);
const currentLatLng = L.latLng(pos);
const betweenMeters = currentLatLng.distanceTo(targetLatLng);
if (betweenMeters > 1000) {
// this.changeDescription(`${(betweenMeters / 1000).toFixed()} KM`);
} else if (betweenMeters > 100) {
// this.changeDescription(`${betweenMeters.toFixed(0)} M`);
} else {
if (this._watchId) {
navigator.geolocation.clearWatch(this._watchId);
// this.unlockContent();
}
}
}
// This callback will be fired on geolocation error
errorCallback(err: GeolocationPositionError) {
let errorMessage;
switch (err.code) {
case GeolocationPositionError.PERMISSION_DENIED:
errorMessage =
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin.";
break;
case GeolocationPositionError.POSITION_UNAVAILABLE:
errorMessage =
"Konumunuz tespit edilemedi, lütfen biraz sonra tekrar deneyiniz.";
break;
case GeolocationPositionError.TIMEOUT:
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();
}
permissionButtonTemplate() {
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
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>
`;
}
lockedButtonTemplate() {
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 px-4 text-center">
<p id="locked-content-description">
İçeriği görmek için konuma gitmelisin!
</p>
</div>
</div>
</div>`;
}
unlockedButtonTemplate() {
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 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"
>
İçeriğin Kilidi ıldı
</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>`;
}
connectedCallback(): void {
super.connectedCallback();
// start geolocation services
const id = navigator.geolocation.watchPosition(
this.successCallback.bind(this),
this.errorCallback,
this.geolocationOptions
);
this._watchId = id;
}
render() { render() {
return html` return html`
<div> <div
Hello from MyElement! ${this.imageId} class="w-full h-[475px] overflow-hidden border border-zinc-200 shadow-sm p-4 rounded"
<p>${this.targetPosition}</p> >
<div class="flex flex-col justify-center items-center image-wrapper">
<img id="content" src="${this.imageURL}" class="blur-2xl h-[450px]" />
${this._watchId
? this.lockedButtonTemplate()
: this.permissionButtonTemplate()}
</div>
</div> </div>
`; `;
} }