@microlink/google 0.1.1 → 1.0.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/css/style.css +0 -1152
- package/src/js/main.js +0 -397
package/src/js/main.js
DELETED
|
@@ -1,397 +0,0 @@
|
|
|
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
|
-
}
|