@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.
Files changed (66) hide show
  1. package/dist/header/desktop-header.d.ts +1 -3
  2. package/dist/header/desktop-header.d.ts.map +1 -1
  3. package/dist/header/desktop-header.js +2 -4
  4. package/dist/header/desktop-header.js.map +1 -1
  5. package/dist/header/header-context.d.ts +0 -6
  6. package/dist/header/header-context.d.ts.map +1 -1
  7. package/dist/header/header-context.js +2 -11
  8. package/dist/header/header-context.js.map +1 -1
  9. package/dist/header/index.d.ts.map +1 -1
  10. package/dist/header/index.js +2 -10
  11. package/dist/header/index.js.map +1 -1
  12. package/dist/header/mobile-header.d.ts +1 -4
  13. package/dist/header/mobile-header.d.ts.map +1 -1
  14. package/dist/header/mobile-header.js +3 -13
  15. package/dist/header/mobile-header.js.map +1 -1
  16. package/dist/icons/index.d.ts +0 -1
  17. package/dist/icons/index.d.ts.map +1 -1
  18. package/dist/icons/index.js +1 -18
  19. package/dist/icons/index.js.map +1 -1
  20. package/dist/index.d.ts +0 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +0 -16
  23. package/dist/index.js.map +1 -1
  24. package/dist/styles.css +6 -0
  25. package/package.json +6 -4
  26. package/.prettierignore +0 -17
  27. package/babel.config.cjs +0 -31
  28. package/dist/header/is-logged-in-setter.d.ts +0 -7
  29. package/dist/header/is-logged-in-setter.d.ts.map +0 -1
  30. package/dist/header/is-logged-in-setter.js +0 -27
  31. package/dist/header/is-logged-in-setter.js.map +0 -1
  32. package/dist/header/mobile-back-button-href-setter.d.ts +0 -6
  33. package/dist/header/mobile-back-button-href-setter.d.ts.map +0 -1
  34. package/dist/header/mobile-back-button-href-setter.js +0 -21
  35. package/dist/header/mobile-back-button-href-setter.js.map +0 -1
  36. package/eslint.config.mjs +0 -56
  37. package/prettier.config.mjs +0 -13
  38. package/scripts/build.sh +0 -18
  39. package/src/components/button.tsx +0 -108
  40. package/src/components/index.tsx +0 -2
  41. package/src/components/input.tsx +0 -171
  42. package/src/constants/default-values.tsx +0 -153
  43. package/src/footer.tsx +0 -149
  44. package/src/header/desktop-header.tsx +0 -132
  45. package/src/header/header-context.tsx +0 -82
  46. package/src/header/index.tsx +0 -104
  47. package/src/header/is-logged-in-setter.tsx +0 -27
  48. package/src/header/menu/header-menu-item-group.tsx +0 -37
  49. package/src/header/menu/header-menu-item.tsx +0 -132
  50. package/src/header/menu/index.tsx +0 -205
  51. package/src/header/mobile-back-button-href-setter.tsx +0 -22
  52. package/src/header/mobile-header.tsx +0 -77
  53. package/src/header/post-title-setter.tsx +0 -22
  54. package/src/header/shared-components.tsx +0 -325
  55. package/src/hooks/index.ts +0 -3
  56. package/src/hooks/use-is-at-top.ts +0 -23
  57. package/src/hooks/use-media-query.ts +0 -57
  58. package/src/hooks/use-scroll-level.ts +0 -52
  59. package/src/icons/index.tsx +0 -378
  60. package/src/index.ts +0 -11
  61. package/src/styles.css +0 -354
  62. package/src/types/index.ts +0 -10
  63. package/src/utils/cn.ts +0 -41
  64. package/src/utils/generate-social-media-config.ts +0 -75
  65. package/src/utils/index.ts +0 -2
  66. package/tsconfig.json +0 -33
@@ -1,153 +0,0 @@
1
- import { SettingsIconSmall } from '../icons'
2
- import { MenuItem } from '../types'
3
-
4
- export const SUBSCRIBE_URL = 'https://solink.soundon.fm/kidstwreporter'
5
- export const DONATE_URL = 'https://support.twreporter.org/'
6
- export const PRIVACY_POLICY = 'https://www.twreporter.org/a/privacy-policy'
7
- export const SEARCH_PLACEHOLDER = '搜尋更多新聞、議題'
8
-
9
- export const MENU_ITEMS: MenuItem[] = [
10
- {
11
- label: '最新',
12
- href: '/all',
13
- subItems: [],
14
- },
15
- {
16
- label: '專題',
17
- href: '/topic/page',
18
- subItems: [],
19
- },
20
- {
21
- label: '新聞',
22
- href: '/category/news',
23
- subItems: [
24
- { label: '焦點新聞', href: '/category/news/times' },
25
- { label: '真的假的', href: '/category/news/knowledge' },
26
- { label: '人物故事', href: '/category/news/story' },
27
- { label: '文化報導', href: '/category/news/explore' },
28
- { label: '專欄', href: '/category/news/column' },
29
- { label: '英文新聞', href: '/categories/news/english-version' },
30
- ],
31
- },
32
- {
33
- label: '多媒體',
34
- href: '/category/comics',
35
- subItems: [
36
- { label: '圖解新聞', href: '/category/comics/times' },
37
- { label: '新聞遊戲', href: '/category/comics/test-news' },
38
- { label: '圖文故事', href: '/category/comics/graphic-story' },
39
- ],
40
- },
41
- {
42
- label: '校園',
43
- href: '/category/campus',
44
- subItems: [
45
- { label: '校園寶可夢', href: '/category/campus/campus-pokemon' },
46
- { label: '上課好好玩', href: '/category/campus/teaching' },
47
- { label: '小讀者連線', href: '/category/campus/joining' },
48
- ],
49
- },
50
- {
51
- label: 'Podcast',
52
- href: '/category/listening-news',
53
- subItems: [
54
- {
55
- label: '小記者,問什麼?',
56
- href: '/category/listening-news/kids-reporter-ask',
57
- },
58
- {
59
- label: '新聞讀報',
60
- href: '/category/listening-news/multilingual-listening-news',
61
- },
62
- {
63
- label: '新聞關鍵字',
64
- href: '/category/listening-news/listening-news-keywords',
65
- },
66
- {
67
- label: '文化關鍵字',
68
- href: '/category/listening-news/listening-news-culture-keywords',
69
- },
70
- ],
71
- },
72
- {
73
- label: '教案',
74
- href: '/category/classroom',
75
- subItems: [],
76
- },
77
- ]
78
-
79
- export const ADDITIONAL_MENU_ITEMS: MenuItem[] = [
80
- {
81
- label: '閱讀探索設定',
82
- href: '/reading-settings',
83
- subItems: [],
84
- showIcon: true,
85
- icon: <SettingsIconSmall />,
86
- },
87
- {
88
- label: '關於我們',
89
- href: '/about',
90
- subItems: [],
91
- },
92
- {
93
- label: '呼叫報導仔流程',
94
- href: '/about#callkidsreporter',
95
- subItems: [],
96
- },
97
- {
98
- label: '投稿專區',
99
- href: 'https://forms.gle/49AEG8kFj7QWjgij8',
100
- subItems: [],
101
- external: true,
102
- },
103
- {
104
- label: '加入小記者',
105
- href: 'https://forms.gle/eGq5jagNTwriwSCX6',
106
- subItems: [],
107
- external: true,
108
- },
109
- {
110
- label: '訂閱Podcast',
111
- href: 'https://solink.soundon.fm/kidstwreporter',
112
- subItems: [],
113
- external: true,
114
- },
115
- {
116
- label: '聯絡我們',
117
- href: '/about#mail',
118
- subItems: [],
119
- },
120
- {
121
- label: '前往《報導者》',
122
- href: 'https://www.twreporter.org/',
123
- subItems: [],
124
- external: true,
125
- },
126
- ]
127
-
128
- export const SOCIAL_MEDIA_ITEMS = [
129
- {
130
- label: 'Facebook',
131
- href: 'https://www.facebook.com/twreporter/',
132
- },
133
- {
134
- label: 'Instagram',
135
- href: 'https://www.instagram.com/twreporter/',
136
- },
137
- {
138
- label: 'YouTube',
139
- href: 'https://www.youtube.com/@TwreporterOrg',
140
- },
141
- {
142
- label: 'Threads',
143
- href: 'https://www.threads.com/@twreporter',
144
- },
145
- {
146
- label: 'Medium',
147
- href: 'https://medium.com/twreporter',
148
- },
149
- {
150
- label: 'RSS',
151
- href: 'https://kids-storage.twreporter.org/rss/rss.xml',
152
- },
153
- ]
package/src/footer.tsx DELETED
@@ -1,149 +0,0 @@
1
- 'use client'
2
-
3
- import Button from './components/button'
4
- import {
5
- ADDITIONAL_MENU_ITEMS,
6
- DONATE_URL,
7
- PRIVACY_POLICY,
8
- SOCIAL_MEDIA_ITEMS,
9
- } from './constants/default-values'
10
- import { MenuItem, SocialMediaHrefs } from './types'
11
- import { generateSocialMediaConfig } from './utils/generate-social-media-config'
12
-
13
- type FooterProps = {
14
- socialMediaHrefs?: SocialMediaHrefs
15
- additionalMenuItems?: MenuItem[]
16
- donateUrl?: string
17
- privacyPolicyUrl?: string
18
- }
19
-
20
- const Footer = ({
21
- socialMediaHrefs = SOCIAL_MEDIA_ITEMS.map((item) => item.href),
22
- additionalMenuItems = ADDITIONAL_MENU_ITEMS,
23
- donateUrl = DONATE_URL,
24
- privacyPolicyUrl = PRIVACY_POLICY,
25
- }: FooterProps) => {
26
- const socialMediaConfig = generateSocialMediaConfig(socialMediaHrefs)
27
-
28
- return (
29
- <footer className="w-full bg-neutral-white">
30
- {/* Main Footer Content */}
31
- <div className="py-12 desktop:py-14 w-full bg-neutral-white px-(--margin-mobile) desktop:px-(--margin-desktop)">
32
- <div className="max-w-300 mx-auto">
33
- <div className="gap-8 flex flex-col items-center desktop:flex-row desktop:justify-between">
34
- {/* Logo and Description */}
35
- <div className="max-w-100 gap-6 flex w-full flex-col items-center desktop:items-start">
36
- <div className="flex items-center">
37
- <a href="/" className="flex items-center">
38
- <img
39
- src="/assets/images/footer-logo.svg"
40
- alt="少年報導者"
41
- loading="lazy"
42
- width={238}
43
- height={26}
44
- />
45
- </a>
46
- </div>
47
- <p className="w-full prose-p2 text-neutral-900">
48
- 《少年報導者》是由非營利媒體《報導者》針對兒少打造的深度新聞報導品牌,與兒童和少年一起理解世界,參與未來。
49
- </p>
50
- <Button size={44} variant="secondary" asChild className="w-75">
51
- <a href={donateUrl} target="_blank" rel="noreferrer">
52
- 贊助我們
53
- </a>
54
- </Button>
55
- </div>
56
-
57
- <div className="gap-6 flex flex-row">
58
- <div className="gap-2 flex flex-col">
59
- {additionalMenuItems.slice(0, 4).map((link) => (
60
- <a
61
- key={link.label}
62
- href={link.href}
63
- className="min-w-30 prose-p2-bold text-neutral-900 transition-colors duration-200 hover:text-red-400"
64
- target={link.external ? '_blank' : undefined}
65
- rel={link.external ? 'noopener noreferrer' : undefined}
66
- >
67
- {link.label}
68
- </a>
69
- ))}
70
- </div>
71
- <div className="gap-2 flex flex-col">
72
- {additionalMenuItems.slice(4).map((link) => (
73
- <a
74
- key={link.label}
75
- href={link.href}
76
- className="min-w-30 prose-p2-bold text-neutral-900 transition-colors duration-200 hover:text-red-400"
77
- target={link.external ? '_blank' : undefined}
78
- rel={link.external ? 'noopener noreferrer' : undefined}
79
- >
80
- {link.label}
81
- </a>
82
- ))}
83
- </div>
84
- </div>
85
- </div>
86
- </div>
87
- </div>
88
-
89
- <div className="py-6 w-full bg-red-400 px-(--margin-mobile) desktop:px-(--margin-desktop)">
90
- <div className="max-w-300 mx-auto">
91
- <div className="gap-5 desktop:gap-4 flex flex-col items-center desktop:flex-row desktop:justify-between">
92
- <div className="gap-4 order-1 flex items-center desktop:order-2">
93
- {socialMediaConfig.map((social) => {
94
- const IconComponent = social.icon
95
- return (
96
- <a
97
- key={social.label}
98
- href={social.href}
99
- className="relative text-neutral-white transition-colors duration-200 hover:text-neutral-200"
100
- target="_blank"
101
- rel="noopener noreferrer"
102
- aria-label={social.label}
103
- >
104
- <div className="peer w-6 h-6 relative z-10 flex items-center justify-center rounded-full text-neutral-white transition-all duration-200 hover:text-red-500">
105
- {IconComponent && <IconComponent />}
106
- </div>
107
- <div className="p-2 peer-hover:bg-white absolute top-1/2 left-1/2 z-1 flex h-[23px] w-[23px] -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full transition-all duration-200"></div>
108
- </a>
109
- )
110
- })}
111
- </div>
112
-
113
- <div className="text-center prose-p3 text-neutral-white desktop:order-1 desktop:text-left">
114
- <p className="desktop:inline">
115
- 衛部救字第1131363879號|勸募期間 2025/1/1~12/31
116
- <span className="hidden desktop:inline">|</span>
117
- </p>
118
- <p className="desktop:inline">
119
- <a
120
- href={privacyPolicyUrl}
121
- target="_blank"
122
- className="desktop:ml-1 text-neutral-white underline"
123
- rel="noopener noreferrer"
124
- >
125
- 隱私政策
126
- </a>
127
-
128
- <a
129
- href="https://www.twreporter.org/a/license-footer"
130
- target="_blank"
131
- className="desktop:ml-1 text-neutral-white underline"
132
- rel="noopener noreferrer"
133
- >
134
- 許可協議
135
- </a>
136
- </p>
137
- <p className="hidden desktop:inline">|</p>
138
- <p className="desktop:inline">
139
- Copyright © {new Date().getFullYear()} The Reporter
140
- </p>
141
- </div>
142
- </div>
143
- </div>
144
- </div>
145
- </footer>
146
- )
147
- }
148
-
149
- export default Footer
@@ -1,132 +0,0 @@
1
- 'use client'
2
-
3
- import { LoginIcon } from '../icons'
4
- import type { MenuItem } from '../types'
5
- import { cn } from '../utils/cn'
6
- import {
7
- ActionButtons,
8
- BottomNavigation,
9
- HamburgerButton,
10
- LogoLink,
11
- } from './shared-components'
12
-
13
- type DesktopHeaderProps = {
14
- onHamburgerOverlayOpen: () => void
15
- keywords: string[]
16
- compactMode: boolean
17
- postTitle?: string
18
- hide: boolean
19
- searchPlaceholder: string
20
- subscribeUrl: string
21
- menuItems: MenuItem[]
22
- isLoggedIn?: boolean
23
- loginUrl?: string
24
- }
25
-
26
- export function DesktopHeader({
27
- onHamburgerOverlayOpen,
28
- keywords,
29
- compactMode,
30
- postTitle,
31
- hide,
32
- searchPlaceholder,
33
- subscribeUrl,
34
- menuItems,
35
- isLoggedIn,
36
- loginUrl,
37
- }: DesktopHeaderProps) {
38
- return (
39
- <>
40
- <div className="hidden h-(--desktop-header-height) desktop:block"></div>
41
- <div
42
- className={cn(
43
- 'top-0 ease-in-out fixed left-1/2 z-1000 hidden w-full -translate-x-1/2 transform transition-all duration-500 desktop:block',
44
- compactMode && 'bg-white',
45
- hide
46
- ? 'pointer-events-none -translate-y-full opacity-0'
47
- : 'translate-y-0 pointer-events-auto opacity-100'
48
- )}
49
- >
50
- <div className="px-12 hidden w-full bg-transparent desktop:block">
51
- <div className="max-w-300 mx-auto">
52
- <div
53
- className={cn(
54
- 'px-4 flex items-center justify-between py-[18px]',
55
- compactMode && 'py-2.5'
56
- )}
57
- >
58
- <div className={'flex items-center'}>
59
- <div
60
- className={cn(
61
- 'ease-in-out overflow-hidden transition-all duration-500',
62
- compactMode
63
- ? 'translate-x-0 max-w-12 mr-4 w-auto scale-100 opacity-100'
64
- : '-translate-x-2 w-0 max-w-0 pointer-events-none scale-95 opacity-0'
65
- )}
66
- >
67
- <HamburgerButton
68
- onHamburgerOverlayOpen={onHamburgerOverlayOpen}
69
- small
70
- />
71
- </div>
72
- <div className={compactMode ? 'mr-12' : 'mr-8'}>
73
- <LogoLink compactMode={compactMode} />
74
- </div>
75
- {postTitle && (
76
- <div className="pr-12 block">
77
- <p className="font-medium tracking-wide max-w-124 overflow-hidden prose-p2 text-ellipsis whitespace-nowrap text-neutral-900">
78
- {postTitle}
79
- </p>
80
- </div>
81
- )}
82
- <div
83
- className={cn(
84
- 'ease-in-out overflow-hidden transition-all duration-500',
85
- compactMode
86
- ? 'max-h-0 -translate-x-8 scale-95 opacity-0'
87
- : 'max-h-20 max-w-auto scale-100 opacity-100',
88
- postTitle && compactMode && 'max-w-0'
89
- )}
90
- >
91
- <span className="font-medium translate-y-0 inline-block prose-p2 tracking-[2.2px]! text-nowrap text-neutral-900 opacity-100">
92
- 理解世界 × 參與未來
93
- </span>
94
- </div>
95
- </div>
96
-
97
- <div className="gap-4 flex items-center">
98
- <ActionButtons
99
- tags={keywords}
100
- hideCtaButtons={compactMode}
101
- searchPlaceholder={searchPlaceholder}
102
- subscribeUrl={subscribeUrl}
103
- />
104
- <a
105
- href={isLoggedIn ? '/member' : (loginUrl ?? '/login')}
106
- className="w-8 h-8 flex items-center justify-center rounded-full text-red-400 transition-colors duration-200 hover:text-red-500"
107
- aria-label="登入"
108
- >
109
- <LoginIcon />
110
- </a>
111
- </div>
112
- </div>
113
-
114
- <div
115
- className={cn(
116
- 'ease-in-out overflow-hidden transition-all duration-500',
117
- compactMode
118
- ? 'h-0 -translate-y-4 opacity-0'
119
- : 'translate-y-0 h-auto opacity-100'
120
- )}
121
- >
122
- <BottomNavigation
123
- onHamburgerOverlayOpen={onHamburgerOverlayOpen}
124
- menuItems={menuItems}
125
- />
126
- </div>
127
- </div>
128
- </div>
129
- </div>
130
- </>
131
- )
132
- }
@@ -1,82 +0,0 @@
1
- 'use client'
2
- import {
3
- createContext,
4
- ReactNode,
5
- useCallback,
6
- useContext,
7
- useMemo,
8
- useState,
9
- } from 'react'
10
-
11
- type HeaderContextType = {
12
- postTitle?: string
13
- setPostTitle: (title?: string) => void
14
- isMenuOpen: boolean
15
- openMenu: () => void
16
- closeMenu: () => void
17
- keywords: string[]
18
- isLoggedIn: boolean
19
- setIsLoggedIn: (isLoggedIn: boolean) => void
20
- mobileBackButtonHref?: string
21
- setMobileBackButtonHref: (href?: string) => void
22
- loginUrl?: string
23
- setLoginUrl: (url?: string) => void
24
- }
25
-
26
- const HeaderContext = createContext<HeaderContextType | undefined>(undefined)
27
-
28
- export function HeaderProvider({
29
- children,
30
- keywords,
31
- }: {
32
- children: ReactNode
33
- keywords: string[]
34
- }) {
35
- const [postTitle, setPostTitle] = useState<string | undefined>(undefined)
36
- const [isMenuOpen, setIsMenuOpen] = useState(false)
37
- const [isLoggedIn, setIsLoggedIn] = useState(false)
38
- const [mobileBackButtonHref, setMobileBackButtonHref] = useState<
39
- string | undefined
40
- >(undefined)
41
- const [loginUrl, setLoginUrl] = useState<string | undefined>(undefined)
42
- const openMenu = useCallback(() => setIsMenuOpen(true), [])
43
- const closeMenu = useCallback(() => setIsMenuOpen(false), [])
44
-
45
- const contextValue = useMemo(
46
- () => ({
47
- postTitle,
48
- setPostTitle,
49
- isMenuOpen,
50
- openMenu,
51
- closeMenu,
52
- keywords,
53
- isLoggedIn,
54
- setIsLoggedIn,
55
- mobileBackButtonHref,
56
- setMobileBackButtonHref,
57
- loginUrl,
58
- setLoginUrl,
59
- }),
60
- [
61
- postTitle,
62
- isMenuOpen,
63
- openMenu,
64
- closeMenu,
65
- keywords,
66
- isLoggedIn,
67
- mobileBackButtonHref,
68
- loginUrl,
69
- ]
70
- )
71
-
72
- return (
73
- <HeaderContext.Provider value={contextValue}>
74
- {children}
75
- </HeaderContext.Provider>
76
- )
77
- }
78
-
79
- export function useHeaderContext() {
80
- const context = useContext(HeaderContext)
81
- return context
82
- }
@@ -1,104 +0,0 @@
1
- 'use client'
2
- import {
3
- ADDITIONAL_MENU_ITEMS,
4
- DONATE_URL,
5
- MENU_ITEMS,
6
- SEARCH_PLACEHOLDER,
7
- SOCIAL_MEDIA_ITEMS,
8
- SUBSCRIBE_URL,
9
- } from '../constants/default-values'
10
- import {
11
- ScrollLevel,
12
- useIsAtTop,
13
- useMediaQuery,
14
- useScrollLevel,
15
- } from '../hooks'
16
- import type { MenuItem, SocialMediaHrefs } from '../types'
17
- import { DesktopHeader } from './desktop-header'
18
- import { useHeaderContext } from './header-context'
19
- import Menu from './menu'
20
- import { MobileHeader } from './mobile-header'
21
-
22
- type HeaderProps = {
23
- menuItems?: MenuItem[]
24
- additionalMenuItems?: MenuItem[]
25
- socialMediaHrefs?: SocialMediaHrefs
26
- searchPlaceholder?: string
27
- subscribeUrl?: string
28
- donateUrl?: string
29
- }
30
-
31
- function Header({
32
- menuItems = MENU_ITEMS,
33
- additionalMenuItems = ADDITIONAL_MENU_ITEMS,
34
- socialMediaHrefs = SOCIAL_MEDIA_ITEMS.map((item) => item.href),
35
- searchPlaceholder = SEARCH_PLACEHOLDER,
36
- subscribeUrl = SUBSCRIBE_URL,
37
- donateUrl = DONATE_URL,
38
- }: HeaderProps) {
39
- const context = useHeaderContext()
40
- const postTitle = context?.postTitle
41
- const isLoggedIn = context?.isLoggedIn || false
42
- const loginUrl = context?.loginUrl || '/login'
43
- const isMenuOpen = context?.isMenuOpen || false
44
- const openMenu = context?.openMenu
45
- const closeMenu = context?.closeMenu
46
- const keywords = context?.keywords || []
47
- const onHamburgerOverlayOpen = () => {
48
- openMenu?.()
49
- }
50
- const mobileBackButtonHref = context?.mobileBackButtonHref
51
-
52
- const onCloseMenu = () => {
53
- closeMenu?.()
54
- }
55
-
56
- const isMobile = useMediaQuery('(max-width: 768px)')
57
-
58
- const isAtTop = useIsAtTop()
59
- const scrollingLevel = useScrollLevel({
60
- scrollDownDistance: 150,
61
- throttleThreshold: 50,
62
- })
63
-
64
- const isScrollingDown = scrollingLevel === ScrollLevel.DOWN_HIDDEN
65
-
66
- return (
67
- <>
68
- <DesktopHeader
69
- onHamburgerOverlayOpen={onHamburgerOverlayOpen}
70
- keywords={keywords}
71
- hide={isScrollingDown}
72
- compactMode={!isAtTop}
73
- postTitle={isAtTop ? undefined : postTitle}
74
- searchPlaceholder={searchPlaceholder}
75
- subscribeUrl={subscribeUrl}
76
- menuItems={menuItems}
77
- isLoggedIn={isLoggedIn}
78
- loginUrl={loginUrl}
79
- />
80
- <MobileHeader
81
- onCloseMenu={onCloseMenu}
82
- showCloseButtonWhenMenuOpen={isMobile}
83
- onHamburgerOverlayOpen={onHamburgerOverlayOpen}
84
- isMenuOpen={isMenuOpen}
85
- isLoggedIn={isLoggedIn}
86
- loginUrl={loginUrl}
87
- mobileBackButtonHref={mobileBackButtonHref}
88
- />
89
- <Menu
90
- isOpen={isMenuOpen}
91
- onClose={closeMenu || (() => undefined)}
92
- keywords={keywords}
93
- menuItems={menuItems}
94
- additionalMenuItems={additionalMenuItems}
95
- socialMediaHrefs={socialMediaHrefs}
96
- donateUrl={donateUrl}
97
- subscribeUrl={subscribeUrl}
98
- searchPlaceholder={searchPlaceholder}
99
- />
100
- </>
101
- )
102
- }
103
-
104
- export default Header
@@ -1,27 +0,0 @@
1
- import { useEffect } from 'react'
2
-
3
- import { useHeaderContext } from './header-context'
4
-
5
- type IsLoggedInSetterProps = {
6
- isLoggedIn: boolean
7
- loginUrl: string
8
- }
9
-
10
- function IsLoggedInSetter({ isLoggedIn, loginUrl }: IsLoggedInSetterProps) {
11
- const context = useHeaderContext()
12
- const setIsLoggedIn = context?.setIsLoggedIn
13
- const setLoginUrl = context?.setLoginUrl
14
-
15
- useEffect(() => {
16
- setIsLoggedIn?.(isLoggedIn)
17
- setLoginUrl?.(loginUrl)
18
- return () => {
19
- setIsLoggedIn?.(false)
20
- setLoginUrl?.(undefined)
21
- }
22
- }, [isLoggedIn, setIsLoggedIn, loginUrl, setLoginUrl])
23
-
24
- return null
25
- }
26
-
27
- export default IsLoggedInSetter
@@ -1,37 +0,0 @@
1
- import { useEffect, useState } from 'react'
2
-
3
- import { MenuItem } from '../../types'
4
- import HeaderMenuItem from './header-menu-item'
5
-
6
- function MenuItemGroup({
7
- isMenuOpen,
8
- menuItems,
9
- }: {
10
- isMenuOpen: boolean
11
- menuItems: MenuItem[]
12
- }) {
13
- const [currentExpandedItem, setCurrentExpandedItem] = useState<string | null>(
14
- null
15
- )
16
-
17
- const handleClick = (label: string | null) => {
18
- setCurrentExpandedItem(label)
19
- }
20
-
21
- useEffect(() => {
22
- if (!isMenuOpen) {
23
- setCurrentExpandedItem(null)
24
- }
25
- }, [isMenuOpen])
26
-
27
- return menuItems.map((item) => (
28
- <HeaderMenuItem
29
- key={item.label}
30
- {...item}
31
- isExpanded={currentExpandedItem === item.label}
32
- onExpand={handleClick}
33
- />
34
- ))
35
- }
36
-
37
- export default MenuItemGroup