@kids-reporter/routing-ui 0.1.0-alpha.5 → 0.1.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/header/desktop-header.d.ts +1 -3
- package/dist/header/desktop-header.d.ts.map +1 -1
- package/dist/header/desktop-header.js +2 -4
- package/dist/header/desktop-header.js.map +1 -1
- package/dist/header/header-context.d.ts +0 -6
- package/dist/header/header-context.d.ts.map +1 -1
- package/dist/header/header-context.js +2 -11
- package/dist/header/header-context.js.map +1 -1
- package/dist/header/index.d.ts.map +1 -1
- package/dist/header/index.js +2 -10
- package/dist/header/index.js.map +1 -1
- package/dist/header/mobile-header.d.ts +1 -4
- package/dist/header/mobile-header.d.ts.map +1 -1
- package/dist/header/mobile-header.js +3 -13
- package/dist/header/mobile-header.js.map +1 -1
- package/dist/icons/index.d.ts +0 -1
- package/dist/icons/index.d.ts.map +1 -1
- package/dist/icons/index.js +1 -18
- package/dist/icons/index.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -16
- package/dist/index.js.map +1 -1
- package/dist/styles.css +6 -0
- package/package.json +6 -4
- package/.prettierignore +0 -17
- package/babel.config.cjs +0 -31
- package/dist/header/is-logged-in-setter.d.ts +0 -7
- package/dist/header/is-logged-in-setter.d.ts.map +0 -1
- package/dist/header/is-logged-in-setter.js +0 -27
- package/dist/header/is-logged-in-setter.js.map +0 -1
- package/dist/header/mobile-back-button-href-setter.d.ts +0 -6
- package/dist/header/mobile-back-button-href-setter.d.ts.map +0 -1
- package/dist/header/mobile-back-button-href-setter.js +0 -21
- package/dist/header/mobile-back-button-href-setter.js.map +0 -1
- package/eslint.config.mjs +0 -56
- package/prettier.config.mjs +0 -13
- package/scripts/build.sh +0 -18
- package/src/components/button.tsx +0 -108
- package/src/components/index.tsx +0 -2
- package/src/components/input.tsx +0 -171
- package/src/constants/default-values.tsx +0 -153
- package/src/footer.tsx +0 -149
- package/src/header/desktop-header.tsx +0 -132
- package/src/header/header-context.tsx +0 -82
- package/src/header/index.tsx +0 -104
- package/src/header/is-logged-in-setter.tsx +0 -27
- package/src/header/menu/header-menu-item-group.tsx +0 -37
- package/src/header/menu/header-menu-item.tsx +0 -132
- package/src/header/menu/index.tsx +0 -205
- package/src/header/mobile-back-button-href-setter.tsx +0 -22
- package/src/header/mobile-header.tsx +0 -77
- package/src/header/post-title-setter.tsx +0 -22
- package/src/header/shared-components.tsx +0 -325
- package/src/hooks/index.ts +0 -3
- package/src/hooks/use-is-at-top.ts +0 -23
- package/src/hooks/use-media-query.ts +0 -57
- package/src/hooks/use-scroll-level.ts +0 -52
- package/src/icons/index.tsx +0 -378
- package/src/index.ts +0 -11
- package/src/styles.css +0 -354
- package/src/types/index.ts +0 -10
- package/src/utils/cn.ts +0 -41
- package/src/utils/generate-social-media-config.ts +0 -75
- package/src/utils/index.ts +0 -2
- package/tsconfig.json +0 -33
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { MenuItem } from '../../types'
|
|
2
|
-
import { cn } from '../../utils/cn'
|
|
3
|
-
import { useHeaderContext } from '../header-context'
|
|
4
|
-
|
|
5
|
-
type HeaderMenuItemProps = {
|
|
6
|
-
contentClassName?: string
|
|
7
|
-
isExpanded?: boolean
|
|
8
|
-
onExpand?: (label: string | null) => void
|
|
9
|
-
} & MenuItem
|
|
10
|
-
|
|
11
|
-
function HeaderMenuItem({
|
|
12
|
-
label,
|
|
13
|
-
href,
|
|
14
|
-
subItems,
|
|
15
|
-
external,
|
|
16
|
-
showIcon,
|
|
17
|
-
icon,
|
|
18
|
-
isExpanded,
|
|
19
|
-
contentClassName,
|
|
20
|
-
onExpand,
|
|
21
|
-
}: HeaderMenuItemProps) {
|
|
22
|
-
const hasSubItems = subItems && subItems.length > 0
|
|
23
|
-
const context = useHeaderContext()
|
|
24
|
-
const closeMenu = context?.closeMenu
|
|
25
|
-
|
|
26
|
-
const handleExpand = () => {
|
|
27
|
-
if (hasSubItems) {
|
|
28
|
-
onExpand?.(isExpanded ? null : label)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const content = (
|
|
33
|
-
<div
|
|
34
|
-
className={cn(
|
|
35
|
-
'group flex w-full items-center justify-between text-neutral-900 transition-colors duration-100 group-hover:text-neutral-900',
|
|
36
|
-
contentClassName
|
|
37
|
-
)}
|
|
38
|
-
>
|
|
39
|
-
<div className="gap-2 flex items-center">
|
|
40
|
-
{showIcon && icon && (
|
|
41
|
-
<div className="w-4 h-4 flex items-center justify-center">{icon}</div>
|
|
42
|
-
)}
|
|
43
|
-
<span
|
|
44
|
-
className={cn(
|
|
45
|
-
'prose-p1-bold',
|
|
46
|
-
isExpanded && 'text-red-400 group-hover:text-red-400'
|
|
47
|
-
)}
|
|
48
|
-
>
|
|
49
|
-
{label}
|
|
50
|
-
</span>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
{hasSubItems && (
|
|
54
|
-
<div
|
|
55
|
-
className={cn(
|
|
56
|
-
'w-6 h-6 flex items-center justify-center transition-transform',
|
|
57
|
-
isExpanded && 'rotate-180 text-red-400 group-hover:text-red-400'
|
|
58
|
-
)}
|
|
59
|
-
>
|
|
60
|
-
<svg width="14" height="7" viewBox="0 0 14 7" fill="none">
|
|
61
|
-
<path
|
|
62
|
-
d="M1 1L7 6L13 1"
|
|
63
|
-
stroke="currentColor"
|
|
64
|
-
strokeWidth="2.5"
|
|
65
|
-
strokeLinecap="round"
|
|
66
|
-
strokeLinejoin="round"
|
|
67
|
-
/>
|
|
68
|
-
</svg>
|
|
69
|
-
</div>
|
|
70
|
-
)}
|
|
71
|
-
</div>
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
if (hasSubItems) {
|
|
75
|
-
return (
|
|
76
|
-
<div className="w-full">
|
|
77
|
-
<button
|
|
78
|
-
onClick={handleExpand}
|
|
79
|
-
className="px-6 tablet:px-8 py-2 flex w-full cursor-pointer items-center justify-between transition-colors duration-200 hover:bg-neutral-black/5 active:bg-neutral-black/10"
|
|
80
|
-
>
|
|
81
|
-
{content}
|
|
82
|
-
</button>
|
|
83
|
-
<div
|
|
84
|
-
className={cn(
|
|
85
|
-
'ease-in-out overflow-hidden transition-all duration-300',
|
|
86
|
-
isExpanded ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
|
|
87
|
-
)}
|
|
88
|
-
>
|
|
89
|
-
{subItems.map((subItem, index) => (
|
|
90
|
-
<a
|
|
91
|
-
key={index}
|
|
92
|
-
href={subItem.href}
|
|
93
|
-
className="px-6 tablet:px-12 py-2 pl-12 font-medium block prose-p2 transition-colors duration-200 hover:bg-neutral-black/5 hover:text-neutral-900 active:bg-neutral-black/10"
|
|
94
|
-
onClick={closeMenu}
|
|
95
|
-
>
|
|
96
|
-
{subItem.label}
|
|
97
|
-
</a>
|
|
98
|
-
))}
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (external) {
|
|
105
|
-
return (
|
|
106
|
-
<a
|
|
107
|
-
href={href}
|
|
108
|
-
target="_blank"
|
|
109
|
-
rel="noopener noreferrer"
|
|
110
|
-
className={
|
|
111
|
-
'px-6 tablet:px-8 py-2 block transition-colors duration-200 hover:bg-neutral-black/5 active:bg-neutral-black/10'
|
|
112
|
-
}
|
|
113
|
-
>
|
|
114
|
-
{content}
|
|
115
|
-
</a>
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return (
|
|
120
|
-
<a
|
|
121
|
-
href={href}
|
|
122
|
-
className={
|
|
123
|
-
'px-6 tablet:px-8 py-2 block transition-colors duration-200 hover:bg-neutral-black/5 active:bg-neutral-black/10'
|
|
124
|
-
}
|
|
125
|
-
onClick={closeMenu}
|
|
126
|
-
>
|
|
127
|
-
{content}
|
|
128
|
-
</a>
|
|
129
|
-
)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export default HeaderMenuItem
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect } from 'react'
|
|
4
|
-
|
|
5
|
-
import Button from '../../components/button'
|
|
6
|
-
import { ClearIcon } from '../../icons'
|
|
7
|
-
import type { MenuItem, SocialMediaHrefs } from '../../types'
|
|
8
|
-
import { cn } from '../../utils/cn'
|
|
9
|
-
import { generateSocialMediaConfig } from '../../utils/generate-social-media-config'
|
|
10
|
-
import { SearchInputSection } from '../shared-components'
|
|
11
|
-
import HeaderMenuItem from './header-menu-item'
|
|
12
|
-
import HeaderMenuItemGroup from './header-menu-item-group'
|
|
13
|
-
|
|
14
|
-
type MenuProps = {
|
|
15
|
-
isOpen: boolean
|
|
16
|
-
onClose: () => void
|
|
17
|
-
keywords: string[]
|
|
18
|
-
menuItems: MenuItem[]
|
|
19
|
-
additionalMenuItems: MenuItem[]
|
|
20
|
-
socialMediaHrefs: SocialMediaHrefs
|
|
21
|
-
donateUrl: string
|
|
22
|
-
subscribeUrl: string
|
|
23
|
-
searchPlaceholder: string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function Divider() {
|
|
27
|
-
return (
|
|
28
|
-
<div className="px-6 tablet:px-8 py-4 w-full">
|
|
29
|
-
<div className="h-px w-full bg-neutral-300"></div>
|
|
30
|
-
</div>
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function Menu({
|
|
35
|
-
isOpen,
|
|
36
|
-
onClose,
|
|
37
|
-
keywords,
|
|
38
|
-
menuItems,
|
|
39
|
-
additionalMenuItems,
|
|
40
|
-
socialMediaHrefs,
|
|
41
|
-
donateUrl,
|
|
42
|
-
subscribeUrl,
|
|
43
|
-
searchPlaceholder,
|
|
44
|
-
}: MenuProps) {
|
|
45
|
-
const socialMediaConfig = generateSocialMediaConfig(socialMediaHrefs)
|
|
46
|
-
|
|
47
|
-
useEffect(() => {
|
|
48
|
-
if (isOpen) {
|
|
49
|
-
document.body.classList.add('no-scroll')
|
|
50
|
-
} else {
|
|
51
|
-
document.body.classList.remove('no-scroll')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return () => {
|
|
55
|
-
document.body.classList.remove('no-scroll')
|
|
56
|
-
}
|
|
57
|
-
}, [isOpen])
|
|
58
|
-
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
const handleEscape = (e: KeyboardEvent) => {
|
|
61
|
-
if (e.key === 'Escape') {
|
|
62
|
-
onClose()
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (isOpen) {
|
|
67
|
-
document.addEventListener('keydown', handleEscape)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return () => {
|
|
71
|
-
document.removeEventListener('keydown', handleEscape)
|
|
72
|
-
}
|
|
73
|
-
}, [isOpen, onClose])
|
|
74
|
-
|
|
75
|
-
return (
|
|
76
|
-
<>
|
|
77
|
-
{/* Overlay */}
|
|
78
|
-
<div
|
|
79
|
-
className={cn(
|
|
80
|
-
'inset-0 fixed z-1001 bg-neutral-500/50 transition-opacity duration-300',
|
|
81
|
-
isOpen ? 'opacity-100' : 'pointer-events-none opacity-0'
|
|
82
|
-
)}
|
|
83
|
-
onClick={onClose}
|
|
84
|
-
/>
|
|
85
|
-
|
|
86
|
-
{/* Menu */}
|
|
87
|
-
<div
|
|
88
|
-
className={cn(
|
|
89
|
-
'top-0 left-0 tablet:w-80 bg-white shadow-2xl ease-in-out tablet:pt-0 fixed z-1001 h-full scrollbar-thin w-full transform pt-(--mobile-header-height) transition-transform duration-300',
|
|
90
|
-
isOpen ? 'translate-x-0' : '-translate-x-full'
|
|
91
|
-
)}
|
|
92
|
-
>
|
|
93
|
-
<div className="flex h-full flex-col overflow-y-auto">
|
|
94
|
-
<div className="px-6 tablet:px-8 py-4 mt-4 hidden items-center justify-between tablet:flex">
|
|
95
|
-
<div className="flex items-center">
|
|
96
|
-
<a href="/">
|
|
97
|
-
<img
|
|
98
|
-
src="/assets/images/brand-icon.svg"
|
|
99
|
-
alt="少年報導者 The Reporter for Kids"
|
|
100
|
-
className="h-5"
|
|
101
|
-
height={20}
|
|
102
|
-
width={183}
|
|
103
|
-
loading="eager"
|
|
104
|
-
/>
|
|
105
|
-
</a>
|
|
106
|
-
</div>
|
|
107
|
-
<button
|
|
108
|
-
onClick={onClose}
|
|
109
|
-
className="w-8 h-8 flex cursor-pointer items-center justify-center rounded-full text-neutral-600 transition-colors duration-200 hover:text-neutral-800"
|
|
110
|
-
aria-label="關閉選單"
|
|
111
|
-
>
|
|
112
|
-
<ClearIcon />
|
|
113
|
-
</button>
|
|
114
|
-
</div>
|
|
115
|
-
|
|
116
|
-
<div className="px-6 tablet:px-8 pt-4 desktop:hidden">
|
|
117
|
-
<SearchInputSection
|
|
118
|
-
mode="inline"
|
|
119
|
-
tags={keywords}
|
|
120
|
-
searchPlaceholder={searchPlaceholder}
|
|
121
|
-
/>
|
|
122
|
-
</div>
|
|
123
|
-
|
|
124
|
-
<div className="py-4 flex-1">
|
|
125
|
-
<HeaderMenuItem {...menuItems?.[0]} />
|
|
126
|
-
|
|
127
|
-
<Divider />
|
|
128
|
-
|
|
129
|
-
{/* Categories */}
|
|
130
|
-
<div className="py-2">
|
|
131
|
-
<HeaderMenuItemGroup isMenuOpen={isOpen} menuItems={menuItems} />
|
|
132
|
-
</div>
|
|
133
|
-
|
|
134
|
-
<Divider />
|
|
135
|
-
|
|
136
|
-
{/* Reading Settings */}
|
|
137
|
-
<HeaderMenuItem
|
|
138
|
-
{...additionalMenuItems?.[0]}
|
|
139
|
-
contentClassName="text-neutral-600 [&_span]:[font-family:var(--font-family-noto)] [&_span]:[font-size:var(--font-size-p2)] [&_span]:[font-weight:500] [&_span]:[line-height:var(--line-height-normal)] [&_span]:[letter-spacing:var(--letter-spacing-wide)] hover:text-neutral-900"
|
|
140
|
-
/>
|
|
141
|
-
|
|
142
|
-
<Divider />
|
|
143
|
-
|
|
144
|
-
{/* About Us Section */}
|
|
145
|
-
<div className="py-2">
|
|
146
|
-
{additionalMenuItems.slice(1).map((item, index) => (
|
|
147
|
-
<HeaderMenuItem
|
|
148
|
-
key={index}
|
|
149
|
-
label={item.label}
|
|
150
|
-
href={item.href}
|
|
151
|
-
external={item.external}
|
|
152
|
-
contentClassName="text-neutral-600 [&_span]:[font-family:var(--font-family-noto)] [&_span]:[font-size:var(--font-size-p2)] [&_span]:[font-weight:500] [&_span]:[line-height:var(--line-height-normal)] [&_span]:[letter-spacing:var(--letter-spacing-wide)] hover:text-neutral-900"
|
|
153
|
-
/>
|
|
154
|
-
))}
|
|
155
|
-
</div>
|
|
156
|
-
|
|
157
|
-
<Divider />
|
|
158
|
-
|
|
159
|
-
{/* Social Media */}
|
|
160
|
-
<div className="px-6 tablet:px-8">
|
|
161
|
-
<div className="gap-4 tablet:gap-0 px-4 flex items-center justify-center tablet:justify-between">
|
|
162
|
-
{socialMediaConfig.map((item) => (
|
|
163
|
-
<a
|
|
164
|
-
key={item.label}
|
|
165
|
-
href={item.href}
|
|
166
|
-
className="text-neutral-900 transition-colors duration-200 hover:text-red-500"
|
|
167
|
-
target="_blank"
|
|
168
|
-
rel="noopener noreferrer"
|
|
169
|
-
aria-label={item.label}
|
|
170
|
-
>
|
|
171
|
-
<div className="w-6 h-6 flex items-center justify-center">
|
|
172
|
-
{item.icon && <item.icon />}
|
|
173
|
-
</div>
|
|
174
|
-
</a>
|
|
175
|
-
))}
|
|
176
|
-
</div>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
{/* Action Buttons */}
|
|
181
|
-
<div className="px-6 tablet:px-8 py-6 tablet:pt-6 tablet:pb-8">
|
|
182
|
-
<div className="gap-4 flex flex-col">
|
|
183
|
-
<Button variant="secondary" size={44} asChild className="w-full">
|
|
184
|
-
<a
|
|
185
|
-
href={subscribeUrl}
|
|
186
|
-
target="_blank"
|
|
187
|
-
rel="noopener noreferrer"
|
|
188
|
-
>
|
|
189
|
-
訂閱電子報
|
|
190
|
-
</a>
|
|
191
|
-
</Button>
|
|
192
|
-
<Button variant="primary" size={44} asChild className="w-full">
|
|
193
|
-
<a href={donateUrl} target="_blank" rel="noopener noreferrer">
|
|
194
|
-
贊助我們
|
|
195
|
-
</a>
|
|
196
|
-
</Button>
|
|
197
|
-
</div>
|
|
198
|
-
</div>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
</>
|
|
202
|
-
)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
export default Menu
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { useEffect } from 'react'
|
|
2
|
-
|
|
3
|
-
import { useHeaderContext } from './header-context'
|
|
4
|
-
|
|
5
|
-
type MobileBackButtonHrefSetterProps = {
|
|
6
|
-
href?: string
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function MobileBackButtonHrefSetter({ href }: MobileBackButtonHrefSetterProps) {
|
|
10
|
-
const context = useHeaderContext()
|
|
11
|
-
const setMobileBackButtonHref = context?.setMobileBackButtonHref
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
setMobileBackButtonHref?.(href)
|
|
15
|
-
|
|
16
|
-
return () => setMobileBackButtonHref?.(undefined)
|
|
17
|
-
}, [href, setMobileBackButtonHref])
|
|
18
|
-
|
|
19
|
-
return null
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default MobileBackButtonHrefSetter
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { ArrowIcon, ClearIcon, LoginIcon } from '../icons'
|
|
4
|
-
import { cn } from '../utils/cn'
|
|
5
|
-
import { HamburgerButton, LogoLink } from './shared-components'
|
|
6
|
-
|
|
7
|
-
type MobileHeaderProps = {
|
|
8
|
-
onHamburgerOverlayOpen: () => void
|
|
9
|
-
onCloseMenu: () => void
|
|
10
|
-
showCloseButtonWhenMenuOpen: boolean
|
|
11
|
-
isMenuOpen: boolean
|
|
12
|
-
isLoggedIn?: boolean
|
|
13
|
-
mobileBackButtonHref?: string
|
|
14
|
-
loginUrl?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function MobileHeader({
|
|
18
|
-
onHamburgerOverlayOpen,
|
|
19
|
-
onCloseMenu,
|
|
20
|
-
showCloseButtonWhenMenuOpen,
|
|
21
|
-
isMenuOpen,
|
|
22
|
-
isLoggedIn,
|
|
23
|
-
loginUrl,
|
|
24
|
-
mobileBackButtonHref,
|
|
25
|
-
}: MobileHeaderProps) {
|
|
26
|
-
const showCloseButton = showCloseButtonWhenMenuOpen && isMenuOpen
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<>
|
|
30
|
-
<div className="h-(--mobile-header-height) desktop:hidden"></div>
|
|
31
|
-
<div
|
|
32
|
-
className={cn(
|
|
33
|
-
'px-6 tablet:px-8 ease-in-out top-0 translate-y-0 pointer-events-auto fixed z-1002 w-full bg-neutral-white opacity-100 transition-all duration-300 tablet:z-1000 desktop:hidden'
|
|
34
|
-
)}
|
|
35
|
-
>
|
|
36
|
-
<div className="py-4 flex items-center justify-between">
|
|
37
|
-
<div className="flex items-center">
|
|
38
|
-
{mobileBackButtonHref && (
|
|
39
|
-
<a
|
|
40
|
-
href={mobileBackButtonHref}
|
|
41
|
-
className="size-8 mr-2 flex cursor-pointer items-center justify-center text-neutral-600 tablet:hidden"
|
|
42
|
-
>
|
|
43
|
-
<ArrowIcon />
|
|
44
|
-
</a>
|
|
45
|
-
)}
|
|
46
|
-
<LogoLink />
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
<div className="gap-4 flex items-center">
|
|
50
|
-
{!showCloseButton && (
|
|
51
|
-
<a
|
|
52
|
-
href={isLoggedIn ? '/member' : (loginUrl ?? '/login')}
|
|
53
|
-
className="w-8 h-8 flex items-center justify-center rounded-full text-red-400 transition-colors duration-200 hover:text-red-500"
|
|
54
|
-
aria-label="登入"
|
|
55
|
-
>
|
|
56
|
-
<LoginIcon />
|
|
57
|
-
</a>
|
|
58
|
-
)}
|
|
59
|
-
{showCloseButton ? (
|
|
60
|
-
<button
|
|
61
|
-
onClick={onCloseMenu}
|
|
62
|
-
className="w-8 h-8 flex cursor-pointer items-center justify-center rounded-full text-neutral-600 transition-colors duration-200 hover:text-neutral-800"
|
|
63
|
-
aria-label="關閉選單"
|
|
64
|
-
>
|
|
65
|
-
<ClearIcon />
|
|
66
|
-
</button>
|
|
67
|
-
) : (
|
|
68
|
-
<HamburgerButton
|
|
69
|
-
onHamburgerOverlayOpen={onHamburgerOverlayOpen}
|
|
70
|
-
/>
|
|
71
|
-
)}
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</>
|
|
76
|
-
)
|
|
77
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect } from 'react'
|
|
4
|
-
|
|
5
|
-
import { useHeaderContext } from './header-context'
|
|
6
|
-
|
|
7
|
-
type PostTitleSetterProps = {
|
|
8
|
-
postTitle?: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function PostTitleSetter({ postTitle }: PostTitleSetterProps) {
|
|
12
|
-
const context = useHeaderContext()
|
|
13
|
-
const setPostTitle = context?.setPostTitle
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
setPostTitle?.(postTitle)
|
|
16
|
-
return () => setPostTitle?.(undefined)
|
|
17
|
-
}, [postTitle, setPostTitle])
|
|
18
|
-
|
|
19
|
-
return null
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default PostTitleSetter
|