mirror of
https://github.com/tabler/tabler.git
synced 2026-08-05 19:03:18 +04:00
Refactor ScreenshotLayout and remove unused pages
This commit is contained in:
@@ -1,19 +1,49 @@
|
||||
---
|
||||
// Chrome-free layout for component screenshots: just @tabler/core CSS/JS
|
||||
// around a single component, no navbar/sidebar/demo styling. Dark/light is
|
||||
// driven by the same ?theme= query param and dist/js/tabler-theme.min.js
|
||||
// as preview/pages/screenshot.astro, so a screenshot tool can request
|
||||
// /button.html?theme=dark without depending on stored/localStorage state.
|
||||
// around a single component, no navbar/sidebar/demo styling. Modeled 1:1 on
|
||||
// preview/pages/screenshot.astro (the marketing hero-shot page): a fixed
|
||||
// 1024x768 .screenshot canvas with the Tabler logo above an elevated
|
||||
// .screenshot-card, on a soft gradient backdrop. Dark/light is driven by the
|
||||
// same ?theme= query param + dist/js/tabler-theme(.min).js + the
|
||||
// hide-theme-light/hide-theme-dark nav-segmented toggle as that page, so a
|
||||
// screenshot tool can request /button.html?theme=dark without depending on
|
||||
// stored/localStorage state.
|
||||
import NavbarLogo from '@shared/components/navbar/NavbarLogo.astro'
|
||||
import PageScripts from '@shared/components/PageScripts.astro'
|
||||
import libs from '@tabler/core/libs.json'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
/** dir="rtl" + the .rtl.css variant of tabler.css */
|
||||
rtl?: boolean
|
||||
/** extra classes on the wrapping container the component is rendered into */
|
||||
/** the Tabler logo above the card (+ balancing spacer below it) */
|
||||
showLogo?: boolean
|
||||
/** wrap the component in the elevated .screenshot-card; when false the slot renders bare */
|
||||
showCard?: boolean
|
||||
/** caps the [data-screenshot-target] width at columns * 320px */
|
||||
columns?: number
|
||||
/** CSS zoom applied to [data-screenshot-target] */
|
||||
zoom?: number
|
||||
/** third-party libs from libs.json the component needs, e.g. ['apexcharts'] */
|
||||
pageLibs?: string[]
|
||||
/** extra classes on the component wrapper */
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { title, rtl = false, class: className } = Astro.props
|
||||
const { title, rtl = false, showLogo = true, showCard = true, columns, zoom = 1, pageLibs = [], class: className } = Astro.props
|
||||
const targetStyle = [columns && `max-width: ${columns * 310}px`, `zoom: ${zoom}`].filter(Boolean).join('; ')
|
||||
const rtlSuffix = rtl ? '.rtl' : ''
|
||||
// core/dist only has .min. files after a full `pnpm build`; `astro dev` (this
|
||||
// package's own dev-prepare-less dev script) runs against whatever core's own
|
||||
// dev watcher last emitted, which is unminified — so match the served core
|
||||
// build instead of hardcoding one variant.
|
||||
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>
|
||||
@@ -26,7 +56,9 @@ const rtlSuffix = rtl ? '.rtl' : ''
|
||||
|
||||
<link rel="icon" href="/favicon-dev.ico" type="image/x-icon" />
|
||||
|
||||
<link href={`/dist/css/tabler${rtlSuffix}.css`} rel="stylesheet" />
|
||||
<link href={`/dist/css/tabler${rtlSuffix}${min}.css`} rel="stylesheet" />
|
||||
|
||||
{libCssFiles.map((href) => <link href={href} rel="stylesheet" />)}
|
||||
|
||||
<style is:inline>
|
||||
/* Deterministic screenshots: no mid-capture animation/transition frames, no blinking caret. */
|
||||
@@ -37,22 +69,94 @@ const rtlSuffix = rtl ? '.rtl' : ''
|
||||
animation: none !important;
|
||||
caret-color: transparent !important;
|
||||
}
|
||||
|
||||
.screenshot {
|
||||
width: 1024px;
|
||||
height: 768px;
|
||||
background: var(--tblr-bg-surface-tertiary) linear-gradient(to top left, rgba(0, 0, 0, 0.04), rgba(0, 0, 0, 0));
|
||||
position: relative;
|
||||
padding: 0 4rem;
|
||||
}
|
||||
|
||||
.screenshot-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.screenshot-wrapper > .card,
|
||||
.screenshot-card {
|
||||
box-shadow:
|
||||
0 1px 1px 0 rgba(0, 0, 0, 0.02),
|
||||
0 8px 24px -4px rgba(0, 0, 0, 0.04),
|
||||
0 24px 40px -8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.screenshot-card {
|
||||
padding: 64px;
|
||||
border-radius: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.screenshot-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 5rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* fake mouse pointer, to make the static screenshot read as a live interaction */
|
||||
.cursor {
|
||||
position: absolute;
|
||||
width: 26px;
|
||||
height: 37px;
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 26 37'%3E%3Cg filter='url(%23a)'%3E%3Cpath fill='%23fff' fill-rule='evenodd' d='M8.56 13.902c-.284-.358-.63-1.092-1.243-1.983-.348-.505-1.211-1.454-1.468-1.935-.223-.426-.2-.617-.146-.97.094-.628.738-1.117 1.425-1.051.519.049.959.392 1.355.716.239.195.533.574.71.788.163.196.203.277.377.509.23.306.302.458.214.12-.071-.495-.187-1.342-.355-2.091-.128-.568-.16-.657-.281-1.093-.13-.464-.195-.79-.316-1.281-.084-.348-.235-1.06-.276-1.46-.057-.546-.087-1.438.264-1.848.275-.321.906-.418 1.296-.22.513.259.803 1.003.937 1.3.238.534.386 1.15.515 1.96.165 1.032.466 2.463.476 2.764.024-.37-.068-1.146-.004-1.5.059-.321.329-.694.667-.795.285-.085.62-.116.915-.055.313.064.643.288.767.499.362.624.369 1.899.384 1.83.085-.375.07-1.228.284-1.583.14-.234.496-.445.686-.48.295-.051.655-.067.964-.007.25.049.587.345.677.487.218.344.343 1.317.38 1.658.015.14.073-.392.293-.736.405-.64 1.843-.763 1.898.639.025.654.02.624.02 1.064 0 .517-.013.828-.04 1.202-.031.4-.117 1.303-.242 1.742-.087.3-.372.977-.652 1.383 0 0-1.075 1.25-1.192 1.814-.117.562-.079.566-.102.964-.023.398.122.922.122.922s-.802.104-1.235.035c-.39-.063-.875-.84-1-1.079-.171-.328-.539-.264-.681-.023-.226.383-.71 1.07-1.051 1.113-.668.084-2.054.032-3.14.02 0 0 .185-1.01-.226-1.357-.306-.26-.83-.784-1.144-1.06l-.832-.921Z' clip-rule='evenodd'/%3E%3Cpath stroke='%23000' stroke-linecap='round' stroke-linejoin='round' d='M16.794 14.257v-3.459m-2.015 3.47-.016-3.472m-1.98.031.02 3.426m-4.243-.35c-.284-.36-.63-1.094-1.243-1.985-.348-.503-1.211-1.452-1.468-1.934-.223-.426-.2-.617-.146-.97.094-.628.738-1.117 1.425-1.051.519.049.959.392 1.355.716.239.195.533.574.71.788.163.196.203.277.377.509.23.306.302.458.214.12-.071-.495-.187-1.342-.355-2.091-.128-.568-.16-.657-.281-1.093-.13-.464-.195-.79-.316-1.281-.084-.348-.235-1.06-.276-1.46-.057-.546-.087-1.438.264-1.848.275-.321.906-.418 1.296-.22.513.259.803 1.003.937 1.3.238.534.386 1.15.515 1.96.165 1.032.466 2.463.476 2.764.024-.37-.068-1.146-.004-1.5.059-.321.329-.694.667-.795.285-.085.62-.116.915-.055.313.064.643.288.767.499.362.624.369 1.899.384 1.83.085-.375.07-1.228.284-1.583.14-.234.496-.445.686-.48.295-.051.655-.067.964-.007.25.049.587.345.677.487.218.344.343 1.317.38 1.658.015.14.073-.392.293-.736.405-.64 1.843-.763 1.898.639.025.654.02.624.02 1.064 0 .517-.013.828-.04 1.202-.031.4-.117 1.303-.242 1.742-.087.3-.372.977-.652 1.383 0 0-1.075 1.25-1.192 1.814-.117.562-.079.566-.102.964-.023.398.122.922.122.922s-.802.104-1.235.035c-.39-.063-.875-.84-1-1.079-.171-.328-.539-.264-.681-.023-.226.383-.71 1.07-1.051 1.113-.668.084-2.054.032-3.14.02 0 0 .185-1.01-.226-1.357-.306-.26-.83-.784-1.144-1.06l-.832-.921Z'/%3E%3C/g%3E%3Cdefs%3E%3Cfilter id='a' width='30' height='40' x='-2' y='-1' color-interpolation-filters='sRGB' filterUnits='userSpaceOnUse'%3E%3CfeFlood flood-opacity='0' result='BackgroundImageFix'/%3E%3CfeColorMatrix in='SourceAlpha' result='hardAlpha' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0'/%3E%3CfeOffset dy='1'/%3E%3CfeGaussianBlur stdDeviation='1'/%3E%3CfeColorMatrix values='0 0 0 0 0.156863 0 0 0 0 0.156863 0 0 0 0 0.2 0 0 0 0.05 0'/%3E%3CfeBlend in2='BackgroundImageFix' result='effect1_dropShadow_55_1571'/%3E%3CfeColorMatrix in='SourceAlpha' result='hardAlpha' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0'/%3E%3CfeOffset dy='3'/%3E%3CfeGaussianBlur stdDeviation='1.5'/%3E%3CfeColorMatrix values='0 0 0 0 0.156863 0 0 0 0 0.156863 0 0 0 0 0.2 0 0 0 0.04 0'/%3E%3CfeBlend in2='effect1_dropShadow_55_1571' result='effect2_dropShadow_55_1571'/%3E%3CfeColorMatrix in='SourceAlpha' result='hardAlpha' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0'/%3E%3CfeOffset dy='8'/%3E%3CfeGaussianBlur stdDeviation='2.5'/%3E%3CfeColorMatrix values='0 0 0 0 0.156863 0 0 0 0 0.156863 0 0 0 0 0.2 0 0 0 0.03 0'/%3E%3CfeBlend in2='effect2_dropShadow_55_1571' result='effect3_dropShadow_55_1571'/%3E%3CfeColorMatrix in='SourceAlpha' result='hardAlpha' values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0'/%3E%3CfeOffset dy='14'/%3E%3CfeGaussianBlur stdDeviation='2.5'/%3E%3CfeColorMatrix values='0 0 0 0 0.156863 0 0 0 0 0.156863 0 0 0 0 0.2 0 0 0 0.01 0'/%3E%3CfeBlend in2='effect3_dropShadow_55_1571' result='effect4_dropShadow_55_1571'/%3E%3CfeBlend in='SourceGraphic' in2='effect4_dropShadow_55_1571' result='shape'/%3E%3C/filter%3E%3C/defs%3E%3C/svg%3E");
|
||||
top: calc(100% - 10px);
|
||||
left: calc(50% - 10px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- loaded early, before paint, so ?theme=dark applies before first render -->
|
||||
<script is:inline src="/dist/js/tabler-theme.min.js"></script>
|
||||
<script is:inline src={`/dist/js/tabler-theme${min}.js`}></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class:list={['container-xl', 'p-4', className]}>
|
||||
<slot />
|
||||
<div class="page page-center align-items-center">
|
||||
<div class="screenshot d-flex flex-column justify-content-center align-items-center px-12" id="screenshot">
|
||||
{
|
||||
showLogo && (
|
||||
<div class="screenshot-logo">
|
||||
<NavbarLogo class="brand-gray" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
<div class:list={['screenshot-wrapper', showCard && ['screenshot-card', 'card'], className]} style={targetStyle} data-screenshot-target>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
{showLogo && <div class="screenshot-logo" />}
|
||||
</div>
|
||||
|
||||
<!-- outside .screenshot on purpose: a screenshot tool crops to [data-screenshot-target], so this toggle never ends up in the capture -->
|
||||
<nav class="nav-segmented mt-4">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<script is:inline src="/dist/js/tabler.min.js" defer></script>
|
||||
{libJsFiles.map((src) => <script is:inline src={src} defer />)}
|
||||
<script is:inline src={`/dist/js/tabler${min}.js`} defer></script>
|
||||
|
||||
<!-- components that render via CaptureScript (e.g. Chart) queue their init script
|
||||
into shared/lib/page-scripts instead of inlining it where used; this drains it. -->
|
||||
<PageScripts />
|
||||
|
||||
<script>
|
||||
// Signals to the screenshot tool that fonts, images and JS-driven
|
||||
// component init (dropdowns, tooltips, ...) are all settled.
|
||||
// window "load" (not just fonts.ready) guarantees the deferred
|
||||
// tabler.min.js above has already run.
|
||||
// tabler(.min).js above has already run.
|
||||
const loaded = new Promise((resolve) => window.addEventListener('load', resolve, { once: true }))
|
||||
Promise.all([document.fonts.ready, loaded]).then(() => {
|
||||
requestAnimationFrame(() => requestAnimationFrame(() => (document.documentElement.dataset.screenshotReady = 'true')))
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import ActiveUsers from '@shared/components/cards/charts/ActiveUsers.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Active subscriptions" showCard={false} columns={1} pageLibs={['apexcharts']}>
|
||||
<ActiveUsers />
|
||||
</ScreenshotLayout>
|
||||
@@ -1,14 +0,0 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import AvatarList from '@ui/AvatarList.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Avatar list">
|
||||
<div class="space-y">
|
||||
<AvatarList limit={5} />
|
||||
<AvatarList limit={5} stacked />
|
||||
<AvatarList limit={3} stacked text="+4" />
|
||||
<AvatarList limit={5} size="sm" stacked />
|
||||
<AvatarList limit={5} size="lg" stacked />
|
||||
</div>
|
||||
</ScreenshotLayout>
|
||||
@@ -1,24 +0,0 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import Badge from '@ui/Badge.astro'
|
||||
import BadgesList from '@ui/BadgesList.astro'
|
||||
import site from '@data/site.json'
|
||||
|
||||
const colors = ['default', ...Object.keys(site.colors), 'dark']
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Badge">
|
||||
<div class="space-y">
|
||||
<BadgesList>
|
||||
{colors.map((color) => <Badge text={color} color={color === 'default' ? undefined : color} />)}
|
||||
</BadgesList>
|
||||
<BadgesList>
|
||||
{colors.map((color) => <Badge text={color} color={color === 'default' ? undefined : color} light />)}
|
||||
</BadgesList>
|
||||
<BadgesList>
|
||||
<Badge text="With icon" icon="check" color="green" />
|
||||
<Badge text="With addon" addon="12" addonColor="red" color="azure" />
|
||||
<Badge text="Small" scale="sm" color="primary" />
|
||||
</BadgesList>
|
||||
</div>
|
||||
</ScreenshotLayout>
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import Button from '@ui/Button.astro'
|
||||
import ButtonList from '@ui/ButtonList.astro'
|
||||
import site from '@data/site.json'
|
||||
|
||||
const colors = ['default', ...Object.keys(site.colors), 'dark']
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Button">
|
||||
<div class="space-y">
|
||||
<ButtonList>
|
||||
{colors.map((color) => <Button text={color} color={color === 'default' ? undefined : color} element="button" />)}
|
||||
</ButtonList>
|
||||
<ButtonList>
|
||||
{colors.map((color) => <Button text={color} color={color === 'default' ? undefined : color} element="button" outline />)}
|
||||
</ButtonList>
|
||||
<ButtonList>
|
||||
{colors.map((color) => <Button text={color} color={color === 'default' ? undefined : color} element="button" ghost />)}
|
||||
</ButtonList>
|
||||
<ButtonList>
|
||||
<Button text="Small" element="button" size="sm" />
|
||||
<Button text="Default" element="button" />
|
||||
<Button text="Large" element="button" size="lg" />
|
||||
<Button text="Disabled" element="button" disabled />
|
||||
<Button text="Loading" element="button" loading />
|
||||
<Button text="With icon" element="button" icon="heart" />
|
||||
<Button text="Icon only" element="button" icon="heart" iconOnly />
|
||||
<Button text="Pill" element="button" pill color="primary" />
|
||||
</ButtonList>
|
||||
</div>
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import ConversionRate from '@shared/components/cards/charts/ConversionRate.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Conversion rate" showCard={false} columns={1}>
|
||||
<ConversionRate />
|
||||
</ScreenshotLayout>
|
||||
@@ -11,12 +11,11 @@ const pages = Object.keys(pageModules)
|
||||
.sort()
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Components">
|
||||
<h1 class="mb-4">Components</h1>
|
||||
<div class="list-group">
|
||||
<ScreenshotLayout title="Components" showCard={false} columns={2}>
|
||||
<div>
|
||||
{
|
||||
pages.map((slug) => (
|
||||
<a href={`/${slug}`} class="list-group-item list-group-item-action">
|
||||
<a href={`/${slug}`} class="d-block">
|
||||
{slug.replace(/-/g, ' ')}
|
||||
</a>
|
||||
))
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import NewClients from '@shared/components/cards/charts/NewClients.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="New clients" showCard={false} columns={1} pageLibs={['apexcharts']}>
|
||||
<NewClients />
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import Revenue from '@shared/components/cards/charts/Revenue.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Revenue" showCard={false} columns={1} pageLibs={['apexcharts']}>
|
||||
<Revenue />
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import SalesOverview from '@shared/components/cards/charts/SalesOverview.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Sales overview" showCard={false} pageLibs={['apexcharts']} columns={2}>
|
||||
<SalesOverview />
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import Sales from '@shared/components/cards/charts/Sales.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Sales" showCard={false} columns={1}>
|
||||
<Sales />
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import TotalUsers from '@shared/components/cards/charts/TotalUsers.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Total Users" showCard={false} columns={1} pageLibs={['apexcharts']}>
|
||||
<TotalUsers />
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
import Welcome from '@shared/components/cards/Welcome.astro'
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Welcome" showCard={false} columns={2}>
|
||||
<Welcome />
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
import Subheader from '@ui/Subheader.astro'
|
||||
import DropdownDays from '@ui/DropdownDays.astro'
|
||||
import Trending from '@ui/Trending.astro'
|
||||
import Progress from '@ui/Progress.astro'
|
||||
---
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center">
|
||||
<Subheader>Conversion rate</Subheader>
|
||||
<div class="ms-auto lh-1">
|
||||
<DropdownDays id="conversion-rate" label="Select time range for conversion rate" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-baseline">
|
||||
<div class="h1 mb-3 me-2">42.8%</div>
|
||||
<div class="me-auto">
|
||||
<Trending value={5} />
|
||||
</div>
|
||||
</div>
|
||||
<Progress value={43} color="primary" size="sm" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
import Subheader from '@ui/Subheader.astro'
|
||||
import Chart from '@ui/Chart.astro'
|
||||
---
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between gap-3 mb-2">
|
||||
<div class="mb-3">
|
||||
<Subheader>Sales overview</Subheader>
|
||||
<div class="d-flex align-items-baseline gap-2 mt-1">
|
||||
<div class="h1 mb-0">$284,300</div>
|
||||
<div class="text-green fw-medium">+12.4%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="legend bg-primary"></span>
|
||||
<span class="text-secondary">This year</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<span class="legend bg-secondary"></span>
|
||||
<span class="text-secondary">Last year</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Chart chartId="sales-overview" height={15} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -691,6 +691,25 @@
|
||||
"categories": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
||||
"y-max": 110
|
||||
},
|
||||
"sales-overview": {
|
||||
"type": "line",
|
||||
"stroke-width": [3, 2],
|
||||
"stroke-dash": [0, 6],
|
||||
"series": [
|
||||
{
|
||||
"name": "This year",
|
||||
"color": "primary",
|
||||
"data": [180, 195, 210, 205, 225, 240, 235, 260, 255, 270, 285, 300]
|
||||
},
|
||||
{
|
||||
"name": "Last year",
|
||||
"color": "secondary",
|
||||
"data": [150, 160, 168, 172, 180, 188, 190, 200, 205, 210, 215, 225]
|
||||
}
|
||||
],
|
||||
"categories": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
||||
"y-max": 320
|
||||
},
|
||||
"new-clients": {
|
||||
"type": "line",
|
||||
"datetime": true,
|
||||
|
||||
Reference in New Issue
Block a user