diff --git a/.gitignore b/.gitignore index f74c781..4ef2107 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ .next node_modules +.source +.open-next +.dev.vars +.wrangler +cloudflare-env.d.ts diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +20 diff --git a/app/(docs)/[[...slug]]/page.tsx b/app/(docs)/[[...slug]]/page.tsx new file mode 100644 index 0000000..47e5299 --- /dev/null +++ b/app/(docs)/[[...slug]]/page.tsx @@ -0,0 +1,48 @@ +import { source } from '@/lib/source'; +import { + DocsPage, + DocsBody, + DocsDescription, + DocsTitle, +} from 'fumadocs-ui/page'; +import { notFound } from 'next/navigation'; +import { getMDXComponents } from '@/mdx-components'; + +export default async function Page(props: { + params: Promise<{ slug?: string[] }>; +}) { + const params = await props.params; + const page = source.getPage(params.slug); + + if (!page) notFound(); + + const MDX = page.data.body; + + return ( + + {page.data.title} + {page.data.description} + + + + + ); +} + +export async function generateStaticParams() { + return source.generateParams(); +} + +export async function generateMetadata(props: { + params: Promise<{ slug?: string[] }>; +}) { + const params = await props.params; + const page = source.getPage(params.slug); + + if (!page) notFound(); + + return { + title: page.data.title, + description: page.data.description, + }; +} diff --git a/app/(docs)/layout.tsx b/app/(docs)/layout.tsx new file mode 100644 index 0000000..08d6826 --- /dev/null +++ b/app/(docs)/layout.tsx @@ -0,0 +1,25 @@ +import { source } from '@/lib/source'; +import { baseOptions } from '@/lib/layout.shared'; +import { DocsLayout } from 'fumadocs-ui/layouts/docs'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: { + template: '%s - Andronix Docs', + default: 'Andronix Documentation', + }, +}; + +export default function RootDocsLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/app/api/search/route.ts b/app/api/search/route.ts new file mode 100644 index 0000000..4f938c6 --- /dev/null +++ b/app/api/search/route.ts @@ -0,0 +1,11 @@ +import { source } from '@/lib/source'; +import { createSearchAPI } from 'fumadocs-core/search/server'; + +export const { GET } = createSearchAPI('advanced', { + indexes: source.getPages().map((page) => ({ + title: page.data.title, + structuredData: page.data.structuredData, + id: page.url, + url: page.url, + })), +}); diff --git a/app/global.css b/app/global.css new file mode 100644 index 0000000..12f10cb --- /dev/null +++ b/app/global.css @@ -0,0 +1,15 @@ +@import 'tailwindcss'; +@import 'fumadocs-ui/css/neutral.css'; +@import 'fumadocs-ui/css/preset.css'; + +@theme { + /* Orange primary color for light mode */ + --color-fd-primary: hsl(24.6, 95%, 53.1%); /* Orange-500 */ + --color-fd-primary-foreground: hsl(0, 0%, 100%); /* White text */ +} + +.dark { + /* Orange primary color for dark mode */ + --color-fd-primary: hsl(20.5, 90.2%, 48.2%); /* Orange-500 adjusted for dark */ + --color-fd-primary-foreground: hsl(0, 0%, 100%); /* White text */ +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..64c8d9c --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,64 @@ +import './global.css'; +import { RootProvider } from 'fumadocs-ui/provider'; +import { Banner } from 'fumadocs-ui/components/banner'; +import { Inter } from 'next/font/google'; + +const inter = Inter({ + subsets: ['latin'], +}); + +export const metadata = { + title: { + template: '%s - Andronix Docs', + default: 'Andronix Documentation', + }, + description: 'Andronix lets you install Linux distributions like Ubuntu, Debian, and Manjaro on non-rooted Android devices. Read our documentation for step-by-step instructions.', + metadataBase: new URL('https://docs.andronix.app'), + openGraph: { + title: 'Andronix Documentation', + description: 'Andronix lets you install Ubuntu, Debian, and Manjaro on non-rooted Android devices. Our documentation provides step-by-step instructions and troubleshooting tips to help you set up your Linux environment quickly and easily. Experience the power of Linux on your mobile device with Andronix.', + url: 'https://docs.andronix.app/', + images: '/og.png', + type: 'website', + }, + twitter: { + card: 'summary_large_image', + title: 'Andronix Documentation', + description: 'Andronix lets you install Ubuntu, Debian, and Manjaro on non-rooted Android devices. Our documentation provides step-by-step instructions and troubleshooting tips to help you set up your Linux environment quickly and easily. Experience the power of Linux on your mobile device with Andronix.', + images: '/og.png', + }, +}; + +export default function Layout({ children }: { children: React.ReactNode }) { + return ( + + + +
+ 🚨 Resolve Process completed (signal 9) error + β†’ + + Read the fix + +
+
+ {children} + + + ); +} diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..925fde4 --- /dev/null +++ b/build.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Cloudflare Pages build script +# This ensures OpenNext is used instead of the deprecated next-on-pages + +echo "Building with OpenNext Cloudflare adapter..." +npx opennextjs-cloudflare build + +# Restructure for Cloudflare Pages +echo "Setting up Cloudflare Pages structure..." + +# Copy worker to root as _worker.js +cp .open-next/worker.js .open-next/_worker.js + +# Move assets to root level (Cloudflare Pages serves from root) +cp -r .open-next/assets/* .open-next/ + +echo "Build complete!" diff --git a/components/author.tsx b/components/author.tsx index 08671e6..63a5ca9 100644 --- a/components/author.tsx +++ b/components/author.tsx @@ -1,4 +1,4 @@ -export default function Authors({ date, children, by = "by" }) { +export default function Authors({ date, children, by = "by" }: { date: string; children: React.ReactNode; by?: string }) { return (
{date} {by} {children} @@ -6,7 +6,7 @@ export default function Authors({ date, children, by = "by" }) { ); } -export function Author({ name, link }) { +export function Author({ name, link }: { name: string; link: string }) { return ( -

{children}

-
- ) +export default function Badge({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); } diff --git a/components/blog_index.tsx b/components/blog_index.tsx index 4840e40..5cb5b9d 100644 --- a/components/blog_index.tsx +++ b/components/blog_index.tsx @@ -1,41 +1,71 @@ -import { getPagesUnderRoute } from "nextra/context"; import Link from "next/link"; -export default function BlogIndex({ more = "Read more" }) { - return getPagesUnderRoute("/blog").reverse().map((page) => { +interface BlogPost { + title: string; + slug: string; + description?: string; + date?: string; +} - return ( -
-

- - {/*@ts-ignore*/} - {page.meta?.title || page.frontMatter?.title || page.name} - -

-

- {/*@ts-ignore*/} - {page.frontMatter?.description}{" "} - - - {more + " β†’"} - - -

- {/*@ts-ignore*/} - {page.frontMatter?.date ? ( -

- {/*@ts-ignore*/} - {page.frontMatter.date} +const blogPosts: BlogPost[] = [ + { + title: "Calling for Andronix Maintainers", + slug: "andronix-maintainers", + description: "We are looking for maintainers for Andronix. If you are interested, please read this blog.", + date: "December 26, 2023" + }, + { + title: "Andronix 7.0 - Refresh", + slug: "v7-0", + description: "Long time no-see, and here we are again. Andronix is getting updated to version 7.0.", + date: "January 17, 2023" + }, + { + title: "Andronix 6.0 - A new beginning...", + slug: "v6-0", + description: "Andronix 6.0 is here. A new beginning for Andronix. Read more about the changes in this blog.", + date: "August 11, 2021" + }, + { + title: "Andronix, Termux and F-Droid", + slug: "andronix-termux-and-f-droid", + description: "Information about migrating Termux from Google Play Store to F-Droid after the shut-down of Bintray, a package hosting service from Jfrog.", + date: "July 14, 2021" + } +]; + +export default function BlogIndex({ more = "Read more" }: { more?: string }) { + return ( + <> + {blogPosts.map((post) => ( +

+

+ + {post.title} + +

+

+ {post.description}{" "} + + + {more + " β†’"} + +

- ) : null} -
- ); - }); -} \ No newline at end of file + {post.date && ( +

+ {post.date} +

+ )} +
+ ))} + + ); +} diff --git a/components/button.tsx b/components/button.tsx index e36ed1a..9b125f8 100644 --- a/components/button.tsx +++ b/components/button.tsx @@ -8,9 +8,9 @@ export default function AndronixButton({ }: { link: string, children?: any, className?: string }) { return ( - {children} - + className={`${className} inline-flex items-center gap-1 text-sm font-medium text-orange-600 dark:text-orange-400 hover:text-orange-700 dark:hover:text-orange-300 underline decoration-orange-600/30 dark:decoration-orange-400/30 underline-offset-4 hover:decoration-orange-600 dark:hover:decoration-orange-400 transition-colors`}> + {children} + ) } \ No newline at end of file diff --git a/components/imagera.tsx b/components/imagera.tsx index b57c6f9..5bdb5a2 100644 --- a/components/imagera.tsx +++ b/components/imagera.tsx @@ -1,20 +1,36 @@ import React from "react"; +import { ImageZoom } from "fumadocs-ui/components/image-zoom"; import Image from "next/image"; export default function Imagera({ - src, - height = 400, - alt = "image" - }: { src: string, height?: number, alt?: string }) { - - return ( -
-
- {!src.includes(".gif") ? - {alt} : - {alt} - } -
- ) + src, + height = 400, + alt = "image", +}: { + src: string; + height?: number; + alt?: string; +}) { + return ( +
+
+ {!src.includes(".gif") ? ( + + ) : ( + {alt} + )} +
+ ); } diff --git a/components/youtubeEmbed.tsx b/components/youtubeEmbed.tsx index 18a219d..7187f75 100644 --- a/components/youtubeEmbed.tsx +++ b/components/youtubeEmbed.tsx @@ -1,4 +1,4 @@ -export default function YoutubeEmbed({id}){ +export default function YoutubeEmbed({ id }: { id: string }) { return (