refactor: replace shadui components with standard html elements
feat: add new unlock button web component
This commit is contained in:
parent
296083577a
commit
68750ad964
|
@ -2,7 +2,7 @@ import { defineConfig } from 'astro/config';
|
||||||
import react from "@astrojs/react";
|
import react from "@astrojs/react";
|
||||||
import tailwind from "@astrojs/tailwind";
|
import tailwind from "@astrojs/tailwind";
|
||||||
|
|
||||||
import vercel from "@astrojs/vercel/serverless";
|
import node from "@astrojs/node";
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
@ -10,5 +10,7 @@ export default defineConfig({
|
||||||
applyBaseStyles: false
|
applyBaseStyles: false
|
||||||
})],
|
})],
|
||||||
output: "server",
|
output: "server",
|
||||||
adapter: vercel()
|
adapter: node({
|
||||||
|
mode: "standalone"
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/check": "^0.4.1",
|
"@astrojs/check": "^0.4.1",
|
||||||
|
"@astrojs/node": "^8.3.2",
|
||||||
"@astrojs/react": "^3.0.9",
|
"@astrojs/react": "^3.0.9",
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.0",
|
||||||
"@astrojs/vercel": "^7.3.1",
|
"@astrojs/vercel": "^7.3.1",
|
||||||
|
@ -19,12 +20,8 @@
|
||||||
"@radix-ui/react-label": "^2.0.2",
|
"@radix-ui/react-label": "^2.0.2",
|
||||||
"@radix-ui/react-separator": "^1.0.3",
|
"@radix-ui/react-separator": "^1.0.3",
|
||||||
"@radix-ui/react-slot": "^1.0.2",
|
"@radix-ui/react-slot": "^1.0.2",
|
||||||
"@supabase/supabase-js": "^2.39.7",
|
|
||||||
"@types/react": "^18.2.47",
|
"@types/react": "^18.2.47",
|
||||||
"@types/react-dom": "^18.2.18",
|
"@types/react-dom": "^18.2.18",
|
||||||
"@vercel/blob": "^0.19.0",
|
|
||||||
"@vercel/postgres-kysely": "^0.7.1",
|
|
||||||
"@vercel/speed-insights": "^1.0.9",
|
|
||||||
"astro": "^4.1.2",
|
"astro": "^4.1.2",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.0",
|
"clsx": "^2.1.0",
|
||||||
|
|
1276
public/css/tailwind.css
Normal file
1276
public/css/tailwind.css
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -95,6 +95,7 @@ const LocationButton = ({
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<div className="w-full h-[475px] overflow-hidden border border-zinc-200 shadow-sm p-4 rounded">
|
<div className="w-full h-[475px] overflow-hidden border border-zinc-200 shadow-sm p-4 rounded">
|
||||||
{atTarget ? (
|
{atTarget ? (
|
||||||
<div className="flex flex-col justify-center items-center image-wrapper">
|
<div className="flex flex-col justify-center items-center image-wrapper">
|
||||||
|
@ -128,7 +129,9 @@ const LocationButton = ({
|
||||||
{hasPermission ? (
|
{hasPermission ? (
|
||||||
<CardContent className="pb-0 text-center">
|
<CardContent className="pb-0 text-center">
|
||||||
<p>İçeriği görmek için konuma gitmelisin!</p>
|
<p>İçeriği görmek için konuma gitmelisin!</p>
|
||||||
<p>{distanceRemain && `Kalan mesafe: ${distanceRemain}`}</p>
|
<p>
|
||||||
|
{distanceRemain && `Kalan mesafe: ${distanceRemain}`}
|
||||||
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
|
@ -150,6 +153,7 @@ const LocationButton = ({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
94
src/components/WebComponentWrapper.astro
Normal file
94
src/components/WebComponentWrapper.astro
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
contentId?: string;
|
||||||
|
imageUrl: string;
|
||||||
|
location?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { contentId = "", imageUrl = "#", location = "" } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<template id="locked-content-template">
|
||||||
|
<link rel="stylesheet" href="css/tailwind.css" />
|
||||||
|
<style>
|
||||||
|
.image-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
/* center overlay text */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
inset: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div
|
||||||
|
class="w-full h-[475px] overflow-hidden border border-zinc-200 shadow-sm p-4 rounded"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col justify-center items-center image-wrapper">
|
||||||
|
<img src={imageUrl} class="blur-2xl h-[450px]" />
|
||||||
|
|
||||||
|
<div class="flex flex-col justify-center gap-4 overlay">
|
||||||
|
<button
|
||||||
|
id="unlock-content-button"
|
||||||
|
class="inline-flex items-center justify-center whitespace-nowrap font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 text-primary-foreground h-11 rounded-md text-lg p-6 animate-pulse bg-indigo-600 hover:bg-indigo-700 hover:animate-none border-2 border-indigo-800"
|
||||||
|
>
|
||||||
|
İçeriğin Kilidi Açıldı
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="rounded-lg border bg-card text-card-foreground shadow-sm p-2"
|
||||||
|
>
|
||||||
|
<div class="pb-0 text-center">İçeriği görmek için butona bas!</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<locked-content contentId={contentId}></locked-content>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
customElements.define(
|
||||||
|
"locked-content",
|
||||||
|
class extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
// Clone the template
|
||||||
|
let template = document.getElementById(
|
||||||
|
"locked-content-template"
|
||||||
|
) as HTMLTemplateElement;
|
||||||
|
let templateContent = template.content;
|
||||||
|
|
||||||
|
// Get attributes
|
||||||
|
const contentId = this.getAttribute("contentId");
|
||||||
|
|
||||||
|
// Attach cloned template to DOM
|
||||||
|
const shadowRoot = this.attachShadow({ mode: "open" });
|
||||||
|
shadowRoot.appendChild(templateContent.cloneNode(true));
|
||||||
|
|
||||||
|
// Add onclick listener to unlock content button
|
||||||
|
const unlockContentButton = shadowRoot.getElementById(
|
||||||
|
"unlock-content-button"
|
||||||
|
);
|
||||||
|
const incrementCounter = async (id: string) =>
|
||||||
|
await fetch(`http://localhost:3000/api/location/increment/${id}`, {
|
||||||
|
method: "PATCH",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (unlockContentButton) {
|
||||||
|
unlockContentButton.addEventListener("click", () => {
|
||||||
|
if (contentId) {
|
||||||
|
incrementCounter(contentId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
|
@ -1,7 +1,3 @@
|
||||||
---
|
|
||||||
import SpeedInsights from '@vercel/speed-insights/astro';
|
|
||||||
---
|
|
||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@ -41,7 +37,6 @@ import SpeedInsights from '@vercel/speed-insights/astro';
|
||||||
</head>
|
</head>
|
||||||
<body class="container my-8">
|
<body class="container my-8">
|
||||||
<slot />
|
<slot />
|
||||||
<SpeedInsights />
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
<style is:global></style>
|
<style is:global></style>
|
||||||
|
|
|
@ -1,35 +1,34 @@
|
||||||
---
|
---
|
||||||
import '@/styles/globals.css';
|
import "@/styles/globals.css";
|
||||||
import '../styles/locked-page.css';
|
import "../styles/locked-page.css";
|
||||||
|
|
||||||
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 LockedContent from "@/components/LockedContent";
|
||||||
import LockedContent from '@/components/LockedContent';
|
import WebComponentWrapper from "@/components/WebComponentWrapper.astro";
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { CalendarIcon } from "@radix-ui/react-icons";
|
||||||
import type { ContentTable } from '@/lib/db';
|
import { Separator } from "@/components/ui/separator";
|
||||||
import dayjs from 'dayjs';
|
import type { ContentTable } from "@/lib/db";
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
import dayjs from "dayjs";
|
||||||
import utc from 'dayjs/plugin/utc';
|
import relativeTime from "dayjs/plugin/relativeTime";
|
||||||
|
import utc from "dayjs/plugin/utc";
|
||||||
|
|
||||||
type Content = ContentTable;
|
type Content = ContentTable;
|
||||||
|
|
||||||
const { id } = Astro.params;
|
const { id } = Astro.params;
|
||||||
|
|
||||||
const res = await fetch(
|
const res = await fetch(`http://localhost:3000/api/location/${id}`);
|
||||||
`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;
|
||||||
|
|
||||||
console.log(data)
|
console.log(data);
|
||||||
|
|
||||||
dayjs.extend(relativeTime);
|
dayjs.extend(relativeTime);
|
||||||
|
|
||||||
|
@ -68,7 +67,6 @@ const dateFromNow = dayjs.utc(data?.created_at).from(dayjs.utc());
|
||||||
<p>{dateFromNow}</p>
|
<p>{dateFromNow}</p>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<LockedContent
|
<LockedContent
|
||||||
contentId={data?.url}
|
contentId={data?.url}
|
||||||
imageUrl={`http://localhost:3000/images/${data?.blob_url}`}
|
imageUrl={`http://localhost:3000/images/${data?.blob_url}`}
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
---
|
---
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
|
||||||
import '@/styles/globals.css';
|
import "@/styles/globals.css";
|
||||||
import Layout from '../layouts/Layout.astro';
|
import "../styles/locked-page.css";
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
|
|
||||||
import '../styles/locked-page.css';
|
import Layout from "../layouts/Layout.astro";
|
||||||
import { Input } from '@/components/ui/input';
|
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
|
||||||
import { ReloadIcon } from '@radix-ui/react-icons';
|
|
||||||
import { Label } from '@/components/ui/label';
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
|
@ -44,13 +39,14 @@ import { Label } from '@/components/ui/label';
|
||||||
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"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<p class="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>
|
||||||
|
@ -101,31 +97,27 @@ import { Label } from '@/components/ui/label';
|
||||||
</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 htmlFor="location-author" className="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."
|
||||||
className="lg:text-lg text-md"
|
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
|
<label for="location-description" class="lg:text-lg text-md">
|
||||||
htmlFor="location-description"
|
|
||||||
className="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"
|
||||||
className="lg:text-lg text-md"
|
class="lg:text-lg text-md py-2 px-3 border border-gray rounded-lg placeholder:text-slate-400 resize-none"
|
||||||
required
|
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.
|
||||||
|
@ -134,26 +126,21 @@ import { Label } from '@/components/ui/label';
|
||||||
</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
|
||||||
htmlFor="kvkk"
|
for="kvkk"
|
||||||
className="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
|
||||||
className="w-full text-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"
|
||||||
size="lg"
|
|
||||||
>
|
>
|
||||||
<ReloadIcon
|
|
||||||
className="mr-2 h-4 w-4 animate-spin hidden"
|
|
||||||
id="submit-button-reload"
|
|
||||||
/>
|
|
||||||
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>
|
||||||
|
@ -164,67 +151,62 @@ import { Label } from '@/components/ui/label';
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const locationSelected = document.getElementById(
|
const locationSelected = document.getElementById(
|
||||||
'location-selected-confirmation'
|
"location-selected-confirmation"
|
||||||
)?.innerText;
|
)?.innerText;
|
||||||
|
|
||||||
if (!locationSelected) {
|
if (!locationSelected) {
|
||||||
const coordinatesText = document.getElementById('coordinates');
|
const coordinatesText = document.getElementById("coordinates");
|
||||||
|
|
||||||
const mapDiv = document.getElementById('map');
|
const mapDiv = document.getElementById("map");
|
||||||
|
|
||||||
mapDiv?.classList.add('border-slate-700');
|
mapDiv?.classList.add("border-slate-700");
|
||||||
coordinatesText?.classList.add('drop-shadow-xl');
|
coordinatesText?.classList.add("drop-shadow-xl");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mapDiv?.classList.remove('border-slate-700');
|
mapDiv?.classList.remove("border-slate-700");
|
||||||
coordinatesText?.classList.remove('drop-shadow-xl');
|
coordinatesText?.classList.remove("drop-shadow-xl");
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const submitButton = document.getElementById(
|
const submitButton = document.getElementById(
|
||||||
'submit-button'
|
"submit-button"
|
||||||
) as HTMLButtonElement;
|
) as HTMLButtonElement;
|
||||||
const reloadIcon = document.getElementById(
|
|
||||||
'submit-button-reload'
|
|
||||||
) as HTMLElement;
|
|
||||||
|
|
||||||
submitButton.disabled = true;
|
submitButton.disabled = true;
|
||||||
reloadIcon.classList.toggle('hidden');
|
|
||||||
|
|
||||||
const formData = new FormData(e.target as HTMLFormElement);
|
const formData = new FormData(e.target as HTMLFormElement);
|
||||||
|
|
||||||
const res = await fetch(`http://127.0.0.1:3000/api/location`, {
|
const res = await fetch(`http://127.0.0.1:3000/api/location`, {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: formData,
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
reloadIcon.classList.toggle('hidden');
|
|
||||||
submitButton.disabled = false;
|
submitButton.disabled = false;
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
|
||||||
if (data.url) location.assign('/' + data.url);
|
if (data.url) location.assign("/" + data.url);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
Toastify({
|
Toastify({
|
||||||
text: 'Konulu konum oluşturulamadı, lütfen tekrar deneyin.',
|
text: "Konulu konum oluşturulamadı, lütfen tekrar deneyin.",
|
||||||
duration: 3000,
|
duration: 3000,
|
||||||
gravity: 'top', // `top` or `bottom`
|
gravity: "top", // `top` or `bottom`
|
||||||
position: 'center', // `left`, `center` or `right`
|
position: "center", // `left`, `center` or `right`
|
||||||
stopOnFocus: true, // Prevents dismissing of toast on hover
|
stopOnFocus: true, // Prevents dismissing of toast on hover
|
||||||
style: {
|
style: {
|
||||||
background: 'black',
|
background: "black",
|
||||||
borderRadius: '6px',
|
borderRadius: "6px",
|
||||||
margin: '16px',
|
margin: "16px",
|
||||||
},
|
},
|
||||||
onClick: function () {}, // Callback after click
|
onClick: function () {}, // Callback after click
|
||||||
}).showToast();
|
}).showToast();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('sample-form')!.onsubmit = handleSubmit;
|
document.getElementById("sample-form")!.onsubmit = handleSubmit;
|
||||||
</script>
|
</script>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user