mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Move the import scripts to the repository root (#2940)
This commit is contained in:
1 parent
c1e1fdf9db
commit
b90554b8ee
12 files changed
+163
-87
No files matched your search
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env node
|
||||
// Regenerates shared/data/icons.json and icons-info.json from the installed
|
||||
// @tabler/icons package. `pnpm run update:icons` bumps the package first.
|
||||
//
|
||||
// Run: pnpm run import:icons
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
interface IconTag {
|
||||
styles: {
|
||||
outline?: unknown
|
||||
filled?: unknown
|
||||
}
|
||||
}
|
||||
|
||||
interface IconEntry {
|
||||
name: string
|
||||
svg: {
|
||||
outline: string | null
|
||||
filled: string | null
|
||||
}
|
||||
}
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const repoRoot = join(__dirname, '..')
|
||||
|
||||
const iconsPackage = join(repoRoot, 'node_modules/@tabler/icons')
|
||||
const iconsTags: Record<string, IconTag> = JSON.parse(readFileSync(join(iconsPackage, 'icons.json'), 'utf8'))
|
||||
const { version }: { version: string } = JSON.parse(readFileSync(join(iconsPackage, 'package.json'), 'utf8'))
|
||||
|
||||
const prepareSvgFile = (svg: string): string => {
|
||||
return svg.replace(/\n/g, '').replace(/>\s+</g, '><').replace(/\s+/g, ' ')
|
||||
}
|
||||
|
||||
const svgList: Record<string, IconEntry> = {}
|
||||
for (const iconName in iconsTags) {
|
||||
const iconData = iconsTags[iconName]
|
||||
svgList[iconName] = {
|
||||
name: iconName,
|
||||
svg: {
|
||||
outline: iconData.styles.outline ? prepareSvgFile(readFileSync(join(iconsPackage, `icons/outline/${iconName}.svg`), 'utf8')) : null,
|
||||
filled: iconData.styles.filled ? prepareSvgFile(readFileSync(join(iconsPackage, `icons/filled/${iconName}.svg`), 'utf8')) : null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync(
|
||||
join(repoRoot, 'shared/data/icons-info.json'),
|
||||
JSON.stringify({
|
||||
version,
|
||||
count: Object.values(svgList).reduce((acc, icon) => {
|
||||
return acc + (icon.svg.outline ? 1 : 0) + (icon.svg.filled ? 1 : 0)
|
||||
}, 0),
|
||||
}),
|
||||
)
|
||||
|
||||
writeFileSync(join(repoRoot, 'shared/data/icons.json'), JSON.stringify(svgList))
|
||||
|
||||
console.log(`import-icons: imported ${Object.keys(svgList).length} icons from @tabler/icons v${version}`)
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env node
|
||||
// Imports illustrations from the tabler/tabler-illustrations repo: the light and
|
||||
// dark PNGs, the name list and the version. The free inline SVGs in
|
||||
// shared/data/free-illustrations.json are hand-picked and stay as they are.
|
||||
//
|
||||
// Run: pnpm run import:illustrations
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, dirname, relative } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const repoRoot = join(__dirname, '..')
|
||||
const imageDir = join(repoRoot, 'shared', 'static', 'illustrations')
|
||||
const dataFile = join(repoRoot, 'shared', 'data', 'illustrations.json')
|
||||
const infoFile = join(repoRoot, 'shared', 'data', 'illustrations-info.json')
|
||||
|
||||
let cloneDir: string | undefined
|
||||
|
||||
function resolveSourceDir(): string {
|
||||
const candidates = [process.env.TABLER_ILLUSTRATIONS_DIR, join(repoRoot, '..', 'tabler-illustrations')].filter((dir): dir is string => Boolean(dir))
|
||||
for (const dir of candidates) {
|
||||
if (existsSync(join(dir, 'dist', 'png', 'light'))) return dir
|
||||
}
|
||||
cloneDir = mkdtempSync(join(tmpdir(), 'tabler-illustrations-'))
|
||||
console.log('No local checkout found, cloning tabler/tabler-illustrations…')
|
||||
execFileSync('git', ['clone', '--depth', '1', 'https://github.com/tabler/tabler-illustrations.git', cloneDir], { stdio: 'inherit' })
|
||||
return cloneDir
|
||||
}
|
||||
|
||||
const pngNames = (dir: string) =>
|
||||
readdirSync(dir)
|
||||
.filter((file) => file.endsWith('.png'))
|
||||
.sort()
|
||||
.map((file) => file.slice(0, -'.png'.length))
|
||||
|
||||
try {
|
||||
const sourceDir = resolveSourceDir()
|
||||
const lightDir = join(sourceDir, 'dist', 'png', 'light')
|
||||
const darkDir = join(sourceDir, 'dist', 'png', 'dark')
|
||||
const packageFile = join(sourceDir, 'package.json')
|
||||
for (const path of [lightDir, darkDir, packageFile]) {
|
||||
if (!existsSync(path)) throw new Error(`import-illustrations: missing ${path} — not a tabler-illustrations checkout?`)
|
||||
}
|
||||
|
||||
const illustrations = pngNames(lightDir)
|
||||
const darkIllustrations = pngNames(darkDir)
|
||||
if (illustrations.join() !== darkIllustrations.join()) {
|
||||
const light = new Set(illustrations)
|
||||
const dark = new Set(darkIllustrations)
|
||||
const onlyLight = illustrations.filter((name) => !dark.has(name))
|
||||
const onlyDark = darkIllustrations.filter((name) => !light.has(name))
|
||||
throw new Error(`import-illustrations: light/dark sets differ (only light: ${onlyLight.join(', ') || '—'}; only dark: ${onlyDark.join(', ') || '—'})`)
|
||||
}
|
||||
|
||||
const previous = existsSync(join(imageDir, 'light')) ? new Set(pngNames(join(imageDir, 'light'))) : new Set<string>()
|
||||
for (const variant of ['light', 'dark'] as const) {
|
||||
const targetDir = join(imageDir, variant)
|
||||
rmSync(targetDir, { recursive: true, force: true })
|
||||
mkdirSync(targetDir, { recursive: true })
|
||||
for (const name of illustrations) {
|
||||
copyFileSync(join(variant === 'light' ? lightDir : darkDir, `${name}.png`), join(targetDir, `${name}.png`))
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync(dataFile, JSON.stringify(illustrations))
|
||||
|
||||
const { version }: { version: string } = JSON.parse(readFileSync(packageFile, 'utf8'))
|
||||
writeFileSync(infoFile, JSON.stringify({ version, count: illustrations.length }))
|
||||
|
||||
const added = illustrations.filter((name) => !previous.has(name))
|
||||
const removed = [...previous].filter((name) => !illustrations.includes(name))
|
||||
console.log(`Imported ${illustrations.length} illustrations v${version} from ${relative(repoRoot, sourceDir)} (${added.length} added, ${removed.length} removed)`)
|
||||
if (added.length) console.log(` added: ${added.join(', ')}`)
|
||||
if (removed.length) console.log(` removed: ${removed.join(', ')}`)
|
||||
} finally {
|
||||
if (cloneDir) rmSync(cloneDir, { recursive: true, force: true })
|
||||
}
|
||||
@@ -1,16 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
// Imports payment provider assets from the tabler/tabler-payments repo, so the
|
||||
// payments plugin never drifts from the icon source of truth:
|
||||
// - core/img/payments/ <- src/light/*.svg + src/dark/*.svg (as *-dark.svg)
|
||||
// - $payment-providers in core/scss/_variables.scss
|
||||
// - shared/data/payments.json <- payments.json (name + logo, demo data)
|
||||
// Imports payment provider assets from the tabler/tabler-payments repo: the light
|
||||
// and dark SVGs, the $payment-providers list and the demo data.
|
||||
//
|
||||
// Source checkout resolution order:
|
||||
// 1. TABLER_PAYMENTS_DIR env var
|
||||
// 2. ../tabler-payments (sibling checkout)
|
||||
// 3. fresh shallow clone into a temp dir (the repo is private — needs git auth)
|
||||
//
|
||||
// Run: pnpm run import-payments
|
||||
// Run: pnpm run import:payments
|
||||
// Then: pnpm run generate-tokens — refreshes PaymentProvider in shared/lib/tokens.ts
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
@@ -37,8 +29,7 @@ function resolveSourceDir(): string {
|
||||
return cloneDir
|
||||
}
|
||||
|
||||
// Provider order everywhere follows the SVG filename (with extension), so
|
||||
// 'amazon-pay' sorts before 'amazon' — same as an `ls` of the source dir.
|
||||
// Sorted by file name, so 'amazon-pay' comes before 'amazon' — as in an `ls`.
|
||||
const svgNames = (dir: string) =>
|
||||
readdirSync(dir)
|
||||
.filter((file) => file.endsWith('.svg'))
|
||||
@@ -64,7 +55,6 @@ try {
|
||||
throw new Error(`import-payments: light/dark sets differ (only light: ${onlyLight.join(', ') || '—'}; only dark: ${onlyDark.join(', ') || '—'})`)
|
||||
}
|
||||
|
||||
// 1. core/img/payments — clean replace, dark variants get a `-dark` suffix
|
||||
const previous = existsSync(imgDir) ? new Set(svgNames(imgDir).map((name) => name.replace(/-dark$/, ''))) : new Set<string>()
|
||||
rmSync(imgDir, { recursive: true, force: true })
|
||||
mkdirSync(imgDir, { recursive: true })
|
||||
@@ -73,14 +63,12 @@ try {
|
||||
copyFileSync(join(darkDir, `${name}.svg`), join(imgDir, `${name}-dark.svg`))
|
||||
}
|
||||
|
||||
// 2. $payment-providers in core/scss/_variables.scss
|
||||
const scss = readFileSync(scssFile, 'utf8')
|
||||
const listPattern = /(\$payment-providers: \(\n)[\s\S]*?(\n\);)/
|
||||
if (!listPattern.test(scss)) throw new Error(`import-payments: $payment-providers list not found in ${scssFile}`)
|
||||
const listBody = providers.map((name) => ` '${name}'`).join(',\n')
|
||||
writeFileSync(scssFile, scss.replace(listPattern, `$1${listBody}$2`))
|
||||
|
||||
// 3. shared/data/payments.json — demo data keeps its `{ name, logo }` shape
|
||||
const meta = JSON.parse(readFileSync(metaFile, 'utf8')) as { name: string; logo: string }[]
|
||||
const names = new Map(meta.map((entry) => [entry.logo, entry.name]))
|
||||
for (const logo of names.keys()) {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/preview": patch
|
||||
---
|
||||
|
||||
Moved the `import:icons` and `import:illustrations` scripts to the repository root, next to `import:payments`.
|
||||
@@ -6,6 +6,7 @@ summary: Tabler Illustrations is a collection of customizable SVG illustrations
|
||||
---
|
||||
|
||||
import { Image } from 'astro:assets'
|
||||
import { site } from '@shared/lib/site'
|
||||
import coverLight from '../../images/cover-illustrations.jpg'
|
||||
import coverDark from '../../images/cover-illustrations-dark.jpg'
|
||||
|
||||
@@ -14,7 +15,7 @@ import coverDark from '../../images/cover-illustrations-dark.jpg'
|
||||
<Image src={coverDark} alt="Tabler Illustrations" class="hide-theme-light" width={800} densities={[1, 2]} loading="eager" />
|
||||
</figure>
|
||||
|
||||
Tabler Illustrations is a set of 130 illustrations for empty states, error pages, onboarding screens and marketing sections. Every illustration comes in a light and a dark variant, so it fits both color modes of your interface.
|
||||
Tabler Illustrations is a set of { site.illustrationsCount } illustrations for empty states, error pages, onboarding screens and marketing sections. Every illustration comes in a light and a dark variant, so it fits both color modes of your interface.
|
||||
|
||||
## What's inside
|
||||
|
||||
|
||||
+5
-1
@@ -18,7 +18,10 @@
|
||||
"html-diff": "tsx .build/html-diff.ts check",
|
||||
"html-diff:baseline": "tsx .build/html-diff.ts baseline",
|
||||
"generate-tokens": "tsx .build/generate-tokens.ts",
|
||||
"import-payments": "tsx .build/import-payments.ts",
|
||||
"import:icons": "tsx .build/import-icons.ts",
|
||||
"import:illustrations": "tsx .build/import-illustrations.ts",
|
||||
"import:payments": "tsx .build/import-payments.ts",
|
||||
"update:icons": "pnpm up -w @tabler/icons@latest && pnpm run import:icons",
|
||||
"check:tokens": "tsx .build/generate-tokens.ts check",
|
||||
"check:docs-links": "tsx .build/check-docs-links.ts",
|
||||
"check:css-vars": "tsx .build/check-css-vars.ts",
|
||||
@@ -46,6 +49,7 @@
|
||||
"@changesets/cli": "^3.0.1",
|
||||
"@mdx-js/mdx": "^3.1.1",
|
||||
"@stylistic/stylelint-config": "^2.0.0",
|
||||
"@tabler/icons": "^3.46.0",
|
||||
"@types/node": "^26.4.0",
|
||||
"adm-zip": "^0.6.0",
|
||||
"autoprefixer": "^10.5.4",
|
||||
|
||||
Generated
+3
-3
@@ -24,6 +24,9 @@ importers:
|
||||
'@stylistic/stylelint-config':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(stylelint@16.26.1(supports-color@5.5.0)(typescript@7.0.2))
|
||||
'@tabler/icons':
|
||||
specifier: ^3.46.0
|
||||
version: 3.46.0
|
||||
'@types/node':
|
||||
specifier: ^26.4.0
|
||||
version: 26.4.0
|
||||
@@ -276,9 +279,6 @@ importers:
|
||||
'@astrojs/mdx':
|
||||
specifier: ^7.0.8
|
||||
version: 7.0.8(@astrojs/markdown-satteri@0.3.8)(astro@7.2.9(@astrojs/markdown-remark@7.2.4(supports-color@5.5.0))(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@26.4.0)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.103.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.0))(supports-color@5.5.0)
|
||||
'@tabler/icons':
|
||||
specifier: ^3.46.0
|
||||
version: 3.46.0
|
||||
'@types/js-beautify':
|
||||
specifier: ^1.14.3
|
||||
version: 1.14.3
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Regenerate shared/data/icons.json and icons-info.json from the installed
|
||||
// @tabler/icons package. `pnpm run import-icons` refreshes the data files from
|
||||
// the installed version; `pnpm run update-icons` bumps the package first.
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const iconsPackage = join(__dirname, '../node_modules/@tabler/icons')
|
||||
const iconsTags = JSON.parse(readFileSync(join(iconsPackage, 'icons.json'), 'utf8'))
|
||||
const { version } = JSON.parse(readFileSync(join(iconsPackage, 'package.json'), 'utf8'))
|
||||
|
||||
const prepareSvgFile = (svg) => {
|
||||
return svg.replace(/\n/g, '').replace(/>\s+</g, '><').replace(/\s+/g, ' ')
|
||||
}
|
||||
|
||||
let svgList = {}
|
||||
for (let iconName in iconsTags) {
|
||||
let iconData = iconsTags[iconName]
|
||||
svgList[iconName] = {
|
||||
name: iconName,
|
||||
svg: {
|
||||
outline: iconData.styles.outline ? prepareSvgFile(readFileSync(join(iconsPackage, `icons/outline/${iconName}.svg`), 'utf8')) : null,
|
||||
filled: iconData.styles.filled ? prepareSvgFile(readFileSync(join(iconsPackage, `icons/filled/${iconName}.svg`), 'utf8')) : null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync(
|
||||
join(__dirname, '../../shared/data/icons-info.json'),
|
||||
JSON.stringify({
|
||||
version,
|
||||
count: Object.values(svgList).reduce((acc, icon) => {
|
||||
return acc + (icon.svg.outline ? 1 : 0) + (icon.svg.filled ? 1 : 0)
|
||||
}, 0),
|
||||
}),
|
||||
)
|
||||
|
||||
writeFileSync(join(__dirname, '../../shared/data/icons.json'), JSON.stringify(svgList))
|
||||
|
||||
console.log(`import-icons: imported ${Object.keys(svgList).length} icons from @tabler/icons v${version}`)
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Regenerate shared/data/illustrations.json from the PNG files in
|
||||
// shared/static/illustrations/light. Run `pnpm run import-illustrations`
|
||||
// after adding or removing illustration files.
|
||||
import { globSync, writeFileSync } from 'node:fs'
|
||||
import { join, basename, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const illustrations = globSync(join(__dirname, '../../shared/static/illustrations/light/*.png'))
|
||||
.map((file) => basename(file, '.png'))
|
||||
.sort()
|
||||
|
||||
writeFileSync(join(__dirname, '../../shared/data/illustrations.json'), JSON.stringify(illustrations))
|
||||
|
||||
console.log(`import-illustrations: imported ${illustrations.length} illustrations`)
|
||||
@@ -18,9 +18,6 @@
|
||||
"build": "pnpm run assets && astro build",
|
||||
"preview": "astro preview",
|
||||
"clean": "shx rm -rf dist public/dist public/preview public/css .astro tmp-assets",
|
||||
"import-icons": "node .build/import-icons.mjs",
|
||||
"update-icons": "pnpm up @tabler/icons@latest && pnpm run import-icons",
|
||||
"import-illustrations": "node .build/import-illustrations.mjs",
|
||||
"type-check": "astro check"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -31,7 +28,6 @@
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/markdown-satteri": "^0.3.8",
|
||||
"@astrojs/mdx": "^7.0.8",
|
||||
"@tabler/icons": "^3.46.0",
|
||||
"@types/js-beautify": "^1.14.3",
|
||||
"js-beautify": "^2.0.3",
|
||||
"prettier": "^3.9.6",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"version":"1.16.0","count":125}
|
||||
@@ -1,5 +1,6 @@
|
||||
import corePackage from '@tabler/core/package.json'
|
||||
import iconsInfo from '../data/icons-info.json'
|
||||
import illustrationsInfo from '../data/illustrations-info.json'
|
||||
|
||||
const version = corePackage.version
|
||||
|
||||
@@ -19,6 +20,9 @@ export const site = {
|
||||
// From shared/data/icons-info.json.
|
||||
iconsCount: 5986,
|
||||
iconsVersion: iconsInfo.version,
|
||||
// From shared/data/illustrations-info.json.
|
||||
illustrationsCount: illustrationsInfo.count,
|
||||
illustrationsVersion: illustrationsInfo.version,
|
||||
descriptionShort: 'Premium and Open Source dashboard template with responsive and high quality UI.',
|
||||
description: 'Tabler is packed with beautifully crafted components and powerful features. Jump in and start building a stunning dashboard — all for free!',
|
||||
themeColor: '#066fd1',
|
||||
|
||||
Reference in new issue
Block a user