@docubook/create 2.4.0 → 2.5.1
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/package.json +1 -1
- package/src/dist/app/docs/[[...slug]]/page.tsx +55 -59
- package/src/dist/app/docs/layout.tsx +11 -4
- package/src/dist/app/layout.tsx +10 -7
- package/src/dist/app/page.tsx +1 -1
- package/src/dist/components/{context-popover.tsx → ContextPopover.tsx} +3 -2
- package/src/dist/components/DocSearch.tsx +16 -15
- package/src/dist/components/{docs-breadcrumb.tsx → DocsBreadcrumb.tsx} +1 -1
- package/src/dist/components/DocsNavbar.tsx +46 -0
- package/src/dist/components/DocsSidebar.tsx +207 -0
- package/src/dist/components/Github.tsx +26 -0
- package/src/dist/components/{scroll-to-top.tsx → ScrollToTop.tsx} +16 -9
- package/src/dist/components/SearchBox.tsx +39 -0
- package/src/dist/components/SearchContext.tsx +47 -0
- package/src/dist/components/SearchModal.tsx +77 -79
- package/src/dist/components/SearchTrigger.tsx +20 -15
- package/src/dist/components/Sponsor.tsx +2 -2
- package/src/dist/components/{theme-toggle.tsx → ThemeToggle.tsx} +10 -10
- package/src/dist/components/TocObserver.tsx +197 -0
- package/src/dist/components/footer.tsx +16 -12
- package/src/dist/components/leftbar.tsx +45 -73
- package/src/dist/components/markdown/AccordionContext.tsx +21 -0
- package/src/dist/components/markdown/AccordionGroupMdx.tsx +11 -22
- package/src/dist/components/markdown/AccordionMdx.tsx +58 -59
- package/src/dist/components/markdown/PreMdx.tsx +2 -2
- package/src/dist/components/navbar.tsx +130 -53
- package/src/dist/components/toc.tsx +16 -14
- package/src/dist/components/typography.tsx +1 -1
- package/src/dist/components/ui/icon-cloud.tsx +353 -0
- package/src/dist/components/ui/scroll-area.tsx +2 -2
- package/src/dist/components/ui/sheet.tsx +4 -4
- package/src/dist/components/ui/toggle.tsx +3 -3
- package/src/dist/docs/components/accordion-group.mdx +13 -12
- package/src/dist/docs/components/accordion.mdx +11 -14
- package/src/dist/docu.json +3 -0
- package/src/dist/hooks/useActiveSection.ts +45 -33
- package/src/dist/hooks/useScrollPosition.ts +16 -14
- package/src/dist/lib/search/algolia.ts +5 -0
- package/src/dist/lib/search/built-in.ts +43 -0
- package/src/dist/lib/search/config.ts +7 -0
- package/src/dist/lib/toc.ts +1 -0
- package/src/dist/lib/utils.ts +13 -54
- package/src/dist/package.json +1 -1
- package/src/dist/styles/algolia.css +12 -35
- package/src/dist/styles/{syntax.css → override.css} +82 -39
- package/src/dist/tailwind.config.ts +11 -110
- package/src/dist/components/AccordionContext.ts +0 -4
- package/src/dist/components/GithubStart.tsx +0 -44
- package/src/dist/components/mob-toc.tsx +0 -134
- package/src/dist/components/search.tsx +0 -55
- package/src/dist/components/toc-observer.tsx +0 -254
- /package/src/dist/components/{docs-menu.tsx → DocsMenu.tsx} +0 -0
- /package/src/dist/components/{edit-on-github.tsx → EditWithGithub.tsx} +0 -0
- /package/src/dist/components/{theme-provider.tsx → ThemeProvider.tsx} +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { Dialog } from "@/components/ui/dialog"
|
|
4
|
+
import { SearchTrigger } from "@/components/SearchTrigger"
|
|
5
|
+
import { SearchModal } from "@/components/SearchModal"
|
|
6
|
+
import AlgoliaSearch from "@/components/DocSearch"
|
|
7
|
+
import { useSearch } from "./SearchContext"
|
|
8
|
+
import { DialogTrigger } from "@/components/ui/dialog"
|
|
9
|
+
import { searchConfig } from "@/lib/search/config"
|
|
10
|
+
|
|
11
|
+
interface SearchProps {
|
|
12
|
+
/**
|
|
13
|
+
* Override the search type from config.
|
|
14
|
+
* If not provided, uses the config value.
|
|
15
|
+
*/
|
|
16
|
+
type?: "default" | "algolia"
|
|
17
|
+
className?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function Search({ type, className }: SearchProps) {
|
|
21
|
+
const { isOpen, setIsOpen } = useSearch()
|
|
22
|
+
const searchType = type ?? searchConfig.type
|
|
23
|
+
|
|
24
|
+
if (searchType === "algolia") {
|
|
25
|
+
return <AlgoliaSearch className={className} />
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Logic for 'default' search
|
|
29
|
+
return (
|
|
30
|
+
<div className={className}>
|
|
31
|
+
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
|
32
|
+
<DialogTrigger asChild>
|
|
33
|
+
<SearchTrigger className={className} />
|
|
34
|
+
</DialogTrigger>
|
|
35
|
+
<SearchModal isOpen={isOpen} setIsOpen={setIsOpen} />
|
|
36
|
+
</Dialog>
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { createContext, useContext, useState, useEffect, useCallback } from "react";
|
|
4
|
+
|
|
5
|
+
interface SearchContextType {
|
|
6
|
+
isOpen: boolean;
|
|
7
|
+
setIsOpen: (open: boolean) => void;
|
|
8
|
+
toggle: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const SearchContext = createContext<SearchContextType | undefined>(undefined);
|
|
12
|
+
|
|
13
|
+
export function SearchProvider({ children }: { children: React.ReactNode }) {
|
|
14
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
15
|
+
|
|
16
|
+
const toggle = useCallback(() => {
|
|
17
|
+
setIsOpen((prev) => !prev);
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
22
|
+
if ((event.ctrlKey || event.metaKey) && event.key === "k") {
|
|
23
|
+
event.preventDefault();
|
|
24
|
+
toggle();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
29
|
+
return () => {
|
|
30
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
31
|
+
};
|
|
32
|
+
}, [toggle]);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<SearchContext.Provider value={{ isOpen, setIsOpen, toggle }}>
|
|
36
|
+
{children}
|
|
37
|
+
</SearchContext.Provider>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useSearch() {
|
|
42
|
+
const context = useContext(SearchContext);
|
|
43
|
+
if (!context) {
|
|
44
|
+
throw new Error("useSearch must be used within a SearchProvider");
|
|
45
|
+
}
|
|
46
|
+
return context;
|
|
47
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
"use client"
|
|
2
|
-
|
|
3
|
-
import { useRouter } from "next/navigation"
|
|
4
|
-
import { useEffect, useMemo, useState, useRef } from "react"
|
|
5
|
-
import { ArrowUpIcon, ArrowDownIcon, CornerDownLeftIcon, FileTextIcon } from "lucide-react"
|
|
6
|
-
import Anchor from "./anchor"
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useRouter } from "next/navigation"
|
|
4
|
+
import { useEffect, useMemo, useState, useRef } from "react"
|
|
5
|
+
import { ArrowUpIcon, ArrowDownIcon, CornerDownLeftIcon, FileTextIcon } from "lucide-react"
|
|
6
|
+
import Anchor from "./anchor"
|
|
7
|
+
import { cn } from "@/lib/utils"
|
|
8
|
+
import { advanceSearch } from "@/lib/search/built-in"
|
|
9
|
+
import { ScrollArea } from "@/components/ui/scroll-area"
|
|
10
|
+
import { page_routes } from "@/lib/routes"
|
|
10
11
|
import {
|
|
11
12
|
DialogContent,
|
|
12
13
|
DialogHeader,
|
|
@@ -14,63 +15,63 @@ import {
|
|
|
14
15
|
DialogClose,
|
|
15
16
|
DialogTitle,
|
|
16
17
|
DialogDescription,
|
|
17
|
-
} from "@/components/ui/dialog"
|
|
18
|
+
} from "@/components/ui/dialog"
|
|
18
19
|
|
|
19
20
|
type ContextInfo = {
|
|
20
|
-
icon: string
|
|
21
|
-
description: string
|
|
22
|
-
title?: string
|
|
23
|
-
}
|
|
21
|
+
icon: string
|
|
22
|
+
description: string
|
|
23
|
+
title?: string
|
|
24
|
+
}
|
|
24
25
|
|
|
25
26
|
type SearchResult = {
|
|
26
|
-
title: string
|
|
27
|
-
href: string
|
|
28
|
-
noLink?: boolean
|
|
29
|
-
items?: undefined
|
|
30
|
-
score?: number
|
|
31
|
-
context?: ContextInfo
|
|
32
|
-
}
|
|
27
|
+
title: string
|
|
28
|
+
href: string
|
|
29
|
+
noLink?: boolean
|
|
30
|
+
items?: undefined
|
|
31
|
+
score?: number
|
|
32
|
+
context?: ContextInfo
|
|
33
|
+
}
|
|
33
34
|
|
|
34
35
|
const paddingMap = {
|
|
35
36
|
1: "pl-2",
|
|
36
37
|
2: "pl-4",
|
|
37
38
|
3: "pl-10",
|
|
38
|
-
} as const
|
|
39
|
+
} as const
|
|
39
40
|
|
|
40
41
|
interface SearchModalProps {
|
|
41
|
-
isOpen: boolean
|
|
42
|
-
setIsOpen: (open: boolean) => void
|
|
42
|
+
isOpen: boolean
|
|
43
|
+
setIsOpen: (open: boolean) => void
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
|
46
|
-
const router = useRouter()
|
|
47
|
-
const [searchedInput, setSearchedInput] = useState("")
|
|
48
|
-
const [selectedIndex, setSelectedIndex] = useState(0)
|
|
49
|
-
const itemRefs = useRef<(HTMLDivElement | null)[]>([])
|
|
47
|
+
const router = useRouter()
|
|
48
|
+
const [searchedInput, setSearchedInput] = useState("")
|
|
49
|
+
const [selectedIndex, setSelectedIndex] = useState(0)
|
|
50
|
+
const itemRefs = useRef<(HTMLDivElement | null)[]>([])
|
|
50
51
|
|
|
51
52
|
useEffect(() => {
|
|
52
53
|
if (!isOpen) {
|
|
53
54
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
54
|
-
setSearchedInput("")
|
|
55
|
+
setSearchedInput("")
|
|
55
56
|
}
|
|
56
|
-
}, [isOpen])
|
|
57
|
+
}, [isOpen])
|
|
57
58
|
|
|
58
59
|
const filteredResults = useMemo<SearchResult[]>(() => {
|
|
59
|
-
const trimmedInput = searchedInput.trim()
|
|
60
|
+
const trimmedInput = searchedInput.trim()
|
|
60
61
|
|
|
61
62
|
if (trimmedInput.length < 3) {
|
|
62
63
|
return page_routes
|
|
63
|
-
.filter((route) => !route.href.endsWith(
|
|
64
|
+
.filter((route) => !route.href.endsWith("/"))
|
|
64
65
|
.slice(0, 6)
|
|
65
66
|
.map((route: { title: string; href: string; noLink?: boolean; context?: ContextInfo }) => ({
|
|
66
67
|
title: route.title,
|
|
67
68
|
href: route.href,
|
|
68
69
|
noLink: route.noLink,
|
|
69
70
|
context: route.context,
|
|
70
|
-
}))
|
|
71
|
+
}))
|
|
71
72
|
}
|
|
72
|
-
return advanceSearch(trimmedInput) as unknown as SearchResult[]
|
|
73
|
-
}, [searchedInput])
|
|
73
|
+
return advanceSearch(trimmedInput) as unknown as SearchResult[]
|
|
74
|
+
}, [searchedInput])
|
|
74
75
|
|
|
75
76
|
// useEffect(() => {
|
|
76
77
|
// setSelectedIndex(0);
|
|
@@ -78,39 +79,39 @@ export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
|
|
78
79
|
|
|
79
80
|
useEffect(() => {
|
|
80
81
|
const handleNavigation = (event: KeyboardEvent) => {
|
|
81
|
-
if (!isOpen || filteredResults.length === 0) return
|
|
82
|
+
if (!isOpen || filteredResults.length === 0) return
|
|
82
83
|
|
|
83
84
|
if (event.key === "ArrowDown") {
|
|
84
|
-
event.preventDefault()
|
|
85
|
-
setSelectedIndex((prev) => (prev + 1) % filteredResults.length)
|
|
85
|
+
event.preventDefault()
|
|
86
|
+
setSelectedIndex((prev) => (prev + 1) % filteredResults.length)
|
|
86
87
|
} else if (event.key === "ArrowUp") {
|
|
87
|
-
event.preventDefault()
|
|
88
|
-
setSelectedIndex((prev) => (prev - 1 + filteredResults.length) % filteredResults.length)
|
|
88
|
+
event.preventDefault()
|
|
89
|
+
setSelectedIndex((prev) => (prev - 1 + filteredResults.length) % filteredResults.length)
|
|
89
90
|
} else if (event.key === "Enter") {
|
|
90
|
-
event.preventDefault()
|
|
91
|
-
const selectedItem = filteredResults[selectedIndex]
|
|
91
|
+
event.preventDefault()
|
|
92
|
+
const selectedItem = filteredResults[selectedIndex]
|
|
92
93
|
if (selectedItem) {
|
|
93
|
-
router.push(`/docs${selectedItem.href}`)
|
|
94
|
-
setIsOpen(false)
|
|
94
|
+
router.push(`/docs${selectedItem.href}`)
|
|
95
|
+
setIsOpen(false)
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
|
-
}
|
|
98
|
+
}
|
|
98
99
|
|
|
99
|
-
window.addEventListener("keydown", handleNavigation)
|
|
100
|
-
return () => window.removeEventListener("keydown", handleNavigation)
|
|
101
|
-
}, [isOpen, filteredResults, selectedIndex, router, setIsOpen])
|
|
100
|
+
window.addEventListener("keydown", handleNavigation)
|
|
101
|
+
return () => window.removeEventListener("keydown", handleNavigation)
|
|
102
|
+
}, [isOpen, filteredResults, selectedIndex, router, setIsOpen])
|
|
102
103
|
|
|
103
104
|
useEffect(() => {
|
|
104
105
|
if (itemRefs.current[selectedIndex]) {
|
|
105
106
|
itemRefs.current[selectedIndex]?.scrollIntoView({
|
|
106
107
|
behavior: "smooth",
|
|
107
108
|
block: "nearest",
|
|
108
|
-
})
|
|
109
|
+
})
|
|
109
110
|
}
|
|
110
|
-
}, [selectedIndex])
|
|
111
|
+
}, [selectedIndex])
|
|
111
112
|
|
|
112
113
|
return (
|
|
113
|
-
<DialogContent className="
|
|
114
|
+
<DialogContent className="rounded-md! top-[45%] max-w-[650px] p-0 sm:top-[38%]">
|
|
114
115
|
<DialogHeader>
|
|
115
116
|
<DialogTitle className="sr-only">Search Documentation</DialogTitle>
|
|
116
117
|
<DialogDescription className="sr-only">Search through the documentation</DialogDescription>
|
|
@@ -119,36 +120,35 @@ export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
|
|
119
120
|
<input
|
|
120
121
|
value={searchedInput}
|
|
121
122
|
onChange={(e) => {
|
|
122
|
-
setSearchedInput(e.target.value)
|
|
123
|
-
setSelectedIndex(0)
|
|
123
|
+
setSearchedInput(e.target.value)
|
|
124
|
+
setSelectedIndex(0)
|
|
124
125
|
}}
|
|
125
126
|
placeholder="Type something to search..."
|
|
126
127
|
autoFocus
|
|
127
|
-
className="h-14
|
|
128
|
+
className="h-14 w-full border-b bg-transparent px-6 text-[14px] outline-none"
|
|
128
129
|
aria-label="Search documentation"
|
|
129
130
|
/>
|
|
130
131
|
|
|
131
132
|
{filteredResults.length == 0 && searchedInput && (
|
|
132
133
|
<p className="text-muted-foreground mx-auto mt-2 text-sm">
|
|
133
|
-
No results found for{"
|
|
134
|
-
<span className="text-primary">{`"${searchedInput}"`}</span>
|
|
134
|
+
No results found for <span className="text-primary">{`"${searchedInput}"`}</span>
|
|
135
135
|
</p>
|
|
136
136
|
)}
|
|
137
137
|
<ScrollArea className="max-h-[400px] overflow-y-auto">
|
|
138
|
-
<div className="flex flex-col items-start overflow-y-auto
|
|
138
|
+
<div className="flex flex-col items-start overflow-y-auto px-1 pb-4 sm:px-2">
|
|
139
139
|
{filteredResults.map((item, index) => {
|
|
140
|
-
const level = (item.href.split("/").slice(1).length - 1) as keyof typeof paddingMap
|
|
141
|
-
const paddingClass = paddingMap[level] ||
|
|
142
|
-
const isActive = index === selectedIndex
|
|
140
|
+
const level = (item.href.split("/").slice(1).length - 1) as keyof typeof paddingMap
|
|
141
|
+
const paddingClass = paddingMap[level] || "pl-2"
|
|
142
|
+
const isActive = index === selectedIndex
|
|
143
143
|
|
|
144
144
|
return (
|
|
145
145
|
<DialogClose key={item.href} asChild>
|
|
146
146
|
<Anchor
|
|
147
147
|
ref={(el) => {
|
|
148
|
-
itemRefs.current[index] = el as HTMLDivElement | null
|
|
148
|
+
itemRefs.current[index] = el as HTMLDivElement | null
|
|
149
149
|
}}
|
|
150
150
|
className={cn(
|
|
151
|
-
"dark:hover:bg-accent/15 hover:bg-accent/10 w-full
|
|
151
|
+
"dark:hover:bg-accent/15 hover:bg-accent/10 flex w-full items-center gap-2.5 rounded-sm px-3 text-sm",
|
|
152
152
|
isActive && "bg-primary/20 dark:bg-primary/30",
|
|
153
153
|
paddingClass
|
|
154
154
|
)}
|
|
@@ -157,46 +157,44 @@ export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) {
|
|
|
157
157
|
>
|
|
158
158
|
<div
|
|
159
159
|
className={cn(
|
|
160
|
-
"flex
|
|
160
|
+
"flex h-full w-full items-center justify-between gap-1.5 px-2 py-3",
|
|
161
161
|
level > 1 && "border-l pl-4"
|
|
162
162
|
)}
|
|
163
163
|
>
|
|
164
164
|
<div className="flex items-center">
|
|
165
|
-
<FileTextIcon className="h-[1.1rem] w-[1.1rem]
|
|
165
|
+
<FileTextIcon className="mr-1 h-[1.1rem] w-[1.1rem]" />
|
|
166
166
|
<span>{item.title}</span>
|
|
167
167
|
</div>
|
|
168
168
|
{isActive && (
|
|
169
|
-
<div className="hidden
|
|
169
|
+
<div className="text-muted-foreground hidden items-center text-xs md:flex">
|
|
170
170
|
<span>Return</span>
|
|
171
|
-
<CornerDownLeftIcon className="h-3 w-3
|
|
171
|
+
<CornerDownLeftIcon className="ml-1 h-3 w-3" />
|
|
172
172
|
</div>
|
|
173
173
|
)}
|
|
174
174
|
</div>
|
|
175
175
|
</Anchor>
|
|
176
176
|
</DialogClose>
|
|
177
|
-
)
|
|
177
|
+
)
|
|
178
178
|
})}
|
|
179
179
|
</div>
|
|
180
180
|
</ScrollArea>
|
|
181
|
-
<DialogFooter className="
|
|
181
|
+
<DialogFooter className="hidden h-14 border-t bg-transparent px-6 text-[14px] outline-none md:flex md:justify-start">
|
|
182
182
|
<div className="flex items-center gap-2">
|
|
183
|
-
<span className="dark:bg-accent/15 bg-slate-200
|
|
184
|
-
<ArrowUpIcon className="
|
|
183
|
+
<span className="dark:bg-accent/15 rounded border bg-slate-200 p-2">
|
|
184
|
+
<ArrowUpIcon className="h-3 w-3" />
|
|
185
185
|
</span>
|
|
186
|
-
<span className="dark:bg-accent/15 bg-slate-200
|
|
187
|
-
<ArrowDownIcon className="
|
|
186
|
+
<span className="dark:bg-accent/15 rounded border bg-slate-200 p-2">
|
|
187
|
+
<ArrowDownIcon className="h-3 w-3" />
|
|
188
188
|
</span>
|
|
189
189
|
<p className="text-muted-foreground">to navigate</p>
|
|
190
|
-
<span className="dark:bg-accent/15 bg-slate-200
|
|
191
|
-
<CornerDownLeftIcon className="
|
|
190
|
+
<span className="dark:bg-accent/15 rounded border bg-slate-200 p-2">
|
|
191
|
+
<CornerDownLeftIcon className="h-3 w-3" />
|
|
192
192
|
</span>
|
|
193
193
|
<p className="text-muted-foreground">to select</p>
|
|
194
|
-
<span className="dark:bg-accent/15 bg-slate-200
|
|
195
|
-
esc
|
|
196
|
-
</span>
|
|
194
|
+
<span className="dark:bg-accent/15 rounded border bg-slate-200 px-2 py-1">esc</span>
|
|
197
195
|
<p className="text-muted-foreground">to close</p>
|
|
198
196
|
</div>
|
|
199
197
|
</DialogFooter>
|
|
200
198
|
</DialogContent>
|
|
201
|
-
)
|
|
202
|
-
}
|
|
199
|
+
)
|
|
200
|
+
}
|
|
@@ -1,31 +1,36 @@
|
|
|
1
|
-
"use client"
|
|
1
|
+
"use client"
|
|
2
2
|
|
|
3
|
-
import { CommandIcon, SearchIcon } from "lucide-react"
|
|
4
|
-
import { DialogTrigger } from "@/components/ui/dialog"
|
|
5
|
-
import { Input } from "@/components/ui/input"
|
|
3
|
+
import { CommandIcon, SearchIcon } from "lucide-react"
|
|
4
|
+
import { DialogTrigger } from "@/components/ui/dialog"
|
|
5
|
+
import { Input } from "@/components/ui/input"
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
interface SearchTriggerProps {
|
|
9
|
+
className?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function SearchTrigger({ className }: SearchTriggerProps) {
|
|
8
13
|
return (
|
|
9
14
|
<DialogTrigger asChild>
|
|
10
|
-
<div className="relative flex-1 cursor-pointer
|
|
15
|
+
<div className={cn("relative flex-1 cursor-pointer", className)}>
|
|
11
16
|
<div className="flex items-center">
|
|
12
|
-
<div className="
|
|
13
|
-
<SearchIcon className="h-
|
|
17
|
+
<div className="-ml-2 block p-2 lg:hidden">
|
|
18
|
+
<SearchIcon className="text-muted-foreground h-6 w-6" />
|
|
14
19
|
</div>
|
|
15
|
-
<div className="hidden
|
|
16
|
-
<SearchIcon className="absolute left-3 top-1/2
|
|
20
|
+
<div className="hidden w-full lg:block">
|
|
21
|
+
<SearchIcon className="text-muted-foreground absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2" />
|
|
17
22
|
<Input
|
|
18
|
-
className="
|
|
23
|
+
className="dark:bg-background/95 bg-background h-9 w-full overflow-ellipsis rounded-full border pl-10 pr-0 text-sm shadow-sm sm:pr-4"
|
|
19
24
|
placeholder="Search"
|
|
20
25
|
readOnly // This input is for display only
|
|
21
26
|
/>
|
|
22
|
-
<div className="
|
|
23
|
-
<CommandIcon className="
|
|
27
|
+
<div className="dark:bg-accent bg-accent absolute right-2 top-1/2 flex -translate-y-1/2 items-center gap-0.5 rounded-full px-2 py-0.5 font-mono text-xs font-medium text-white">
|
|
28
|
+
<CommandIcon className="h-3 w-3" />
|
|
24
29
|
<span>K</span>
|
|
25
30
|
</div>
|
|
26
31
|
</div>
|
|
27
32
|
</div>
|
|
28
33
|
</div>
|
|
29
34
|
</DialogTrigger>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -89,7 +89,7 @@ export function Sponsor() {
|
|
|
89
89
|
// Safely get sponsor data with optional chaining and default values
|
|
90
90
|
const sponsor = docuConfig?.sponsor || {};
|
|
91
91
|
const item = sponsor?.item;
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
// Return null if required fields are missing
|
|
94
94
|
if (!item?.url || !item?.image || !item?.title) {
|
|
95
95
|
return null;
|
|
@@ -106,7 +106,7 @@ export function Sponsor() {
|
|
|
106
106
|
rel="noopener noreferrer"
|
|
107
107
|
className="flex flex-col justify-center gap-2 p-4 border rounded-lg hover:shadow transition-shadow"
|
|
108
108
|
>
|
|
109
|
-
<div className="relative w-8 h-8
|
|
109
|
+
<div className="relative w-8 h-8 shrink-0">
|
|
110
110
|
<Image
|
|
111
111
|
src={item.image}
|
|
112
112
|
alt={item.title}
|
|
@@ -17,9 +17,9 @@ export function ModeToggle() {
|
|
|
17
17
|
// Jika belum mounted, jangan render apapun untuk menghindari mismatch
|
|
18
18
|
if (!mounted) {
|
|
19
19
|
return (
|
|
20
|
-
<div className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-
|
|
21
|
-
<div className="rounded-full p-
|
|
22
|
-
<div className="rounded-full p-
|
|
20
|
+
<div className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-0.5">
|
|
21
|
+
<div className="rounded-full p-0 w-1 h-1" />
|
|
22
|
+
<div className="rounded-full p-0 w-1 h-1" />
|
|
23
23
|
</div>
|
|
24
24
|
);
|
|
25
25
|
}
|
|
@@ -43,29 +43,29 @@ export function ModeToggle() {
|
|
|
43
43
|
type="single"
|
|
44
44
|
value={activeTheme}
|
|
45
45
|
onValueChange={handleToggle}
|
|
46
|
-
className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-
|
|
46
|
+
className="flex items-center gap-1 rounded-full border border-border bg-background/50 p-0.5 transition-all"
|
|
47
47
|
>
|
|
48
48
|
<ToggleGroupItem
|
|
49
49
|
value="light"
|
|
50
|
-
size="
|
|
50
|
+
size="xs"
|
|
51
51
|
aria-label="Light Mode"
|
|
52
|
-
className={`rounded-full cursor-pointer p-
|
|
52
|
+
className={`rounded-full cursor-pointer p-0.5 transition-all ${activeTheme === "light"
|
|
53
53
|
? "bg-primary text-primary-foreground"
|
|
54
54
|
: "bg-transparent hover:bg-muted/50"
|
|
55
55
|
}`}
|
|
56
56
|
>
|
|
57
|
-
<Sun className="h-
|
|
57
|
+
<Sun className="h-0.5 w-0.5" />
|
|
58
58
|
</ToggleGroupItem>
|
|
59
59
|
<ToggleGroupItem
|
|
60
60
|
value="dark"
|
|
61
|
-
size="
|
|
61
|
+
size="xs"
|
|
62
62
|
aria-label="Dark Mode"
|
|
63
|
-
className={`rounded-full cursor-pointer p-
|
|
63
|
+
className={`rounded-full cursor-pointer p-0.5 transition-all ${activeTheme === "dark"
|
|
64
64
|
? "bg-primary text-primary-foreground"
|
|
65
65
|
: "bg-transparent hover:bg-muted/50"
|
|
66
66
|
}`}
|
|
67
67
|
>
|
|
68
|
-
<Moon className="h-
|
|
68
|
+
<Moon className="h-0.5 w-0.5" />
|
|
69
69
|
</ToggleGroupItem>
|
|
70
70
|
</ToggleGroup>
|
|
71
71
|
);
|