mirror of
https://github.com/tabler/tabler.git
synced 2026-08-28 12:56:24 +04:00
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
152 lines
5.4 KiB
Plaintext
152 lines
5.4 KiB
Plaintext
---
|
|
import Icon from '@ui/Icon.astro'
|
|
import DocsLogo from './DocsLogo.astro'
|
|
import { site } from '@shared/lib/site'
|
|
|
|
// Eventually belongs in src/lib/site.ts (out of scope for this task).
|
|
const previewUrl = 'https://preview.tabler.io'
|
|
const changelogUrl = 'https://tabler.io/changelog'
|
|
---
|
|
|
|
<!-- BEGIN DOCS NAVBAR -->
|
|
<nav class="navbar navbar-expand sticky-top" aria-label="Docs">
|
|
<div class="container">
|
|
<div class="row flex-fill align-items-md-center">
|
|
<div class="col">
|
|
<div class="d-flex align-items-center gap-4">
|
|
<a href="/" class="navbar-brand navbar-brand-autodark gap-4">
|
|
<DocsLogo />
|
|
</a>
|
|
<div>
|
|
<span class="badge">v{site.version}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="d-none d-md-block col">
|
|
{
|
|
/* Native Tabler search input. The script below lazy-imports @docsearch/js on
|
|
interaction and opens its modal; DocSearch mounts into the hidden #docsearch. */
|
|
}
|
|
<div class="input-icon">
|
|
<span class="input-icon-addon">
|
|
<Icon name="search" />
|
|
</span>
|
|
<input type="search" id="docs-search-input" class="form-control cursor-pointer" placeholder="Search…" aria-label="Search documentation" autocomplete="off" readonly />
|
|
<span class="input-icon-addon">
|
|
<kbd id="docs-search-kbd">⌘K</kbd>
|
|
</span>
|
|
</div>
|
|
<div id="docsearch" class="d-none"></div>
|
|
</div>
|
|
<div class="col d-flex">
|
|
<ul class="navbar-nav ms-auto gap-2 align-items-center">
|
|
<li class="nav-item d-none d-md-block">
|
|
<a href={previewUrl} class="nav-link">Preview</a>
|
|
</li>
|
|
<li class="nav-item d-none d-md-block">
|
|
<a href={changelogUrl} class="nav-link">Changelog</a>
|
|
</li>
|
|
<li class="nav-item hide-theme-dark">
|
|
<a href="?theme=dark" class="btn btn-icon">
|
|
<Icon name="moon" />
|
|
</a>
|
|
</li>
|
|
<li class="nav-item hide-theme-light">
|
|
<a href="?theme=light" class="btn btn-icon">
|
|
<Icon name="sun" />
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a href={site.githubUrl} class="btn btn-icon" target="_blank" rel="noopener noreferrer">
|
|
<Icon name="brand-github" />
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a href={previewUrl} class="btn btn-primary" target="_blank" rel="noopener noreferrer">
|
|
<Icon name="eye" /> Preview
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
<!-- END DOCS NAVBAR -->
|
|
|
|
<script>
|
|
// Lazy DocSearch: the native input above triggers a dynamic import of
|
|
// @docsearch/js, which Vite splits into its own hashed chunk — nothing is
|
|
// downloaded until the first interaction. DocSearch mounts into the hidden
|
|
// #docsearch container; opening the modal means clicking its hidden button.
|
|
import { DOCSEARCH_APP_ID, DOCSEARCH_INDEX_NAME, DOCSEARCH_API_KEY } from 'astro:env/client'
|
|
|
|
const input = document.getElementById('docs-search-input')
|
|
const mount = document.getElementById('docsearch')
|
|
// Local consts so TypeScript narrows `string | undefined` inside the closures below.
|
|
const appId = DOCSEARCH_APP_ID
|
|
const indexName = DOCSEARCH_INDEX_NAME
|
|
const apiKey = DOCSEARCH_API_KEY
|
|
|
|
if (input && !(appId && indexName && apiKey)) {
|
|
// No Algolia env config (see .env.example) — hide the dead search input.
|
|
input.closest<HTMLElement>('.input-icon')?.classList.add('d-none')
|
|
console.warn('Docs search disabled: DOCSEARCH_* env variables are not set.')
|
|
}
|
|
|
|
if (input && mount && appId && indexName && apiKey) {
|
|
const isMac = /Mac|iPhone|iPad|iPod/.test(navigator.userAgent)
|
|
const kbd = document.getElementById('docs-search-kbd')
|
|
if (kbd && !isMac) kbd.textContent = 'Ctrl K'
|
|
|
|
let state: 'idle' | 'loading' | 'ready' = 'idle'
|
|
let openWhenReady = false
|
|
|
|
const openModal = () => mount.querySelector<HTMLElement>('.DocSearch-Button')?.click()
|
|
|
|
const load = async (open: boolean) => {
|
|
openWhenReady = openWhenReady || open
|
|
if (state === 'ready') {
|
|
if (open) openModal()
|
|
return
|
|
}
|
|
if (state === 'loading') return
|
|
state = 'loading'
|
|
try {
|
|
const { default: docsearch } = await import('@docsearch/js')
|
|
docsearch({
|
|
container: '#docsearch',
|
|
appId,
|
|
indexName,
|
|
apiKey,
|
|
})
|
|
state = 'ready'
|
|
// The bundle renders its (hidden) button and binds its own shortcuts.
|
|
if (openWhenReady) openModal()
|
|
} catch {
|
|
state = 'idle'
|
|
}
|
|
}
|
|
|
|
input.addEventListener('click', () => {
|
|
load(true)
|
|
input.blur()
|
|
})
|
|
// Keyboard users: prefetch on focus, open on Enter or when they start typing.
|
|
input.addEventListener('focus', () => load(false))
|
|
input.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Enter' || event.key.length === 1) {
|
|
event.preventDefault()
|
|
load(true)
|
|
input.blur()
|
|
}
|
|
})
|
|
input.addEventListener('pointerenter', () => load(false))
|
|
document.addEventListener('keydown', (event) => {
|
|
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === 'k' && state !== 'ready') {
|
|
event.preventDefault()
|
|
load(true)
|
|
}
|
|
})
|
|
}
|
|
</script>
|