@microlink/google 0.1.0 → 1.0.0
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 +36 -15
- package/src/css/style.css +1152 -0
- package/src/index.d.ts +19 -0
- package/src/index.js +23 -16
- package/src/js/main.js +397 -0
- package/README.md +0 -280
package/src/index.d.ts
CHANGED
|
@@ -90,6 +90,7 @@ interface SearchResult {
|
|
|
90
90
|
url: string
|
|
91
91
|
description: string
|
|
92
92
|
html(): Promise<string>
|
|
93
|
+
markdown(): Promise<string>
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
interface SearchPage {
|
|
@@ -98,6 +99,7 @@ interface SearchPage {
|
|
|
98
99
|
peopleAlsoAsk?: PeopleAlsoAsk[]
|
|
99
100
|
relatedSearches?: RelatedSearch[]
|
|
100
101
|
html(): Promise<string>
|
|
102
|
+
markdown(): Promise<string>
|
|
101
103
|
next(): Promise<SearchPage>
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -109,11 +111,13 @@ interface NewsResult {
|
|
|
109
111
|
publisher: string
|
|
110
112
|
image?: { url: string }
|
|
111
113
|
html(): Promise<string>
|
|
114
|
+
markdown(): Promise<string>
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
interface NewsPage {
|
|
115
118
|
results: NewsResult[]
|
|
116
119
|
html(): Promise<string>
|
|
120
|
+
markdown(): Promise<string>
|
|
117
121
|
next(): Promise<NewsPage>
|
|
118
122
|
}
|
|
119
123
|
|
|
@@ -126,11 +130,13 @@ interface ImageResult {
|
|
|
126
130
|
creator?: string
|
|
127
131
|
credit?: string
|
|
128
132
|
html(): Promise<string>
|
|
133
|
+
markdown(): Promise<string>
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
interface ImagesPage {
|
|
132
137
|
results: ImageResult[]
|
|
133
138
|
html(): Promise<string>
|
|
139
|
+
markdown(): Promise<string>
|
|
134
140
|
next(): Promise<ImagesPage>
|
|
135
141
|
}
|
|
136
142
|
|
|
@@ -146,11 +152,13 @@ interface VideoResult {
|
|
|
146
152
|
channel?: string
|
|
147
153
|
date?: string
|
|
148
154
|
html(): Promise<string>
|
|
155
|
+
markdown(): Promise<string>
|
|
149
156
|
}
|
|
150
157
|
|
|
151
158
|
interface VideosPage {
|
|
152
159
|
results: VideoResult[]
|
|
153
160
|
html(): Promise<string>
|
|
161
|
+
markdown(): Promise<string>
|
|
154
162
|
next(): Promise<VideosPage>
|
|
155
163
|
}
|
|
156
164
|
|
|
@@ -163,11 +171,13 @@ interface PlaceResult {
|
|
|
163
171
|
url?: string
|
|
164
172
|
cid: string
|
|
165
173
|
html(): Promise<string>
|
|
174
|
+
markdown(): Promise<string>
|
|
166
175
|
}
|
|
167
176
|
|
|
168
177
|
interface PlacesPage {
|
|
169
178
|
results: PlaceResult[]
|
|
170
179
|
html(): Promise<string>
|
|
180
|
+
markdown(): Promise<string>
|
|
171
181
|
next(): Promise<PlacesPage>
|
|
172
182
|
}
|
|
173
183
|
|
|
@@ -190,11 +200,13 @@ interface MapPlaceResult {
|
|
|
190
200
|
fid?: string
|
|
191
201
|
place?: { id: string }
|
|
192
202
|
html(): Promise<string>
|
|
203
|
+
markdown(): Promise<string>
|
|
193
204
|
}
|
|
194
205
|
|
|
195
206
|
interface MapsPage {
|
|
196
207
|
results: MapPlaceResult[]
|
|
197
208
|
html(): Promise<string>
|
|
209
|
+
markdown(): Promise<string>
|
|
198
210
|
next(): Promise<MapsPage>
|
|
199
211
|
}
|
|
200
212
|
|
|
@@ -207,11 +219,13 @@ interface ShoppingResult {
|
|
|
207
219
|
rating?: { score: number; total: number; reviews?: number }
|
|
208
220
|
id?: string
|
|
209
221
|
html(): Promise<string>
|
|
222
|
+
markdown(): Promise<string>
|
|
210
223
|
}
|
|
211
224
|
|
|
212
225
|
interface ShoppingPage {
|
|
213
226
|
results: ShoppingResult[]
|
|
214
227
|
html(): Promise<string>
|
|
228
|
+
markdown(): Promise<string>
|
|
215
229
|
next(): Promise<ShoppingPage>
|
|
216
230
|
}
|
|
217
231
|
|
|
@@ -225,11 +239,13 @@ interface ScholarResult {
|
|
|
225
239
|
pdf?: { url: string }
|
|
226
240
|
id: string
|
|
227
241
|
html(): Promise<string>
|
|
242
|
+
markdown(): Promise<string>
|
|
228
243
|
}
|
|
229
244
|
|
|
230
245
|
interface ScholarPage {
|
|
231
246
|
results: ScholarResult[]
|
|
232
247
|
html(): Promise<string>
|
|
248
|
+
markdown(): Promise<string>
|
|
233
249
|
next(): Promise<ScholarPage>
|
|
234
250
|
}
|
|
235
251
|
|
|
@@ -249,11 +265,13 @@ interface PatentResult {
|
|
|
249
265
|
figures?: Array<{ image: { url: string }; thumbnail: { url: string } }>
|
|
250
266
|
id?: string
|
|
251
267
|
html(): Promise<string>
|
|
268
|
+
markdown(): Promise<string>
|
|
252
269
|
}
|
|
253
270
|
|
|
254
271
|
interface PatentsPage {
|
|
255
272
|
results: PatentResult[]
|
|
256
273
|
html(): Promise<string>
|
|
274
|
+
markdown(): Promise<string>
|
|
257
275
|
next(): Promise<PatentsPage>
|
|
258
276
|
}
|
|
259
277
|
|
|
@@ -264,6 +282,7 @@ interface SuggestionResult {
|
|
|
264
282
|
interface AutocompletePage {
|
|
265
283
|
results: SuggestionResult[]
|
|
266
284
|
html(): Promise<string>
|
|
285
|
+
markdown(): Promise<string>
|
|
267
286
|
next(): Promise<AutocompletePage>
|
|
268
287
|
}
|
|
269
288
|
|
package/src/index.js
CHANGED
|
@@ -18,6 +18,14 @@ const buildUrl = (query, { limit, location, type, period } = {}) => {
|
|
|
18
18
|
|
|
19
19
|
const resultUrl = result => result.url
|
|
20
20
|
|
|
21
|
+
const fetchDataField = async (url, mqlOpts, field, attr) => {
|
|
22
|
+
const { data } = await mql(url, {
|
|
23
|
+
...mqlOpts,
|
|
24
|
+
data: { [field]: { attr } }
|
|
25
|
+
})
|
|
26
|
+
return data[field]
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
const fetchPage = async (url, mqlOpts, offset, query) => {
|
|
22
30
|
url.searchParams.set('start', String(offset))
|
|
23
31
|
const { data } = await mql(url.toString(), mqlOpts)
|
|
@@ -25,28 +33,27 @@ const fetchPage = async (url, mqlOpts, offset, query) => {
|
|
|
25
33
|
|
|
26
34
|
return {
|
|
27
35
|
...extra,
|
|
28
|
-
html:
|
|
29
|
-
|
|
36
|
+
html: () =>
|
|
37
|
+
fetchDataField(
|
|
30
38
|
`https://www.google.com/search?q=${encodeURIComponent(query)}`,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
mqlOpts,
|
|
40
|
+
'content',
|
|
41
|
+
'html'
|
|
42
|
+
),
|
|
43
|
+
markdown: () =>
|
|
44
|
+
fetchDataField(
|
|
45
|
+
`https://www.google.com/search?q=${encodeURIComponent(query)}`,
|
|
46
|
+
mqlOpts,
|
|
47
|
+
'markdown',
|
|
48
|
+
'markdown'
|
|
49
|
+
),
|
|
38
50
|
results: results.map(result => {
|
|
39
51
|
const url = resultUrl(result)
|
|
40
52
|
return {
|
|
41
53
|
...result,
|
|
42
54
|
...(url && {
|
|
43
|
-
html:
|
|
44
|
-
|
|
45
|
-
...mqlOpts,
|
|
46
|
-
data: { content: { attr: 'html' } }
|
|
47
|
-
})
|
|
48
|
-
return data.content
|
|
49
|
-
}
|
|
55
|
+
html: () => fetchDataField(url, mqlOpts, 'content', 'html'),
|
|
56
|
+
markdown: () => fetchDataField(url, mqlOpts, 'markdown', 'markdown')
|
|
50
57
|
})
|
|
51
58
|
}
|
|
52
59
|
}),
|
package/src/js/main.js
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
const createHeroStats = () => {
|
|
2
|
+
const stats = document.createElement('div')
|
|
3
|
+
stats.className = 'hero-stats reveal-on-load'
|
|
4
|
+
stats.innerHTML = `
|
|
5
|
+
<div class="hero-stat"><strong>10</strong><span>Google verticals</span></div>
|
|
6
|
+
<div class="hero-stat"><strong>~1s</strong><span>Typical latency</span></div>
|
|
7
|
+
<div class="hero-stat hero-stat--serialization"><strong>HTML/MARKDOWN</strong><span>Output serialization</span></div>
|
|
8
|
+
`
|
|
9
|
+
return stats
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const createVisualBadges = () => {
|
|
13
|
+
const badges = document.createElement('div')
|
|
14
|
+
badges.className = 'hero-badges'
|
|
15
|
+
badges.innerHTML = `
|
|
16
|
+
<div class="hero-badge top">10 products</div>
|
|
17
|
+
<div class="hero-badge bottom"><1s response</div>
|
|
18
|
+
`
|
|
19
|
+
return badges
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const decorateHero = section => {
|
|
23
|
+
const hero = section.querySelector('div[align="center"]')
|
|
24
|
+
if (!hero || hero.dataset.enhanced === 'true') return
|
|
25
|
+
|
|
26
|
+
hero.dataset.enhanced = 'true'
|
|
27
|
+
hero.className = 'hero-block'
|
|
28
|
+
|
|
29
|
+
const image = hero.querySelector('img')
|
|
30
|
+
const summary = hero.querySelector('p')
|
|
31
|
+
|
|
32
|
+
const copy = document.createElement('div')
|
|
33
|
+
copy.className = 'hero-copy'
|
|
34
|
+
|
|
35
|
+
const eyebrow = document.createElement('div')
|
|
36
|
+
eyebrow.className = 'hero-eyebrow reveal-on-load'
|
|
37
|
+
eyebrow.textContent = 'npm i @microlink/google'
|
|
38
|
+
|
|
39
|
+
const title = document.createElement('h1')
|
|
40
|
+
title.innerHTML = 'Structured <span>Google</span><br>API for LLMs.'
|
|
41
|
+
title.className = 'reveal-on-load'
|
|
42
|
+
|
|
43
|
+
copy.append(eyebrow, title)
|
|
44
|
+
|
|
45
|
+
if (summary) {
|
|
46
|
+
summary.classList.add('reveal-on-load')
|
|
47
|
+
copy.append(summary)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const visual = document.createElement('div')
|
|
51
|
+
visual.className = 'hero-visual reveal-on-load'
|
|
52
|
+
visual.innerHTML = `
|
|
53
|
+
<div class="browser-frame">
|
|
54
|
+
<div class="browser-bar">
|
|
55
|
+
<span class="browser-dots"><i></i><i></i><i></i></span>
|
|
56
|
+
<span class="browser-url">https://search.microlink.io</span>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="browser-screen"></div>
|
|
59
|
+
</div>
|
|
60
|
+
`
|
|
61
|
+
|
|
62
|
+
if (image) {
|
|
63
|
+
image.className = 'hero-banner'
|
|
64
|
+
visual.querySelector('.browser-screen').append(image)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
visual.append(createVisualBadges())
|
|
68
|
+
|
|
69
|
+
hero.replaceChildren(copy, visual)
|
|
70
|
+
hero.after(createHeroStats())
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const decorateUseCases = section => {
|
|
74
|
+
const useCasesHeading = [...section.querySelectorAll('h2')].find(
|
|
75
|
+
node => node.textContent.trim().toLowerCase() === 'common llm use cases'
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if (!useCasesHeading) return
|
|
79
|
+
|
|
80
|
+
const intro = useCasesHeading.nextElementSibling
|
|
81
|
+
const list = intro?.nextElementSibling
|
|
82
|
+
if (!list || list.tagName !== 'UL' || list.dataset.enhanced === 'true') return
|
|
83
|
+
|
|
84
|
+
list.dataset.enhanced = 'true'
|
|
85
|
+
list.classList.add('use-case-grid')
|
|
86
|
+
|
|
87
|
+
const variants = [
|
|
88
|
+
'use-case-card--agentic',
|
|
89
|
+
'use-case-card--rag',
|
|
90
|
+
'use-case-card--news',
|
|
91
|
+
'use-case-card--local'
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
;[...list.children].forEach((item, index) => {
|
|
95
|
+
item.classList.add('use-case-card', 'reveal-on-load')
|
|
96
|
+
if (variants[index]) item.classList.add(variants[index])
|
|
97
|
+
|
|
98
|
+
const link = item.querySelector('a')
|
|
99
|
+
if (link) {
|
|
100
|
+
const title = link.textContent.trim()
|
|
101
|
+
const description = item.textContent.replace(title, '').trim()
|
|
102
|
+
const heading = document.createElement('strong')
|
|
103
|
+
|
|
104
|
+
heading.textContent = title
|
|
105
|
+
link.replaceChildren(heading)
|
|
106
|
+
|
|
107
|
+
if (description) {
|
|
108
|
+
const body = document.createElement('p')
|
|
109
|
+
body.textContent = description
|
|
110
|
+
link.append(body)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
link.classList.add('use-case-link')
|
|
114
|
+
item.replaceChildren(link)
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
const heroStats = section.querySelector('.hero-stats')
|
|
119
|
+
if (heroStats && !section.querySelector('.hero-use-cases')) {
|
|
120
|
+
const heroUseCases = document.createElement('div')
|
|
121
|
+
const heroIntro = document.createElement('p')
|
|
122
|
+
|
|
123
|
+
heroUseCases.className = 'hero-use-cases reveal-on-load'
|
|
124
|
+
heroIntro.className = 'hero-use-cases__intro'
|
|
125
|
+
heroIntro.textContent =
|
|
126
|
+
'Explore the most common LLM workflows and jump straight to the tutorial that matches your use case.'
|
|
127
|
+
|
|
128
|
+
list.classList.add('hero-use-cases__grid')
|
|
129
|
+
|
|
130
|
+
heroUseCases.append(heroIntro, list)
|
|
131
|
+
heroStats.after(heroUseCases)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const decorateCodeBlocks = section => {
|
|
136
|
+
section.querySelectorAll('pre').forEach(pre => {
|
|
137
|
+
if (pre.parentElement?.classList.contains('code-shell')) return
|
|
138
|
+
const shell = document.createElement('div')
|
|
139
|
+
const header = document.createElement('div')
|
|
140
|
+
const code = pre.querySelector('code')
|
|
141
|
+
const languageClass = [...(code?.classList || [])].find(value =>
|
|
142
|
+
value.startsWith('language-')
|
|
143
|
+
)
|
|
144
|
+
shell.className = 'code-shell'
|
|
145
|
+
header.className = 'code-shell__header'
|
|
146
|
+
header.innerHTML = `
|
|
147
|
+
<span class="code-shell__dots" aria-hidden="true"><i></i><i></i><i></i></span>
|
|
148
|
+
<span class="code-shell__label">${
|
|
149
|
+
languageClass ? languageClass.replace('language-', '') : 'code'
|
|
150
|
+
}</span>
|
|
151
|
+
`
|
|
152
|
+
pre.parentNode.insertBefore(shell, pre)
|
|
153
|
+
shell.append(header, pre)
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const decorateTables = section => {
|
|
158
|
+
section.querySelectorAll('table').forEach(table => {
|
|
159
|
+
if (table.parentElement?.classList.contains('table-shell')) return
|
|
160
|
+
const shell = document.createElement('div')
|
|
161
|
+
shell.className = 'table-shell'
|
|
162
|
+
table.parentNode.insertBefore(shell, table)
|
|
163
|
+
shell.append(table)
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const revealContent = section => {
|
|
168
|
+
;[...section.querySelectorAll('h2, h3')].forEach(node =>
|
|
169
|
+
node.classList.add('reveal-on-load')
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const disableDocsifyDefaultScrollSpy = section => {
|
|
174
|
+
section
|
|
175
|
+
.querySelectorAll(':is(h1, h2, h3, h4, h5) > a.anchor[data-id]')
|
|
176
|
+
.forEach(anchor => {
|
|
177
|
+
anchor.classList.remove('anchor')
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let teardownNavigationTracking = () => {}
|
|
182
|
+
|
|
183
|
+
const decodeValue = value => {
|
|
184
|
+
try {
|
|
185
|
+
return decodeURIComponent(value)
|
|
186
|
+
} catch {
|
|
187
|
+
return value
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const extractSectionIdFromHref = href => {
|
|
192
|
+
if (!href) return null
|
|
193
|
+
|
|
194
|
+
const value = href.trim()
|
|
195
|
+
const hashIndex = value.indexOf('#')
|
|
196
|
+
const hash = hashIndex >= 0 ? value.slice(hashIndex + 1) : value
|
|
197
|
+
|
|
198
|
+
if (!hash) return null
|
|
199
|
+
|
|
200
|
+
const isRouteHash = hash.startsWith('/')
|
|
201
|
+
const normalizedHash = isRouteHash ? hash.slice(1) : hash
|
|
202
|
+
const [, query = ''] = normalizedHash.split('?')
|
|
203
|
+
const idFromQuery = query ? new URLSearchParams(query).get('id') : null
|
|
204
|
+
|
|
205
|
+
if (idFromQuery) return decodeValue(idFromQuery)
|
|
206
|
+
if (isRouteHash) return null
|
|
207
|
+
|
|
208
|
+
const [idCandidate = ''] = normalizedHash.split('?')
|
|
209
|
+
return idCandidate ? decodeValue(idCandidate) : null
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const setupNavigationTracking = section => {
|
|
213
|
+
const sidebarNav = document.querySelector('.sidebar .sidebar-nav')
|
|
214
|
+
if (!sidebarNav) return () => {}
|
|
215
|
+
|
|
216
|
+
const navLinks = [...sidebarNav.querySelectorAll('a[href]')]
|
|
217
|
+
const trackedLinks = navLinks
|
|
218
|
+
.map(link => ({
|
|
219
|
+
id: extractSectionIdFromHref(link.getAttribute('href')),
|
|
220
|
+
link
|
|
221
|
+
}))
|
|
222
|
+
.filter(entry => entry.id)
|
|
223
|
+
|
|
224
|
+
const trackedIds = new Set(trackedLinks.map(entry => entry.id))
|
|
225
|
+
const headings = [...section.querySelectorAll('h2[id], h3[id]')]
|
|
226
|
+
const headingsToTrack = headings.filter(heading => trackedIds.has(heading.id))
|
|
227
|
+
const scopedHeadings = headingsToTrack.length > 0 ? headingsToTrack : headings
|
|
228
|
+
const firstHeadingId = scopedHeadings[0]?.id || trackedLinks[0]?.id || null
|
|
229
|
+
|
|
230
|
+
let activeId = null
|
|
231
|
+
|
|
232
|
+
const setActiveLink = id => {
|
|
233
|
+
navLinks.forEach(link => {
|
|
234
|
+
link.classList.remove('active')
|
|
235
|
+
link.classList.remove('is-active')
|
|
236
|
+
link.removeAttribute('aria-current')
|
|
237
|
+
link.closest('li')?.classList.remove('active')
|
|
238
|
+
link.closest('li')?.classList.remove('is-active')
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
const targetId = id || firstHeadingId
|
|
242
|
+
const activeLink =
|
|
243
|
+
trackedLinks.find(entry => entry.id === targetId)?.link ||
|
|
244
|
+
navLinks.find(link => link.closest('li')?.classList.contains('active')) ||
|
|
245
|
+
navLinks[0]
|
|
246
|
+
|
|
247
|
+
if (!activeLink) return
|
|
248
|
+
|
|
249
|
+
activeLink.classList.add('active', 'is-active')
|
|
250
|
+
activeLink.setAttribute('aria-current', 'location')
|
|
251
|
+
const activeItem = activeLink.closest('li')
|
|
252
|
+
|
|
253
|
+
activeItem?.classList.add('active', 'is-active')
|
|
254
|
+
|
|
255
|
+
let parentItem = activeItem?.parentElement?.closest('li')
|
|
256
|
+
while (parentItem) {
|
|
257
|
+
parentItem.classList.add('active')
|
|
258
|
+
parentItem = parentItem.parentElement?.closest('li')
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
activeId = extractSectionIdFromHref(activeLink.getAttribute('href'))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const getCurrentSectionId = () => {
|
|
265
|
+
const triggerOffset = Math.max(8, window.innerHeight * 0.03)
|
|
266
|
+
const threshold = window.scrollY + triggerOffset
|
|
267
|
+
let currentSectionId = null
|
|
268
|
+
|
|
269
|
+
for (const heading of scopedHeadings) {
|
|
270
|
+
if (heading.offsetTop <= threshold) {
|
|
271
|
+
currentSectionId = heading.id
|
|
272
|
+
continue
|
|
273
|
+
}
|
|
274
|
+
break
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return currentSectionId
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let frameId = null
|
|
281
|
+
|
|
282
|
+
const syncActiveLink = () => {
|
|
283
|
+
frameId = null
|
|
284
|
+
|
|
285
|
+
if (scopedHeadings.length === 0) {
|
|
286
|
+
setActiveLink(null)
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const sectionId = getCurrentSectionId()
|
|
291
|
+
const firstHeadingTop = scopedHeadings[0].offsetTop
|
|
292
|
+
const nearTopThreshold = Math.max(8, window.innerHeight * 0.03)
|
|
293
|
+
const isBeforeFirstHeading =
|
|
294
|
+
window.scrollY + nearTopThreshold < firstHeadingTop
|
|
295
|
+
|
|
296
|
+
if (isBeforeFirstHeading) {
|
|
297
|
+
setActiveLink(firstHeadingId)
|
|
298
|
+
return
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (sectionId) {
|
|
302
|
+
setActiveLink(sectionId)
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!activeId) {
|
|
307
|
+
setActiveLink(firstHeadingId)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const requestSync = () => {
|
|
312
|
+
if (frameId !== null) return
|
|
313
|
+
frameId = window.requestAnimationFrame(syncActiveLink)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const handleNavClick = event => {
|
|
317
|
+
const link = event.target.closest('a[href]')
|
|
318
|
+
if (!link || !sidebarNav.contains(link)) return
|
|
319
|
+
|
|
320
|
+
const sectionId = extractSectionIdFromHref(link.getAttribute('href'))
|
|
321
|
+
if (sectionId) setActiveLink(sectionId)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
sidebarNav.addEventListener('click', handleNavClick)
|
|
325
|
+
window.addEventListener('scroll', requestSync, { passive: true })
|
|
326
|
+
window.addEventListener('resize', requestSync)
|
|
327
|
+
|
|
328
|
+
requestSync()
|
|
329
|
+
window.setTimeout(requestSync, 140)
|
|
330
|
+
|
|
331
|
+
return () => {
|
|
332
|
+
sidebarNav.removeEventListener('click', handleNavClick)
|
|
333
|
+
window.removeEventListener('scroll', requestSync)
|
|
334
|
+
window.removeEventListener('resize', requestSync)
|
|
335
|
+
if (frameId !== null) window.cancelAnimationFrame(frameId)
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const enhancePage = () => {
|
|
340
|
+
teardownNavigationTracking()
|
|
341
|
+
teardownNavigationTracking = () => {}
|
|
342
|
+
|
|
343
|
+
const section = document.querySelector('.markdown-section')
|
|
344
|
+
const content = document.querySelector('.content')
|
|
345
|
+
const sidebar = document.querySelector('.sidebar')
|
|
346
|
+
if (!section) return
|
|
347
|
+
|
|
348
|
+
if (content) {
|
|
349
|
+
content.id = 'main-content'
|
|
350
|
+
content.setAttribute('role', 'main')
|
|
351
|
+
content.setAttribute('tabindex', '-1')
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (sidebar) {
|
|
355
|
+
sidebar.setAttribute('role', 'navigation')
|
|
356
|
+
sidebar.setAttribute('aria-label', 'Primary navigation')
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
decorateHero(section)
|
|
360
|
+
decorateUseCases(section)
|
|
361
|
+
decorateCodeBlocks(section)
|
|
362
|
+
decorateTables(section)
|
|
363
|
+
revealContent(section)
|
|
364
|
+
disableDocsifyDefaultScrollSpy(section)
|
|
365
|
+
teardownNavigationTracking = setupNavigationTracking(section)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
window.$docsify = {
|
|
369
|
+
name: '@microlink/google',
|
|
370
|
+
repo: 'microlinkhq/google',
|
|
371
|
+
logo: '/static/banner.png',
|
|
372
|
+
externalLinkRel: 'noopener noreferrer',
|
|
373
|
+
subMaxLevel: 2,
|
|
374
|
+
auto2top: true,
|
|
375
|
+
maxLevel: 3,
|
|
376
|
+
plugins: [
|
|
377
|
+
hook => {
|
|
378
|
+
hook.doneEach(() => {
|
|
379
|
+
enhancePage()
|
|
380
|
+
const appLink = document.querySelector('.app-name-link')
|
|
381
|
+
if (appLink && !appLink.dataset.bound) {
|
|
382
|
+
appLink.dataset.bound = 'true'
|
|
383
|
+
appLink.onclick = event => {
|
|
384
|
+
event.preventDefault()
|
|
385
|
+
const shouldReduceMotion = window.matchMedia(
|
|
386
|
+
'(prefers-reduced-motion: reduce)'
|
|
387
|
+
).matches
|
|
388
|
+
window.scrollTo({
|
|
389
|
+
top: 0,
|
|
390
|
+
behavior: shouldReduceMotion ? 'auto' : 'smooth'
|
|
391
|
+
})
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
})
|
|
395
|
+
}
|
|
396
|
+
]
|
|
397
|
+
}
|