Skip to content

Commit 04eae01

Browse files
committed
main 🧊 start rework header
1 parent 2458c60 commit 04eae01

367 files changed

Lines changed: 1519 additions & 45045 deletions

File tree

Some content is hidden

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

packages/core/src/bundle/hooks/index.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
export * from './async';
2-
// Browser API Hooks - Хуки для работы с Web APIs браузера
32
export * from './browser';
43
export * from './debug';
54
export * from './elements';
6-
export * from './fun';
5+
export * from './humor';
76
export * from './lifecycle';
8-
// Sensor Hooks - Хуки-сенсоры для отслеживания событий и состояний
97
export * from './sensors';
108
export * from './state';
119
export * from './time';

packages/core/src/hooks/humor.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// fun
2+
export * from './useFul/useFul';
3+
export * from './useLess/useLess';
4+
export * from './useOnce/useOnce';

packages/core/src/hooks/index.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
export * from './async';
2-
3-
// Browser API Hooks - Хуки для работы с Web APIs браузера
42
export * from './browser';
53
export * from './debug';
64
export * from './elements';
7-
export * from './fun';
5+
export * from './humor';
86
export * from './lifecycle';
9-
// Sensor Hooks - Хуки-сенсоры для отслеживания событий и состояний
107
export * from './sensors';
118
export * from './state';
129
export * from './time';
Lines changed: 28 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,38 @@
1-
import { DocsCopyPage } from '@docs/components/docs-copy-page';
2-
import { DocsTableOfContents } from '@docs/components/docs-toc';
31
import { functionsSource } from '@docs/lib/source';
4-
import { mdxComponents } from '@docs/mdx-components';
5-
import { Button } from '@docs/ui/button';
6-
import { IconArrowLeft, IconArrowRight } from '@tabler/icons-react';
72
import { findNeighbour } from 'fumadocs-core/page-tree';
8-
import Link from 'next/link';
93
import { notFound } from 'next/navigation';
104

5+
import { FunctionHeader } from '../../_components/function-header';
6+
117
export const revalidate = false;
128
export const dynamic = 'force-static';
139
export const dynamicParams = false;
1410

15-
export function generateStaticParams() {
16-
return functionsSource.generateParams();
11+
export const generateStaticParams = () => functionsSource.generateParams();
12+
13+
interface FunctionPageProps {
14+
params: Promise<{ name: string; type: string }>;
1715
}
1816

19-
export async function generateMetadata(props: { params: Promise<{ name: string; type: string }> }) {
17+
export const generateMetadata = async (props: FunctionPageProps) => {
2018
const params = await props.params;
2119
const page = functionsSource.getPage([params.type, params.name]);
2220

23-
if (!page) {
24-
notFound();
25-
}
26-
27-
const doc = page.data;
28-
29-
if (!doc.title || !doc.description) {
30-
notFound();
31-
}
21+
if (!page) notFound();
3222

3323
return {
34-
title: doc.title,
35-
description: doc.description
24+
title: page.data.title,
25+
description: page.data.description
3626
};
37-
}
27+
};
3828

39-
export default async function Page(props: { params: Promise<{ name: string; type: string }> }) {
29+
const FunctionPage = async (props: FunctionPageProps) => {
4030
const params = await props.params;
4131
const page = functionsSource.getPage([params.type, params.name]);
4232

43-
if (!page) {
44-
notFound();
45-
}
33+
if (!page) notFound();
4634

4735
const doc = page.data;
48-
const MDX = doc.body;
4936
const neighbours = findNeighbour(functionsSource.pageTree, page.url);
5037
const raw = await doc.getText('raw');
5138

@@ -57,82 +44,22 @@ export default async function Page(props: { params: Promise<{ name: string; type
5744
<div className='flex min-w-0 flex-1 flex-col'>
5845
<div className='h-(--top-spacing) shrink-0' />
5946
<div className='mx-auto flex w-full max-w-[45rem] min-w-0 flex-1 flex-col gap-6 px-4 py-6 text-neutral-800 md:px-0 lg:py-8 dark:text-neutral-300'>
60-
<div className='flex flex-col gap-2'>
61-
<div className='flex flex-col gap-2'>
62-
<div className='flex items-center justify-between md:items-start'>
63-
<h1 className='scroll-m-24 text-3xl font-semibold tracking-tight sm:text-3xl'>
64-
{doc.title}
65-
</h1>
66-
<div className='docs-nav flex items-center gap-2'>
67-
<div className='hidden sm:block'>
68-
<DocsCopyPage page={raw} />
69-
</div>
70-
<div className='ml-auto flex gap-2'>
71-
{neighbours.previous && (
72-
<Button
73-
asChild
74-
className='extend-touch-target size-8 shadow-none md:size-7'
75-
size='icon'
76-
variant='secondary'
77-
>
78-
<Link href={neighbours.previous.url}>
79-
<IconArrowLeft />
80-
<span className='sr-only'>Previous</span>
81-
</Link>
82-
</Button>
83-
)}
84-
{neighbours.next && (
85-
<Button
86-
asChild
87-
className='extend-touch-target size-8 shadow-none md:size-7'
88-
size='icon'
89-
variant='secondary'
90-
>
91-
<Link href={neighbours.next.url}>
92-
<span className='sr-only'>Next</span>
93-
<IconArrowRight />
94-
</Link>
95-
</Button>
96-
)}
97-
</div>
98-
</div>
99-
</div>
100-
{doc.description && (
101-
<p className='text-muted-foreground text-[1.05rem] sm:text-base sm:text-balance md:max-w-[90%]'>
102-
{doc.description}
103-
</p>
104-
)}
105-
</div>
106-
</div>
107-
<div className='w-full flex-1 pb-16 *:data-[slot=alert]:first:mt-0 sm:pb-0'>
108-
<MDX components={mdxComponents} />
109-
</div>
110-
<div className='hidden h-16 w-full items-center gap-2 px-4 sm:flex sm:px-0'>
111-
{neighbours.previous && (
112-
<Button asChild className='shadow-none' size='sm' variant='secondary'>
113-
<Link href={neighbours.previous.url}>
114-
<IconArrowLeft /> {neighbours.previous.name}
115-
</Link>
116-
</Button>
117-
)}
118-
{neighbours.next && (
119-
<Button asChild className='ml-auto shadow-none' size='sm' variant='secondary'>
120-
<Link href={neighbours.next.url}>
121-
{neighbours.next.name} <IconArrowRight />
122-
</Link>
123-
</Button>
124-
)}
125-
</div>
47+
<FunctionHeader
48+
category={doc.category}
49+
description={doc.description}
50+
isDemo={doc.isDemo}
51+
isTest={doc.isTest}
52+
name={doc.title}
53+
next={neighbours.next?.url}
54+
page={raw}
55+
previous={neighbours.previous?.url}
56+
type={doc.type}
57+
usage={doc.usage}
58+
/>
12659
</div>
12760
</div>
128-
<div className='sticky top-[calc(var(--header-height)+1px)] z-30 ml-auto hidden h-[90svh] w-(--sidebar-width) flex-col gap-4 overflow-hidden overscroll-none pb-8 xl:flex'>
129-
<div className='h-(--top-spacing) shrink-0' />
130-
{doc.toc?.length && (
131-
<div className='no-scrollbar flex flex-col gap-8 overflow-y-auto px-8'>
132-
<DocsTableOfContents toc={doc.toc} />
133-
</div>
134-
)}
135-
</div>
13661
</div>
13762
);
138-
}
63+
};
64+
65+
export default FunctionPage;
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
'use client';
2+
3+
import { Callout } from '@docs/components/callout';
4+
import { timeAgo } from '@docs/lib/utils';
5+
import { Badge } from '@docs/ui/badge';
6+
import { Button } from '@docs/ui/button';
7+
import { ButtonGroup } from '@docs/ui/button-group';
8+
import {
9+
DropdownMenu,
10+
DropdownMenuContent,
11+
DropdownMenuItem,
12+
DropdownMenuSeparator,
13+
DropdownMenuTrigger
14+
} from '@docs/ui/dropdown-menu';
15+
import { useCopy } from '@siberiacancode/reactuse';
16+
import {
17+
IconArrowLeft,
18+
IconArrowRight,
19+
IconBrandOpenai,
20+
IconCheck,
21+
IconChevronDown,
22+
IconCopy,
23+
IconFlame,
24+
IconMarkdown,
25+
IconRosetteDiscountCheck,
26+
IconRosetteDiscountCheckOff,
27+
IconSparkles
28+
} from '@tabler/icons-react';
29+
import Link from 'next/link';
30+
31+
import { CATEGORIES } from '../_constants/categories';
32+
import { USAGE } from '../_constants/usage';
33+
34+
interface FunctionHeaderProps {
35+
category?: string;
36+
description?: string;
37+
isDemo?: boolean;
38+
isTest?: boolean;
39+
name: string;
40+
next?: string;
41+
page: string;
42+
previous?: string;
43+
type?: string;
44+
usage?: string;
45+
}
46+
47+
export const FunctionHeader = ({
48+
category,
49+
type,
50+
description,
51+
name,
52+
next,
53+
page,
54+
previous
55+
}: FunctionHeaderProps) => {
56+
const { copy, copied } = useCopy();
57+
58+
// const categoryMeta = CATEGORIES[category as Category];
59+
// const badgeBaseClass =
60+
// 'border-0 px-3 py-1 text-sm font-medium shadow-none [&_svg]:size-3.5 [&_svg]:opacity-80';
61+
62+
return (
63+
<div className='flex flex-col gap-4'>
64+
<div className='flex flex-col gap-2'>
65+
<div className='flex items-center justify-between md:items-start'>
66+
<h1 className='scroll-m-24 text-3xl font-semibold tracking-tight sm:text-3xl'>{name}</h1>
67+
<div className='docs-nav flex items-center gap-2'>
68+
<div className='hidden sm:block'>
69+
<div className='bg-secondary relative flex rounded-lg *:[[data-slot=button]]:focus-visible:relative *:[[data-slot=button]]:focus-visible:z-10'>
70+
<ButtonGroup>
71+
<Button variant='secondary' onClick={() => copy(page)}>
72+
{copied ? <IconCheck /> : <IconCopy />}
73+
Copy Page
74+
</Button>
75+
76+
<DropdownMenu>
77+
<DropdownMenuTrigger asChild>
78+
<Button aria-label='Open actions' variant='secondary'>
79+
<IconChevronDown />
80+
</Button>
81+
</DropdownMenuTrigger>
82+
<DropdownMenuContent align='end' className='w-56 min-w-56'>
83+
<DropdownMenuItem asChild>
84+
<a
85+
href={`/functions/${type}s/${name}.md`}
86+
rel='noopener noreferrer'
87+
target='_blank'
88+
>
89+
<IconMarkdown />
90+
View as Markdown
91+
</a>
92+
</DropdownMenuItem>
93+
<DropdownMenuSeparator />
94+
<DropdownMenuItem onSelect={(event) => event.preventDefault()}>
95+
<IconSparkles />
96+
Open in v0
97+
</DropdownMenuItem>
98+
<DropdownMenuItem onSelect={(event) => event.preventDefault()}>
99+
<IconBrandOpenai />
100+
Open in ChatGPT
101+
</DropdownMenuItem>
102+
<DropdownMenuItem onSelect={(event) => event.preventDefault()}>
103+
<IconSparkles />
104+
Open in Claude
105+
</DropdownMenuItem>
106+
<DropdownMenuItem onSelect={(event) => event.preventDefault()}>
107+
<IconSparkles />
108+
Open in Scira
109+
</DropdownMenuItem>
110+
</DropdownMenuContent>
111+
</DropdownMenu>
112+
</ButtonGroup>
113+
</div>
114+
</div>
115+
<div className='ml-auto flex gap-2'>
116+
{previous && (
117+
<Button
118+
asChild
119+
className='extend-touch-target size-8 shadow-none md:size-7'
120+
size='icon'
121+
variant='secondary'
122+
>
123+
<Link href={previous}>
124+
<IconArrowLeft />
125+
<span className='sr-only'>Previous</span>
126+
</Link>
127+
</Button>
128+
)}
129+
{next && (
130+
<Button
131+
asChild
132+
className='extend-touch-target size-8 shadow-none md:size-7'
133+
size='icon'
134+
variant='secondary'
135+
>
136+
<Link href={next}>
137+
<span className='sr-only'>Next</span>
138+
<IconArrowRight />
139+
</Link>
140+
</Button>
141+
)}
142+
</div>
143+
</div>
144+
</div>
145+
{description && (
146+
<p className='text-muted-foreground text-[1.05rem] sm:text-base sm:text-balance md:max-w-[90%]'>
147+
{description}
148+
</p>
149+
)}
150+
</div>
151+
{/*
152+
<div className='flex flex-wrap gap-3'>
153+
<Badge
154+
className={`${badgeBaseClass} ${
155+
categoryMeta.className ??
156+
'bg-zinc-100 text-zinc-900 dark:bg-zinc-800 dark:text-zinc-100'
157+
}`}
158+
>
159+
{categoryMeta && <categoryMeta.Icon />}
160+
{categoryKey}
161+
</Badge>
162+
<Badge
163+
className={`${badgeBaseClass} ${
164+
props.usage
165+
? usageMap[props.usage]
166+
: 'bg-zinc-100 text-zinc-900 dark:bg-zinc-800 dark:text-zinc-100'
167+
}`}
168+
>
169+
<IconFlame />
170+
{props.usage}
171+
</Badge>
172+
<Badge className={badgeBaseClass}>
173+
{props.hasTests ? <IconRosetteDiscountCheck /> : <IconRosetteDiscountCheckOff />}
174+
test coverage
175+
</Badge>
176+
</div>
177+
178+
<p className='leading-7'>Last changed: {timeAgo(props.lastModified)}</p>
179+
180+
{props.warning && (
181+
<Callout className='border-yellow-600 bg-yellow-100 dark:border-yellow-400 dark:bg-yellow-900'>
182+
<h4 className='text-l font-semibold'>Important</h4>
183+
{props.warning}
184+
</Callout>
185+
)}
186+
187+
{props.browserapi && (
188+
<Callout className='border-blue-600 bg-blue-100 dark:border-blue-400 dark:bg-blue-900'>
189+
<h4 className='text-l font-semibold'>TIP</h4>
190+
This hook uses {props.browserapi} browser api to provide enhanced functionality. Make sure
191+
to check for compatibility with different browsers when using this api
192+
</Callout>
193+
)} */}
194+
</div>
195+
);
196+
};

0 commit comments

Comments
 (0)