diff --git a/astro.config.mjs b/astro.config.mjs index f720a2b..a9a66ad 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -9,6 +9,6 @@ export default defineConfig({ integrations: [react(), tailwind({ applyBaseStyles: false })], - output: "hybrid", + output: "server", adapter: vercel() }); diff --git a/package-lock.json b/package-lock.json index cb61019..c5527ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "clsx": "^2.1.0", "kysely": "^0.26.0", "lucide-react": "^0.309.0", + "nanoid": "^5.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^2.2.0", @@ -5003,9 +5004,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.4.tgz", + "integrity": "sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==", "funding": [ { "type": "github", @@ -5013,10 +5014,10 @@ } ], "bin": { - "nanoid": "bin/nanoid.cjs" + "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^18 || >=20" } }, "node_modules/napi-build-utils": { @@ -5689,6 +5690,23 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", diff --git a/package.json b/package.json index 58a6eee..7d5e4af 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "clsx": "^2.1.0", "kysely": "^0.26.0", "lucide-react": "^0.309.0", + "nanoid": "^5.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^2.2.0", diff --git a/src/components/LockedContent.tsx b/src/components/LockedContent.tsx index 2ac74e7..0367776 100644 --- a/src/components/LockedContent.tsx +++ b/src/components/LockedContent.tsx @@ -7,7 +7,7 @@ import { useEffect, useState } from "react" import "../styles/locked-content.css" -const LocationButton = () => { +const LocationButton = ({ imageUrl = "#" }: { imageUrl?: string }) => { const [atTarget, setAtTarget] = useState(false) const [contentVisible, setContentVisible] = useState(false) const [hasPermission, setHasPermission] = useState(false) @@ -47,48 +47,56 @@ const LocationButton = () => { }, []) if (contentVisible) { - return
+ return ( +
+ +
+ ) } else { return ( -
+
{atTarget ? ( -
-
+
+ + +
-
- - İçeriği görmek için butona bas! - + + İçeriği görmek için butona bas! + +
) : ( -
- +
+ +
+ + + {hasPermission ? ( + İçeriği görmek için konuma gitmelisin! + ) : ( +
+ + Ne kadar yaklaştığını görmek için aşağıdaki butona bas. + - - {hasPermission ? ( - İçeriği görmek için konuma gitmelisin! - ) : ( -
- - Ne kadar yaklaştığını görmek için aşağıdaki butona bas. - - - -
- )} -
+ +
+ )} +
+
)}
diff --git a/src/lib/db.ts b/src/lib/db.ts new file mode 100644 index 0000000..c1e7bc9 --- /dev/null +++ b/src/lib/db.ts @@ -0,0 +1,13 @@ +import type { Generated } from "kysely" + +export interface Database { + contents: ContentTable +} + +export interface ContentTable { + id: Generated + url: string + blob_url: string + loc: string + description: string +} diff --git a/src/pages/index.astro b/src/pages/[id].astro similarity index 80% rename from src/pages/index.astro rename to src/pages/[id].astro index 00e8990..2592407 100644 --- a/src/pages/index.astro +++ b/src/pages/[id].astro @@ -15,6 +15,14 @@ import { CalendarIcon } from '@radix-ui/react-icons'; import '../styles/locked-page.css'; import LockedContent from '@/components/LockedContent'; import { Separator } from '@/components/ui/separator'; + +const { id } = Astro.params; + +const res = await fetch(`http://localhost:4321/api/content?id=${id}`); + +const data = await res.json(); + +console.log(data); --- @@ -39,10 +47,7 @@ import { Separator } from '@/components/ui/separator'; Abdurrahman -

- Hacı sana çok özel bir sürpriz hazırladık, aşağıdaki konuma muhakak - git. -

+

{data.description}

@@ -50,9 +55,14 @@ import { Separator } from '@/components/ui/separator'; - + -
+
+
diff --git a/src/pages/create-url.ts b/src/pages/api/content.ts similarity index 54% rename from src/pages/create-url.ts rename to src/pages/api/content.ts index 759f0dc..e633ec5 100644 --- a/src/pages/create-url.ts +++ b/src/pages/api/content.ts @@ -1,20 +1,9 @@ -export const prerender = false - import { put } from "@vercel/blob" -import type { Generated } from "kysely" import type { APIRoute } from "astro" import { createKysely } from "@vercel/postgres-kysely" +import { customAlphabet } from "nanoid" -interface ContentTable { - id: Generated - blob_url: string - loc: string - description: string -} - -interface Database { - contents: ContentTable -} +import type { Database } from "../../lib/db" export const POST: APIRoute = async ({ request }) => { const data = await request.formData() @@ -43,9 +32,14 @@ export const POST: APIRoute = async ({ request }) => { const db = createKysely({ connectionString: import.meta.env.POSTGRES_URL }) + const nanoid = customAlphabet("abcdefghijklmnoprstuvyz", 10) + + const newUrl = nanoid() + const res = await db .insertInto("contents") .values({ + url: `${newUrl.slice(0, 3)}-${newUrl.slice(3, 7)}-${newUrl.slice(7)}`, blob_url: blob.url, description: description?.toString() ?? "", loc: `SRID=4326;POINT(${pos[0]} ${pos[1]})` @@ -66,3 +60,39 @@ export const POST: APIRoute = async ({ request }) => { }) } } + +export const GET: APIRoute = async ({ request }) => { + const contentId = new URL(request.url).searchParams.get("id") + + if (!contentId) { + return new Response(null, { + status: 400, + statusText: "Content id is required" + }) + } + + const db = createKysely({ connectionString: import.meta.env.POSTGRES_URL }) + + try { + const content = await db + .selectFrom("contents") + .select(({ fn }) => ["blob_url", fn("ST_AsGeoJSON", ["loc"]).as("loc"), "description"]) + .where("url", "=", contentId) + .executeTakeFirst() + + if (content) { + return new Response(JSON.stringify(content)) + } else { + return new Response(null, { + status: 404, + statusText: "Content not found" + }) + } + } catch (error) { + console.error("Error fetching content:", error) + return new Response(null, { + status: 500, + statusText: "Error while fetching content" + }) + } +} diff --git a/src/pages/create.astro b/src/pages/create.astro index e92bf60..52a2894 100644 --- a/src/pages/create.astro +++ b/src/pages/create.astro @@ -1,4 +1,6 @@ --- +export const prerender = true; + import '@/styles/globals.css'; import Layout from '../layouts/Layout.astro'; import { Button } from '@/components/ui/button'; @@ -109,7 +111,7 @@ import { Textarea } from '@/components/ui/textarea'; const formData = new FormData(e.target as HTMLFormElement); - const response = await fetch(`/create-url`, { + const response = await fetch(`/api/content`, { method: 'POST', body: formData, }); diff --git a/src/scripts/initMap.js b/src/scripts/initMap.js index 0f2aa29..0642a0c 100644 --- a/src/scripts/initMap.js +++ b/src/scripts/initMap.js @@ -1,4 +1,6 @@ -const TARGET_LOCATION = [41.01907795861253, 29.01715377829709]; +const data = JSON.parse(document.getElementById('map').dataset.targetLocation) + +const TARGET_LOCATION = data.coordinates var map = L.map('map').setView(TARGET_LOCATION, 13); diff --git a/src/styles/locked-content.css b/src/styles/locked-content.css index bb3a8b9..ab9bd43 100644 --- a/src/styles/locked-content.css +++ b/src/styles/locked-content.css @@ -1,42 +1,14 @@ -.module { - display: grid; - place-items: center; +.image-wrapper { position: relative; - overflow: hidden; } -.module-unlocked { - display: grid; - place-items: center; - position: relative; - overflow: hidden; -} - -.module::before { - content: ""; - top: 0; - left: 0; - width: 100%; - height: 100%; +.overlay { position: absolute; - background-image: url("/sample-selfie.webp"); - background-position: center; - background-repeat: no-repeat; - filter: blur(20px); -} -.module-unlocked::before { - content: ""; - top: 0; - left: 0; - width: 100%; - height: 100%; - position: absolute; - background-image: url("/sample-selfie.webp"); - background-position: center; - background-repeat: no-repeat; -} + /* center overlay text */ + display: flex; + align-items: center; + justify-content: center; -.module-inside { - position: relative; + inset: 0; }