chore: remove unnecessary packages

style: run prettier
This commit is contained in:
log101 2024-07-27 14:25:28 +03:00
parent 86cc813977
commit 9c74cc7263
19 changed files with 350 additions and 542 deletions

View File

@ -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",

View File

@ -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).

BIN
bun.lockb

Binary file not shown.

View File

@ -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",

View File

@ -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>&rarr;</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>

View File

@ -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,
}; }

View File

@ -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,
}; }

View File

@ -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 }

View File

@ -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
View File

@ -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
} }
} }
} }

View File

@ -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
} }

View File

@ -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()
}

View File

@ -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()
} }

View File

@ -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>

View File

@ -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'>
ıklama ı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();
} }
}; };

View File

@ -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:
'&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', '&copy; <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()

View File

@ -1,28 +1,29 @@
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:
'&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', '&copy; <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 })
@ -33,87 +34,78 @@ function onLocationSuccess(locationEvent) {
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`
stopOnFocus: true, // Prevents dismissing of toast on hover
style: {
background: 'black',
borderRadius: '6px',
margin: '16px',
},
onClick: function () { }, // Callback after click
}).showToast();
} }
} }
L.DomEvent.stopPropagation(ev) L.DomEvent.stopPropagation(ev)
}) })
return locationButton; 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) => {
map.on('click', (e) => {
if (targetLocationMarker) { if (targetLocationMarker) {
targetLocationMarker.setLatLng(e.latlng) targetLocationMarker.setLatLng(e.latlng)
targetLocationCircle.setLatLng(e.latlng) targetLocationCircle.setLatLng(e.latlng)
} else { } else {
targetLocationMarker = L.marker(e.latlng, { icon: targetLocationIcon }).addTo(map); targetLocationMarker = L.marker(e.latlng, {
icon: targetLocationIcon,
}).addTo(map)
targetLocationCircle = L.circle(e.latlng, { targetLocationCircle = L.circle(e.latlng, {
color: 'blue', color: "blue",
fillColor: '#30f', fillColor: "#30f",
fillOpacity: 0.2, fillOpacity: 0.2,
radius: 50 radius: 50,
}).addTo(map); }).addTo(map)
} }
const pos = targetLocationMarker.getLatLng() const pos = targetLocationMarker.getLatLng()
document.getElementById('coordinates').innerText = `${pos.lat}. Enlem, ${pos.lng}. Boylam` document.getElementById("coordinates").innerText =
document.getElementById('geolocation-input').value = `${pos.lat},${pos.lng}` `${pos.lat}. Enlem, ${pos.lng}. Boylam`
document.getElementById('location-selected-confirmation').innerText = "Konum seçildi, bir sonraki adıma geçebilirsiniz." document.getElementById("geolocation-input").value = `${pos.lat},${pos.lng}`
document.getElementById("location-selected-confirmation").innerText =
"Konum seçildi, bir sonraki adıma geçebilirsiniz."
}) })

View File

@ -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
.query({ name: "geolocation" })
.then((permissionStatus) => {
switch (permissionStatus.state) { switch (permissionStatus.state) {
case "granted": case "granted":
watchId = window.navigator.geolocation.watchPosition( watchId = window.navigator.geolocation.watchPosition(
position => locationSuccessCallback(position, TARGET_POSITION), (position) => locationSuccessCallback(position, TARGET_POSITION),
errorCallback errorCallback
); )
break; break
case "denied": case "denied":
case "prompt": case "prompt":
default: default:
break; break
} }
}); })

View File

@ -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 {
else { var radlat1 = (Math.PI * lat1) / 180
var radlat1 = Math.PI * lat1 / 180; var radlat2 = (Math.PI * lat2) / 180
var radlat2 = Math.PI * lat2 / 180; var theta = lon1 - lon2
var theta = lon1 - lon2; var radtheta = (Math.PI * theta) / 180
var radtheta = Math.PI * theta / 180; var dist =
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta); Math.sin(radlat1) * Math.sin(radlat2) +
Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta)
if (dist > 1) { if (dist > 1) {
dist = 1; dist = 1
} }
dist = Math.acos(dist); dist = Math.acos(dist)
dist = dist * 180 / Math.PI; dist = (dist * 180) / Math.PI
dist = dist * 60 * 1.1515; dist = dist * 60 * 1.1515
if (unit == "K") { dist = dist * 1.609344 } if (unit == "K") {
if (unit == "N") { dist = dist * 0.8684 } dist = dist * 1.609344
return dist; }
if (unit == "N") {
dist = dist * 0.8684
}
return dist
} }
} }