fix sponsor and footer social
This commit is contained in:
@@ -49,8 +49,9 @@ export default function Home() {
|
|||||||
>
|
>
|
||||||
Mulai Tutorial
|
Mulai Tutorial
|
||||||
</Link>
|
</Link>
|
||||||
{/* <Link
|
<Link
|
||||||
href="/blog"
|
href="https://www.youtube.com/channel/UC3uU_grYJ8dl4FBLSLvreeA?sub_confirmation=1"
|
||||||
|
target="_blank"
|
||||||
className={buttonVariants({
|
className={buttonVariants({
|
||||||
variant: "secondary",
|
variant: "secondary",
|
||||||
className:
|
className:
|
||||||
@@ -58,8 +59,8 @@ export default function Home() {
|
|||||||
size: "lg",
|
size: "lg",
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
Read Blog
|
Subscribe
|
||||||
</Link> */}
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 py-12">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 py-12">
|
||||||
<Card className="px-2 py-6">
|
<Card className="px-2 py-6">
|
||||||
|
|||||||
@@ -1,16 +1,45 @@
|
|||||||
import docuConfig from "@/docu.json";
|
import docuData from "@/docu.json";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
export function Sponsor() {
|
// Define types for docu.json
|
||||||
const sponsor = docuConfig.sponsor;
|
interface SponsorItem {
|
||||||
const item = sponsor?.item;
|
url: string;
|
||||||
|
image: string;
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
if (!item) return null;
|
interface DocuConfig {
|
||||||
|
sponsor?: {
|
||||||
|
title?: string;
|
||||||
|
item?: SponsorItem;
|
||||||
|
};
|
||||||
|
navbar: any; // Anda bisa mendefinisikan tipe yang lebih spesifik jika diperlukan
|
||||||
|
footer: any;
|
||||||
|
meta: any;
|
||||||
|
repository: any;
|
||||||
|
routes: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type assertion for docu.json
|
||||||
|
const docuConfig = docuData as DocuConfig;
|
||||||
|
|
||||||
|
export function Sponsor() {
|
||||||
|
// Safely get sponsor data with optional chaining and default values
|
||||||
|
const sponsor = docuConfig?.sponsor || {};
|
||||||
|
const item = sponsor?.item;
|
||||||
|
|
||||||
|
// Return null if required fields are missing
|
||||||
|
if (!item?.url || !item?.image || !item?.title) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<h2 className="mb-4 text-sm font-medium">{sponsor.title || "Sponsor"}</h2>
|
{sponsor?.title && (
|
||||||
|
<h2 className="mb-4 text-sm font-medium">{sponsor.title}</h2>
|
||||||
|
)}
|
||||||
<Link
|
<Link
|
||||||
href={item.url}
|
href={item.url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
@@ -23,11 +52,14 @@ export function Sponsor() {
|
|||||||
alt={item.title}
|
alt={item.title}
|
||||||
fill
|
fill
|
||||||
className="object-contain"
|
className="object-contain"
|
||||||
|
sizes="32px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-center sm:text-left">
|
<div className="text-center sm:text-left">
|
||||||
<h3 className="text-sm font-medium">{item.title}</h3>
|
<h3 className="text-sm font-medium">{item.title}</h3>
|
||||||
<p className="text-muted-foreground text-sm">{item.description}</p>
|
{item.description && (
|
||||||
|
<p className="text-muted-foreground text-sm">{item.description}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,37 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { ModeToggle } from "@/components/theme-toggle";
|
import { ModeToggle } from "@/components/theme-toggle";
|
||||||
import docuConfig from "@/docu.json";
|
import docuData from "@/docu.json";
|
||||||
import * as LucideIcons from "lucide-react"; // Import all icons
|
import * as LucideIcons from "lucide-react";
|
||||||
|
|
||||||
|
// Define types for docu.json
|
||||||
|
interface SocialItem {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
iconName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FooterConfig {
|
||||||
|
copyright: string;
|
||||||
|
social?: SocialItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MetaConfig {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
baseURL: string;
|
||||||
|
favicon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DocuConfig {
|
||||||
|
footer: FooterConfig;
|
||||||
|
meta: MetaConfig;
|
||||||
|
navbar: any;
|
||||||
|
repository: any;
|
||||||
|
routes: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type assertion for docu.json
|
||||||
|
const docuConfig = docuData as DocuConfig;
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
const { footer } = docuConfig;
|
const { footer } = docuConfig;
|
||||||
@@ -33,7 +63,7 @@ export function FooterButtons() {
|
|||||||
const footer = docuConfig?.footer;
|
const footer = docuConfig?.footer;
|
||||||
|
|
||||||
// Jangan render apapun jika tidak ada data sosial
|
// Jangan render apapun jika tidak ada data sosial
|
||||||
if (!footer?.social || !Array.isArray(footer.social) || footer.social.length === 0) {
|
if (!footer || !Array.isArray(footer.social) || footer.social.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
docu.json
14
docu.json
@@ -12,19 +12,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"copyright": "Addon Sejoli Pro",
|
"copyright": "Addon Sejoli Pro"
|
||||||
"social": [
|
|
||||||
{
|
|
||||||
"name": "Youtube",
|
|
||||||
"url": "https://www.youtube.com/@AddonsSejoliPro",
|
|
||||||
"iconName": "YoutubeIcon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Website",
|
|
||||||
"url": "https://addonsejoli.pro/product",
|
|
||||||
"iconName": "RocketIcon"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"baseURL": "https://docs.addonsejoli.pro",
|
"baseURL": "https://docs.addonsejoli.pro",
|
||||||
|
|||||||
Reference in New Issue
Block a user