{title &&
{title}
}
diff --git a/packages/chronicle/src/components/mdx/details.module.css b/packages/chronicle/src/components/mdx/details.module.css
index f79a00a..01f0dd1 100644
--- a/packages/chronicle/src/components/mdx/details.module.css
+++ b/packages/chronicle/src/components/mdx/details.module.css
@@ -4,32 +4,9 @@
margin: var(--rs-space-5) 0;
}
-.summary {
- padding: var(--rs-space-4) var(--rs-space-5);
- cursor: pointer;
+.trigger {
font-weight: 500;
font-size: var(--rs-font-size-small);
- color: var(--rs-color-text-base-primary);
- background: var(--rs-color-background-base-secondary);
- list-style: none;
- display: flex;
- align-items: center;
- gap: var(--rs-space-3);
-}
-
-.summary::-webkit-details-marker {
- display: none;
-}
-
-.summary::before {
- content: '▶';
- font-size: 10px;
- transition: transform 0.2s ease;
- color: var(--rs-color-text-base-secondary);
-}
-
-.details[open] > .summary::before {
- transform: rotate(90deg);
}
.content {
diff --git a/packages/chronicle/src/components/mdx/details.tsx b/packages/chronicle/src/components/mdx/details.tsx
index 2d29ac0..aa98714 100644
--- a/packages/chronicle/src/components/mdx/details.tsx
+++ b/packages/chronicle/src/components/mdx/details.tsx
@@ -1,9 +1,8 @@
import type { ComponentProps } from 'react'
-import styles from './details.module.css'
export function MdxDetails({ children, className, ...props }: ComponentProps<'details'>) {
return (
-
+
{children}
)
@@ -11,7 +10,7 @@ export function MdxDetails({ children, className, ...props }: ComponentProps<'de
export function MdxSummary({ children, className, ...props }: ComponentProps<'summary'>) {
return (
-
+
{children}
)
diff --git a/packages/chronicle/src/components/mdx/image.tsx b/packages/chronicle/src/components/mdx/image.tsx
index fcf511d..a2bdb5b 100644
--- a/packages/chronicle/src/components/mdx/image.tsx
+++ b/packages/chronicle/src/components/mdx/image.tsx
@@ -1,6 +1,5 @@
'use client'
-import NextImage from 'next/image'
import type { ComponentProps } from 'react'
type ImageProps = Omit, 'src'> & {
@@ -12,27 +11,14 @@ type ImageProps = Omit, 'src'> & {
export function Image({ src, alt, width, height, ...props }: ImageProps) {
if (!src || typeof src !== 'string') return null
- const isExternal = src.startsWith('http://') || src.startsWith('https://')
-
- if (isExternal) {
- return (
- // eslint-disable-next-line @next/next/no-img-element
-
- )
- }
-
return (
-
)
}
diff --git a/packages/chronicle/src/components/mdx/index.tsx b/packages/chronicle/src/components/mdx/index.tsx
index b22d73e..0fc8cb8 100644
--- a/packages/chronicle/src/components/mdx/index.tsx
+++ b/packages/chronicle/src/components/mdx/index.tsx
@@ -1,6 +1,6 @@
import type { MDXComponents } from 'mdx/types'
import { Image } from './image'
-import { Link } from './link'
+import { MdxLink } from './link'
import { MdxTable, MdxThead, MdxTbody, MdxTr, MdxTh, MdxTd } from './table'
import { MdxPre, MdxCode } from './code'
import { MdxDetails, MdxSummary } from './details'
@@ -12,7 +12,7 @@ import { Tabs } from '@raystack/apsara'
export const mdxComponents: MDXComponents = {
p: MdxParagraph,
img: Image,
- a: Link,
+ a: MdxLink,
table: MdxTable,
thead: MdxThead,
tbody: MdxTbody,
@@ -32,4 +32,4 @@ export const mdxComponents: MDXComponents = {
}
export { Image } from './image'
-export { Link } from './link'
+export { MdxLink } from './link'
diff --git a/packages/chronicle/src/components/mdx/link.tsx b/packages/chronicle/src/components/mdx/link.tsx
index 8193d6f..93f7fa5 100644
--- a/packages/chronicle/src/components/mdx/link.tsx
+++ b/packages/chronicle/src/components/mdx/link.tsx
@@ -1,12 +1,11 @@
'use client'
-import NextLink from 'next/link'
-import { Link as ApsaraLink } from '@raystack/apsara'
+import { Link } from 'react-router-dom'
import type { ComponentProps } from 'react'
type LinkProps = ComponentProps<'a'>
-export function Link({ href, children, ...props }: LinkProps) {
+export function MdxLink({ href, children, ...props }: LinkProps) {
if (!href) {
return {children}
}
@@ -14,25 +13,25 @@ export function Link({ href, children, ...props }: LinkProps) {
const isExternal = href.startsWith('http://') || href.startsWith('https://')
const isAnchor = href.startsWith('#')
- if (isAnchor) {
+ if (isExternal) {
return (
-
+
{children}
-
+
)
}
- if (isExternal) {
+ if (isAnchor) {
return (
-
+
{children}
-
+
)
}
return (
-
+
{children}
-
+
)
}
diff --git a/packages/chronicle/src/components/ui/footer.tsx b/packages/chronicle/src/components/ui/footer.tsx
index 0f3c35f..457bd01 100644
--- a/packages/chronicle/src/components/ui/footer.tsx
+++ b/packages/chronicle/src/components/ui/footer.tsx
@@ -1,4 +1,5 @@
-import { Flex, Link, Text } from "@raystack/apsara";
+import { Link } from "react-router-dom";
+import { Flex, Text } from "@raystack/apsara";
import type { FooterConfig } from "@/types";
import styles from "./footer.module.css";
@@ -18,7 +19,7 @@ export function Footer({ config }: FooterProps) {
{config?.links && config.links.length > 0 && (
{config.links.map((link) => (
-
+
{link.label}
))}
diff --git a/packages/chronicle/src/components/ui/search.tsx b/packages/chronicle/src/components/ui/search.tsx
index fb56aaa..e5a2f6a 100644
--- a/packages/chronicle/src/components/ui/search.tsx
+++ b/packages/chronicle/src/components/ui/search.tsx
@@ -1,21 +1,54 @@
"use client";
-import { useState, useEffect, useCallback } from "react";
-import { useRouter } from "next/navigation";
+import { useState, useEffect, useCallback, useRef } from "react";
+import { useNavigate } from "react-router-dom";
import { Button, Command, Dialog, Text } from "@raystack/apsara";
import { cx } from "class-variance-authority";
-import { useDocsSearch } from "fumadocs-core/search/client";
-import type { SortedResult } from "fumadocs-core/search";
import { DocumentIcon, HashtagIcon } from "@heroicons/react/24/outline";
-import { isMacOs } from "react-device-detect";
import { MethodBadge } from "@/components/api/method-badge";
import styles from "./search.module.css";
+interface SearchResult {
+ id: string;
+ url: string;
+ type: "page" | "api";
+ content: string;
+}
+
+function useSearch(query: string) {
+ const [results, setResults] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const timerRef = useRef | null>(null);
+
+ useEffect(() => {
+ let cancelled = false;
+ if (timerRef.current) clearTimeout(timerRef.current);
+ timerRef.current = setTimeout(async () => {
+ setIsLoading(true);
+ try {
+ const params = new URLSearchParams();
+ if (query) params.set("query", query);
+ const res = await fetch(`/api/search?${params}`);
+ if (!cancelled) setResults(await res.json());
+ } catch {
+ if (!cancelled) setResults([]);
+ }
+ if (!cancelled) setIsLoading(false);
+ }, 100);
+ return () => {
+ cancelled = true;
+ if (timerRef.current) clearTimeout(timerRef.current);
+ };
+ }, [query]);
+
+ return { results, isLoading };
+}
+
function SearchShortcutKey({ className }: { className?: string }) {
- const [key, setKey] = useState("⌘");
+ const [key, setKey] = useState("\u2318");
useEffect(() => {
- setKey(isMacOs ? "⌘" : "Ctrl");
+ setKey(navigator.platform?.startsWith("Mac") ? "\u2318" : "Ctrl");
}, []);
return (
@@ -26,26 +59,21 @@ function SearchShortcutKey({ className }: { className?: string }) {
}
interface SearchProps {
- className?: string
+ className?: string;
}
export function Search({ className }: SearchProps) {
const [open, setOpen] = useState(false);
- const router = useRouter();
-
- const { search, setSearch, query } = useDocsSearch({
- type: "fetch",
- api: "/api/search",
- delayMs: 100,
- allowEmpty: true,
- });
+ const navigate = useNavigate();
+ const [search, setSearch] = useState("");
+ const { results, isLoading } = useSearch(search);
const onSelect = useCallback(
(url: string) => {
setOpen(false);
- router.push(url);
+ navigate(url);
},
- [router],
+ [navigate],
);
useEffect(() => {
@@ -60,10 +88,6 @@ export function Search({ className }: SearchProps) {
return () => document.removeEventListener("keydown", down);
}, []);
- const results = deduplicateByUrl(
- query.data === "empty" ? [] : (query.data ?? []),
- );
-
return (
<>
- {query.isLoading && Loading...}
- {!query.isLoading &&
+ {isLoading && Loading...}
+ {!isLoading &&
search.length > 0 &&
results.length === 0 && (
No results found.
)}
- {!query.isLoading &&
+ {!isLoading &&
search.length === 0 &&
results.length > 0 && (
- {results.slice(0, 8).map((result: SortedResult) => (
+ {results.slice(0, 8).map((result) => (
{getResultIcon(result)}
-
+ {result.content}
@@ -119,7 +143,7 @@ export function Search({ className }: SearchProps) {
)}
{search.length > 0 &&
- results.map((result: SortedResult) => (
+ results.map((result) => (