Skip to content

Commit 30d5e52

Browse files
committed
feat: header
Signed-off-by: Innei <[email protected]>
1 parent 9805007 commit 30d5e52

22 files changed

+465
-102
lines changed

next.config.mts

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@ const isProd = process.env.NODE_ENV === 'production'
1717
let nextConfig: NextConfig = {
1818
experimental: {
1919
appDir: true,
20-
serverComponentsExternalPackages: ['socket.io-client', 'ws'],
2120
},
2221

2322
webpack: (config, options) => {
23+
config.externals.push({
24+
'utf-8-validate': 'commonjs utf-8-validate',
25+
bufferutil: 'commonjs bufferutil',
26+
})
27+
2428
if (
2529
process.env.SENTRY === 'true' &&
2630
process.env.NEXT_PUBLIC_SENTRY_DSN &&

src/app/notes/[id]/page.tsx

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
'use client'
22

3-
import { useRef } from 'react'
43
import { useParams } from 'next/navigation'
54

65
import { PageDataHolder } from '~/components/common/PageHolder'
76
import { Toc, TocAutoScroll } from '~/components/widgets/toc'
7+
import { useBeforeMounted } from '~/hooks/common/use-before-mounted'
88
import { useNoteByNidQuery } from '~/hooks/data/use-note'
99
import { ArticleElementProvider } from '~/providers/article/article-element-provider'
1010
import { useSetCurrentNoteId } from '~/providers/note/current-note-id-provider'
1111
import { NoteLayoutRightSidePortal } from '~/providers/note/right-side-provider'
1212
import { parseMarkdown } from '~/remark'
13-
import { isClientSide } from '~/utils/env'
1413

1514
const PageImpl = () => {
1615
const { id } = useParams() as { id: string }
@@ -23,11 +22,11 @@ const PageImpl = () => {
2322
// For example, `ComA` use `useParams()` just want to get value `id`,
2423
// but if router params or query changes `page` params, will cause `CompA` re - render.
2524
const setNoteId = useSetCurrentNoteId()
26-
const onceRef = useRef(false)
27-
if (isClientSide() && !onceRef.current) {
28-
onceRef.current = true
25+
26+
useBeforeMounted(() => {
2927
setNoteId(id)
30-
}
28+
})
29+
3130
return (
3231
<article className="prose">
3332
<header>

src/atoms/viewport.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { atom } from 'jotai'
1+
import { useCallback } from 'react'
2+
import { atom, useAtomValue } from 'jotai'
3+
import { selectAtom } from 'jotai/utils'
4+
import type { ExtractAtomValue } from 'jotai'
25

36
export const viewportAtom = atom({
47
/**
@@ -29,3 +32,14 @@ export const viewportAtom = atom({
2932
h: 0,
3033
w: 0,
3134
})
35+
36+
export const useViewport = <T>(
37+
selector: (value: ExtractAtomValue<typeof viewportAtom>) => T,
38+
): T =>
39+
useAtomValue(
40+
// @ts-ignore
41+
selectAtom(
42+
viewportAtom,
43+
useCallback((atomValue) => selector(atomValue), []),
44+
),
45+
)

src/components/common/PageHolder.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const LoadingComponent = () => <Loading loadingText="别着急,坐和放宽" /
77
export const PageDataHolder = (
88
PageImpl: FC<any>,
99
useQuery: () => UseQueryResult<any>,
10-
) => {
10+
): FC => {
1111
const Component: FC = (props) => {
1212
const { data, isLoading } = useQuery()
1313

src/components/layout/footer/FooterInfo.tsx

+1-67
Original file line numberDiff line numberDiff line change
@@ -2,75 +2,9 @@ import Link from 'next/link'
22

33
import { clsxm } from '~/utils/helper'
44

5+
import { linkSections } from './config'
56
import { GatewayCount } from './GatewayCount'
67

7-
interface LinkSection {
8-
name: string
9-
links: {
10-
name: string
11-
href: string
12-
external?: boolean
13-
}[]
14-
}
15-
16-
export const linkSections: LinkSection[] = [
17-
{
18-
name: '关于',
19-
links: [
20-
{
21-
name: '关于本站',
22-
href: '/about-site',
23-
},
24-
{
25-
name: '关于我',
26-
href: '/about-me',
27-
},
28-
{
29-
name: '关于此项目',
30-
href: 'https://github.com/innei/springtide',
31-
external: true,
32-
},
33-
],
34-
},
35-
{
36-
name: '更多',
37-
links: [
38-
{
39-
name: '时间线',
40-
href: '/timeline',
41-
},
42-
{
43-
name: '友链',
44-
href: '/friends',
45-
},
46-
{
47-
name: '监控',
48-
href: 'https://status.shizuri.net/status/main',
49-
external: true,
50-
},
51-
],
52-
},
53-
{
54-
name: '联系',
55-
links: [
56-
{
57-
name: '写留言',
58-
href: '/message',
59-
},
60-
{
61-
name: '发邮件',
62-
href: 'mailto:[email protected]',
63-
external: true,
64-
},
65-
{
66-
name: 'GitHub',
67-
href: 'https://github.com/innei',
68-
external: true,
69-
},
70-
],
71-
},
72-
]
73-
748
export const FooterInfo = () => {
759
return (
7610
<>
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
interface LinkSection {
2+
name: string
3+
links: {
4+
name: string
5+
href: string
6+
external?: boolean
7+
}[]
8+
}
9+
10+
export const linkSections: LinkSection[] = [
11+
{
12+
name: '关于',
13+
links: [
14+
{
15+
name: '关于本站',
16+
href: '/about-site',
17+
},
18+
{
19+
name: '关于我',
20+
href: '/about-me',
21+
},
22+
{
23+
name: '关于此项目',
24+
href: 'https://github.com/innei/springtide',
25+
external: true,
26+
},
27+
],
28+
},
29+
{
30+
name: '更多',
31+
links: [
32+
{
33+
name: '时间线',
34+
href: '/timeline',
35+
},
36+
{
37+
name: '友链',
38+
href: '/friends',
39+
},
40+
{
41+
name: '监控',
42+
href: 'https://status.shizuri.net/status/main',
43+
external: true,
44+
},
45+
],
46+
},
47+
{
48+
name: '联系',
49+
links: [
50+
{
51+
name: '写留言',
52+
href: '/message',
53+
},
54+
{
55+
name: '发邮件',
56+
href: 'mailto:[email protected]',
57+
external: true,
58+
},
59+
{
60+
name: 'GitHub',
61+
href: 'https://github.com/innei',
62+
external: true,
63+
},
64+
],
65+
},
66+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use client'
2+
3+
import { useDeferredValue } from 'react'
4+
5+
import { usePageScrollLocation } from '~/providers/root/page-scroll-info-provider'
6+
import { clsxm } from '~/utils/helper'
7+
8+
export const useHeaderOpacity = () => {
9+
const threshold = 50
10+
const y = usePageScrollLocation()
11+
const headerOpacity = useDeferredValue(
12+
y >= threshold ? 1 : Math.floor((y / threshold) * 100) / 100,
13+
)
14+
15+
return headerOpacity
16+
}
17+
18+
export const BluredBackground = () => {
19+
const headerOpacity = useHeaderOpacity()
20+
return (
21+
<div
22+
className={clsxm(
23+
'absolute inset-0 transform-gpu [backdrop-filter:saturate(180%)_blur(20px)] [backface-visibility:hidden]',
24+
'bg-themed-bg_opacity [border-bottom:1px_solid_rgb(187_187_187_/_20%)]',
25+
)}
26+
style={{
27+
opacity: headerOpacity,
28+
}}
29+
/>
30+
)
31+
}

src/components/layout/header/Header.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { BluredBackground } from './BluredBackground'
2+
import { HeaderContent } from './HeaderContent'
3+
14
const Logo = () => {
25
return (
36
<svg
@@ -40,12 +43,13 @@ const Logo = () => {
4043

4144
export const Header = () => {
4245
return (
43-
<header className="uk-material-ultrathin fixed left-0 right-0 top-0 z-[9] h-[4.5rem]">
46+
<header className="fixed left-0 right-0 top-0 z-[9] h-[4.5rem]">
47+
<BluredBackground />
4448
<div className="relative mx-auto grid h-full min-h-0 max-w-7xl grid-cols-[4.5rem_auto_8rem] lg:px-8">
4549
<Logo />
4650
<div className="flex min-w-0 flex-grow">
4751
<div className="flex flex-grow items-center justify-center">
48-
Content
52+
<HeaderContent />
4953
</div>
5054
</div>
5155
<div className="flex items-center">

0 commit comments

Comments
 (0)