Skip to content

Commit cbd4588

Browse files
google-labs-jules[bot]admdly
authored andcommitted
Update to Nextra v4
1 parent 42039cd commit cbd4588

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+788
-835
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# Next.js
1111
/.next/
1212
/out/
13+
_pagefind/
1314

1415
# Production
1516
/build

app/[[...mdxPath]]/page.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { generateStaticParamsFor, importPage } from 'nextra/pages';
2+
import { useMDXComponents as getMDXComponents } from '../../mdx-components';
3+
import type { Metadata } from 'next';
4+
import type { ComponentType, ReactNode, ReactElement } from 'react';
5+
6+
interface PageParams {
7+
mdxPath: string[];
8+
}
9+
interface GenerateMetadataProps {
10+
params: Promise<PageParams>;
11+
}
12+
interface PageComponentProps {
13+
params: Promise<PageParams>;
14+
}
15+
interface TocEntry {
16+
id: string;
17+
value: string;
18+
depth: number;
19+
}
20+
interface ImportPageData {
21+
default: ComponentType<any>;
22+
toc?: TocEntry[];
23+
metadata: Metadata;
24+
}
25+
26+
export const generateStaticParams = generateStaticParamsFor('mdxPath');
27+
28+
export async function generateMetadata(props: GenerateMetadataProps): Promise<Metadata> {
29+
const params = await props.params;
30+
const { metadata } = (await importPage(params.mdxPath)) as ImportPageData;
31+
return metadata;
32+
}
33+
34+
const Wrapper: ComponentType<{ toc?: TocEntry[]; metadata: Metadata; children: ReactNode }> = getMDXComponents({}).wrapper;
35+
36+
export default async function Page(props: PageComponentProps): Promise<ReactElement> {
37+
const params = await props.params;
38+
const result = (await importPage(params.mdxPath)) as ImportPageData;
39+
const { default: MDXContent, toc, metadata } = result;
40+
return (
41+
<Wrapper toc={toc} metadata={metadata}>
42+
<MDXContent {...props} params={params} />
43+
</Wrapper>
44+
);
45+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { FOSSBillingAPIResponse } from 'interfaces/index';
2+
import { NextRequest, NextResponse } from 'next/server'
3+
import { CentralAlerts } from 'data/CentralAlerts';
4+
5+
export async function GET(req: NextRequest) {
6+
return NextResponse.json({
7+
result: {
8+
alerts: CentralAlerts
9+
},
10+
error: null
11+
} as FOSSBillingAPIResponse, { status: 200 })
12+
}

pages/api/releases.ts renamed to app/api/releases/route.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FOSSBillingAPIResponse, FOSSBillingVersion } from 'interfaces/index';
2-
import type { NextApiRequest, NextApiResponse } from 'next'
2+
import { NextRequest, NextResponse } from 'next/server';
33

4-
export default function handler(req: NextApiRequest, res: NextApiResponse<FOSSBillingAPIResponse>) {
4+
export async function GET(req: NextRequest) {
55
const versions = ["0.1.0", "0.1.1", "0.2.0", "0.2.1", "0.2.2",
66
"0.2.3", "0.2.4", "0.2.5", "0.2.6", "0.2.7",
77
"0.2.8", "0.2.9", "0.2.10", "0.3.0", "0.4.0",
@@ -27,10 +27,10 @@ export default function handler(req: NextApiRequest, res: NextApiResponse<FOSSBi
2727
} as FOSSBillingVersion
2828
});
2929

30-
res.status(200).json({
30+
return NextResponse.json({
3131
result: {
3232
versions: versionsWithSupport
3333
},
3434
error: null
35-
})
35+
} as FOSSBillingAPIResponse, { status: 200 })
3636
}

app/layout.tsx

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { Analytics } from '@vercel/analytics/react';
2+
import { Layout, Navbar, Footer } from 'nextra-theme-docs';
3+
import { Banner, Head, Search } from 'nextra/components';
4+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
5+
import { faDiscord, faGithub, faTwitter, faMastodon } from '@fortawesome/free-brands-svg-icons';
6+
import { faMessage, faSignal } from "@fortawesome/free-solid-svg-icons";
7+
import { getPageMap } from 'nextra/page-map';
8+
import { config } from '@fortawesome/fontawesome-svg-core';
9+
import type { Metadata, Viewport } from 'next';
10+
import '@fortawesome/fontawesome-svg-core/styles.css';
11+
config.autoAddCss = false;
12+
13+
import '../style.css';
14+
import '../styles/globals.css';
15+
import 'nextra-theme-docs/style.css';
16+
17+
const navbarProps = {
18+
logo: <>
19+
<span className="logo"></span>
20+
</>,
21+
projectLink: 'https://github.com/FOSSBilling/FOSSBilling',
22+
projectIcon: <FontAwesomeIcon icon={faGithub} size="xl" />,
23+
chatLink: 'https://fossbilling.org/discord',
24+
chatIcon: <FontAwesomeIcon icon={faDiscord} size="xl" />,
25+
};
26+
27+
const bannerProps = {
28+
storageKey: 'mollie',
29+
children: (
30+
<a href="https://github.com/NerdbyteIO/FOSSBilling-CyberPanel" target="_blank" rel="noopener noreferrer">
31+
⭐️ There's now a community maintained integration for CyberPanel! Click here to check it out.
32+
</a>
33+
),
34+
};
35+
36+
const SiteFooter = () => {
37+
return (
38+
<div>
39+
<div className="mb-2">
40+
<a href="mailto:[email protected]" className="hover:text-gray-500 dark:hover:text-gray-300">[email protected]</a>
41+
</div>
42+
<div className="mb-6">
43+
<a href="/discord" className="hover:text-gray-500 dark:hover:text-gray-300" target="_blank" rel="noopener noreferrer"><FontAwesomeIcon icon={faDiscord} size="xl" className="mr-4" /></a>
44+
<a href="https://fosstodon.org/@fossbilling" className="hover:text-gray-500 dark:hover:text-gray-300" target="_blank" rel="noopener noreferrer"><FontAwesomeIcon icon={faMastodon} size="xl" className="mr-4" /></a>
45+
<a href="https://twitter.com/FOSSBilling" className="hover:text-gray-500 dark:hover:text-gray-300" target="_blank" rel="noopener noreferrer"><FontAwesomeIcon icon={faTwitter} size="xl" className="mr-4" /></a>
46+
<a href="https://forum.fossbilling.org" className="hover:text-gray-500 dark:hover:text-gray-300" target="_blank" rel="noopener noreferrer"><FontAwesomeIcon icon={faMessage} size="xl" className="mr-4" /></a>
47+
<a href="https://status.fossbilling.org/" className="hover:text-gray-500 dark:hover:text-gray-300" target="_blank" rel="noopener noreferrer"><FontAwesomeIcon icon={faSignal} size="xl" className="mr-4" /></a>
48+
</div>
49+
<p className="mt-6 text-xs">© {new Date().getFullYear()}, The FOSSBilling project. Content licensed under the <a href="https://github.com/FOSSBilling/fossbilling.org/blob/main/LICENSE" target="_blank" rel="noopener noreferrer">Apache 2.0 license</a>.</p>
50+
</div>
51+
);
52+
};
53+
54+
export const metadata: Metadata = {
55+
title: {
56+
default: 'FOSSBilling',
57+
template: '%s | FOSSBilling',
58+
},
59+
description: "Empower your hosting business with FOSSBilling, the free and open-source solution for efficient billing and client management.",
60+
openGraph: {
61+
title: {
62+
default: 'FOSSBilling',
63+
template: '%s | FOSSBilling',
64+
},
65+
description: "Empower your hosting business with FOSSBilling, the free and open-source solution for efficient billing and client management.",
66+
images: [
67+
{
68+
url: ''
69+
},
70+
],
71+
locale: 'en_US',
72+
type: 'website'
73+
},
74+
twitter: {
75+
card: "summary_large_image",
76+
site: "@FOSSBilling",
77+
images: [''],
78+
},
79+
appleWebApp: {
80+
title: "FOSSBilling",
81+
}
82+
};
83+
84+
export const viewport: Viewport = {
85+
width: 'device-width',
86+
initialScale: 1.0
87+
}
88+
89+
export default async function RootLayout({ children }) {
90+
const pageMap = await getPageMap();
91+
return (
92+
<html lang="en" dir="ltr" suppressHydrationWarning>
93+
<Head
94+
color={{
95+
hue: { dark: 200, light: 200 }
96+
}}
97+
/>
98+
<body>
99+
<Layout
100+
banner={<Banner {...bannerProps} />}
101+
navbar={<Navbar {...navbarProps} />}
102+
pageMap={pageMap}
103+
docsRepositoryBase="https://github.com/FOSSBilling/FOSSBilling.org/blob/main"
104+
sidebar={{ defaultMenuCollapseLevel: 1 }}
105+
feedback={{ content: undefined }}
106+
footer={<Footer><SiteFooter /></Footer>}
107+
>
108+
{children}
109+
</Layout>
110+
<Analytics />
111+
</body>
112+
</html>
113+
);
114+
}

components/FAIcon.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react';
2+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3+
import {
4+
faDownload,
5+
faCode,
6+
faServer,
7+
faBoxOpen,
8+
faWrench,
9+
faHand,
10+
faPersonDigging,
11+
faCircleInfo,
12+
faRobot,
13+
faTriangleExclamation,
14+
faUserShield,
15+
faLanguage,
16+
faScrewdriverWrench,
17+
faBell
18+
} from '@fortawesome/free-solid-svg-icons';
19+
import {
20+
faGithub,
21+
faDocker,
22+
faCpanel
23+
} from '@fortawesome/free-brands-svg-icons';
24+
25+
// Map of icon names to icon objects
26+
const iconMap = {
27+
faDownload,
28+
faCode,
29+
faServer,
30+
faBoxOpen,
31+
faWrench,
32+
faHand,
33+
faPersonDigging,
34+
faCircleInfo,
35+
faRobot,
36+
faTriangleExclamation,
37+
faUserShield,
38+
faLanguage,
39+
faScrewdriverWrench,
40+
faBell,
41+
faGithub,
42+
faDocker,
43+
faCpanel,
44+
};
45+
46+
type IconName = keyof typeof iconMap;
47+
48+
interface FAIconProps {
49+
icon: IconName;
50+
className?: string;
51+
}
52+
53+
export function FAIcon({ icon, className }: FAIconProps) {
54+
const iconObject = iconMap[icon];
55+
if (!iconObject) {
56+
console.warn(`Icon ${icon} not found in iconMap`);
57+
return null;
58+
}
59+
return <FontAwesomeIcon icon={iconObject} className={className} />;
60+
}
61+
62+
export default FAIcon;

components/Features/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
"use client";
12
import cn from 'clsx'
23
import { motion } from 'framer-motion'
34

components/Features/themes-animation.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"use client";
2+
13
export function ThemesAnimation(props) {
24
return (
35
<svg

components/LatestVersion.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
3+
async function getLatestReleaseData() {
4+
try {
5+
const res = await fetch('https://api.github.com/repos/FOSSBilling/FOSSBilling/releases', {
6+
next: { revalidate: 600 } // Revalidate every 10 minutes
7+
});
8+
const releases = await res.json();
9+
return {
10+
latest_version: releases[0].tag_name,
11+
released_on: releases[0].published_at,
12+
};
13+
} catch (error) {
14+
console.error('Failed to fetch release data:', error);
15+
return {
16+
latest_version: 'N/A',
17+
released_on: new Date().toISOString(),
18+
};
19+
}
20+
}
21+
22+
export default async function LatestVersion(): Promise<React.JSX.Element> {
23+
const { latest_version } = await getLatestReleaseData();
24+
return <>{latest_version}</>;
25+
}

components/Motion/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"use client";
2+
import { motion } from 'framer-motion';
3+
4+
export default motion;

0 commit comments

Comments
 (0)