@ -18,6 +18,7 @@
|
||||
"@payloadcms/plugin-form-builder": "^3.35.1",
|
||||
"@payloadcms/richtext-lexical": "^3.35.1",
|
||||
"@payloadcms/storage-s3": "^3.35.1",
|
||||
"clsx": "^2.1.1",
|
||||
"country-state-city": "^3.2.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"graphql": "^16.8.1",
|
||||
@ -29,7 +30,8 @@
|
||||
"react-hook-form": "^7.56.1",
|
||||
"react-select": "^5.10.1",
|
||||
"react-toastify": "^11.0.5",
|
||||
"swiper": "^11.2.6"
|
||||
"swiper": "^11.2.6",
|
||||
"tailwind-merge": "^3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
|
@ -3744,13 +3744,13 @@ html .page .divider-secondary::after {
|
||||
}
|
||||
|
||||
.button-primary, .button-primary:focus {
|
||||
color: #ffffff;
|
||||
background-color: #bc986b;
|
||||
border-color: #bc986b;
|
||||
color: var(--color-colorBtnPrimaryText);
|
||||
background-color: var(--color-colorBtnPrimary);
|
||||
border-color: var(--color-colorBtnPrimary);
|
||||
}
|
||||
|
||||
.button-primary:hover, .button-primary:active {
|
||||
color: #151515;
|
||||
color: var(--color-colorBtnPrimaryText);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@ -3759,15 +3759,14 @@ html .page .divider-secondary::after {
|
||||
}
|
||||
|
||||
.button-secondary, .button-secondary:focus {
|
||||
color: #151515;
|
||||
background-color: #fdde52;
|
||||
border-color: #fdde52;
|
||||
color: var(--color-colorBtnSecondaryText);
|
||||
background-color: var(--color-colorBtnSecondary);
|
||||
border-color: var(--color-colorBtnSecondary);
|
||||
}
|
||||
|
||||
.button-secondary:hover, .button-secondary:active {
|
||||
color: #ffffff;
|
||||
background-color: #bc986b;
|
||||
border-color: #bc986b;
|
||||
color: var(--color-colorBtnSecondaryText);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.button-secondary.button-ujarak::before {
|
||||
@ -11354,7 +11353,7 @@ html:not(.lt-ie10) .not-animated {
|
||||
|
||||
.ui-to-top:hover {
|
||||
color: #151515;
|
||||
background: #fdde52;
|
||||
opacity: 0.8;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@ -11699,7 +11698,7 @@ html.tablet .ui-to-top {
|
||||
}
|
||||
|
||||
.rd-navbar-static .rd-menu {
|
||||
z-index: 15;
|
||||
z-index: 30;
|
||||
position: absolute;
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
|
BIN
public/images/bg-header4.jpg
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
public/images/bg-header5.jpg
Normal file
After Width: | Height: | Size: 7.0 MiB |
BIN
public/images/home1.jpg
Normal file
After Width: | Height: | Size: 769 KiB |
BIN
public/images/home2.jpg
Normal file
After Width: | Height: | Size: 1.1 MiB |
BIN
public/images/home3.jpg
Normal file
After Width: | Height: | Size: 3.2 MiB |
BIN
public/images/home4.jpg
Normal file
After Width: | Height: | Size: 2.5 MiB |
BIN
public/images/home5.jpg
Normal file
After Width: | Height: | Size: 1.3 MiB |
BIN
public/images/home6.jpg
Normal file
After Width: | Height: | Size: 2.8 MiB |
BIN
public/images/home7.jpg
Normal file
After Width: | Height: | Size: 2.2 MiB |
BIN
public/images/logo1.png
Normal file
After Width: | Height: | Size: 17 KiB |
5
src/app/(main)/[slug]/loading.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import LoaderFixed from "@/components/loaders/LoaderFixed";
|
||||
|
||||
export default function Loading() {
|
||||
return <LoaderFixed />;
|
||||
}
|
111
src/app/(main)/[slug]/page.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import DetailPageBlog from "@/components/blogs/DetailPageBlog";
|
||||
import DetailPage from "@/components/pages/DetailPage";
|
||||
import { fetchBlogDetail } from "@/services/payload/blog";
|
||||
import { fetchPageBySlug } from "@/services/payload/page";
|
||||
import { getDefaultMetadata } from "@/utils/metadata";
|
||||
import { Metadata } from "next";
|
||||
import { headers } from "next/headers";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
export async function generateMetadata(props: { params: Promise<{ slug: string }> }): Promise<Metadata> {
|
||||
const metadata = await getDefaultMetadata();
|
||||
const params = await props.params;
|
||||
|
||||
let title = `Page Not Found - ${metadata.openGraph?.siteName}`;
|
||||
let description = title;
|
||||
let publishedAt = "";
|
||||
let updatedAt = "";
|
||||
let imgUrl = "";
|
||||
let createdByName = "";
|
||||
let canonicalUrl = "";
|
||||
|
||||
const blog = await fetchBlogDetail(params.slug);
|
||||
if (!!blog) {
|
||||
// check for blog data
|
||||
title = `${!!blog.data?.meta?.title ? blog.data?.meta?.title : blog.data.title} - ${metadata.openGraph?.siteName}`;
|
||||
description = `${!!blog.data?.meta?.description ? blog.data?.meta?.description : blog.data.title}`;
|
||||
imgUrl = blog.img.url;
|
||||
publishedAt = blog.data.createdAt;
|
||||
updatedAt = blog.data.updatedAt;
|
||||
if (!!blog.data?.meta?.canonical_url) {
|
||||
canonicalUrl = blog.data.meta.canonical_url;
|
||||
}
|
||||
if (!!blog?.data?.createdBy && typeof blog.data.createdBy !== "number") {
|
||||
createdByName = blog.data.createdBy?.name ?? "";
|
||||
}
|
||||
} else {
|
||||
// check for page data when blog is not found
|
||||
const page = await fetchPageBySlug({ slug: params.slug });
|
||||
if (!!page) {
|
||||
title = `${!!page?.data?.meta?.title ? page?.data?.meta?.title : page.data.title} - ${metadata.openGraph?.siteName}`;
|
||||
description = `${!!page?.data?.meta?.description ? page?.data?.meta?.description : page.data.title}`;
|
||||
imgUrl = page.heroImg?.url;
|
||||
publishedAt = page.createdAt;
|
||||
updatedAt = page.updatedAt;
|
||||
if (!!page.data?.meta?.canonical_url) {
|
||||
canonicalUrl = page.data.meta.canonical_url;
|
||||
}
|
||||
if (!!page?.data?.createdBy && typeof page?.data?.createdBy !== "number") {
|
||||
createdByName = page?.data?.createdBy?.name ?? "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metadata.title = title;
|
||||
metadata.description = description;
|
||||
if (!!metadata.openGraph) {
|
||||
// @ts-ignore
|
||||
metadata.openGraph.type = "article";
|
||||
metadata.openGraph.title = title;
|
||||
metadata.openGraph.description = description;
|
||||
metadata.openGraph.images = !!imgUrl ? [imgUrl] : undefined;
|
||||
}
|
||||
if (!!metadata.alternates && !!canonicalUrl) {
|
||||
metadata.alternates.canonical = canonicalUrl;
|
||||
}
|
||||
metadata.twitter = {
|
||||
card: "summary_large_image",
|
||||
title: title,
|
||||
description: description,
|
||||
images: !!imgUrl ? [imgUrl] : undefined,
|
||||
};
|
||||
metadata.other = {
|
||||
"article:published_time": publishedAt,
|
||||
"article:modified_time": updatedAt,
|
||||
"twitter:label1": "Written by",
|
||||
"twitter:data1": !!createdByName ? createdByName : "Admin",
|
||||
"twitter:label2": "Est. reading time",
|
||||
"twitter:data2": "3 minutes",
|
||||
};
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
export default async function SinglePage(props: { params: Promise<{ slug: string }> }) {
|
||||
const params = await props.params;
|
||||
const headersList = await headers();
|
||||
const fullUrl = headersList.get("x-full-url");
|
||||
const shareUrl = {
|
||||
facebook: `https://www.facebook.com/sharer/sharer.php?u=${fullUrl}`,
|
||||
linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${fullUrl}`,
|
||||
twitter: `https://twitter.com/intent/tweet?url=${fullUrl}`,
|
||||
};
|
||||
|
||||
const blog = await fetchBlogDetail(params.slug);
|
||||
if (!!blog) {
|
||||
return (
|
||||
<>
|
||||
<DetailPageBlog data={blog} shareUrl={shareUrl} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const page = await fetchPageBySlug({ slug: params.slug });
|
||||
if (!page) return notFound();
|
||||
|
||||
return (
|
||||
<>
|
||||
<DetailPage data={page} shareUrl={shareUrl} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,19 +1,16 @@
|
||||
import ListOfRecentBlog from "@/components/blogs/ListOfRecentBlog";
|
||||
import HeroImage from "@/components/HeroImage";
|
||||
import DetailPageBlog from "@/components/blogs/DetailPageBlog";
|
||||
import { fetchBlogDetail } from "@/services/payload/blog";
|
||||
import { getDefaultMetadata } from "@/utils/metadata";
|
||||
import { RichText } from "@payloadcms/richtext-lexical/react";
|
||||
import { Metadata } from "next";
|
||||
import { headers } from "next/headers";
|
||||
import Image from "next/image";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
export async function generateMetadata(props: { params: Promise<{ slug: string }> }): Promise<Metadata> {
|
||||
const metadata = await getDefaultMetadata();
|
||||
const params = await props.params;
|
||||
|
||||
let title = "Page";
|
||||
let description = "Page";
|
||||
let title = `Page Not Found - ${metadata.openGraph?.siteName}`;
|
||||
let description = title;
|
||||
let publishedAt = "";
|
||||
let updatedAt = "";
|
||||
let imgUrl = "";
|
||||
@ -81,135 +78,7 @@ export default async function BlogDetail(props: { params: Promise<{ slug: string
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeroImage title={blog.data.title} />
|
||||
|
||||
<section className="section section-md bg-colorSection1">
|
||||
<div className="container">
|
||||
<div className="row justify-content-lg-center">
|
||||
<div className="col-lg-8">
|
||||
<article className="blog-post-solo">
|
||||
<div className="blog-post-solo-part">
|
||||
<div className="w-full h-56 md:h-80 bg-colorImgPlaceholder/50 relative">
|
||||
<Image className="object-cover" src={blog.img.url} alt={blog.img.alt} fill />
|
||||
</div>
|
||||
|
||||
<RichText className="mt-4" data={blog.data.content} />
|
||||
</div>
|
||||
|
||||
<div className="blog-post-solo-footer">
|
||||
<div className="blog-post-solo-footer-left">
|
||||
<ul className="blog-post-solo-footer-list">
|
||||
<li>
|
||||
<span className="icon mdi mdi-clock"></span>
|
||||
<a href="#">{blog.createdAt}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="blog-post-solo-footer-right">
|
||||
<ul className="blog-post-solo-footer-list-1">
|
||||
<li>
|
||||
<span>Share this post</span>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-5 fa-facebook"
|
||||
href={shareUrl.facebook}
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-6 fa-twitter"
|
||||
href={shareUrl.twitter}
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-4 fa-linkedin"
|
||||
href={shareUrl.linkedin}
|
||||
></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ListOfRecentBlog currentBlogId={blog?.data?.id} />
|
||||
</article>
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div className="col-lg-4">
|
||||
<div className="pdl-xl-40">
|
||||
<div className="row row-60">
|
||||
<div className="col-md-6 col-lg-12">
|
||||
<form action="/blog" className="form-lg rd-search rd-search-classic">
|
||||
<div className="form-wrap">
|
||||
<input
|
||||
className="form-input"
|
||||
id="rd-search-form-input"
|
||||
type="text"
|
||||
name="s"
|
||||
autoComplete="off"
|
||||
placeholder="Search blog..."
|
||||
/>
|
||||
</div>
|
||||
<button className="rd-search-submit" type="submit"></button>
|
||||
</form>
|
||||
</div>
|
||||
<div className="col-md-6 col-lg-12">
|
||||
<div className="block-info-2">
|
||||
<div className="block-info-2-title">
|
||||
<h3>Latest Listings</h3>
|
||||
</div>
|
||||
<a className="post-minimal-1" href="#">
|
||||
<div className="post-minimal-1-left">
|
||||
<Image src="/images/post-agent-01-212x208.jpg" alt="" width="212" height="208" />
|
||||
</div>
|
||||
<div className="post-minimal-1-body">
|
||||
<div className="post-minimal-1-title">
|
||||
<span>401 Biscayne Blvd</span>
|
||||
</div>
|
||||
<div className="post-minimal-1-text">
|
||||
<span>$5000\mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a className="post-minimal-1" href="#">
|
||||
<div className="post-minimal-1-left">
|
||||
<Image src="/images/post-agent-02-212x208.jpg" alt="" width="212" height="208" />
|
||||
</div>
|
||||
<div className="post-minimal-1-body">
|
||||
<div className="post-minimal-1-title">
|
||||
<span>35 Pond St, New York</span>
|
||||
</div>
|
||||
<div className="post-minimal-1-text">
|
||||
<span>$5550\mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a className="post-minimal-1" href="#">
|
||||
<div className="post-minimal-1-left">
|
||||
<Image src="/images/post-agent-03-212x208.jpg" alt="" width="212" height="208" />
|
||||
</div>
|
||||
<div className="post-minimal-1-body">
|
||||
<div className="post-minimal-1-title">
|
||||
<span>182 3rd St, Seattle</span>
|
||||
</div>
|
||||
<div className="post-minimal-1-text">
|
||||
<span>$2520\mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<DetailPageBlog data={blog} shareUrl={shareUrl} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -33,8 +33,15 @@
|
||||
--color-colorContactForm: var(--color-colorExt50);
|
||||
--color-colorText1: var(--color-colorExt10);
|
||||
--color-colorText2: var(--color-colorExt20);
|
||||
--color-colorText3: var(--color-colorExt30);
|
||||
--color-colorLoaderBackground: var(--color-colorExt20);
|
||||
--color-colorPriceTag: var(--color-colorExt30);
|
||||
--color-colorBtnPrimary: var(--color-colorext40);
|
||||
--color-colorBtnPrimaryText: var(--color-colorExt20);
|
||||
--color-colorBtnSecondary: var(--color-colorExt50);
|
||||
--color-colorBtnSecondaryText: var(--color-colorExt20);
|
||||
--color-colorLinkText1: var(--color-colorExt30);
|
||||
--color-colorLinkText2: var(--color-colorext40);
|
||||
}
|
||||
|
||||
@layer components {
|
||||
|
@ -1,10 +1,5 @@
|
||||
import GoogleReviewBox from "@/components/GoogleReviewBox";
|
||||
import HomeTopSection from "@/components/homes/HomeTopSection";
|
||||
import Loader from "@/components/loaders/Loader";
|
||||
import ListOfFeaturedProperty from "@/components/properties/ListOfFeaturedProperty";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { Suspense } from "react";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
@ -13,95 +8,57 @@ export default function Home() {
|
||||
|
||||
<section className="section section-lg bg-colorSection1">
|
||||
<div className="container">
|
||||
<h2 className="heading-decoration-1">
|
||||
<span className="heading-inner">Why Dynamic Realty?</span>
|
||||
</h2>
|
||||
<div className="row row-30">
|
||||
<div className="col-md-6 col-lg-3">
|
||||
<Link href="/">
|
||||
<div className="col-md-12 col-lg-4">
|
||||
<div>
|
||||
<article className="box-modern">
|
||||
<span className="icon box-modern-icon fl-bigmug-line-search74"></span>
|
||||
<div className="flex justify-center">
|
||||
<span className="icon box-modern-icon fa-home"></span>
|
||||
</div>
|
||||
<div className="box-modern-main">
|
||||
<h4 className="box-modern-title">Buy</h4>
|
||||
<p>
|
||||
Discover a wide selection of properties available for purchase in prime locations at competitive
|
||||
prices.
|
||||
<h4 className="box-modern-title">Tailored Management, Trusted Care</h4>
|
||||
<p className="text-colorText3">
|
||||
Committed to providing a personalized structure to each client, with on-site management & a robust
|
||||
property management
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="col-md-6 col-lg-3">
|
||||
<Link href="/">
|
||||
</div>
|
||||
<div className="col-md-12 col-lg-4">
|
||||
<div>
|
||||
<article className="box-modern">
|
||||
<span className="icon box-modern-icon fl-bigmug-line-label25"></span>
|
||||
<div className="flex justify-center">
|
||||
<span className="icon box-modern-icon fa-calendar"></span>
|
||||
</div>
|
||||
<div className="box-modern-main">
|
||||
<h4 className="box-modern-title">Sell</h4>
|
||||
<p>
|
||||
List your property with ease and reach potential buyers quickly with our expert marketing support.
|
||||
<h4 className="box-modern-title">20 Years of Real Estate Excellence</h4>
|
||||
<p className="text-colorText3">
|
||||
We strive to provide a service that meets the needs of all our customers & are proud to have been
|
||||
helping people with their real estate needs for the past 20 years
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="col-md-6 col-lg-3">
|
||||
<Link href="/">
|
||||
</div>
|
||||
<div className="col-md-12 col-lg-4">
|
||||
<div>
|
||||
<article className="box-modern">
|
||||
<span className="icon box-modern-icon fl-bigmug-line-timer35"></span>
|
||||
<div className="box-modern-main">
|
||||
<h4 className="box-modern-title">Rent</h4>
|
||||
<p>Find the perfect rental home or apartment with flexible lease terms and no hidden fees.</p>
|
||||
<div className="flex justify-center">
|
||||
<span className="icon box-modern-icon fa-map"></span>
|
||||
</div>
|
||||
</article>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="col-md-6 col-lg-3">
|
||||
<Link href="/">
|
||||
<article className="box-modern">
|
||||
<span className="icon box-modern-icon fl-bigmug-line-big104"></span>
|
||||
<div className="box-modern-main">
|
||||
<h4 className="box-modern-title">Need Help?</h4>
|
||||
<p>
|
||||
Have questions? Our support team is here to guide you through every step of your real estate
|
||||
journey.
|
||||
<h4 className="box-modern-title">Expert Guidance, Stress-Free Journeys</h4>
|
||||
<p className="text-colorText3">
|
||||
We understand the real estate sector inside out & are committed to providing a professional
|
||||
service to our clients. We strive to make the process of reaching your real estate goals as easy &
|
||||
stress-free as possible
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="section relative!">
|
||||
<Image
|
||||
alt="Experience the Difference in Every Key Turn"
|
||||
src={"/images/bg-header.webp"}
|
||||
quality={100}
|
||||
fill
|
||||
sizes="100vw"
|
||||
style={{
|
||||
objectFit: "cover",
|
||||
}}
|
||||
/>
|
||||
<div className="box-1-cell height-fill context-dark bg-colorHeader/80!">
|
||||
<div className="cell-inner box-1-outer">
|
||||
<div className="box-1">
|
||||
<div className="text-center">
|
||||
<h2>Experience the Difference in Every Key Turn</h2>
|
||||
</div>
|
||||
<div className="mt-4 text-lg">
|
||||
<p>
|
||||
Dynamic Realty is a full-service veteran-owned real estate company based in Centerville, GA,
|
||||
established in 2004. Our services include buying & selling, rentals, & property management. We are
|
||||
committed to providing a personalized structure to each client, with on-site management & a robust
|
||||
property management division. We strive to provide a service that meets the needs of all our customers
|
||||
& are proud to have been helping people with their real estate needs for the past 20 years.
|
||||
</p>
|
||||
<p>
|
||||
At Dynamic Realty, we offer a comprehensive range of realty services to meet the needs of our
|
||||
customers in Central Georgia. Our services include buying & selling, renting, & property management.
|
||||
We understand the real estate sector inside out & are committed to providing a professional service to
|
||||
our clients. We strive to make the process of reaching your real estate goals as easy & stress-free as
|
||||
possible. Get in touch with us today to find out more.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -109,101 +66,6 @@ export default function Home() {
|
||||
</section>
|
||||
|
||||
<GoogleReviewBox />
|
||||
|
||||
<section className="section section-lg bg-colorSection2">
|
||||
<div className="container">
|
||||
<div className="layout-4">
|
||||
<h2 className="heading-decoration-1">
|
||||
<span className="heading-inner">Featured Properties</span>
|
||||
</h2>
|
||||
<div className="layout-4-item">
|
||||
<ul className="list-inline-bordered heading-7">
|
||||
<li>
|
||||
<a href="/listings-for-rent">For Rent</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/listings-for-sale">For Sale</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-10!">
|
||||
<Suspense
|
||||
fallback={
|
||||
<>
|
||||
<div className="mt-5">
|
||||
<Loader />
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<ListOfFeaturedProperty />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="section parallax-container" data-parallax-img="/images/bg-02-1920x916.jpg">
|
||||
<div className="parallax-content section-lg context-dark text-center">
|
||||
<div className="container">
|
||||
<div className="row row-30">
|
||||
<div className="col-6 col-md-3">
|
||||
<article className="box-counter">
|
||||
<div className="box-counter-main">
|
||||
<span>860</span>
|
||||
</div>
|
||||
<p className="box-counter-title">Properties on Map</p>
|
||||
</article>
|
||||
</div>
|
||||
<div className="col-6 col-md-3">
|
||||
<article className="box-counter">
|
||||
<div className="box-counter-main">
|
||||
<div className="counter">29</div>
|
||||
</div>
|
||||
<p className="box-counter-title">Professional Agents</p>
|
||||
</article>
|
||||
</div>
|
||||
<div className="col-6 col-md-3">
|
||||
<article className="box-counter">
|
||||
<div className="box-counter-main">
|
||||
<div className="counter">10</div>
|
||||
<span>k</span>
|
||||
</div>
|
||||
<p className="box-counter-title">Happy Clients</p>
|
||||
</article>
|
||||
</div>
|
||||
<div className="col-6 col-md-3">
|
||||
<article className="box-counter">
|
||||
<div className="box-counter-main">
|
||||
<div className="counter">15</div>
|
||||
</div>
|
||||
<p className="box-counter-title">New Apartments Daily</p>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="section section-lg bg-colorSection1">
|
||||
<div className="container">
|
||||
<h2 className="heading-decoration-1">
|
||||
<span className="heading-inner">Find Us</span>
|
||||
</h2>
|
||||
<div className="row row-30">
|
||||
<div className="col-12">
|
||||
<iframe
|
||||
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3360.4823498818855!2d-83.68565822483802!3d32.61997607372962!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x88f3e6ce99781991%3A0xabfd803ad30f6d12!2s100%20N%20Houston%20Lake%20Blvd%2C%20Centerville%2C%20GA%2031028%2C%20USA!5e0!3m2!1sen!2sid!4v1744883077476!5m2!1sen!2sid"
|
||||
width={"100%"}
|
||||
height={450}
|
||||
style={{ border: 0 }}
|
||||
loading="lazy"
|
||||
referrerPolicy="no-referrer-when-downgrade"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ type HeroImageProps = {
|
||||
|
||||
export default function HeroImage({ title = "", imgSrc = "/images/breadcrumbs-bg-05-1922x441.jpg" }: HeroImageProps) {
|
||||
return (
|
||||
<section className="breadcrumbs-custom bg-image context-dark">
|
||||
<section className="breadcrumbs-custom context-dark min-h-[300px]!">
|
||||
<Image
|
||||
alt="Blog"
|
||||
src={imgSrc}
|
||||
@ -18,7 +18,7 @@ export default function HeroImage({ title = "", imgSrc = "/images/breadcrumbs-bg
|
||||
objectFit: "cover",
|
||||
}}
|
||||
/>
|
||||
<div className="bg-colorHeroOverlay/50 w-full h-full absolute top-0 left-0" />
|
||||
<div className="bg-colorHeroOverlay/85 w-full h-full absolute top-0 left-0" />
|
||||
<div className="container relative">
|
||||
<h2 className="breadcrumbs-custom-title">{title}</h2>
|
||||
</div>
|
||||
|
@ -4,11 +4,6 @@ import Image from "next/image";
|
||||
import { useState } from "react";
|
||||
import { Autoplay } from "swiper/modules";
|
||||
import { Swiper, SwiperSlide } from "swiper/react";
|
||||
import ContactFormBox from "./ContactFormBox";
|
||||
|
||||
type HeroSliderProps = {
|
||||
onClickBook?: () => void;
|
||||
};
|
||||
|
||||
type HeroSlideItem = {
|
||||
title: string;
|
||||
@ -16,28 +11,30 @@ type HeroSlideItem = {
|
||||
img: string;
|
||||
};
|
||||
|
||||
export default function HeroSlider({ onClickBook }: HeroSliderProps) {
|
||||
export default function HeroSlider() {
|
||||
const [slideItems] = useState<HeroSlideItem[]>([
|
||||
{
|
||||
title: "Real Estate, Redefined",
|
||||
description: "Where Southern Charm Meets Boutique Real Estate",
|
||||
img: "/images/bg-header2.jpg",
|
||||
title: "Full-Service Veteran-Owned Real Estate Company",
|
||||
description:
|
||||
"Dynamic Realty is a full-service veteran-owned real estate company based in Centerville, GA, established in 2004. Our services include buying & selling, rentals, & property management. We strive to provide a service that meets the needs of all our customers & are proud to have been helping people with their real estate needs for the past 20 years.",
|
||||
img: "/images/bg-header4.jpg",
|
||||
},
|
||||
{
|
||||
title: "Your Vision, Our Expertise",
|
||||
description: "Discover a Smarter Way to Buy & Sell",
|
||||
img: "/images/bg-header3.jpg",
|
||||
title: "Comprehensive Range of Realty Services",
|
||||
description:
|
||||
"Our services include buying & selling, renting, & property management. We understand the real estate sector inside out & are committed to providing a professional service to our clients. We strive to make the process of reaching your real estate goals as easy & stress-free as possible.",
|
||||
img: "/images/bg-header5.jpg",
|
||||
},
|
||||
]);
|
||||
|
||||
return (
|
||||
<section className="section flex! flex-row! justify-end! relative! min-h-96! lg:min-h-auto!">
|
||||
<section className="section flex! flex-row! justify-end! relative! min-h-[900px]! lg:min-h-[600px]!">
|
||||
<Swiper
|
||||
className="absolute w-full h-full"
|
||||
modules={[Autoplay]}
|
||||
spaceBetween={50}
|
||||
slidesPerView={1}
|
||||
autoplay={{ delay: 4000 }}
|
||||
autoplay={{ delay: 10000 }}
|
||||
loop
|
||||
>
|
||||
{slideItems.map((slide, idx) => (
|
||||
@ -52,21 +49,29 @@ export default function HeroSlider({ onClickBook }: HeroSliderProps) {
|
||||
objectFit: "cover",
|
||||
}}
|
||||
/>
|
||||
<section className="section section-lg text-colorText2! bg-colorHeroOverlay/50 w-full h-full z-20">
|
||||
<section className="section section-lg text-colorText2! bg-colorHeroOverlay/85 w-full h-full z-20">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col-12 col-lg-4 flex justify-center">
|
||||
<div className="w-[200px] h-[200px] relative mb-4 lg:hidden">
|
||||
<Image alt="Logo" src={"/images/logo1.png"} quality={100} fill />
|
||||
</div>
|
||||
<div className="w-[300px] h-[300px] relative mb-4 hidden lg:block">
|
||||
<Image alt="Logo" src={"/images/logo1.png"} quality={100} fill />
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-8 text-wrap space-y-5 md:space-y-8 lg:space-y-12">
|
||||
<div className="text-4xl lg:text-8xl! font-playfairdisplay text-center! lg:text-left!">
|
||||
<div className="text-4xl lg:text-6xl! font-playfairdisplay text-center! lg:text-left!">
|
||||
{slide.title}
|
||||
</div>
|
||||
<div className="text-lg lg:text-5xl! font-montserrat text-center! lg:text-left!">
|
||||
<div className="text-lg lg:text-xl! font-montserrat text-center! lg:text-left!">
|
||||
{slide.description}
|
||||
</div>
|
||||
<div className="context-dark flex flex-row justify-center lg:hidden">
|
||||
{/* <div className="context-dark flex flex-row justify-center lg:hidden">
|
||||
<button onClick={onClickBook} className="button button-xs button-primary-outline">
|
||||
BOOK APPOINTMENT
|
||||
</button>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="context-dark flex flex-row justify-center lg:hidden">
|
||||
<a href="tel:(478) 225 9061" className="button button-xs button-primary-outline">
|
||||
Call Us
|
||||
@ -80,7 +85,7 @@ export default function HeroSlider({ onClickBook }: HeroSliderProps) {
|
||||
))}
|
||||
</Swiper>
|
||||
|
||||
<ContactFormBox />
|
||||
{/* <ContactFormBox /> */}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
@ -4,23 +4,9 @@ import { RichText } from "@payloadcms/richtext-lexical/react";
|
||||
|
||||
export function ContentBlock(props: any) {
|
||||
return (
|
||||
<div className="container relative">
|
||||
<div className="row">
|
||||
{/* Content */}
|
||||
<div className="col-md-10 offset-md-1 col-lg-10 offset-lg-1">
|
||||
{/* Post */}
|
||||
<div className="blog-item mb-10">
|
||||
<div className="blog-item-body">
|
||||
<div>
|
||||
{/* @ts-ignore */}
|
||||
<RichText data={props.content} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* End Post */}
|
||||
</div>
|
||||
{/* End Content */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ type CardBlogProps = {
|
||||
};
|
||||
|
||||
export default function CardBlog({ data, colorPreset = 1, isDescriptionVisible = true }: CardBlogProps) {
|
||||
const linkDetail = `/blog/${data.slug}`;
|
||||
const linkDetail = `/${data.slug}`;
|
||||
|
||||
if (colorPreset === 2) {
|
||||
return (
|
||||
|
151
src/components/blogs/DetailPageBlog.tsx
Normal file
@ -0,0 +1,151 @@
|
||||
import { fetchBlogDetail } from "@/services/payload/blog";
|
||||
import Image from "next/image";
|
||||
import ListOfRecentBlog from "./ListOfRecentBlog";
|
||||
import HeroImage from "../HeroImage";
|
||||
import { RichText } from "@payloadcms/richtext-lexical/react";
|
||||
|
||||
type shareUrlDestination = "facebook" | "linkedin" | "twitter";
|
||||
|
||||
type DetailPageBlogProps = {
|
||||
data: Awaited<ReturnType<typeof fetchBlogDetail>>;
|
||||
shareUrl: Record<shareUrlDestination, string>;
|
||||
};
|
||||
|
||||
export default function DetailPageBlog({ data, shareUrl }: DetailPageBlogProps) {
|
||||
const blog = data;
|
||||
if (!blog) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeroImage title={blog.data.title} />
|
||||
|
||||
<section className="section section-md bg-colorSection1">
|
||||
<div className="container">
|
||||
<div className="row justify-content-lg-center">
|
||||
<div className="col-lg-8">
|
||||
<article className="blog-post-solo">
|
||||
<div className="blog-post-solo-part">
|
||||
<div className="w-full h-56 md:h-80 bg-colorImgPlaceholder/50 relative">
|
||||
<Image className="object-cover" src={blog.img.url} alt={blog.img.alt} fill />
|
||||
</div>
|
||||
|
||||
<RichText className="mt-4" data={blog.data.content} />
|
||||
</div>
|
||||
|
||||
<div className="blog-post-solo-footer">
|
||||
<div className="blog-post-solo-footer-left">
|
||||
<ul className="blog-post-solo-footer-list">
|
||||
<li>
|
||||
<span className="icon mdi mdi-clock"></span>
|
||||
<a href="#">{blog.createdAt}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="blog-post-solo-footer-right">
|
||||
<ul className="blog-post-solo-footer-list-1">
|
||||
<li>
|
||||
<span>Share this post</span>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-5 fa-facebook"
|
||||
href={shareUrl.facebook}
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-6 fa-twitter"
|
||||
href={shareUrl.twitter}
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-4 fa-linkedin"
|
||||
href={shareUrl.linkedin}
|
||||
></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ListOfRecentBlog currentBlogId={blog?.data?.id} />
|
||||
</article>
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
<div className="col-lg-4">
|
||||
<div className="pdl-xl-40">
|
||||
<div className="row row-60">
|
||||
<div className="col-md-6 col-lg-12">
|
||||
<form action="/blog" className="form-lg rd-search rd-search-classic">
|
||||
<div className="form-wrap">
|
||||
<input
|
||||
className="form-input"
|
||||
id="rd-search-form-input"
|
||||
type="text"
|
||||
name="s"
|
||||
autoComplete="off"
|
||||
placeholder="Search blog..."
|
||||
/>
|
||||
</div>
|
||||
<button className="rd-search-submit" type="submit"></button>
|
||||
</form>
|
||||
</div>
|
||||
<div className="col-md-6 col-lg-12">
|
||||
<div className="block-info-2">
|
||||
<div className="block-info-2-title">
|
||||
<h3>Latest Listings</h3>
|
||||
</div>
|
||||
<a className="post-minimal-1" href="#">
|
||||
<div className="post-minimal-1-left">
|
||||
<Image src="/images/post-agent-01-212x208.jpg" alt="" width="212" height="208" />
|
||||
</div>
|
||||
<div className="post-minimal-1-body">
|
||||
<div className="post-minimal-1-title">
|
||||
<span>401 Biscayne Blvd</span>
|
||||
</div>
|
||||
<div className="post-minimal-1-text">
|
||||
<span>$5000\mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a className="post-minimal-1" href="#">
|
||||
<div className="post-minimal-1-left">
|
||||
<Image src="/images/post-agent-02-212x208.jpg" alt="" width="212" height="208" />
|
||||
</div>
|
||||
<div className="post-minimal-1-body">
|
||||
<div className="post-minimal-1-title">
|
||||
<span>35 Pond St, New York</span>
|
||||
</div>
|
||||
<div className="post-minimal-1-text">
|
||||
<span>$5550\mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a className="post-minimal-1" href="#">
|
||||
<div className="post-minimal-1-left">
|
||||
<Image src="/images/post-agent-03-212x208.jpg" alt="" width="212" height="208" />
|
||||
</div>
|
||||
<div className="post-minimal-1-body">
|
||||
<div className="post-minimal-1-title">
|
||||
<span>182 3rd St, Seattle</span>
|
||||
</div>
|
||||
<div className="post-minimal-1-text">
|
||||
<span>$2520\mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,23 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import HeroSlider from "@/components/HeroSlider";
|
||||
import { useRef } from "react";
|
||||
import ContactFormSection from "../ContactFormSection";
|
||||
|
||||
export default function HomeTopSection() {
|
||||
const formRef = useRef<HTMLDivElement | null>(null);
|
||||
// const formRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
function scrollToForm() {
|
||||
formRef.current?.scrollIntoView?.({ behavior: "smooth" });
|
||||
}
|
||||
// function scrollToForm() {
|
||||
// formRef.current?.scrollIntoView?.({ behavior: "smooth" });
|
||||
// }
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeroSlider onClickBook={scrollToForm} />
|
||||
<HeroSlider />
|
||||
|
||||
<div className="lg:hidden" ref={formRef}>
|
||||
{/* <div className="lg:hidden" ref={formRef}>
|
||||
<ContactFormSection />
|
||||
</div>
|
||||
</div> */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,16 @@
|
||||
import Image from "next/image";
|
||||
import ListOfFeaturedProperiesFooter from "@/components/properties/ListOfFeaturedPropertiesFooter";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export default async function Footer() {
|
||||
const headersList = await headers();
|
||||
const fullUrl = headersList.get("x-full-url");
|
||||
|
||||
const shareUrl = {
|
||||
facebook: `https://www.facebook.com/sharer/sharer.php?u=${fullUrl}`,
|
||||
linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${fullUrl}`,
|
||||
twitter: `https://twitter.com/intent/tweet?url=${fullUrl}`,
|
||||
};
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<>
|
||||
<section className="section section-md bg-colorFooter context-dark">
|
||||
@ -10,36 +20,7 @@ export default function Footer() {
|
||||
<h3 className="heading-square font-weight-sbold" data-item=".heading-square-item">
|
||||
<span className="heading-square-item"></span>Latest Properties
|
||||
</h3>
|
||||
<a className="post-minimal" href="single-property.html">
|
||||
<div className="post-minimal-image">
|
||||
<Image src="/images/featured-properties-17-480x287.jpg" alt="" width="161" height="136" />
|
||||
</div>
|
||||
<div className="post-minimal-body">
|
||||
<div className="post-minimal-title">
|
||||
<span className="text-colorFooterText! hover:text-colorFooterTextHover!">
|
||||
Retail Store Southwest 186th Street
|
||||
</span>
|
||||
</div>
|
||||
<div className="post-minimal-text">
|
||||
<span>From $120/month</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a className="post-minimal" href="single-property.html">
|
||||
<div className="post-minimal-image">
|
||||
<Image src="/images/featured-properties-17-480x287.jpg" alt="" width="161" height="136" />
|
||||
</div>
|
||||
<div className="post-minimal-body">
|
||||
<div className="post-minimal-title">
|
||||
<span className="text-colorFooterText! hover:text-colorFooterTextHover!">
|
||||
Apartment Building with Subunits
|
||||
</span>
|
||||
</div>
|
||||
<div className="post-minimal-text">
|
||||
<span>From $120/month</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<ListOfFeaturedProperiesFooter />
|
||||
</div>
|
||||
<div className="col-md-6 col-lg-4 col-xl-3 col-bordered">
|
||||
<h3 className="heading-square font-weight-sbold" data-item=".heading-square-item">
|
||||
@ -103,16 +84,13 @@ export default function Footer() {
|
||||
</form> */}
|
||||
<ul className="list-inline-1 space-x-5">
|
||||
<li>
|
||||
<a className="icon fa-facebook text-4xl!" href="#"></a>
|
||||
<a target="_blank" className="icon fa-facebook text-4xl!" href={shareUrl.facebook}></a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon fa-twitter text-4xl!" href="#"></a>
|
||||
<a target="_blank" className="icon fa-twitter text-4xl!" href={shareUrl.twitter}></a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon fa-google-plus text-4xl!" href="#"></a>
|
||||
</li>
|
||||
<li>
|
||||
<a className="icon fa-pinterest-p text-4xl!" href="#"></a>
|
||||
<a target="_blank" className="icon fa-linkedin text-4xl!" href={shareUrl.linkedin}></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -127,15 +105,15 @@ export default function Footer() {
|
||||
<span>Dynamic Realty</span> <span>© </span>
|
||||
<span className="copyright-year"></span>
|
||||
<span> </span>
|
||||
<a href="privacy-policy.html">Privacy Policy</a>
|
||||
<a href="/privacy-policy">Privacy Policy</a>
|
||||
</p>
|
||||
</div>
|
||||
<div className="col-sm-6 text-sm-right">
|
||||
<div className="right-1">
|
||||
{/* <div className="right-1">
|
||||
<a href="#">
|
||||
<span className="icon mdi mdi-plus"></span>Book Appointment
|
||||
</a>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,16 +1,7 @@
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export default async function Header() {
|
||||
const headerList = await headers();
|
||||
const fullUrl = headerList.get("x-full-url");
|
||||
|
||||
const headerActive = (pathName: string) => {
|
||||
if (!fullUrl) return "";
|
||||
const splittedUrl = fullUrl.split("/");
|
||||
|
||||
return splittedUrl[3] === pathName ? "active" : "";
|
||||
};
|
||||
import { HeaderDropdown, HeaderDropdownGroup, HeaderDropdownMenu } from "./HeaderDropdown";
|
||||
import HeaderFeaturedHomes from "./HeaderFeaturedHomes";
|
||||
|
||||
export default function Header() {
|
||||
return (
|
||||
<header className="section page-header">
|
||||
<div className="rd-navbar-wrap">
|
||||
@ -103,213 +94,248 @@ export default async function Header() {
|
||||
srcSet="images/logo2.png 2x"
|
||||
/>
|
||||
</a>
|
||||
{/* <h3 className="text-colorHeaderText! font-montserrat! font-semibold! hidden lg:inline">
|
||||
Dynamic Realty
|
||||
</h3> */}
|
||||
</div>
|
||||
</div>
|
||||
<div className="rd-navbar-nav-wrap">
|
||||
<ul className="rd-navbar-nav">
|
||||
<li className="rd-nav-item">
|
||||
<a className={`rd-nav-link rd-nav-link-custom ${headerActive("")}`} href="/">
|
||||
HOME
|
||||
<a className="rd-nav-link rd-nav-link-custom" href="#">
|
||||
Buying / Selling
|
||||
</a>
|
||||
<HeaderDropdown>
|
||||
<HeaderDropdownGroup>
|
||||
<div className="pr-2">
|
||||
<form>
|
||||
<div className="form-wrap">
|
||||
<input
|
||||
type="text"
|
||||
id="search"
|
||||
className="form-input border-colorHeader!"
|
||||
placeholder="Search"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<HeaderFeaturedHomes />
|
||||
</div>
|
||||
</HeaderDropdownGroup>
|
||||
<HeaderDropdownGroup title="Why Dynamic Realty?">
|
||||
<HeaderDropdownMenu
|
||||
list={[
|
||||
{
|
||||
title:
|
||||
"Committed to providing a personalized structure to each client, with on-site management & a robust property management",
|
||||
},
|
||||
{
|
||||
title:
|
||||
"We strive to provide a service that meets the needs of all our customers & are proud to have been helping people with their real estate needs for the past 20 years",
|
||||
},
|
||||
{
|
||||
title:
|
||||
"We understand the real estate sector inside out & are committed to providing a professional service to our clients. We strive to make the process of reaching your real estate goals as easy & stress-free as possible",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</HeaderDropdownGroup>
|
||||
<HeaderDropdownGroup title="Future Owners">
|
||||
<HeaderDropdownMenu
|
||||
list={[
|
||||
{
|
||||
title: "Moving In",
|
||||
child: [
|
||||
{
|
||||
title: "What To Be Done Prior",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Next Steps (keys, utilities, etc)",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Common Questions",
|
||||
href: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Welcome home",
|
||||
child: [
|
||||
{
|
||||
title: "Payment",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Utilities",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Maintenance",
|
||||
href: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Moving Out",
|
||||
child: [
|
||||
{
|
||||
title: "What To Be Done Prior",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Next Steps (keys, utilities, etc)",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Common Questions",
|
||||
href: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</HeaderDropdownGroup>
|
||||
<HeaderDropdownGroup className="flex! pr-4!">
|
||||
<div className="flex flex-col self-end!">
|
||||
<a className="button button-secondary" href="/">
|
||||
FAQ
|
||||
</a>
|
||||
<a className="button button-primary mt-2!" href="/">
|
||||
LOOKING FOR SELL
|
||||
</a>
|
||||
</div>
|
||||
</HeaderDropdownGroup>
|
||||
</HeaderDropdown>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a
|
||||
className="rd-nav-link rd-nav-link-custom"
|
||||
href="https://dynamicrealtyinc.managebuilding.com/Resident/public/rentals"
|
||||
target="_blank"
|
||||
>
|
||||
RENTAL PORTAL
|
||||
<a className="rd-nav-link rd-nav-link-custom" href="#">
|
||||
Leasing
|
||||
</a>
|
||||
<HeaderDropdown>
|
||||
<HeaderDropdownGroup>
|
||||
<div className="pr-2">
|
||||
<form>
|
||||
<div className="form-wrap">
|
||||
<input
|
||||
type="text"
|
||||
id="search"
|
||||
className="form-input border-colorHeader!"
|
||||
placeholder="Search"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<HeaderFeaturedHomes />
|
||||
</div>
|
||||
</HeaderDropdownGroup>
|
||||
<HeaderDropdownGroup title="Future Residents">
|
||||
<HeaderDropdownMenu
|
||||
list={[
|
||||
{
|
||||
title: "Our Rentals",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Application Process",
|
||||
child: [
|
||||
{
|
||||
title: "Before You Apply",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Rental Criteria",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Before You Apply",
|
||||
href: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</HeaderDropdownGroup>
|
||||
<HeaderDropdownGroup title="Current Residents">
|
||||
<HeaderDropdownMenu
|
||||
list={[
|
||||
{
|
||||
title: "Moving In",
|
||||
child: [
|
||||
{
|
||||
title: "What To Be Done Prior",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Next Steps (keys, utilities, etc)",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Common Questions",
|
||||
href: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Welcome home",
|
||||
child: [
|
||||
{
|
||||
title: "Payment",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Utilities",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Maintenance",
|
||||
href: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Moving Out",
|
||||
child: [
|
||||
{
|
||||
title: "What To Be Done Prior",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Next Steps (keys, utilities, etc)",
|
||||
href: "#",
|
||||
},
|
||||
{
|
||||
title: "Common Questions",
|
||||
href: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</HeaderDropdownGroup>
|
||||
<HeaderDropdownGroup className="flex! pr-4!">
|
||||
<div className="flex flex-col self-end!">
|
||||
<a className="button button-secondary" href="#">
|
||||
FAQ
|
||||
</a>
|
||||
<a className="button button-primary mt-2!" href="#">
|
||||
APPLY NOW
|
||||
</a>
|
||||
</div>
|
||||
</HeaderDropdownGroup>
|
||||
</HeaderDropdown>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a
|
||||
className={`rd-nav-link rd-nav-link-custom ${headerActive("listings-for-sale")}`}
|
||||
href="/listings-for-sale"
|
||||
>
|
||||
LISTINGS FOR SALE
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a
|
||||
className={`rd-nav-link rd-nav-link-custom ${headerActive("listings-for-rent")}`}
|
||||
href="/listings-for-rent"
|
||||
>
|
||||
LISTINGS FOR RENT
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a className={`rd-nav-link rd-nav-link-custom ${headerActive("blog")}`} href="/blog">
|
||||
BLOGS
|
||||
<a className={`rd-nav-link rd-nav-link-custom`} href="/blog">
|
||||
Resources
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-nav-item block lg:hidden!">
|
||||
<a className="rd-nav-link rd-nav-link-custom" href="/login">
|
||||
LOGIN
|
||||
</a>
|
||||
</li>
|
||||
{/* <li className="rd-nav-item">
|
||||
<a className="rd-nav-link" href="#">
|
||||
Properties
|
||||
</a>
|
||||
|
||||
<ul className="rd-menu rd-navbar-dropdown">
|
||||
<li className="rd-dropdown-item">
|
||||
<a className="rd-dropdown-link" href="properties-grid.html">
|
||||
Properties Grid
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-dropdown-item">
|
||||
<a className="rd-dropdown-link" href="properties-grid-2.html">
|
||||
Properties Grid 2
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-dropdown-item">
|
||||
<a className="rd-dropdown-link" href="properties-list.html">
|
||||
Properties List
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-dropdown-item">
|
||||
<a className="rd-dropdown-link" href="submit-property.html">
|
||||
Submit property
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-dropdown-item">
|
||||
<a className="rd-dropdown-link" href="single-property.html">
|
||||
Single Property
|
||||
Login
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a className="rd-nav-link" href="about-us.html">
|
||||
About Us
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a className="rd-nav-link" href="blog.html">
|
||||
Blog
|
||||
</a>
|
||||
|
||||
<ul className="rd-menu rd-navbar-dropdown">
|
||||
<li className="rd-dropdown-item">
|
||||
<a className="rd-dropdown-link" href="blog-post.html">
|
||||
Blog post
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a className="rd-nav-link" href="#">
|
||||
Pages
|
||||
</a>
|
||||
|
||||
<ul className="rd-menu rd-navbar-megamenu">
|
||||
<li className="rd-megamenu-item">
|
||||
<h6 className="rd-megamenu-title">Pages 1</h6>
|
||||
<ul className="rd-megamenu-list">
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="agents.html">
|
||||
Agents
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="agent-single-page.html">
|
||||
Agent Single Page
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="careers.html">
|
||||
Careers
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="gallery.html">
|
||||
Gallery
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li className="rd-megamenu-item">
|
||||
<h6 className="rd-megamenu-title">Pages 2</h6>
|
||||
<ul className="rd-megamenu-list">
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="search-results.html">
|
||||
Search results
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="coming-soon.html">
|
||||
Coming Soon
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="404.html">
|
||||
404
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="privacy-policy.html">
|
||||
Privacy Policy
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li className="rd-megamenu-item">
|
||||
<h6 className="rd-megamenu-title">Elements</h6>
|
||||
<ul className="rd-megamenu-list">
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="typography.html">
|
||||
Typography
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="buttons.html">
|
||||
Buttons
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="forms.html">
|
||||
Forms
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="tabs-and-accordions.html">
|
||||
Tabs and accordions
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="progress-bars.html">
|
||||
Progress bars
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="tables.html">
|
||||
Tables
|
||||
</a>
|
||||
</li>
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className="rd-megamenu-list-link" href="grid-system.html">
|
||||
Grid System
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li className="rd-nav-item">
|
||||
<a className="rd-nav-link" href="contact-us.html">
|
||||
Contact Us
|
||||
</a>
|
||||
</li> */}
|
||||
</ul>
|
||||
<div className="rd-navbar-main-item context-dark">
|
||||
<a className="button button-sm button-primary-outline" href="#">
|
||||
BOOK APPOINTMENT
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
81
src/components/layouts/HeaderDropdown.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
import { createSlug } from "@/utils/general";
|
||||
import { cn } from "@/utils/style";
|
||||
import { FC, Fragment, PropsWithChildren } from "react";
|
||||
|
||||
type HeaderDropdownProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const HeaderDropdown: FC<PropsWithChildren<HeaderDropdownProps>> = ({ children, className }) => {
|
||||
return <ul className={cn("rd-menu rd-navbar-megamenu", className)}>{children}</ul>;
|
||||
};
|
||||
|
||||
type HeaderDropdownGroupProps = {
|
||||
title?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const HeaderDropdownGroup: FC<PropsWithChildren<HeaderDropdownGroupProps>> = ({
|
||||
children,
|
||||
title,
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<li className={cn("rd-megamenu-item", className)}>
|
||||
{!!title && <h6 className="rd-megamenu-title">{title}</h6>}
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
type HeaderDropdownMenuItem = { title: string; href?: string };
|
||||
type HeaderDropdownMenuItemWithChild = { title: string; child: HeaderDropdownMenuItem[] };
|
||||
|
||||
type HeaderDropdownMenuProps = {
|
||||
list?: (HeaderDropdownMenuItem | HeaderDropdownMenuItemWithChild)[];
|
||||
};
|
||||
|
||||
export const HeaderDropdownMenu: FC<HeaderDropdownMenuProps> = ({ list = [] }) => {
|
||||
return (
|
||||
<ul className="rd-megamenu-list">
|
||||
{list.map((item, idx) => {
|
||||
const collapseId = createSlug(`collapse-${item.title}-${idx}`);
|
||||
const hasChild = "child" in item;
|
||||
const hrefClass = hasChild || !!item?.href ? "text-colorLinkText1! hover:text-colorLinkText2!" : "";
|
||||
|
||||
return (
|
||||
<Fragment key={idx}>
|
||||
{hasChild && (
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a
|
||||
className={`rd-megamenu-list-link cursor-pointer ${hrefClass}`}
|
||||
data-toggle="collapse"
|
||||
data-target={`#${collapseId}`}
|
||||
aria-controls={collapseId}
|
||||
aria-expanded="false"
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
<div className="pl-3 mt-2 space-y-2 collapse visible!" id={collapseId}>
|
||||
{item.child.map((itemChild, itemChildIdx) => (
|
||||
<a key={itemChildIdx} className={`rd-megamenu-list-link ${hrefClass}`} href={itemChild.href}>
|
||||
- {itemChild.title}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</li>
|
||||
)}
|
||||
|
||||
{!hasChild && (
|
||||
<li className="rd-megamenu-list-item">
|
||||
<a className={`rd-megamenu-list-link ${hrefClass}`} href={item.href}>
|
||||
{item.title}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
);
|
||||
};
|
34
src/components/layouts/HeaderFeaturedHomes.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
|
||||
export default function HeaderFeaturedHomes() {
|
||||
const images = [
|
||||
"/images/home1.jpg",
|
||||
"/images/home2.jpg",
|
||||
"/images/home3.jpg",
|
||||
"/images/home4.jpg",
|
||||
"/images/home5.jpg",
|
||||
"/images/home6.jpg",
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="p-2">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-1">
|
||||
{images.map((src, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="overflow-hidden rounded-lg shadow hover:shadow-lg transition-shadow duration-300 relative h-16"
|
||||
>
|
||||
<Image
|
||||
src={src}
|
||||
alt={`Gallery image ${index + 1}`}
|
||||
className="object-cover transform transition-transform duration-300 hover:scale-105 cursor-pointer"
|
||||
fill
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
74
src/components/pages/DetailPage.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { fetchPageBySlug } from "@/services/payload/page";
|
||||
import HeroImage from "../HeroImage";
|
||||
import { RenderBlocks } from "../blocks/RenderBlocks";
|
||||
|
||||
type shareUrlDestination = "facebook" | "linkedin" | "twitter";
|
||||
|
||||
type DetailPageProps = {
|
||||
data: Awaited<ReturnType<typeof fetchPageBySlug>>;
|
||||
shareUrl: Record<shareUrlDestination, string>;
|
||||
};
|
||||
|
||||
export default function DetailPage({ data, shareUrl }: DetailPageProps) {
|
||||
const page = data;
|
||||
if (!page) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<HeroImage imgSrc={page.heroImg?.url} title={page.data.title} />
|
||||
|
||||
<section className="section section-md bg-colorSection1">
|
||||
<div className="container">
|
||||
<div className="row justify-content-lg-center">
|
||||
<div className="col-12">
|
||||
<article className="blog-post-solo">
|
||||
<div className="blog-post-solo-part">
|
||||
<RenderBlocks blocks={page.data.layout} />
|
||||
</div>
|
||||
|
||||
<div className="blog-post-solo-footer">
|
||||
<div className="blog-post-solo-footer-left">
|
||||
<ul className="blog-post-solo-footer-list">
|
||||
<li>
|
||||
<span className="icon mdi mdi-clock"></span>
|
||||
<a href="#">{page.createdAt}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="blog-post-solo-footer-right">
|
||||
<ul className="blog-post-solo-footer-list-1">
|
||||
<li>
|
||||
<span>Share this post</span>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-5 fa-facebook"
|
||||
href={shareUrl.facebook}
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-6 fa-twitter"
|
||||
href={shareUrl.twitter}
|
||||
></a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
className="icon icon-circle icon-rounded icon-4 fa-linkedin"
|
||||
href={shareUrl.linkedin}
|
||||
></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
37
src/components/properties/ListOfFeaturedPropertiesFooter.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
"use client";
|
||||
|
||||
import { useLatestPropertyQuery } from "@/services/hooks/property";
|
||||
import { formatCurrency } from "@/utils/general";
|
||||
import Image from "next/image";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function ListOfFeaturedProperiesFooter() {
|
||||
const { data, _fetch } = useLatestPropertyQuery();
|
||||
|
||||
useEffect(() => {
|
||||
_fetch();
|
||||
}, []);
|
||||
|
||||
const latestProperties = data ? data.slice(0, 2) : [];
|
||||
|
||||
return (
|
||||
<>
|
||||
{latestProperties.length > 0 &&
|
||||
latestProperties.map((property, index) => (
|
||||
<a key={index} className="post-minimal" href={`single-property/${property.slug}`}>
|
||||
<div className="post-minimal-image">
|
||||
<Image src={property.images?.[0]?.url ?? ""} alt={property.title} width={161} height={136} />
|
||||
</div>
|
||||
<div className="post-minimal-body">
|
||||
<div className="post-minimal-title">
|
||||
<span className="text-colorFooterText! hover:text-colorFooterTextHover!">{property.title}</span>
|
||||
</div>
|
||||
<div className="post-minimal-text">
|
||||
<span>From {formatCurrency(property.price)}/month</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import { CardPropertyData } from "@/schema/property";
|
||||
import { useState } from "react";
|
||||
import { fetchLatestPropertyREST } from "../rest/property";
|
||||
|
40
src/services/payload/page.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import payloadConfig from "@/payload.config";
|
||||
import { formatDate } from "@/utils/datetime";
|
||||
import { getPayload } from "payload";
|
||||
|
||||
export const fetchPageBySlug = async ({ slug }: { slug: string | undefined }) => {
|
||||
const payload = await getPayload({ config: payloadConfig });
|
||||
|
||||
const result = await payload.find({
|
||||
collection: "pages",
|
||||
// draft,
|
||||
limit: 1,
|
||||
pagination: false,
|
||||
// overrideAccess: draft,
|
||||
where: {
|
||||
_status: { equals: "published" },
|
||||
slug: {
|
||||
equals: slug,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!result.docs?.[0]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = result.docs[0];
|
||||
|
||||
const heroImgUrl = typeof data.hero_img !== "number" ? (data?.hero_img?.url ?? "") : "";
|
||||
const heroImgAlt = typeof data.hero_img !== "number" ? (data?.hero_img?.alt ?? "") : "";
|
||||
|
||||
return {
|
||||
data: data,
|
||||
createdAt: formatDate(data.createdAt),
|
||||
updatedAt: formatDate(data.updatedAt),
|
||||
heroImg: {
|
||||
url: heroImgUrl,
|
||||
alt: heroImgAlt,
|
||||
},
|
||||
};
|
||||
};
|
@ -24,3 +24,10 @@ export function formatCurrency(num: number): string {
|
||||
//maximumFractionDigits: 0, // Causes 2500.99 to be printed as $2,501
|
||||
}).format(num);
|
||||
}
|
||||
|
||||
export function createSlug(val: string) {
|
||||
return val
|
||||
.replace(/ /g, "-")
|
||||
.replace(/[^\w-/]+/g, "")
|
||||
.toLowerCase();
|
||||
}
|
||||
|
6
src/utils/style.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
@ -5044,6 +5044,7 @@ __metadata:
|
||||
"@types/node": "npm:^20"
|
||||
"@types/react": "npm:^19"
|
||||
"@types/react-dom": "npm:^19"
|
||||
clsx: "npm:^2.1.1"
|
||||
country-state-city: "npm:^3.2.1"
|
||||
dayjs: "npm:^1.11.13"
|
||||
eslint: "npm:^9"
|
||||
@ -5061,6 +5062,7 @@ __metadata:
|
||||
react-select: "npm:^5.10.1"
|
||||
react-toastify: "npm:^11.0.5"
|
||||
swiper: "npm:^11.2.6"
|
||||
tailwind-merge: "npm:^3.2.0"
|
||||
tailwindcss: "npm:^4"
|
||||
typescript: "npm:^5"
|
||||
languageName: unknown
|
||||
@ -9759,6 +9761,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tailwind-merge@npm:^3.2.0":
|
||||
version: 3.2.0
|
||||
resolution: "tailwind-merge@npm:3.2.0"
|
||||
checksum: 10c0/294f6c2db0df74405bff126107107426c3126a70a1717d78e8d6811db65546c9bb3d61282bdb8d9fbded23f6bc8ec3e8e61031a4f53265f90b7f3dba558f88f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tailwindcss@npm:4.1.4, tailwindcss@npm:^4":
|
||||
version: 4.1.4
|
||||
resolution: "tailwindcss@npm:4.1.4"
|
||||
|