mirror of
https://github.com/tabler/tabler.git
synced 2026-08-07 03:42:27 +04:00
f27c70ad38
`Render Modal as real markup` (#2742) reformatted ~140 files back to tabs/semicolons, breaking the Prettier config added by the Astro quality gates (#2749). Re-run prettier --write to restore it, and fix the type errors it had been masking: HTMLElement casts and `this` typing in ChangePasswordModalContent/ConfirmDeleteModalContent scripts, plain-JS syntax in the inline-injected progress.astro script, narrowed prop unions in Button/Check/Spinner, nullable icon svg casts in Icons/Rating, and a duplicate firstLetters/invalid `placeholder` attribute in Select.astro. Also fix shared/vitest.config.mts's stale `astro/lib/**/*.test.ts` include glob left over from the shared source restructure, which made `pnpm test` report zero test files.
213 lines
7.4 KiB
Plaintext
213 lines
7.4 KiB
Plaintext
---
|
|
import ThemeSettings from '@ui/ThemeSettings.astro'
|
|
import { site } from '@shared/lib/site'
|
|
import PageModals from '@shared/components/PageModals.astro'
|
|
import PageScripts from '@shared/components/PageScripts.astro'
|
|
import libs from '@tabler/core/libs.json'
|
|
|
|
interface Props {
|
|
title?: string
|
|
/** Third-party libs from libs.json, e.g. ['apexcharts', 'jsvectormap'] */
|
|
pageLibs?: string[]
|
|
/** Extra body classes, e.g. "layout-boxed" / "layout-fluid" */
|
|
bodyClass?: string
|
|
/** dir="rtl" + RTL variants of the tabler/plugin stylesheets */
|
|
rtl?: boolean
|
|
/** Relative asset base: '.' for root pages, '..' one level deep */
|
|
base?: string
|
|
}
|
|
|
|
const { title, pageLibs = [], bodyClass, rtl = false, base = '.' } = Astro.props
|
|
|
|
// Development build: unminified assets, dev favicon.
|
|
const environment = 'development'
|
|
const min = environment === 'development' ? '' : '.min'
|
|
// RTL swaps tabler/plugin stylesheets for their .rtl.css variants (demo stays LTR)
|
|
const rtlSuffix = rtl ? '.rtl' : ''
|
|
|
|
type Lib = { npm?: string; js?: string[]; css?: string[]; head?: boolean }
|
|
const pageLibEntries = Object.entries(libs as Record<string, Lib>).filter(([name]) => pageLibs.includes(name))
|
|
const googleMapsKey = site.googleMapsDevKey
|
|
// External URLs (http/https) are emitted verbatim (with the maps-key placeholder
|
|
// replaced); local files as ./dist/libs/{npm}/{file}.
|
|
const libHref = (lib: Lib, file: string) => (/^https?:\/\//.test(file) ? file.replace('GOOGLE_MAPS_KEY', googleMapsKey) : `${base}/dist/libs/${lib.npm}/${file}`)
|
|
const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((file) => libHref(lib, file)))
|
|
const libJsFiles = (head: boolean) => pageLibEntries.filter(([, lib]) => Boolean(lib.head) === head).flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
|
---
|
|
|
|
<!doctype html>
|
|
<html lang="en" dir={rtl ? 'rtl' : undefined}>
|
|
<head>
|
|
<!-- BEGIN META -->
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
|
|
|
<title>{title ? `${title} - ` : ''}{site.title} - {site.descriptionShort}</title>
|
|
|
|
<link rel="icon" href={`${base}/favicon-dev.ico`} type="image/x-icon" />
|
|
<link rel="shortcut icon" href={`${base}/favicon-dev.ico`} type="image/x-icon" />
|
|
<!-- END META -->
|
|
|
|
{
|
|
libCssFiles.length > 0 && (
|
|
<Fragment>
|
|
<Fragment set:html={'<!-- BEGIN PAGE LEVEL STYLES -->'} />
|
|
{libCssFiles.map((href) => (
|
|
<link href={href} rel="stylesheet" />
|
|
))}
|
|
<Fragment set:html={'<!-- END PAGE LEVEL STYLES -->'} />
|
|
</Fragment>
|
|
)
|
|
}
|
|
|
|
<!-- BEGIN GLOBAL MANDATORY STYLES -->
|
|
<link href={`${base}/dist/css/tabler${rtlSuffix}${min}.css`} rel="stylesheet" />
|
|
<!-- END GLOBAL MANDATORY STYLES -->
|
|
|
|
<!-- BEGIN PLUGINS STYLES -->
|
|
{site.cssPlugins.map((plugin) => <link href={`${base}/dist/css/tabler-${plugin}${rtlSuffix}${min}.css`} rel="stylesheet" />)}
|
|
<!-- END PLUGINS STYLES -->
|
|
|
|
<!-- BEGIN DEMO STYLES -->
|
|
<link href={`${base}/preview/css/demo${min}.css`} rel="stylesheet" />
|
|
<!-- END DEMO STYLES -->
|
|
|
|
{
|
|
libJsFiles(true).length > 0 && (
|
|
<Fragment>
|
|
<Fragment set:html={'<!-- BEGIN PAGE LIBRARIES -->'} />
|
|
{libJsFiles(true).map((src) => (
|
|
<script is:inline src={src} defer />
|
|
))}
|
|
<Fragment set:html={'<!-- END PAGE LIBRARIES -->'} />
|
|
</Fragment>
|
|
)
|
|
}
|
|
|
|
<!-- BEGIN CUSTOM FONT -->
|
|
{/* is:inline: keep the tag verbatim — Astro's scoped-style pipeline would add data-astro-cid-* attributes across the page */}
|
|
<style is:inline>
|
|
@import url('https://rsms.me/inter/inter.css');
|
|
</style>
|
|
<!-- END CUSTOM FONT -->
|
|
</head>
|
|
|
|
<body class={bodyClass}>
|
|
<a href="#content" class="visually-hidden skip-link">Skip to main content</a>
|
|
|
|
<!-- BEGIN GLOBAL THEME SCRIPT -->
|
|
<script is:inline src={`${base}/dist/js/tabler-theme${min}.js`}></script>
|
|
<!-- END GLOBAL THEME SCRIPT -->
|
|
|
|
<slot />
|
|
|
|
<PageModals />
|
|
|
|
<ThemeSettings />
|
|
|
|
{
|
|
libJsFiles(false).length > 0 && (
|
|
<Fragment>
|
|
<Fragment set:html={'<!-- BEGIN PAGE LIBRARIES -->'} />
|
|
{libJsFiles(false).map((src) => (
|
|
<script is:inline src={src} defer />
|
|
))}
|
|
<Fragment set:html={'<!-- END PAGE LIBRARIES -->'} />
|
|
</Fragment>
|
|
)
|
|
}
|
|
|
|
<!-- BEGIN GLOBAL MANDATORY SCRIPTS -->
|
|
<script is:inline src={`${base}/dist/js/tabler${min}.js`} defer></script>
|
|
<!-- END GLOBAL MANDATORY SCRIPTS -->
|
|
|
|
<!-- BEGIN DEMO SCRIPTS -->
|
|
<script is:inline src={`${base}/preview/js/demo${min}.js`} defer></script>
|
|
<!-- END DEMO SCRIPTS -->
|
|
|
|
<PageScripts />
|
|
|
|
<!-- BEGIN PAGE SCRIPTS -->
|
|
<script is:inline>
|
|
/*
|
|
This script handles the theme settings offcanvas functionality
|
|
It saves the selected settings to localStorage and applies them to the document
|
|
It also updates the URL with the selected settings as query parameters
|
|
It also has a reset button to clear all settings and revert to default
|
|
|
|
This is just a demo script to show how to implement theme settings. You can modify it as needed.
|
|
*/
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
var themeConfig = {
|
|
'theme': 'light',
|
|
'theme-base': 'gray',
|
|
'theme-font': 'sans-serif',
|
|
'theme-primary': 'blue',
|
|
'theme-radius': '1',
|
|
}
|
|
|
|
var url = new URL(window.location)
|
|
var form = document.getElementById('offcanvas-settings')
|
|
var resetButton = document.getElementById('reset-changes')
|
|
|
|
var checkItems = function () {
|
|
for (var key in themeConfig) {
|
|
var value = window.localStorage['tabler-' + key] || themeConfig[key]
|
|
|
|
if (!!value) {
|
|
var radios = form.querySelectorAll(`[name="${key}"]`)
|
|
|
|
if (!!radios) {
|
|
radios.forEach((radio) => {
|
|
radio.checked = radio.value === value
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
form.addEventListener('change', function (event) {
|
|
var target = event.target,
|
|
name = target.name,
|
|
value = target.value
|
|
|
|
for (var key in themeConfig) {
|
|
if (name === key) {
|
|
var applied = value
|
|
if (key === 'theme' && value === 'auto') {
|
|
applied = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
}
|
|
if (applied !== themeConfig[key]) {
|
|
document.documentElement.setAttribute('data-bs-' + key, applied)
|
|
} else {
|
|
document.documentElement.removeAttribute('data-bs-' + key)
|
|
}
|
|
window.localStorage.setItem('tabler-' + key, value)
|
|
url.searchParams.set(key, value)
|
|
}
|
|
}
|
|
|
|
window.history.pushState({}, '', url)
|
|
})
|
|
|
|
resetButton.addEventListener('click', function () {
|
|
for (var key in themeConfig) {
|
|
var value = themeConfig[key]
|
|
document.documentElement.removeAttribute('data-bs-' + key)
|
|
window.localStorage.removeItem('tabler-' + key)
|
|
url.searchParams.delete(key)
|
|
}
|
|
|
|
checkItems()
|
|
|
|
window.history.pushState({}, '', url)
|
|
})
|
|
|
|
checkItems()
|
|
})
|
|
</script>
|
|
<!-- END PAGE SCRIPTS -->
|
|
</body>
|
|
</html>
|