chore: remove unnecessary packages
style: run prettier
This commit is contained in:
parent
86cc813977
commit
9c74cc7263
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"endOfLine": "lf",
|
"endOfLine": "lf",
|
||||||
"printWidth": 80,
|
"printWidth": 80,
|
||||||
"arrowParens": "avoid",
|
"arrowParens": "always",
|
||||||
"bracketSpacing": true,
|
"bracketSpacing": true,
|
||||||
"htmlWhitespaceSensitivity": "css",
|
"htmlWhitespaceSensitivity": "css",
|
||||||
"insertPragma": false,
|
"insertPragma": false,
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
"proseWrap": "always",
|
"proseWrap": "always",
|
||||||
"quoteProps": "as-needed",
|
"quoteProps": "as-needed",
|
||||||
"requirePragma": false,
|
"requirePragma": false,
|
||||||
"semi": true,
|
"semi": false,
|
||||||
"singleQuote": false,
|
"singleQuote": false,
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
|
|
55
README.md
55
README.md
|
@ -1,54 +1 @@
|
||||||
# Astro Starter Kit: Basics
|
# KONULU KONUM
|
||||||
|
|
||||||
```sh
|
|
||||||
npm create astro@latest -- --template basics
|
|
||||||
```
|
|
||||||
|
|
||||||
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
|
|
||||||
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
|
|
||||||
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
|
|
||||||
|
|
||||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
|
||||||
|
|
||||||
![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554)
|
|
||||||
|
|
||||||
## 🚀 Project Structure
|
|
||||||
|
|
||||||
Inside of your Astro project, you'll see the following folders and files:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/
|
|
||||||
├── public/
|
|
||||||
│ └── favicon.svg
|
|
||||||
├── src/
|
|
||||||
│ ├── components/
|
|
||||||
│ │ └── Card.astro
|
|
||||||
│ ├── layouts/
|
|
||||||
│ │ └── Layout.astro
|
|
||||||
│ └── pages/
|
|
||||||
│ └── index.astro
|
|
||||||
└── package.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
|
||||||
|
|
||||||
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
|
||||||
|
|
||||||
Any static assets, like images, can be placed in the `public/` directory.
|
|
||||||
|
|
||||||
## 🧞 Commands
|
|
||||||
|
|
||||||
All commands are run from the root of the project, from a terminal:
|
|
||||||
|
|
||||||
| Command | Action |
|
|
||||||
| :------------------------ | :----------------------------------------------- |
|
|
||||||
| `npm install` | Installs dependencies |
|
|
||||||
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
|
||||||
| `npm run build` | Build your production site to `./dist/` |
|
|
||||||
| `npm run preview` | Preview your build locally, before deploying |
|
|
||||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
|
||||||
| `npm run astro -- --help` | Get help using the Astro CLI |
|
|
||||||
|
|
||||||
## 👀 Want to learn more?
|
|
||||||
|
|
||||||
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
|
||||||
|
|
|
@ -25,9 +25,7 @@
|
||||||
"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",
|
||||||
"kysely": "^0.26.3",
|
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
"lit": "^3.1.4",
|
|
||||||
"lucide-react": "^0.309.0",
|
"lucide-react": "^0.309.0",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
---
|
|
||||||
interface Props {
|
|
||||||
title: string;
|
|
||||||
body: string;
|
|
||||||
href: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { href, title, body } = Astro.props;
|
|
||||||
---
|
|
||||||
|
|
||||||
<li class="link-card">
|
|
||||||
<a href={href}>
|
|
||||||
<h2>
|
|
||||||
{title}
|
|
||||||
<span>→</span>
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
{body}
|
|
||||||
</p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<style>
|
|
||||||
.link-card {
|
|
||||||
list-style: none;
|
|
||||||
display: flex;
|
|
||||||
padding: 1px;
|
|
||||||
background-color: #23262d;
|
|
||||||
background-image: none;
|
|
||||||
background-size: 400%;
|
|
||||||
border-radius: 7px;
|
|
||||||
background-position: 100%;
|
|
||||||
transition: background-position 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
||||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
.link-card > a {
|
|
||||||
width: 100%;
|
|
||||||
text-decoration: none;
|
|
||||||
line-height: 1.4;
|
|
||||||
padding: calc(1.5rem - 1px);
|
|
||||||
border-radius: 8px;
|
|
||||||
color: white;
|
|
||||||
background-color: #23262d;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
transition: color 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.link-card:is(:hover, :focus-within) {
|
|
||||||
background-position: 0;
|
|
||||||
background-image: var(--accent-gradient);
|
|
||||||
}
|
|
||||||
.link-card:is(:hover, :focus-within) h2 {
|
|
||||||
color: rgb(var(--accent-light));
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,45 +1,45 @@
|
||||||
import { incrementUnlockCounter } from "./serverUtils";
|
import { incrementUnlockCounter } from "./serverUtils"
|
||||||
|
|
||||||
function updateText(elemId: string, text: string) {
|
function updateText(elemId: string, text: string) {
|
||||||
const elem = document.getElementById(elemId);
|
const elem = document.getElementById(elemId)
|
||||||
if (elem) elem.innerText = text;
|
if (elem) elem.innerText = text
|
||||||
else console.error("Element could not be found!");
|
else console.error("Element could not be found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleClass(elemId: string, className: string) {
|
function toggleClass(elemId: string, className: string) {
|
||||||
const elem = document.getElementById(elemId);
|
const elem = document.getElementById(elemId)
|
||||||
if (elem) elem.classList.toggle(className);
|
if (elem) elem.classList.toggle(className)
|
||||||
else console.error("Element could not be found!");
|
else console.error("Element could not be found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeClasses(elemId: string, ...inputs: string[]) {
|
function removeClasses(elemId: string, ...inputs: string[]) {
|
||||||
const elem = document.getElementById(elemId);
|
const elem = document.getElementById(elemId)
|
||||||
if (elem) elem.classList.remove(...inputs);
|
if (elem) elem.classList.remove(...inputs)
|
||||||
else console.error("Element could not be found!");
|
else console.error("Element could not be found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function addClasses(elemId: string, ...inputs: string[]) {
|
function addClasses(elemId: string, ...inputs: string[]) {
|
||||||
const elem = document.getElementById(elemId);
|
const elem = document.getElementById(elemId)
|
||||||
if (elem) elem.classList.add(...inputs);
|
if (elem) elem.classList.add(...inputs)
|
||||||
else console.error("Element could not be found!");
|
else console.error("Element could not be found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeElement(elemId: string) {
|
function removeElement(elemId: string) {
|
||||||
const elem = document.getElementById(elemId);
|
const elem = document.getElementById(elemId)
|
||||||
if (elem) elem.remove();
|
if (elem) elem.remove()
|
||||||
else console.error("Element could not be found!");
|
else console.error("Element could not be found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAttribute(elemId: string, attribute: string, value: string) {
|
function addAttribute(elemId: string, attribute: string, value: string) {
|
||||||
const elem = document.getElementById(elemId);
|
const elem = document.getElementById(elemId)
|
||||||
if (elem) elem.setAttribute(attribute, value);
|
if (elem) elem.setAttribute(attribute, value)
|
||||||
else console.error("Element could not be found!");
|
else console.error("Element could not be found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
function revealContent() {
|
function revealContent() {
|
||||||
incrementUnlockCounter(document.URL.slice(-12));
|
incrementUnlockCounter(document.URL.slice(-12))
|
||||||
removeClasses("content", "blur-2xl");
|
removeClasses("content", "blur-2xl")
|
||||||
removeElement("unlock-button-container");
|
removeElement("unlock-button-container")
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -50,4 +50,4 @@ export {
|
||||||
updateText,
|
updateText,
|
||||||
revealContent,
|
revealContent,
|
||||||
addAttribute,
|
addAttribute,
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import Toastify from "toastify-js";
|
import L, { type LatLngTuple } from "leaflet"
|
||||||
import L, { type LatLngTuple } from "leaflet";
|
|
||||||
import {
|
import {
|
||||||
addAttribute,
|
addAttribute,
|
||||||
addClasses,
|
addClasses,
|
||||||
|
@ -8,34 +7,36 @@ import {
|
||||||
revealContent,
|
revealContent,
|
||||||
toggleClass,
|
toggleClass,
|
||||||
updateText,
|
updateText,
|
||||||
} from "./domUtils";
|
} from "./domUtils"
|
||||||
import { mapLocationSuccessCallback } from "@/scripts/initMap";
|
import { mapLocationSuccessCallback } from "@/scripts/initMap"
|
||||||
|
import { toast } from "@/lib/utils"
|
||||||
|
|
||||||
// Update the elements according to distance remaining
|
// Update the elements according to distance remaining
|
||||||
function locationSuccessCallback(
|
function locationSuccessCallback(
|
||||||
position: GeolocationPosition,
|
position: GeolocationPosition,
|
||||||
targetPosition: LatLngTuple
|
targetPosition: LatLngTuple
|
||||||
) {
|
) {
|
||||||
const newPosition = position.coords;
|
removeClasses("current-location-control", "disabled-button")
|
||||||
|
const newPosition = position.coords
|
||||||
|
|
||||||
// Calculate the distance remaining
|
// Calculate the distance remaining
|
||||||
const distance = calculateDistance(
|
const distance = calculateDistance(
|
||||||
[newPosition.latitude, newPosition.longitude],
|
[newPosition.latitude, newPosition.longitude],
|
||||||
targetPosition
|
targetPosition
|
||||||
);
|
)
|
||||||
|
|
||||||
// If user has arrived to destination
|
// If user has arrived to destination
|
||||||
if (distance < 100) {
|
if (distance < 100) {
|
||||||
// Change the description texts
|
// Change the description texts
|
||||||
updateText("button-text", "İçeriği Göster");
|
updateText("button-text", "İçeriği Göster")
|
||||||
updateText("locked-content-description", "İçeriği görmek için butona bas!");
|
updateText("locked-content-description", "İçeriği görmek için butona bas!")
|
||||||
|
|
||||||
// Swap the icon
|
// Swap the icon
|
||||||
toggleClass("lock-icon", "hidden");
|
toggleClass("lock-icon", "hidden")
|
||||||
toggleClass("unlock-icon", "hidden");
|
toggleClass("unlock-icon", "hidden")
|
||||||
|
|
||||||
// Tansform the unlock button
|
// Tansform the unlock button
|
||||||
removeClasses("unlock-content-button", "bg-primary", "hover:bg-primary/90");
|
removeClasses("unlock-content-button", "bg-primary", "hover:bg-primary/90")
|
||||||
addClasses(
|
addClasses(
|
||||||
"unlock-content-button",
|
"unlock-content-button",
|
||||||
"bg-indigo-600",
|
"bg-indigo-600",
|
||||||
|
@ -43,71 +44,57 @@ function locationSuccessCallback(
|
||||||
"hover:animate-none",
|
"hover:animate-none",
|
||||||
"border-2",
|
"border-2",
|
||||||
"border-indigo-800"
|
"border-indigo-800"
|
||||||
);
|
)
|
||||||
|
|
||||||
// Wait for transition to finish then add animation
|
// Wait for transition to finish then add animation
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
removeClasses("unlock-content-button", "duration-1000");
|
removeClasses("unlock-content-button", "duration-1000")
|
||||||
addClasses("unlock-content-button", "animate-pulse");
|
addClasses("unlock-content-button", "animate-pulse")
|
||||||
}, 800);
|
}, 800)
|
||||||
|
|
||||||
// Reveal image when the unlock button is clicked
|
// Reveal image when the unlock button is clicked
|
||||||
const unlockButton = document.getElementById("unlock-content-button");
|
const unlockButton = document.getElementById("unlock-content-button")
|
||||||
unlockButton?.addEventListener("click", revealContent);
|
unlockButton?.addEventListener("click", revealContent)
|
||||||
} else {
|
} else {
|
||||||
const distanceText = generateDistanceText(distance);
|
const distanceText = generateDistanceText(distance)
|
||||||
updateText("locked-content-description", `Kalan mesafe: ${distanceText}`);
|
updateText("locked-content-description", `Kalan mesafe: ${distanceText}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
removeElement("location-permission-button");
|
removeElement("location-permission-button")
|
||||||
|
|
||||||
// Update leaflet controls
|
// Update leaflet controls
|
||||||
mapLocationSuccessCallback(position);
|
mapLocationSuccessCallback(position)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This callback will be fired on geolocation error
|
// This callback will be fired on geolocation error
|
||||||
function errorCallback(err: GeolocationPositionError) {
|
function errorCallback(err: GeolocationPositionError) {
|
||||||
let errorMessage;
|
let errorMessage
|
||||||
// Show toast accoring to the error state
|
// Show toast accoring to the error state
|
||||||
switch (err.code) {
|
switch (err.code) {
|
||||||
case GeolocationPositionError.PERMISSION_DENIED:
|
case GeolocationPositionError.PERMISSION_DENIED:
|
||||||
errorMessage =
|
errorMessage =
|
||||||
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin.";
|
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin."
|
||||||
updateText(
|
updateText(
|
||||||
"locked-content-description",
|
"locked-content-description",
|
||||||
"Konum izleme izni alınamadı. \nİçeriği görüntüleyebilmek için konum bilginiz gerekiyor."
|
"Konum izleme izni alınamadı. \nİçeriği görüntüleyebilmek için konum bilginiz gerekiyor."
|
||||||
);
|
)
|
||||||
addAttribute("current-location-control", "disabled", "true");
|
addAttribute("current-location-control", "disabled", "true")
|
||||||
addClasses("current-location-control", "disabled-button");
|
addClasses("current-location-control", "disabled-button")
|
||||||
removeElement("location-permission-button");
|
removeElement("location-permission-button")
|
||||||
break;
|
break
|
||||||
case GeolocationPositionError.POSITION_UNAVAILABLE:
|
case GeolocationPositionError.POSITION_UNAVAILABLE:
|
||||||
errorMessage =
|
errorMessage =
|
||||||
"Konumunuz tespit edilemedi, lütfen biraz sonra tekrar deneyiniz.";
|
"Konumunuz tespit edilemedi, lütfen biraz sonra tekrar deneyiniz."
|
||||||
break;
|
break
|
||||||
case GeolocationPositionError.TIMEOUT:
|
case GeolocationPositionError.TIMEOUT:
|
||||||
errorMessage =
|
return
|
||||||
"Konum isteği zaman aşımına uğradı, lütfen sayfayı yenileyip tekrar deneyiniz.";
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
errorMessage =
|
errorMessage =
|
||||||
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin.";
|
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin."
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
Toastify({
|
toast(errorMessage)
|
||||||
text: errorMessage,
|
|
||||||
duration: 3000,
|
|
||||||
gravity: "top",
|
|
||||||
position: "center",
|
|
||||||
stopOnFocus: true,
|
|
||||||
style: {
|
|
||||||
background: "black",
|
|
||||||
borderRadius: "6px",
|
|
||||||
margin: "16px",
|
|
||||||
},
|
|
||||||
onClick: function () {},
|
|
||||||
}).showToast();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateDistance(
|
function calculateDistance(
|
||||||
|
@ -115,24 +102,24 @@ function calculateDistance(
|
||||||
targetPosition: L.LatLngTuple
|
targetPosition: L.LatLngTuple
|
||||||
) {
|
) {
|
||||||
// Get target position in latitudes and longitudes
|
// Get target position in latitudes and longitudes
|
||||||
const targetLatLng = L.latLng(targetPosition);
|
const targetLatLng = L.latLng(targetPosition)
|
||||||
|
|
||||||
// Get current position in latitudes and longitudes
|
// Get current position in latitudes and longitudes
|
||||||
const currentLatLng = L.latLng(currentPosition);
|
const currentLatLng = L.latLng(currentPosition)
|
||||||
|
|
||||||
// Calculate the distance between target and current position in meters
|
// Calculate the distance between target and current position in meters
|
||||||
const betweenMeters = currentLatLng.distanceTo(targetLatLng);
|
const betweenMeters = currentLatLng.distanceTo(targetLatLng)
|
||||||
|
|
||||||
return betweenMeters;
|
return betweenMeters
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a human readable destination text according to
|
// Generates a human readable destination text according to
|
||||||
// distance remaining
|
// distance remaining
|
||||||
function generateDistanceText(distance: number) {
|
function generateDistanceText(distance: number) {
|
||||||
if (distance > 1000) {
|
if (distance > 1000) {
|
||||||
return `${(distance / 1000).toFixed()} KM`;
|
return `${(distance / 1000).toFixed()} KM`
|
||||||
} else if (distance > 100) {
|
} else if (distance > 100) {
|
||||||
return `${distance.toFixed(0)} M`;
|
return `${distance.toFixed(0)} M`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,4 +128,4 @@ export {
|
||||||
locationSuccessCallback,
|
locationSuccessCallback,
|
||||||
calculateDistance,
|
calculateDistance,
|
||||||
generateDistanceText,
|
generateDistanceText,
|
||||||
};
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ function incrementUnlockCounter(id: string | undefined) {
|
||||||
if (id) {
|
if (id) {
|
||||||
fetch(`http://localhost:3000/api/location/increment/${id}`, {
|
fetch(`http://localhost:3000/api/location/increment/${id}`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { incrementUnlockCounter };
|
export { incrementUnlockCounter }
|
||||||
|
|
|
@ -1,37 +1,25 @@
|
||||||
import { Button } from "./ui/button"
|
import { toast } from "@/lib/utils";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
|
||||||
const ShareButton = () => {
|
const ShareButton = () => {
|
||||||
const shareLink = async () => {
|
const shareLink = async () => {
|
||||||
const shareData = {
|
const shareData = {
|
||||||
title: "Konulu Konum",
|
title: "Konulu Konum",
|
||||||
text: "Sevdiklerinizi şaşırtın!",
|
text: "Sevdiklerinizi şaşırtın!",
|
||||||
url: document.URL
|
url: document.URL,
|
||||||
}
|
};
|
||||||
|
|
||||||
await navigator.share(shareData)
|
await navigator.share(shareData);
|
||||||
}
|
};
|
||||||
|
|
||||||
const copyLink = async () => {
|
const copyLink = async () => {
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText(document.URL)
|
await navigator.clipboard.writeText(document.URL);
|
||||||
// @ts-ignore
|
toast("Konulu konum kopyalandı.");
|
||||||
Toastify({
|
|
||||||
text: "Konulu konum kopyalandı.",
|
|
||||||
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()
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error(err.message)
|
console.error(err.message);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -48,7 +36,7 @@ const ShareButton = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ShareButton
|
export default ShareButton;
|
||||||
|
|
4
src/env.d.ts
vendored
4
src/env.d.ts
vendored
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
export declare global {
|
export declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
htmx: any;
|
htmx: any
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace astroHTML.JSX {
|
namespace astroHTML.JSX {
|
||||||
interface HTMLAttributes {
|
interface HTMLAttributes {
|
||||||
_?: any;
|
_?: any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
import type { Generated } from "kysely"
|
|
||||||
|
|
||||||
export interface Database {
|
export interface Database {
|
||||||
contents: ContentTable
|
contents: ContentTable
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ContentTable {
|
export interface ContentTable {
|
||||||
id: Generated<string>
|
id: string
|
||||||
url: string
|
url: string
|
||||||
blob_url: string
|
blob_url: string
|
||||||
loc: string
|
loc: string
|
||||||
author: string
|
author: string
|
||||||
description: string
|
description: string
|
||||||
created_at: Generated<string>
|
created_at: string
|
||||||
unlocked_counter: Generated<number>
|
unlocked_counter: number
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
export function onLocationError(err: GeolocationPositionError) {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
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()
|
|
||||||
}
|
|
|
@ -1,6 +1,23 @@
|
||||||
import { type ClassValue, clsx } from "clsx";
|
import { type ClassValue, clsx } from "clsx"
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge"
|
||||||
|
import Toastify from "toastify-js"
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toast(errorMessage: string) {
|
||||||
|
Toastify({
|
||||||
|
text: errorMessage,
|
||||||
|
duration: 3000,
|
||||||
|
gravity: "top",
|
||||||
|
position: "center",
|
||||||
|
stopOnFocus: true,
|
||||||
|
style: {
|
||||||
|
background: "black",
|
||||||
|
borderRadius: "6px",
|
||||||
|
margin: "16px",
|
||||||
|
},
|
||||||
|
onClick: function () {},
|
||||||
|
}).showToast()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,41 @@
|
||||||
---
|
---
|
||||||
// Styles
|
// Styles
|
||||||
import "@/styles/globals.css";
|
import "@/styles/globals.css"
|
||||||
import "../styles/locked-page.css";
|
import "../styles/locked-page.css"
|
||||||
import "../styles/locked-content.css";
|
import "../styles/locked-content.css"
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import Layout from "../layouts/Layout.astro";
|
import Layout from "../layouts/Layout.astro"
|
||||||
import ShareButton from "../components/ShareButton";
|
import ShareButton from "../components/ShareButton"
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardFooter,
|
CardFooter,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card"
|
||||||
import { CalendarIcon } from "@radix-ui/react-icons";
|
import { CalendarIcon } from "@radix-ui/react-icons"
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator"
|
||||||
import type { ContentTable } from "@/lib/db";
|
import type { ContentTable } from "@/lib/db"
|
||||||
|
|
||||||
// Dayjs
|
// Dayjs
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs"
|
||||||
import relativeTime from "dayjs/plugin/relativeTime";
|
import relativeTime from "dayjs/plugin/relativeTime"
|
||||||
import utc from "dayjs/plugin/utc";
|
import utc from "dayjs/plugin/utc"
|
||||||
|
|
||||||
type Content = ContentTable;
|
type Content = ContentTable
|
||||||
|
|
||||||
const { id } = Astro.params;
|
const { id } = Astro.params
|
||||||
|
|
||||||
const res = await fetch(`http://localhost:3000/api/location/${id}`);
|
const res = await fetch(`http://localhost:3000/api/location/${id}`)
|
||||||
|
|
||||||
const data: Content | null = res.status === 200 ? await res.json() : null;
|
const data: Content | null = res.status === 200 ? await res.json() : null
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc)
|
||||||
|
|
||||||
// @ts-expect-error Generated<string> is string
|
const dateFromNow = dayjs.utc(data?.created_at).from(dayjs.utc())
|
||||||
const dateFromNow = dayjs.utc(data?.created_at).from(dayjs.utc());
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
|
|
|
@ -10,17 +10,15 @@ import Layout from "../layouts/Layout.astro";
|
||||||
<Layout>
|
<Layout>
|
||||||
<main>
|
<main>
|
||||||
<form
|
<form
|
||||||
class="flex flex-col gap-8"
|
class='flex flex-col gap-8'
|
||||||
id="sample-form"
|
id='sample-form'
|
||||||
enctype="multipart/form-data"
|
enctype='multipart/form-data'>
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<h1
|
<h1
|
||||||
class="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl hover:underline"
|
class='scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl hover:underline'>
|
||||||
>
|
|
||||||
<a href=`${import.meta.env.PUBLIC_HOME_URL}`> Konulu Konum</a>
|
<a href=`${import.meta.env.PUBLIC_HOME_URL}`> Konulu Konum</a>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="leading-7 [&:not(:first-child)]:mt-6">
|
<p class='leading-7 [&:not(:first-child)]:mt-6'>
|
||||||
3 basit adımda fotoğraflarınızı ve videolarınızı <b
|
3 basit adımda fotoğraflarınızı ve videolarınızı <b
|
||||||
>yalnızca belirli bir konumda</b
|
>yalnızca belirli bir konumda</b
|
||||||
> açılacak şekilde kilitleyin:
|
> açılacak şekilde kilitleyin:
|
||||||
|
@ -29,24 +27,23 @@ import Layout from "../layouts/Layout.astro";
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2
|
<h2
|
||||||
class="mt-10 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight transition-colors first:mt-0"
|
class='mt-10 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight transition-colors first:mt-0'>
|
||||||
>
|
|
||||||
1. Fotoğraf Seçimi
|
1. Fotoğraf Seçimi
|
||||||
</h2>
|
</h2>
|
||||||
<p class="leading-7 [&:not(:first-child)]:mt-6">
|
<p class='leading-7 [&:not(:first-child)]:mt-6'>
|
||||||
Aşağıdaki butona basıp galerinizden bir fotoğraf seçin, seçtiğiniz
|
Aşağıdaki butona basıp galerinizden bir fotoğraf seçin, seçtiğiniz
|
||||||
fotoğraf yalnızca belirli bir konumda açılabilecek bir hale
|
fotoğraf yalnızca belirli bir konumda açılabilecek bir hale
|
||||||
getirilecek.
|
getirilecek.
|
||||||
</p>
|
</p>
|
||||||
<div class="grid w-full max-w-sm items-center gap-1.5 mt-4">
|
<div class='grid w-full max-w-sm items-center gap-1.5 mt-4'>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type='file'
|
||||||
name="selected-photo"
|
name='selected-photo'
|
||||||
id="photo-selector"
|
id='photo-selector'
|
||||||
class="p-2 border border-gray rounded-lg file:bg-inherit file:border-0"
|
class='p-2 border border-gray rounded-lg file:bg-inherit file:border-0'
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<p class="px-2 text-sm text-muted-foreground">
|
<p class='px-2 text-sm text-muted-foreground'>
|
||||||
Galerinizden bir fotoğraf seçin.
|
Galerinizden bir fotoğraf seçin.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,99 +51,94 @@ import Layout from "../layouts/Layout.astro";
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2
|
<h2
|
||||||
class="mt-10 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight transition-colors first:mt-0"
|
class='mt-10 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight transition-colors first:mt-0'>
|
||||||
>
|
|
||||||
2. Fotoğrafın Açılacağı Konum
|
2. Fotoğrafın Açılacağı Konum
|
||||||
</h2>
|
</h2>
|
||||||
<p class="leading-7 [&:not(:first-child)]:mt-6">
|
<p class='leading-7 [&:not(:first-child)]:mt-6'>
|
||||||
Haritadan bir nokta seçin. Bağlantıyı gönderdiğiniz kişi bu konuma
|
Haritadan bir nokta seçin. Bağlantıyı gönderdiğiniz kişi bu konuma
|
||||||
gittiği zaman seçtiğiniz fotoğrafı görebilecek.
|
gittiği zaman seçtiğiniz fotoğrafı görebilecek.
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
id="map"
|
id='map'
|
||||||
class="w-full h-[450px] rounded mt-4 transition-colors ease-in-out border-2 duration-300"
|
class='w-full h-[450px] rounded mt-4 transition-colors ease-in-out border-2 duration-300'>
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="text-xl mt-2">
|
<p class='text-xl mt-2'>
|
||||||
<span class="font-semibold">Seçilen Konum:</span>
|
<span class='font-semibold'>Seçilen Konum:</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p
|
<p
|
||||||
class="text-lg transition ease-in-out duration-700"
|
class='text-lg transition ease-in-out duration-700'
|
||||||
id="coordinates"
|
id='coordinates'>
|
||||||
>
|
|
||||||
Henüz konum seçmediniz, konum seçmek için haritadaki bir noktaya
|
Henüz konum seçmediniz, konum seçmek için haritadaki bir noktaya
|
||||||
basınız.
|
basınız.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p
|
<p
|
||||||
class="text-lg text-muted-foreground mt-2"
|
class='text-lg text-muted-foreground mt-2'
|
||||||
id="location-selected-confirmation"
|
id='location-selected-confirmation'>
|
||||||
>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<input name="geolocation" id="geolocation-input" hidden />
|
<input name='geolocation' id='geolocation-input' hidden />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2
|
<h2
|
||||||
class="mt-10 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight transition-colors first:mt-0"
|
class='mt-10 scroll-m-20 border-b pb-2 text-2xl font-semibold tracking-tight transition-colors first:mt-0'>
|
||||||
>
|
|
||||||
3. Fotoğraf Açıklaması
|
3. Fotoğraf Açıklaması
|
||||||
</h2>
|
</h2>
|
||||||
<div class="grid w-full max-w-md items-center gap-2 mt-4">
|
<div class='grid w-full max-w-md items-center gap-2 mt-4'>
|
||||||
<div class="grid w-full items-center gap-1.5">
|
<div class='grid w-full items-center gap-1.5'>
|
||||||
<label for="location-author" class="lg:text-lg text-md">
|
<label for='location-author' class='lg:text-lg text-md'>
|
||||||
Gönderici
|
Gönderici
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="location-author"
|
id='location-author'
|
||||||
name="author"
|
name='author'
|
||||||
placeholder="İsminizi buraya yazınız."
|
placeholder='İsminizi buraya yazınız.'
|
||||||
class="lg:text-lg text-md py-2 px-3 border border-gray rounded-lg placeholder:text-slate-400"
|
class='lg:text-lg text-md py-2 px-3 border border-gray rounded-lg placeholder:text-slate-400'
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid w-full items-center gap-1.5">
|
<div class='grid w-full items-center gap-1.5'>
|
||||||
<label for="location-description" class="lg:text-lg text-md">
|
<label for='location-description' class='lg:text-lg text-md'>
|
||||||
Açıklama
|
Açıklama
|
||||||
</label>
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
placeholder="Açıklamanızı buraya yazınız."
|
placeholder='Açıklamanızı buraya yazınız.'
|
||||||
name="description"
|
name='description'
|
||||||
id="location-description"
|
id='location-description'
|
||||||
class="lg:text-lg text-md py-2 px-3 border border-gray rounded-lg placeholder:text-slate-400 resize-none"
|
class='lg:text-lg text-md py-2 px-3 border border-gray rounded-lg placeholder:text-slate-400 resize-none'
|
||||||
required></textarea>
|
required></textarea>
|
||||||
<p class="text-sm text-muted-foreground">
|
<p class='text-sm text-muted-foreground'>
|
||||||
Bir açıklama girin, yüklediğiniz içeriğin üzerine bu metin
|
Bir açıklama girin, yüklediğiniz içeriğin üzerine bu metin
|
||||||
görünecek.
|
görünecek.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2 my-6 items-center">
|
<div class='flex gap-2 my-6 items-center'>
|
||||||
<input type="checkbox" id="kvkk" class="w-6 h-6" required />
|
<input type='checkbox' id='kvkk' class='w-6 h-6' required />
|
||||||
<label
|
<label
|
||||||
for="kvkk"
|
for='kvkk'
|
||||||
class="text-lg font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
class='text-lg font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'>
|
||||||
>
|
|
||||||
Konulu Konum'u KVKK kapsamında dava etmeyeceğimi onaylıyorum.
|
Konulu Konum'u KVKK kapsamında dava etmeyeceğimi onaylıyorum.
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="w-full text-lg bg-slate-900 text-white p-2 rounded-lg"
|
class='w-full text-lg bg-slate-900 text-white p-2 rounded-lg'
|
||||||
type="submit"
|
type='submit'
|
||||||
id="submit-button"
|
id='submit-button'>
|
||||||
>
|
|
||||||
Bağlantıyı Oluştur
|
Bağlantıyı Oluştur
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<script src="../scripts/initSelectionMap.js"></script>
|
<script src='../scripts/initSelectionMap.js'></script>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { toast } from "@/lib/utils";
|
||||||
|
|
||||||
const handleSubmit = async (e: SubmitEvent) => {
|
const handleSubmit = async (e: SubmitEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -208,20 +200,7 @@ import Layout from "../layouts/Layout.astro";
|
||||||
|
|
||||||
if (data.url) location.assign("/" + data.url);
|
if (data.url) location.assign("/" + data.url);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
toast("Konulu konum oluşturulamadı, lütfen tekrar deneyin.");
|
||||||
Toastify({
|
|
||||||
text: "Konulu konum oluşturulamadı, lütfen tekrar deneyin.",
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,129 +1,117 @@
|
||||||
import L from "leaflet";
|
import { toast } from "@/lib/utils"
|
||||||
import Toastify from "toastify-js";
|
import L from "leaflet"
|
||||||
|
|
||||||
type TargetLocation = [lat: number, lng: number] | null;
|
type TargetLocation = [lat: number, lng: number] | null
|
||||||
|
|
||||||
const mapEl = document.getElementById("map");
|
const mapEl = document.getElementById("map")
|
||||||
|
|
||||||
var targetLocationIcon = L.icon({
|
var targetLocationIcon = L.icon({
|
||||||
iconUrl: "goal.svg",
|
iconUrl: "goal.svg",
|
||||||
iconSize: [32, 32],
|
iconSize: [32, 32],
|
||||||
});
|
})
|
||||||
|
|
||||||
var currentLocationIcon = L.icon({
|
var currentLocationIcon = L.icon({
|
||||||
iconUrl: "blue-dot.png",
|
iconUrl: "blue-dot.png",
|
||||||
iconSize: [32, 32],
|
iconSize: [32, 32],
|
||||||
});
|
})
|
||||||
|
|
||||||
const targetLocation = mapEl?.dataset.targetLocation;
|
const targetLocation = mapEl?.dataset.targetLocation
|
||||||
|
|
||||||
const data = targetLocation ? JSON.parse(targetLocation) : null;
|
const data = targetLocation ? JSON.parse(targetLocation) : null
|
||||||
|
|
||||||
const TARGET_LOCATION = data as TargetLocation;
|
const TARGET_LOCATION = data as TargetLocation
|
||||||
|
|
||||||
var map = L.map("map");
|
var map = L.map("map")
|
||||||
|
|
||||||
if (TARGET_LOCATION) map.setView(TARGET_LOCATION, 13);
|
if (TARGET_LOCATION) map.setView(TARGET_LOCATION, 13)
|
||||||
|
|
||||||
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
attribution:
|
attribution:
|
||||||
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||||
}).addTo(map);
|
}).addTo(map)
|
||||||
|
|
||||||
let currentLocationMarker: L.Marker;
|
let currentLocationMarker: L.Marker
|
||||||
|
|
||||||
export function mapLocationSuccessCallback(position: GeolocationPosition) {
|
export function mapLocationSuccessCallback(position: GeolocationPosition) {
|
||||||
const currentPos = {
|
const currentPos = {
|
||||||
lat: position.coords.latitude,
|
lat: position.coords.latitude,
|
||||||
lng: position.coords.longitude,
|
lng: position.coords.longitude,
|
||||||
};
|
}
|
||||||
|
|
||||||
if (currentLocationMarker) {
|
if (currentLocationMarker) {
|
||||||
currentLocationMarker.setLatLng(currentPos);
|
currentLocationMarker.setLatLng(currentPos)
|
||||||
} else {
|
} else {
|
||||||
currentLocationMarker = L.marker(currentPos, { icon: currentLocationIcon });
|
currentLocationMarker = L.marker(currentPos, { icon: currentLocationIcon })
|
||||||
currentLocationMarker.addTo(map);
|
currentLocationMarker.addTo(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CurrentLocation = L.Control.extend({
|
const CurrentLocation = L.Control.extend({
|
||||||
onAdd: function (map: L.Map) {
|
onAdd: function (map: L.Map) {
|
||||||
const locationButton = document.createElement("button");
|
const locationButton = document.createElement("button")
|
||||||
|
|
||||||
locationButton.textContent = "Konumuma Git";
|
locationButton.textContent = "Konumuma Git"
|
||||||
|
|
||||||
locationButton.classList.add("custom-map-control-button");
|
locationButton.classList.add("custom-map-control-button", "disabled-button")
|
||||||
|
|
||||||
locationButton.type = "button";
|
locationButton.type = "button"
|
||||||
|
|
||||||
locationButton.id = "current-location-control";
|
locationButton.id = "current-location-control"
|
||||||
|
|
||||||
locationButton.addEventListener("click", () => {
|
locationButton.addEventListener("click", () => {
|
||||||
if (currentLocationMarker) {
|
if (currentLocationMarker) {
|
||||||
map.setView(currentLocationMarker.getLatLng(), 12);
|
map.setView(currentLocationMarker.getLatLng(), 12)
|
||||||
} else {
|
} else {
|
||||||
Toastify({
|
toast("Konumunuza erişilemiyor, lütfen biraz bekleyip tekrar deneyin.")
|
||||||
text: "Konumunuza erişilemiyor, lütfen biraz bekleyip tekrar deneyin.",
|
|
||||||
duration: 3000,
|
|
||||||
gravity: "top",
|
|
||||||
position: "center",
|
|
||||||
stopOnFocus: true,
|
|
||||||
style: {
|
|
||||||
background: "black",
|
|
||||||
borderRadius: "6px",
|
|
||||||
margin: "16px",
|
|
||||||
},
|
|
||||||
onClick: function () {},
|
|
||||||
}).showToast();
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return locationButton;
|
return locationButton
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
const GoToTargetLocation = L.Control.extend({
|
const GoToTargetLocation = L.Control.extend({
|
||||||
onAdd: function (map: L.Map) {
|
onAdd: function (map: L.Map) {
|
||||||
const locationButton = document.createElement("button");
|
const locationButton = document.createElement("button")
|
||||||
|
|
||||||
locationButton.textContent = "Hedefe Git";
|
locationButton.textContent = "Hedefe Git"
|
||||||
|
|
||||||
locationButton.classList.add("custom-map-control-button");
|
locationButton.classList.add("custom-map-control-button")
|
||||||
|
|
||||||
locationButton.addEventListener("click", () => {
|
locationButton.addEventListener("click", () => {
|
||||||
if (TARGET_LOCATION) map.setView(TARGET_LOCATION, 12);
|
if (TARGET_LOCATION) map.setView(TARGET_LOCATION, 12)
|
||||||
});
|
})
|
||||||
|
|
||||||
return locationButton;
|
return locationButton
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
const goToCurrentLocationControl = new CurrentLocation({
|
const goToCurrentLocationControl = new CurrentLocation({
|
||||||
position: "bottomleft",
|
position: "bottomleft",
|
||||||
});
|
})
|
||||||
|
|
||||||
const targetLocationControl = new GoToTargetLocation({
|
const targetLocationControl = new GoToTargetLocation({
|
||||||
position: "bottomleft",
|
position: "bottomleft",
|
||||||
});
|
})
|
||||||
|
|
||||||
function addTargetLocationMarker(target: TargetLocation) {
|
function addTargetLocationMarker(target: TargetLocation) {
|
||||||
if (target) {
|
if (target) {
|
||||||
L.marker(target, { icon: targetLocationIcon }).addTo(map);
|
L.marker(target, { icon: targetLocationIcon }).addTo(map)
|
||||||
|
|
||||||
L.circle(target, {
|
L.circle(target, {
|
||||||
color: "blue",
|
color: "blue",
|
||||||
fillColor: "#30f",
|
fillColor: "#30f",
|
||||||
fillOpacity: 0.2,
|
fillOpacity: 0.2,
|
||||||
radius: 50,
|
radius: 50,
|
||||||
}).addTo(map);
|
}).addTo(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initLocationControls() {
|
function initLocationControls() {
|
||||||
targetLocationControl.addTo(map);
|
targetLocationControl.addTo(map)
|
||||||
goToCurrentLocationControl.addTo(map);
|
goToCurrentLocationControl.addTo(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
addTargetLocationMarker(TARGET_LOCATION);
|
addTargetLocationMarker(TARGET_LOCATION)
|
||||||
initLocationControls();
|
initLocationControls()
|
||||||
|
|
|
@ -1,119 +1,111 @@
|
||||||
import { onLocationError } from "@/lib/error";
|
import { onLocationError } from "@/lib/error"
|
||||||
|
import { toast } from "@/lib/utils"
|
||||||
|
|
||||||
var map = L.map('map').setView([41.024857599001905, 28.940787550837882], 10);
|
var map = L.map("map").setView([41.024857599001905, 28.940787550837882], 10)
|
||||||
|
|
||||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
attribution:
|
attribution:
|
||||||
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||||
}).addTo(map);
|
}).addTo(map)
|
||||||
|
|
||||||
let targetLocationMarker;
|
let targetLocationMarker
|
||||||
|
|
||||||
let targetLocationCircle;
|
let targetLocationCircle
|
||||||
|
|
||||||
var targetLocationIcon = L.icon({
|
var targetLocationIcon = L.icon({
|
||||||
iconUrl: 'goal.svg',
|
iconUrl: "goal.svg",
|
||||||
iconSize: [32, 32],
|
iconSize: [32, 32],
|
||||||
});
|
})
|
||||||
|
|
||||||
var currentLocationIcon = L.icon({
|
var currentLocationIcon = L.icon({
|
||||||
iconUrl: 'blue-dot.png',
|
iconUrl: "blue-dot.png",
|
||||||
iconSize: [32, 32],
|
iconSize: [32, 32],
|
||||||
});
|
})
|
||||||
|
|
||||||
let currentLocationMarker;
|
let currentLocationMarker
|
||||||
|
|
||||||
function startWatchingLocation() {
|
function startWatchingLocation() {
|
||||||
map.locate({ watch: true })
|
map.locate({ watch: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLocationSuccess(locationEvent) {
|
function onLocationSuccess(locationEvent) {
|
||||||
const position = locationEvent.latlng
|
const position = locationEvent.latlng
|
||||||
|
|
||||||
const currentPos = {
|
const currentPos = {
|
||||||
lat: position.lat,
|
lat: position.lat,
|
||||||
lng: position.lng
|
lng: position.lng,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentLocationMarker) {
|
if (currentLocationMarker) {
|
||||||
currentLocationMarker.setLatLng(currentPos);
|
currentLocationMarker.setLatLng(currentPos)
|
||||||
} else {
|
} else {
|
||||||
currentLocationMarker = L.marker(currentPos, { icon: currentLocationIcon });
|
currentLocationMarker = L.marker(currentPos, { icon: currentLocationIcon })
|
||||||
currentLocationMarker.addTo(map);
|
currentLocationMarker.addTo(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
map.on('locationerror', onLocationError);
|
map.on("locationerror", onLocationError)
|
||||||
|
|
||||||
map.on('locationfound', onLocationSuccess)
|
map.on("locationfound", onLocationSuccess)
|
||||||
|
|
||||||
L.Control.AskPermisson = L.Control.extend({
|
L.Control.AskPermisson = L.Control.extend({
|
||||||
onAdd: function (map) {
|
onAdd: function (map) {
|
||||||
const locationButton = document.createElement('button');
|
const locationButton = document.createElement("button")
|
||||||
|
|
||||||
locationButton.textContent = 'Konum İzni Ver';
|
locationButton.textContent = "Konum İzni Ver"
|
||||||
|
|
||||||
locationButton.classList.add('custom-map-control-button');
|
locationButton.classList.add("custom-map-control-button")
|
||||||
|
|
||||||
locationButton.type = 'button'
|
locationButton.type = "button"
|
||||||
|
|
||||||
locationButton.addEventListener('click', (ev) => {
|
locationButton.addEventListener("click", (ev) => {
|
||||||
if (locationButton.textContent != 'Konumuma Git') {
|
if (locationButton.textContent != "Konumuma Git") {
|
||||||
startWatchingLocation()
|
startWatchingLocation()
|
||||||
locationButton.textContent = 'Konumuma Git';
|
locationButton.textContent = "Konumuma Git"
|
||||||
} else {
|
} else {
|
||||||
if (currentLocationMarker) {
|
if (currentLocationMarker) {
|
||||||
map.setView(currentLocationMarker.getLatLng(), 12);
|
map.setView(currentLocationMarker.getLatLng(), 12)
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
toast(
|
||||||
Toastify({
|
"Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin."
|
||||||
text: 'Konum izni alınamadı, lütfen tarayıcınızın ve cihazınızın gizlilik ayarlarını kontrol edin.',
|
)
|
||||||
duration: 3000,
|
}
|
||||||
gravity: 'top', // `top` or `bottom`
|
}
|
||||||
position: 'center', // `left`, `center` or `right`
|
L.DomEvent.stopPropagation(ev)
|
||||||
stopOnFocus: true, // Prevents dismissing of toast on hover
|
})
|
||||||
style: {
|
|
||||||
background: 'black',
|
|
||||||
borderRadius: '6px',
|
|
||||||
margin: '16px',
|
|
||||||
},
|
|
||||||
onClick: function () { }, // Callback after click
|
|
||||||
}).showToast();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
return locationButton
|
||||||
L.DomEvent.stopPropagation(ev)
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
return locationButton;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
L.control.askPermission = function (opts) {
|
L.control.askPermission = function (opts) {
|
||||||
return new L.Control.AskPermisson(opts);
|
return new L.Control.AskPermisson(opts)
|
||||||
};
|
}
|
||||||
|
|
||||||
L.control.askPermission({ position: 'bottomleft' }).addTo(map);
|
L.control.askPermission({ position: "bottomleft" }).addTo(map)
|
||||||
|
|
||||||
|
map.on("click", (e) => {
|
||||||
|
if (targetLocationMarker) {
|
||||||
|
targetLocationMarker.setLatLng(e.latlng)
|
||||||
|
targetLocationCircle.setLatLng(e.latlng)
|
||||||
|
} else {
|
||||||
|
targetLocationMarker = L.marker(e.latlng, {
|
||||||
|
icon: targetLocationIcon,
|
||||||
|
}).addTo(map)
|
||||||
|
|
||||||
map.on('click', (e) => {
|
targetLocationCircle = L.circle(e.latlng, {
|
||||||
if (targetLocationMarker) {
|
color: "blue",
|
||||||
targetLocationMarker.setLatLng(e.latlng)
|
fillColor: "#30f",
|
||||||
targetLocationCircle.setLatLng(e.latlng)
|
fillOpacity: 0.2,
|
||||||
} else {
|
radius: 50,
|
||||||
targetLocationMarker = L.marker(e.latlng, { icon: targetLocationIcon }).addTo(map);
|
}).addTo(map)
|
||||||
|
}
|
||||||
|
|
||||||
targetLocationCircle = L.circle(e.latlng, {
|
const pos = targetLocationMarker.getLatLng()
|
||||||
color: 'blue',
|
document.getElementById("coordinates").innerText =
|
||||||
fillColor: '#30f',
|
`${pos.lat}. Enlem, ${pos.lng}. Boylam`
|
||||||
fillOpacity: 0.2,
|
document.getElementById("geolocation-input").value = `${pos.lat},${pos.lng}`
|
||||||
radius: 50
|
document.getElementById("location-selected-confirmation").innerText =
|
||||||
}).addTo(map);
|
"Konum seçildi, bir sonraki adıma geçebilirsiniz."
|
||||||
}
|
|
||||||
|
|
||||||
const pos = targetLocationMarker.getLatLng()
|
|
||||||
document.getElementById('coordinates').innerText = `${pos.lat}. Enlem, ${pos.lng}. Boylam`
|
|
||||||
document.getElementById('geolocation-input').value = `${pos.lat},${pos.lng}`
|
|
||||||
document.getElementById('location-selected-confirmation').innerText = "Konum seçildi, bir sonraki adıma geçebilirsiniz."
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,64 +1,66 @@
|
||||||
import {
|
import {
|
||||||
errorCallback,
|
errorCallback,
|
||||||
locationSuccessCallback,
|
locationSuccessCallback,
|
||||||
} from "@/components/LockedContent/geolocation";
|
} from "@/components/LockedContent/geolocation"
|
||||||
import type { LatLngTuple } from "leaflet";
|
import type { LatLngTuple } from "leaflet"
|
||||||
|
|
||||||
// Geolocation watch id to avoid duplicate watchPosition calls
|
// Geolocation watch id to avoid duplicate watchPosition calls
|
||||||
let watchId: number;
|
let watchId: number
|
||||||
|
|
||||||
// DOM ELEMENTS
|
// DOM ELEMENTS
|
||||||
const locationPermissionButton = document.getElementById(
|
const locationPermissionButton = document.getElementById(
|
||||||
"location-permission-button"
|
"location-permission-button"
|
||||||
);
|
)
|
||||||
|
|
||||||
const unlockButton = document.getElementById("unlock-content-button");
|
const unlockButton = document.getElementById("unlock-content-button")
|
||||||
|
|
||||||
const lockedContentContainer = document.getElementById(
|
const lockedContentContainer = document.getElementById(
|
||||||
"locked-content-container"
|
"locked-content-container"
|
||||||
);
|
)
|
||||||
|
|
||||||
// These elements MUST be defined
|
// These elements MUST be defined
|
||||||
// Throw error if they are not found
|
// Throw error if they are not found
|
||||||
if (!locationPermissionButton || !lockedContentContainer || !unlockButton) {
|
if (!locationPermissionButton || !lockedContentContainer || !unlockButton) {
|
||||||
throw new Error("Element not found!");
|
throw new Error("Element not found!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// EVENT LISTENERS
|
// EVENT LISTENERS
|
||||||
locationPermissionButton.addEventListener("click", startWatchingLocation);
|
locationPermissionButton.addEventListener("click", startWatchingLocation)
|
||||||
|
|
||||||
lockedContentContainer.addEventListener("askpermission", startWatchingLocation);
|
lockedContentContainer.addEventListener("askpermission", startWatchingLocation)
|
||||||
|
|
||||||
const targetPositionString = lockedContentContainer.dataset.targetPosition;
|
const targetPositionString = lockedContentContainer.dataset.targetPosition
|
||||||
|
|
||||||
// TARGET_POSITION is required to calculate distance
|
// TARGET_POSITION is required to calculate distance
|
||||||
if (!targetPositionString) throw new Error("Target position is not provided!");
|
if (!targetPositionString) throw new Error("Target position is not provided!")
|
||||||
|
|
||||||
const TARGET_POSITION = JSON.parse(targetPositionString) as LatLngTuple;
|
const TARGET_POSITION = JSON.parse(targetPositionString) as LatLngTuple
|
||||||
|
|
||||||
// Call Geolocation API to start watching user location
|
// Call Geolocation API to start watching user location
|
||||||
function startWatchingLocation() {
|
function startWatchingLocation() {
|
||||||
if (!watchId) {
|
if (!watchId) {
|
||||||
watchId = window.navigator.geolocation.watchPosition(
|
watchId = window.navigator.geolocation.watchPosition(
|
||||||
position => locationSuccessCallback(position, TARGET_POSITION),
|
(position) => locationSuccessCallback(position, TARGET_POSITION),
|
||||||
errorCallback
|
errorCallback
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the web page is loaded, check if user has given geolocation
|
// When the web page is loaded, check if user has given geolocation
|
||||||
// permission before
|
// permission before
|
||||||
navigator.permissions.query({ name: "geolocation" }).then(permissionStatus => {
|
navigator.permissions
|
||||||
switch (permissionStatus.state) {
|
.query({ name: "geolocation" })
|
||||||
case "granted":
|
.then((permissionStatus) => {
|
||||||
watchId = window.navigator.geolocation.watchPosition(
|
switch (permissionStatus.state) {
|
||||||
position => locationSuccessCallback(position, TARGET_POSITION),
|
case "granted":
|
||||||
errorCallback
|
watchId = window.navigator.geolocation.watchPosition(
|
||||||
);
|
(position) => locationSuccessCallback(position, TARGET_POSITION),
|
||||||
break;
|
errorCallback
|
||||||
case "denied":
|
)
|
||||||
case "prompt":
|
break
|
||||||
default:
|
case "denied":
|
||||||
break;
|
case "prompt":
|
||||||
}
|
default:
|
||||||
});
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
|
@ -1,21 +1,26 @@
|
||||||
export default function distance(lat1, lon1, lat2, lon2, unit = 'K') {
|
export default function distance(lat1, lon1, lat2, lon2, unit = "K") {
|
||||||
if ((lat1 == lat2) && (lon1 == lon2)) {
|
if (lat1 == lat2 && lon1 == lon2) {
|
||||||
return 0;
|
return 0
|
||||||
|
} else {
|
||||||
|
var radlat1 = (Math.PI * lat1) / 180
|
||||||
|
var radlat2 = (Math.PI * lat2) / 180
|
||||||
|
var theta = lon1 - lon2
|
||||||
|
var radtheta = (Math.PI * theta) / 180
|
||||||
|
var dist =
|
||||||
|
Math.sin(radlat1) * Math.sin(radlat2) +
|
||||||
|
Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta)
|
||||||
|
if (dist > 1) {
|
||||||
|
dist = 1
|
||||||
}
|
}
|
||||||
else {
|
dist = Math.acos(dist)
|
||||||
var radlat1 = Math.PI * lat1 / 180;
|
dist = (dist * 180) / Math.PI
|
||||||
var radlat2 = Math.PI * lat2 / 180;
|
dist = dist * 60 * 1.1515
|
||||||
var theta = lon1 - lon2;
|
if (unit == "K") {
|
||||||
var radtheta = Math.PI * theta / 180;
|
dist = dist * 1.609344
|
||||||
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
|
|
||||||
if (dist > 1) {
|
|
||||||
dist = 1;
|
|
||||||
}
|
|
||||||
dist = Math.acos(dist);
|
|
||||||
dist = dist * 180 / Math.PI;
|
|
||||||
dist = dist * 60 * 1.1515;
|
|
||||||
if (unit == "K") { dist = dist * 1.609344 }
|
|
||||||
if (unit == "N") { dist = dist * 0.8684 }
|
|
||||||
return dist;
|
|
||||||
}
|
}
|
||||||
|
if (unit == "N") {
|
||||||
|
dist = dist * 0.8684
|
||||||
|
}
|
||||||
|
return dist
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user