You've already forked Atomcms-edit
e6d92f27b3
- Rename all .js/.jsx files to .ts/.tsx across resources/js and theme dirs - Add TypeScript 6.0 with strict mode, tsconfig.json - Add type definitions for Inertia page props, Alpine.js, Turbolinks - Update vite.config.js entries to .ts/.tsx extensions - Update all Blade @vite() calls to match new .ts/.tsx entry points - Add TypeScript ESLint config (replacing unused Vue plugin) - Add @types/react, @types/react-dom, @types/lodash - Add typecheck script and integrate into check pipeline - Full tsc --noEmit, ESLint, and production build pass cleanly
207 lines
8.7 KiB
TypeScript
Executable File
207 lines
8.7 KiB
TypeScript
Executable File
import { Head, usePage } from "@inertiajs/react";
|
|
|
|
interface User {
|
|
look: string;
|
|
username: string;
|
|
}
|
|
|
|
interface Article {
|
|
id: number;
|
|
slug: string;
|
|
title: string;
|
|
image: string;
|
|
user?: User;
|
|
}
|
|
|
|
interface Photo {
|
|
id: number;
|
|
url: string;
|
|
user?: User;
|
|
}
|
|
|
|
interface IndexProps {
|
|
articles: Article[];
|
|
photos: Photo[];
|
|
}
|
|
|
|
interface SharedProps extends Record<string, unknown> {
|
|
avatarImager: string;
|
|
}
|
|
|
|
export default function Index({ articles, photos }: IndexProps) {
|
|
const { avatarImager } = usePage<SharedProps>().props;
|
|
|
|
return (
|
|
<>
|
|
<Head title="Welkom" />
|
|
|
|
<div className="col-span-12 space-y-14">
|
|
<div className="col-span-12">
|
|
<div className="flex w-full flex-col gap-y-4 overflow-hidden rounded-lg p-3">
|
|
<div className="flex gap-x-2">
|
|
<div className="hotel-icon relative flex min-h-[50px] min-w-[50px] max-w-[50px] items-center justify-center rounded-full" />
|
|
<div className="flex flex-col">
|
|
<p className="font-semibold text-black dark:text-gray-200">
|
|
Laatste nieuws
|
|
</p>
|
|
<p className="dark:text-gray-500">
|
|
Blijf op de hoogte van het laatste hotel nieuws.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
|
|
{articles.length > 0
|
|
? articles.map((article) => (
|
|
<a
|
|
key={article.id}
|
|
href={`/community/article/${article.slug}`}
|
|
className="group relative block h-[210px] w-full overflow-hidden rounded shadow-sm transition-all duration-200 ease-in-out hover:scale-[101%]"
|
|
style={{ backgroundColor: "var(--color-surface)" }}
|
|
onMouseEnter={(e) => {
|
|
const el = e.currentTarget.querySelector(
|
|
".article-img-inner",
|
|
);
|
|
if (el) el.classList.add("article-image-slide");
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
const el = e.currentTarget.querySelector(
|
|
".article-img-inner",
|
|
);
|
|
if (el) el.classList.remove("article-image-slide");
|
|
}}
|
|
>
|
|
<div
|
|
className="article-img-inner h-[100px] w-full bg-cover bg-center transition-[background-position] duration-300"
|
|
style={{
|
|
backgroundImage: `url('/storage/${article.image}')`,
|
|
backgroundPosition: "300px 220px",
|
|
}}
|
|
/>
|
|
<div className="px-3 md:px-4">
|
|
<p className="truncate text-base font-semibold md:text-lg dark:text-gray-200">
|
|
{article.title}
|
|
</p>
|
|
<div className="flex items-center gap-x-2">
|
|
{article.user && (
|
|
<>
|
|
<div
|
|
className="mt-2 flex h-8 w-8 items-center justify-center overflow-hidden rounded-full md:mt-3 md:h-10 md:w-10"
|
|
style={{
|
|
backgroundColor: "var(--color-background)",
|
|
}}
|
|
>
|
|
<img
|
|
src={`${avatarImager}${article.user.look}&headonly=1`}
|
|
alt=""
|
|
className="h-full w-full object-cover"
|
|
/>
|
|
</div>
|
|
<p
|
|
className="mt-2 text-sm font-semibold md:mt-4 md:text-base"
|
|
style={{
|
|
color: "var(--color-text-muted)",
|
|
}}
|
|
>
|
|
{article.user.username}
|
|
</p>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</a>
|
|
))
|
|
: [1, 2, 3, 4].map((i) => (
|
|
<div
|
|
key={i}
|
|
className="h-[210px] w-full overflow-hidden rounded bg-white shadow-sm dark:bg-gray-900"
|
|
>
|
|
<div
|
|
className="article-image"
|
|
style={{
|
|
background:
|
|
"url('https://i.imgur.com/uGLDOUu.png')",
|
|
}}
|
|
/>
|
|
<div className="mt-4 px-4">
|
|
<p className="truncate text-lg font-semibold dark:text-gray-200">
|
|
Geen artikelen
|
|
</p>
|
|
<div className="flex items-center gap-x-2">
|
|
<div className="mt-3 flex h-10 w-10 items-center justify-center overflow-hidden rounded-full bg-gray-100 dark:bg-gray-800">
|
|
<img
|
|
src={`${avatarImager}&headonly=1`}
|
|
alt=""
|
|
/>
|
|
</div>
|
|
<p className="mt-4 font-semibold dark:text-gray-400">
|
|
Epicnabbo
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{photos.length > 0 && (
|
|
<div className="col-span-12">
|
|
<div className="flex w-full flex-col gap-y-4 overflow-hidden rounded-lg p-3">
|
|
<div className="flex gap-x-2">
|
|
<div className="camera-icon relative flex min-h-[50px] min-w-[50px] max-w-[50px] items-center justify-center rounded-full" />
|
|
<div className="flex flex-col">
|
|
<p className="font-semibold text-black dark:text-gray-200">
|
|
Laatste foto's
|
|
</p>
|
|
<p className="dark:text-gray-500">
|
|
Bekijk de mooiste momenten vastgelegd door gebruikers.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-4 xl:grid-cols-5">
|
|
{photos.map((photo) => (
|
|
<a
|
|
key={photo.id}
|
|
href={photo.url}
|
|
data-fancybox="gallery"
|
|
className="group block cursor-pointer"
|
|
>
|
|
<div className="relative overflow-hidden rounded-lg border border-gray-600 shadow-md transition-all duration-300 hover:border-[#eeb425]">
|
|
<div className="relative aspect-[4/3] overflow-hidden">
|
|
<img
|
|
src={photo.url}
|
|
alt={`Photo by ${photo.user?.username || "Unknown"}`}
|
|
className="h-full w-full object-cover object-center transition-transform duration-300 group-hover:scale-110"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
|
|
</div>
|
|
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/90 to-transparent p-2">
|
|
<div className="flex items-center gap-2">
|
|
<div className="flex h-7 w-7 items-center justify-center overflow-hidden rounded-full border border-gray-500 bg-gray-700">
|
|
<img
|
|
src={`${avatarImager}${photo.user?.look || ""}&direction=2&headonly=1&head_direction=2&gesture=sml`}
|
|
alt={photo.user?.username || "Unknown"}
|
|
className="h-full w-full object-cover"
|
|
/>
|
|
</div>
|
|
<div className="min-w-0 flex-1">
|
|
<p className="truncate text-sm font-semibold text-white">
|
|
{photo.user?.username || "Unknown"}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|