UI: Adjust design

This commit is contained in:
Fuma Nama
2025-05-07 21:38:36 +08:00
parent 6f50f4eb62
commit abce713591
21 changed files with 93 additions and 93 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'fumadocs-ui': patch
---
Adjust design (Accordion, Tabs, border color of themes)
+2 -2
View File
@@ -75,10 +75,10 @@ export default async function Page(props: {
}}
>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription className="mb-2">
<DocsDescription className="mb-0">
{page.data.description}
</DocsDescription>
<div className="flex flex-row gap-2 items-center">
<div className="flex flex-row gap-2 items-center mb-4">
<LLMCopyButton slug={params.slug} />
<EditOnGitHub
url={`https://github.com/${owner}/${repo}/blob/dev/${path}`}
+4 -4
View File
@@ -14,11 +14,11 @@ import { owner, repo } from '@/lib/github';
import {
Banner,
DynamicCodeBlock,
InlineTOC,
Folder,
Files,
File,
Files,
Folder,
ImageZoom,
InlineTOC,
} from '@/components/preview/lazy';
import BannerImage from '@/public/banner.png';
@@ -55,7 +55,7 @@ export function card(): ReactNode {
export function tabs(): ReactNode {
return (
<Wrapper>
<div className="space-y-4 rounded-xl bg-fd-background p-4 text-sm">
<div className="prose-no-margin">
<Tabs
groupId="language"
persist
+1 -1
View File
@@ -6,7 +6,7 @@ export function Wrapper(props: HTMLAttributes<HTMLDivElement>) {
<div
{...props}
className={cn(
'rounded-lg bg-black/20 p-4 border prose-no-margin',
'rounded-lg bg-radial-[at_bottom] from-blue-500/20 p-4 border border-fd-primary/10 prose-no-margin dark:bg-black/20',
props.className,
)}
>
+1 -1
View File
@@ -1,7 +1,7 @@
{
"title": "Fumadocs Core",
"description": "The headless library",
"icon": "Library",
"icon": "Cuboid",
"root": true,
"pages": [
"---Guide---",
@@ -183,11 +183,9 @@ loader({
### Page Tree
The page tree is generated from your file system, using the **Page Tree Builder**.
It also filters out some unnecessary information (e.g. unused frontmatter properties).
The page tree is generated from your file system, some unnecessary information (e.g. unused frontmatter properties) will be filtered.
To customise the process, use the `pageTree` option.
You can attach custom properties to page tree nodes, like customising the display name of pages and folders.
You can customise it using the `pageTree` option, such as attaching custom properties to nodes, or customising the display name of pages.
```tsx
import React from 'react';
+1 -1
View File
@@ -2,6 +2,6 @@
"title": "OpenAPI Example",
"description": "A demo for Fumadocs OpenAPI",
"root": true,
"icon": "Terminal",
"icon": "Play",
"pages": ["index", "...(generated)"]
}
@@ -13,13 +13,13 @@ Before continuing, make sure:
fumadocs-ui fumadocs-core
```
### 1. MDX Components
### MDX Components
<include cwd meta='title="mdx-components.tsx"'>
../../examples/next-mdx/mdx-components.tsx
</include>
### 2. Content Source
### Content Source
Fumadocs supports different content sources, including Fumadocs MDX and [Content Collections](/docs/headless/content-collections).
@@ -29,7 +29,7 @@ Fumadocs MDX is our official content source, you can configure it with:
fumadocs-mdx @types/mdx
```
```js title="next.config.mjs"
```js tab="next.config.mjs"
import { createMDX } from 'fumadocs-mdx/next';
const withMDX = createMDX();
@@ -42,7 +42,7 @@ const config = {
export default withMDX(config);
```
```ts title="source.config.ts"
```ts tab="source.config.ts"
import { defineDocs } from 'fumadocs-mdx/config';
export const docs = defineDocs({
@@ -50,12 +50,10 @@ export const docs = defineDocs({
});
```
Add a `postinstall` script to generate types:
```json title="package.json"
```json tab="package.json"
{
"scripts": {
"postinstall": "fumadocs-mdx"
"postinstall": "fumadocs-mdx" // [!code ++]
}
}
```
@@ -73,7 +71,7 @@ export const source = loader({
});
```
### 3. Root Layout
### Root Layout
Wrap the entire application inside [Root Provider](/docs/ui/layouts/root-provider), and add required styles to `body`.
@@ -99,7 +97,7 @@ export default function Layout({ children }: { children: ReactNode }) {
}
```
### 4. Styles
### Styles
Add the following to `global.css`.
@@ -111,7 +109,7 @@ Add the following to `global.css`.
> It doesn't come with a default font, you may choose one from `next/font`.
### 5. Layout
### Layout
Create a `app/layout.config.tsx` file to put the shared options for our layouts.
@@ -137,7 +135,7 @@ Create a folder `/app/docs` for our docs, and give it a proper layout.
> `pageTree` refers to Page Tree, it should be provided by your content source.
### 6. Page
### Page
Create a catch-all route `/app/docs/[[...slug]]` for docs pages.
@@ -151,7 +149,7 @@ In the page, wrap your content in the [Page](/docs/ui/layouts/page) component.
</Tabs>
### 7. Search
### Search
Use the default document search based on Orama.
@@ -161,7 +159,7 @@ Use the default document search based on Orama.
Learn more about [Document Search](/docs/headless/search).
### 8. Done
### Done
You can start the dev server and create MDX files.
+1 -1
View File
@@ -1,7 +1,7 @@
{
"title": "Framework",
"description": "The docs framework",
"icon": "Building2",
"icon": "Building",
"root": true,
"pages": [
"---Introduction---",
@@ -116,11 +116,7 @@ export function Operation({
<>
{heading(headingLevel, 'Response Body', ctx)}
<Tabs
items={statuses}
groupId="fumadocs_openapi_responses"
className="bg-transparent"
>
<Tabs items={statuses} groupId="fumadocs_openapi_responses">
{statuses.map((status) => (
<ResponseTab
key={status}
+24 -23
View File
@@ -205,30 +205,31 @@ export function Schema({
(s) => isComplexType(s) && !stack.includes(s),
);
footer = (
<div className="flex flex-col gap-2">
{mentionedObjectTypes.map((s, idx) => {
let title = typeof s === 'object' ? s.title : null;
title ??=
mentionedObjectTypes.length === 1
? 'Show Attributes'
: `Object ${idx + 1}`;
if (mentionedObjectTypes.length > 0)
footer = (
<div className="flex flex-col gap-2">
{mentionedObjectTypes.map((s, idx) => {
let title = typeof s === 'object' ? s.title : null;
title ??=
mentionedObjectTypes.length === 1
? 'Show Attributes'
: `Object ${idx + 1}`;
return (
<renderer.ObjectCollapsible key={idx} name={title}>
<Schema
name="element"
schema={s}
ctx={{
...ctx,
stack: [schema, ...stack],
}}
/>
</renderer.ObjectCollapsible>
);
})}
</div>
);
return (
<renderer.ObjectCollapsible key={idx} name={title}>
<Schema
name="element"
schema={s}
ctx={{
...ctx,
stack: [schema, ...stack],
}}
/>
</renderer.ObjectCollapsible>
);
})}
</div>
);
}
return (
+2 -2
View File
@@ -7,7 +7,7 @@
--color-fd-popover-foreground: hsl(0, 0%, 15.1%);
--color-fd-card: hsl(0, 0%, 99.7%);
--color-fd-card-foreground: hsl(0, 0%, 3.9%);
--color-fd-border: hsl(0, 0%, 89.8%);
--color-fd-border: hsla(0, 0%, 60%, 0.2);
--color-fd-primary: hsl(0, 0%, 9%);
--color-fd-primary-foreground: hsl(0, 0%, 98%);
--color-fd-secondary: hsl(0, 0%, 96.1%);
@@ -26,7 +26,7 @@
--color-fd-popover-foreground: hsl(0, 0%, 98%);
--color-fd-card: hsl(0, 0%, 4%);
--color-fd-card-foreground: hsl(0, 0%, 98%);
--color-fd-border: hsl(0, 0%, 14%);
--color-fd-border: hsl(0, 0%, 50%, 0.2);
--color-fd-primary: hsl(0, 0%, 98%);
--color-fd-primary-foreground: hsl(0, 0%, 9%);
--color-fd-secondary: hsl(0, 0%, 12.9%);
+2 -2
View File
@@ -7,7 +7,7 @@
--color-fd-popover-foreground: hsl(0, 0%, 15.1%);
--color-fd-card: hsl(0, 0%, 94.7%);
--color-fd-card-foreground: hsl(0, 0%, 3.9%);
--color-fd-border: hsl(0, 0%, 89.8%);
--color-fd-border: hsla(0, 0%, 62%, 20%);
--color-fd-primary: hsl(0, 0%, 9%);
--color-fd-primary-foreground: hsl(0, 0%, 98%);
--color-fd-secondary: hsl(0, 0%, 93.1%);
@@ -26,7 +26,7 @@
--color-fd-popover-foreground: hsl(0, 0%, 88%);
--color-fd-card: hsl(0, 0%, 9.8%);
--color-fd-card-foreground: hsl(0, 0%, 98%);
--color-fd-border: hsl(0, 0%, 14%);
--color-fd-border: hsla(0, 0%, 40%, 20%);
--color-fd-primary: hsl(0, 0%, 98%);
--color-fd-primary-foreground: hsl(0, 0%, 9%);
--color-fd-secondary: hsl(0, 0%, 12.9%);
+3 -3
View File
@@ -18,15 +18,15 @@
}
.dark {
--color-fd-background: hsl(220, 60%, 6%);
--color-fd-background: hsl(220, 60%, 8%);
--color-fd-foreground: hsl(220, 60%, 94.5%);
--color-fd-muted: hsl(220, 50%, 10%);
--color-fd-muted-foreground: hsl(220, 30%, 65%);
--color-fd-popover: hsl(220, 50%, 10%);
--color-fd-popover-foreground: hsl(220, 60%, 94.5%);
--color-fd-card: hsl(220, 50%, 10%);
--color-fd-card: hsla(220, 56%, 15%, 0.4);
--color-fd-card-foreground: hsl(220, 60%, 94.5%);
--color-fd-border: hsl(220, 50%, 20%);
--color-fd-border: hsla(220, 50%, 50%, 0.2);
--color-fd-primary: hsl(205, 100%, 85%);
--color-fd-primary-foreground: hsl(0, 0%, 9%);
--color-fd-secondary: hsl(220, 50%, 20%);
+10 -10
View File
@@ -1,8 +1,8 @@
@theme {
--color-fd-background: hsl(256, 100%, 96%);
--color-fd-primary: hsl(270, 100%, 52%);
--color-fd-border: hsl(270, 40%, 80%);
--color-fd-accent: hsl(270, 60%, 86%);
--color-fd-border: hsla(270, 40%, 80%, 0.5);
--color-fd-accent: hsl(270, 40%, 88%);
--color-fd-accent-foreground: hsl(270, 100%, 20%);
--color-fd-muted: hsl(256, 60%, 94%);
--color-fd-muted-foreground: hsl(256, 50%, 50%);
@@ -18,20 +18,20 @@
}
.dark {
--color-fd-background: hsl(256, 60%, 6%);
--color-fd-background: hsl(256, 20%, 6%);
--color-fd-primary: hsl(270, 100%, 86%);
--color-fd-border: hsl(270, 100%, 20%);
--color-fd-accent: hsl(256, 60%, 26%);
--color-fd-accent-foreground: hsl(270, 100%, 86%);
--color-fd-muted: hsl(256, 60%, 10%);
--color-fd-border: hsla(270, 50%, 40%, 0.3);
--color-fd-accent: hsl(256, 23%, 22%);
--color-fd-accent-foreground: hsl(270, 40%, 86%);
--color-fd-muted: hsl(256, 23%, 10%);
--color-fd-foreground: hsl(256, 60%, 90%);
--color-fd-muted-foreground: hsl(256, 50%, 75%);
--color-fd-secondary: hsl(270, 100%, 20%);
--color-fd-secondary: hsl(270, 23%, 20%);
--color-fd-secondary-foreground: hsl(256, 60%, 90%);
--color-fd-card: hsl(256, 60%, 10%);
--color-fd-card: hsl(256, 23%, 10%);
--color-fd-card-foreground: hsl(256, 60%, 90%);
--color-fd-popover-foreground: hsl(256, 60%, 90%);
--color-fd-popover: hsl(256, 60%, 6%);
--color-fd-popover: hsl(256, 23%, 6%);
--color-fd-primary-foreground: hsl(256, 60%, 6%);
--color-fd-ring: hsl(270, 100%, 86%);
}
+3 -3
View File
@@ -69,14 +69,14 @@ export const Accordion = forwardRef<
id={id}
className="not-prose flex flex-row items-center text-fd-card-foreground font-medium has-focus-visible:bg-fd-accent"
>
<AccordionPrimitive.Trigger className="flex flex-1 items-center gap-2 px-4 py-2.5 text-start focus-visible:outline-none">
<ChevronRight className="-ms-1 size-4 shrink-0 text-fd-muted-foreground transition-transform duration-200 group-data-[state=open]/accordion:rotate-90" />
<AccordionPrimitive.Trigger className="flex flex-1 items-center gap-2 px-3 py-2.5 text-start focus-visible:outline-none">
<ChevronRight className="size-4 shrink-0 text-fd-muted-foreground transition-transform duration-200 group-data-[state=open]/accordion:rotate-90" />
{title}
</AccordionPrimitive.Trigger>
{id ? <CopyButton id={id} /> : null}
</AccordionPrimitive.Header>
<AccordionPrimitive.Content className="overflow-hidden data-[state=closed]:animate-fd-accordion-up data-[state=open]:animate-fd-accordion-down">
<div className="px-4 py-2 prose-no-margin">{children}</div>
<div className="px-4 pb-2 text-[15px] prose-no-margin">{children}</div>
</AccordionPrimitive.Content>
</AccordionPrimitive.Item>
);
+2 -2
View File
@@ -93,13 +93,13 @@ export const CodeBlock = forwardRef<HTMLElement, CodeBlockProps>(
ref={ref}
{...props}
className={cn(
'not-prose group fd-codeblock relative my-4 overflow-hidden rounded-lg border bg-fd-secondary/50 text-sm',
'not-prose group fd-codeblock relative my-4 overflow-hidden rounded-lg border bg-fd-card text-sm',
keepBackground && 'bg-(--shiki-light-bg) dark:bg-(--shiki-dark-bg)',
props.className,
)}
>
{title ? (
<div className="flex items-center gap-2 border-b bg-fd-muted px-4 py-1.5">
<div className="flex items-center gap-2 bg-fd-secondary px-4 py-1.5">
{icon ? (
<div
className="text-fd-muted-foreground [&_svg]:size-3.5"
@@ -366,7 +366,9 @@ export function SidebarFolderContent(props: CollapsibleContentProps) {
[ctx],
)}
>
<div className="absolute w-px inset-y-0 bg-fd-border start-3" />
{ctx.level === 1 && (
<div className="absolute w-px inset-y-0 bg-fd-border start-3" />
)}
{props.children}
</Context.Provider>
</CollapsibleContent>
+5 -5
View File
@@ -5,13 +5,13 @@ import type {
TabsProps as BaseProps,
} from '@radix-ui/react-tabs';
import {
useMemo,
useState,
createContext,
useContext,
useLayoutEffect,
useId,
useEffect,
useId,
useLayoutEffect,
useMemo,
useState,
} from 'react';
import { cn } from '@/utils/cn';
import * as Primitive from './ui/tabs';
@@ -186,7 +186,7 @@ export function Tab({ value, className, ...props }: TabProps) {
<Primitive.TabsContent
value={v}
className={cn(
'prose-no-margin [&>figure:only-child]:-m-4 [&>figure:only-child]:rounded-none [&>figure:only-child]:border-none',
'prose-no-margin [&>figure:only-child]:-m-4 [&>figure:only-child]:border-none',
className,
)}
{...props}
+7 -7
View File
@@ -12,7 +12,7 @@ const Tabs = React.forwardRef<
ref={ref}
{...props}
className={cn(
'flex flex-col overflow-hidden rounded-xl border bg-fd-card',
'flex flex-col overflow-hidden rounded-xl border bg-fd-secondary',
props.className,
)}
/>
@@ -28,10 +28,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
{...props}
className={cn(
'flex flex-row items-end gap-4 overflow-x-auto bg-fd-secondary px-4 text-fd-muted-foreground',
props.className,
)}
className={cn('flex flex-row gap-4 overflow-x-auto px-4', props.className)}
/>
));
TabsList.displayName = 'TabsList';
@@ -44,7 +41,7 @@ const TabsTrigger = React.forwardRef<
ref={ref}
{...props}
className={cn(
'whitespace-nowrap border-b border-transparent py-2 text-sm font-medium transition-colors hover:text-fd-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=active]:border-fd-primary data-[state=active]:text-fd-primary',
'whitespace-nowrap text-fd-muted-foreground border-b border-transparent py-2 text-sm font-medium transition-colors hover:text-fd-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=active]:border-fd-primary data-[state=active]:text-fd-primary',
props.className,
)}
/>
@@ -58,7 +55,10 @@ const TabsContent = React.forwardRef<
<TabsPrimitive.Content
ref={ref}
{...props}
className={cn('p-4', props.className)}
className={cn(
'p-4 text-[15px] bg-fd-background rounded-xl',
props.className,
)}
/>
));
TabsContent.displayName = 'TabsContent';
+2 -2
View File
@@ -56,7 +56,7 @@ export function CollapsibleControl() {
return (
<div
className="fixed flex flex-row animate-fd-fade-in rounded-xl p-0.5 border bg-fd-muted text-fd-muted-foreground z-10 xl:start-4 max-xl:end-4"
className="fixed flex shadow-lg animate-fd-fade-in rounded-xl p-0.5 border bg-fd-muted text-fd-muted-foreground z-10 xl:start-4 max-xl:end-4"
style={{
top: 'calc(var(--fd-banner-height) + var(--fd-tocnav-height) + var(--spacing) * 4)',
}}
@@ -66,8 +66,8 @@ export function CollapsibleControl() {
buttonVariants({
color: 'ghost',
size: 'icon-sm',
className: 'rounded-lg',
}),
'rounded-lg',
)}
>
<SidebarIcon />