mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 21:27:06 +04:00
197 lines
8.6 KiB
Plaintext
197 lines
8.6 KiB
Plaintext
---
|
|
// Chrome-full counterpart to ScreenshotLayout: a whole app screen (sidebar,
|
|
// navbar, page header and body) inside one capture frame, for the features
|
|
// that only exist at layout level — the folded sidebar, the theme settings
|
|
// panel, the navbar dropdowns.
|
|
//
|
|
// The frame is 1708x1068 CSS px — the capture viewport itself, not the
|
|
// 1024x768 card frame of ScreenshotLayout — and the capture scales it down to
|
|
// the 1280 px wide picture it asks for (data-screenshot-width), i.e. by 0.75.
|
|
// That is how the screen fits more of the page than a 1280 px window would:
|
|
// the browser lays out and rasterizes a real 1708 px screen, so charts measure
|
|
// their axes right and the grid uses the full width, and only the finished
|
|
// raster is reduced. (Even numbers on purpose: the card frame centers in the
|
|
// same viewport and must land on whole pixels.) A CSS
|
|
// `zoom` on the page would show the same amount but clips ApexCharts axis
|
|
// labels and leaves the container short of the frame's edge.
|
|
// The frame matches the viewport because media queries resolve against the
|
|
// viewport: a narrower frame would lay the grid out for a width the picture
|
|
// does not show.
|
|
//
|
|
// It also carries `transform: translateZ(0)` on purpose: `.navbar-vertical`
|
|
// and the offcanvas panels are `position: fixed`, and a transformed ancestor
|
|
// becomes their containing block, so they anchor to the frame.
|
|
import Navbar from '@shared/components/navbar/Navbar.astro'
|
|
import Sidebar from '@shared/components/navbar/Sidebar.astro'
|
|
import PageHeader from '@shared/components/layout/PageHeader.astro'
|
|
import PageScripts from '@shared/components/PageScripts.astro'
|
|
import ThemeSettings from '@shared/components/demo/ThemeSettings.astro'
|
|
import { themeDataAttributes, type ThemeKey } from '@shared/lib/theme-config'
|
|
import libs from '@tabler/core/libs.json'
|
|
|
|
interface Props {
|
|
title: string
|
|
/** page header title; defaults to `title` */
|
|
pageHeader?: string
|
|
/** text below the page title */
|
|
description?: string
|
|
/** active menu entry, e.g. "dashboards.crm" */
|
|
pageMenu?: string
|
|
/** icon-only sidebar rail: folded, or folded until hovered */
|
|
sidebarMode?: 'folded' | 'folded-hover'
|
|
/** where the main menu lives */
|
|
navbarPosition?: 'horizontal' | 'vertical'
|
|
/** container width; fluid by default so the page fills the wide frame instead of centering a capped column */
|
|
layout?: 'default' | 'fluid' | 'boxed'
|
|
/** renders the theme settings offcanvas (needed for a capture of the panel) */
|
|
themeSettings?: boolean
|
|
/**
|
|
* Theme switcher values rendered as data-bs-* on <html> — `theme-primary`,
|
|
* `theme-font`, `theme-base`, `theme-radius` (see themeDefaults). Pulls in
|
|
* tabler-themes.css, which holds the variants.
|
|
*/
|
|
theme?: Partial<Record<ThemeKey, string>>
|
|
/** third-party libs from libs.json the page needs, e.g. ['apexcharts'] */
|
|
pageLibs?: string[]
|
|
/** core CSS plugins (site.cssPlugins), e.g. ['payments'] */
|
|
cssPlugins?: string[]
|
|
}
|
|
|
|
const { title, pageHeader, description, pageMenu, sidebarMode, navbarPosition = 'vertical', layout = 'fluid', themeSettings = false, theme = {}, pageLibs = [], cssPlugins = [] } = Astro.props
|
|
|
|
// tabler-vendors.css carries the third-party styling (the ApexCharts tokens
|
|
// among them, which is what themes a chart's labels, grid and legend for the
|
|
// color mode), so a page that pulls a lib in gets it without asking.
|
|
const stylePlugins = [...new Set([...(pageLibs.length > 0 ? ['vendors'] : []), ...(Object.keys(theme).length > 0 ? ['themes'] : []), ...cssPlugins])]
|
|
|
|
const headerTitle = pageHeader ?? title
|
|
|
|
// Same as BaseLayout: the page states its own layout as data-bs-* on <html>.
|
|
const themeAttributes = themeDataAttributes({ ...theme, 'navbar-position': navbarPosition, 'layout': layout, 'sidebar': sidebarMode } as Partial<Record<ThemeKey, string | undefined>>)
|
|
|
|
// core/dist only has .min. files after a full `pnpm build`; `astro dev` serves
|
|
// whatever core's own watcher last emitted, which is unminified.
|
|
const min = import.meta.env.DEV ? '' : '.min'
|
|
|
|
type Lib = { npm?: string; js?: string[]; css?: string[] }
|
|
const pageLibEntries = Object.entries(libs as Record<string, Lib>).filter(([name]) => pageLibs.includes(name))
|
|
const libHref = (lib: Lib, file: string) => `/dist/libs/${lib.npm}/${file}`
|
|
const libCssFiles = pageLibEntries.flatMap(([, lib]) => (lib.css ?? []).map((file) => libHref(lib, file)))
|
|
const libJsFiles = pageLibEntries.flatMap(([, lib]) => (lib.js ?? []).map((file) => libHref(lib, file)))
|
|
---
|
|
|
|
<!doctype html>
|
|
<html lang="en" {...themeAttributes}>
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
|
|
<title>{title} - Tabler screenshots</title>
|
|
|
|
<link rel="icon" href="./favicon-dev.ico" type="image/x-icon" />
|
|
|
|
<link href={`./dist/css/tabler${min}.css`} rel="stylesheet" />
|
|
|
|
{stylePlugins.map((plugin) => <link href={`./dist/css/tabler-${plugin}${min}.css`} rel="stylesheet" />)}
|
|
|
|
{libCssFiles.map((href) => <link href={href} rel="stylesheet" />)}
|
|
|
|
<!-- Inter for the captures: Tabler ships system font stacks (no web font),
|
|
and the body's cv03/cv04/cv11 feature settings were tuned for Inter, so the
|
|
pictures show the face the design was drawn in — the same on every machine
|
|
that runs the capture. The serif and monospace theme variants keep their own
|
|
stacks; only the sans token is replaced. -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
|
|
<style is:inline>
|
|
:root {
|
|
--tblr-font-sans-serif: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
}
|
|
|
|
/* Deterministic screenshots: no mid-capture animation/transition frames, no blinking caret. */
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
transition: none !important;
|
|
animation: none !important;
|
|
caret-color: transparent !important;
|
|
}
|
|
|
|
body {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 100vh;
|
|
background: var(--tblr-bg-surface-tertiary);
|
|
}
|
|
|
|
.screenshot {
|
|
width: 1708px;
|
|
height: 1068px;
|
|
overflow: hidden;
|
|
/* containing block for the layout's position: fixed elements — see the
|
|
frontmatter note */
|
|
transform: translateZ(0);
|
|
}
|
|
|
|
/* The frame is its own viewport, so the page inside scrolls within it. */
|
|
.screenshot .page {
|
|
height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
</style>
|
|
|
|
<!-- loaded early, before paint, so ?theme=dark applies before first render -->
|
|
<script is:inline src={`/dist/js/tabler-theme${min}.js`}></script>
|
|
</head>
|
|
<body>
|
|
<div class="screenshot" id="screenshot" data-screenshot-width="1280">
|
|
<div class="page">
|
|
<Sidebar breakpoint="lg" folded={sidebarMode === 'folded'} foldedHover={sidebarMode === 'folded-hover'} pageMenu={pageMenu} />
|
|
|
|
<Navbar hideSearch pageMenu={pageMenu} />
|
|
|
|
<div class="page-wrapper">
|
|
<PageHeader title={headerTitle} description={description} />
|
|
|
|
<main id="content" class="page-body">
|
|
<div class="container-xl">
|
|
<slot />
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
{themeSettings && <ThemeSettings />}
|
|
</div>
|
|
|
|
<!-- The frame fills the viewport, so this toggle overlaps it; the capture
|
|
hides everything marked data-screenshot-chrome before taking the picture. -->
|
|
<nav class="nav-segmented position-fixed bottom-0 mb-4" data-screenshot-chrome>
|
|
<a href="?theme=light" class="nav-link hide-theme-light">Light</a>
|
|
<a href="?theme=light" class="nav-link active hide-theme-dark">Light</a>
|
|
<a href="?theme=dark" class="nav-link hide-theme-dark">Dark</a>
|
|
<a href="?theme=dark" class="nav-link active hide-theme-light">Dark</a>
|
|
</nav>
|
|
|
|
{libJsFiles.map((src) => <script is:inline src={src} defer />)}
|
|
<script is:inline src={`/dist/js/tabler${min}.js`} defer></script>
|
|
|
|
<PageScripts />
|
|
|
|
<script>
|
|
// Signals to the screenshot tool that fonts and JS-driven component init
|
|
// are settled — same contract as ScreenshotLayout.
|
|
const domReady = new Promise((resolve) => {
|
|
if (document.readyState !== 'loading') resolve(undefined)
|
|
else document.addEventListener('DOMContentLoaded', () => resolve(undefined), { once: true })
|
|
})
|
|
Promise.all([document.fonts.ready, domReady]).then(() => {
|
|
requestAnimationFrame(() => requestAnimationFrame(() => (document.documentElement.dataset.screenshotReady = 'true')))
|
|
})
|
|
</script>
|
|
</body>
|
|
</html>
|