mirror of
https://github.com/tabler/tabler.git
synced 2026-08-05 19:03:18 +04:00
Add @tabler/screenshots package with initial configuration and components
This commit is contained in:
+2
-2
@@ -18,10 +18,10 @@
|
||||
"lint:fix": "pnpm run lint-md-fix && pnpm run format-prettier",
|
||||
"lint-md": "markdownlint --config .markdownlint-docs.json \"docs/pages/**/*.mdx\"",
|
||||
"lint-md-fix": "markdownlint --fix --config .markdownlint-docs.json \"docs/pages/**/*.mdx\"",
|
||||
"lint-prettier": "prettier --check \"core/scss/**/*.scss\" \"core/js/**/*.{js,ts}\" \"core/.build/**/*.{ts,mts,mjs}\" \".build/**/*.ts\" \"preview/scss/**/*.scss\" \"preview/js/**/*.{js,ts}\" \"{preview,docs,shared}/**/*.astro\" \"{preview,docs}/**/*.{mjs,mts}\" \"shared/**/*.{js,mjs,mts,ts}\" --cache",
|
||||
"lint-prettier": "prettier --check \"core/scss/**/*.scss\" \"core/js/**/*.{js,ts}\" \"core/.build/**/*.{ts,mts,mjs}\" \".build/**/*.ts\" \"preview/scss/**/*.scss\" \"preview/js/**/*.{js,ts}\" \"{preview,docs,screenshots,shared}/**/*.astro\" \"{preview,docs,screenshots}/**/*.{mjs,mts}\" \"shared/**/*.{js,mjs,mts,ts}\" --cache",
|
||||
"lint-scss-vars": "pnpm --filter @tabler/core css-lint",
|
||||
"format": "pnpm run format-prettier && pnpm run reformat-md",
|
||||
"format-prettier": "prettier --write \"core/scss/**/*.scss\" \"core/js/**/*.{js,ts}\" \"core/.build/**/*.{ts,mts,mjs}\" \".build/**/*.ts\" \"preview/scss/**/*.scss\" \"preview/js/**/*.{js,ts}\" \"{preview,docs,shared}/**/*.astro\" \"{preview,docs}/**/*.{mjs,mts}\" \"shared/**/*.{js,mjs,mts,ts}\" --cache",
|
||||
"format-prettier": "prettier --write \"core/scss/**/*.scss\" \"core/js/**/*.{js,ts}\" \"core/.build/**/*.{ts,mts,mjs}\" \".build/**/*.ts\" \"preview/scss/**/*.scss\" \"preview/js/**/*.{js,ts}\" \"{preview,docs,screenshots,shared}/**/*.astro\" \"{preview,docs,screenshots}/**/*.{mjs,mts}\" \"shared/**/*.{js,mjs,mts,ts}\" --cache",
|
||||
"check": "pnpm run lint && pnpm run type-check",
|
||||
"zip-package": "tsx .build/zip-package.ts",
|
||||
"start": "pnpm dev"
|
||||
|
||||
Generated
+19
@@ -271,6 +271,25 @@ importers:
|
||||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
|
||||
screenshots:
|
||||
dependencies:
|
||||
'@tabler/core':
|
||||
specifier: workspace:*
|
||||
version: link:../core
|
||||
astro:
|
||||
specifier: ^7.1.6
|
||||
version: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
|
||||
devDependencies:
|
||||
'@astrojs/check':
|
||||
specifier: ^0.9.4
|
||||
version: 0.9.10(prettier-plugin-astro@0.14.1)(prettier@3.9.6)(typescript@5.9.3)
|
||||
shx:
|
||||
specifier: ^0.4.0
|
||||
version: 0.4.0
|
||||
typescript:
|
||||
specifier: ^5.7.3
|
||||
version: 5.9.3
|
||||
|
||||
shared:
|
||||
dependencies:
|
||||
'@tabler/core':
|
||||
|
||||
@@ -2,6 +2,7 @@ packages:
|
||||
- core
|
||||
- preview
|
||||
- docs
|
||||
- screenshots
|
||||
- shared
|
||||
|
||||
allowBuilds:
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# build output
|
||||
dist/
|
||||
.astro/
|
||||
|
||||
# public/ is fully generated by .build/copy-assets.ts
|
||||
public/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -0,0 +1,66 @@
|
||||
// @ts-check
|
||||
import { defineConfig } from 'astro/config'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { copyAssets } from '../.build/copy-assets'
|
||||
|
||||
/** @param {string} p */
|
||||
const path = (p) => fileURLToPath(new URL(p, import.meta.url))
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// pages live at the package root (./pages) — components/lib/data are shared
|
||||
// (see the @shared alias)
|
||||
srcDir: '.',
|
||||
server: {
|
||||
port: 3020,
|
||||
// bind on all interfaces so the dev server is reachable from Docker
|
||||
// port mappings and other devices on the local network
|
||||
host: true,
|
||||
},
|
||||
vite: {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@data': fileURLToPath(new URL('../shared/data', import.meta.url)),
|
||||
'@shared': fileURLToPath(new URL('../shared', import.meta.url)),
|
||||
'@ui': fileURLToPath(new URL('../shared/ui', import.meta.url)),
|
||||
'@components': fileURLToPath(new URL('../shared/components', import.meta.url)),
|
||||
},
|
||||
},
|
||||
},
|
||||
build: {
|
||||
// Emit button.html instead of button/index.html — a stable, predictable
|
||||
// URL per component for the screenshot tool to iterate over.
|
||||
format: 'file',
|
||||
},
|
||||
compressHTML: false,
|
||||
integrations: [
|
||||
copyAssets({
|
||||
repo: path('..'),
|
||||
publicDir: path('./public'),
|
||||
copies: [
|
||||
{
|
||||
// @tabler/core dist (css/js/fonts/img/libs).
|
||||
// Fallback keeps current assets if core rebuilds dist mid-copy in turbo dev.
|
||||
from: path('./node_modules/@tabler/core/dist'),
|
||||
to: path('./public/dist'),
|
||||
label: '@tabler/core',
|
||||
allowDestinationFallback: true,
|
||||
},
|
||||
{
|
||||
// static assets referenced by demo data (avatar photos, brand svgs...).
|
||||
from: path('../shared/static'),
|
||||
to: path('./public/static'),
|
||||
label: 'shared assets',
|
||||
},
|
||||
{ from: path('./assets/favicon.ico'), to: path('./public/favicon.ico'), label: '@tabler/screenshots' },
|
||||
{ from: path('./assets/favicon-dev.ico'), to: path('./public/favicon-dev.ico'), label: '@tabler/screenshots' },
|
||||
],
|
||||
// Watch the real core/dist, not the node_modules symlink the startup copy
|
||||
// reads from — same directory.
|
||||
syncDirs: [
|
||||
{ from: path('../core/dist'), to: path('./public/dist') },
|
||||
{ from: path('../shared/static'), to: path('./public/static') },
|
||||
],
|
||||
}),
|
||||
],
|
||||
})
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="astro/client" />
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
// 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.
|
||||
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 */
|
||||
class?: string
|
||||
}
|
||||
|
||||
const { title, rtl = false, class: className } = Astro.props
|
||||
const rtlSuffix = rtl ? '.rtl' : ''
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en" dir={rtl ? 'rtl' : undefined}>
|
||||
<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${rtlSuffix}.css`} rel="stylesheet" />
|
||||
|
||||
<style is:inline>
|
||||
/* Deterministic screenshots: no mid-capture animation/transition frames, no blinking caret. */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
caret-color: transparent !important;
|
||||
}
|
||||
</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:list={['container-xl', 'p-4', className]}>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<script is:inline src="/dist/js/tabler.min.js" defer></script>
|
||||
<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.
|
||||
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')))
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@tabler/screenshots",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"description": "Astro app: one page per UI component, for automated screenshotting",
|
||||
"engines": {
|
||||
"node": ">=22.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"clean": "shx rm -rf dist public .astro",
|
||||
"type-check": "astro check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tabler/core": "workspace:*",
|
||||
"astro": "^7.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"shx": "^0.4.0",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
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>
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
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>
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
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,25 @@
|
||||
---
|
||||
// Every other page under pages/ is a screenshot target. Listing them via a
|
||||
// glob (instead of a hand-maintained array) means adding a new component
|
||||
// page is the only step needed for it to show up here.
|
||||
import ScreenshotLayout from '../layouts/ScreenshotLayout.astro'
|
||||
|
||||
const pageModules = import.meta.glob('./*.astro')
|
||||
const pages = Object.keys(pageModules)
|
||||
.map((path) => path.replace(/^\.\//, '').replace(/\.astro$/, ''))
|
||||
.filter((slug) => slug !== 'index')
|
||||
.sort()
|
||||
---
|
||||
|
||||
<ScreenshotLayout title="Components">
|
||||
<h1 class="mb-4">Components</h1>
|
||||
<div class="list-group">
|
||||
{
|
||||
pages.map((slug) => (
|
||||
<a href={`/${slug}`} class="list-group-item list-group-item-action">
|
||||
{slug.replace(/-/g, ' ')}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</ScreenshotLayout>
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"include": [".astro/types.d.ts", "**/*"],
|
||||
"exclude": ["dist", "public"],
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@data/*": ["../shared/data/*"],
|
||||
"@shared/*": ["../shared/*"],
|
||||
"@ui/*": ["../shared/ui/*"],
|
||||
"@components/*": ["../shared/components/*"]
|
||||
},
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
||||
+20
@@ -47,6 +47,19 @@
|
||||
],
|
||||
"cache": true
|
||||
},
|
||||
"@tabler/screenshots#build": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"inputs": [
|
||||
"$TURBO_DEFAULT$",
|
||||
"$TURBO_ROOT$/shared/**"
|
||||
],
|
||||
"outputs": [
|
||||
"dist/**"
|
||||
],
|
||||
"cache": true
|
||||
},
|
||||
"dev": {
|
||||
"cache": false,
|
||||
"persistent": true
|
||||
@@ -74,6 +87,13 @@
|
||||
"cache": false,
|
||||
"persistent": true
|
||||
},
|
||||
"@tabler/screenshots#dev": {
|
||||
"dependsOn": [
|
||||
"@tabler/core#dev-prepare"
|
||||
],
|
||||
"cache": false,
|
||||
"persistent": true
|
||||
},
|
||||
"@tabler/docs#dev": {
|
||||
"dependsOn": [
|
||||
"@tabler/core#dev-prepare",
|
||||
|
||||
Reference in New Issue
Block a user