mirror of
https://github.com/tabler/tabler.git
synced 2026-01-25 04:16:36 +00:00
Migrate core JavaScript to TypeScript (#2582)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,63 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { sync } from 'glob';
|
||||
import * as prettier from "prettier";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const docs = sync(join(__dirname, '..', 'docs', '**', '*.md'))
|
||||
|
||||
async function formatHTML(htmlString) {
|
||||
try {
|
||||
const formattedHtml = await prettier.format(htmlString, {
|
||||
parser: "html",
|
||||
printWidth: 100,
|
||||
});
|
||||
return formattedHtml;
|
||||
} catch (error) {
|
||||
console.error("Error formatting HTML:", error);
|
||||
return htmlString; // Return original in case of an error
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceAsync(str, regex, asyncFn) {
|
||||
const matches = [...str.matchAll(regex)];
|
||||
|
||||
const replacements = await Promise.all(
|
||||
matches.map(async (match) => asyncFn(...match))
|
||||
);
|
||||
|
||||
let result = str;
|
||||
matches.forEach((match, i) => {
|
||||
result = result.replace(match[0], replacements[i]);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
for (const file of docs) {
|
||||
const oldContent = readFileSync(file, 'utf8')
|
||||
|
||||
// get codeblocks from markdown
|
||||
const content = await replaceAsync(oldContent, /(```([a-z0-9]+).*?\n)(.*?)(```)/gs, async (m, m1, m2, m3, m4) => {
|
||||
if (m2 === 'html') {
|
||||
m3 = await formatHTML(m3);
|
||||
|
||||
// remove empty lines
|
||||
m3 = m3.replace(/^\s*[\r\n]/gm, '');
|
||||
|
||||
return m1 + m3.trim() + "\n" + m4;
|
||||
}
|
||||
return m.trim();
|
||||
})
|
||||
|
||||
if (content !== oldContent) {
|
||||
writeFileSync(file, content, 'utf8')
|
||||
console.log(`Reformatted ${file}`)
|
||||
}
|
||||
}
|
||||
79
.build/reformat-mdx.ts
Normal file
79
.build/reformat-mdx.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { sync } from 'glob'
|
||||
import * as prettier from 'prettier'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const docs: string[] = sync(join(__dirname, '..', 'docs', '**', '*.md'))
|
||||
|
||||
async function formatHTML(htmlString: string): Promise<string> {
|
||||
try {
|
||||
const formattedHtml = await prettier.format(htmlString, {
|
||||
parser: 'html',
|
||||
printWidth: 100,
|
||||
})
|
||||
return formattedHtml
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error formatting HTML:', errorMessage)
|
||||
return htmlString // Return original in case of an error
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceAsync(
|
||||
str: string,
|
||||
regex: RegExp,
|
||||
asyncFn: (...args: string[]) => Promise<string>
|
||||
): Promise<string> {
|
||||
const matches = [...str.matchAll(regex)]
|
||||
|
||||
const replacements = await Promise.all(
|
||||
matches.map(async (match: RegExpMatchArray) => asyncFn(...match))
|
||||
)
|
||||
|
||||
let result = str
|
||||
matches.forEach((match: RegExpMatchArray, i: number) => {
|
||||
result = result.replace(match[0], replacements[i])
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async function processFiles(): Promise<void> {
|
||||
for (const file of docs) {
|
||||
const oldContent = readFileSync(file, 'utf8')
|
||||
|
||||
// get codeblocks from markdown
|
||||
const content = await replaceAsync(
|
||||
oldContent,
|
||||
/(```([a-z0-9]+).*?\n)(.*?)(```)/gs,
|
||||
async (m: string, m1: string, m2: string, m3: string, m4: string) => {
|
||||
if (m2 === 'html') {
|
||||
let formattedHtml = await formatHTML(m3)
|
||||
|
||||
// remove empty lines
|
||||
formattedHtml = formattedHtml.replace(/^\s*[\r\n]/gm, '')
|
||||
|
||||
return m1 + formattedHtml.trim() + '\n' + m4
|
||||
}
|
||||
return m.trim()
|
||||
}
|
||||
)
|
||||
|
||||
if (content !== oldContent) {
|
||||
writeFileSync(file, content, 'utf8')
|
||||
console.log(`Reformatted ${file}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processFiles().catch((error) => {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error processing files:', errorMessage)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
/**
|
||||
* Creates a Vite configuration for building libraries
|
||||
* @param {Object} options - Configuration options
|
||||
* @param {string} options.entry - Path to the entry file
|
||||
* @param {string|undefined} options.name - Library name (undefined for ESM)
|
||||
* @param {string|Function} options.fileName - Output file name or function returning it
|
||||
* @param {string[]} options.formats - Output formats (e.g., ['es'], ['umd'], ['es', 'umd'])
|
||||
* @param {string} options.outDir - Output directory path
|
||||
* @param {string|undefined} options.banner - Optional banner text to add to output
|
||||
* @returns {import('vite').UserConfig} Vite configuration
|
||||
*/
|
||||
export function createViteConfig({
|
||||
entry,
|
||||
name,
|
||||
fileName,
|
||||
formats,
|
||||
outDir,
|
||||
banner
|
||||
}) {
|
||||
const rollupOutput = {
|
||||
generatedCode: {
|
||||
constBindings: true
|
||||
}
|
||||
}
|
||||
|
||||
// Add banner if provided
|
||||
if (banner) {
|
||||
rollupOutput.banner = banner
|
||||
}
|
||||
|
||||
return defineConfig({
|
||||
build: {
|
||||
lib: {
|
||||
entry: path.resolve(entry),
|
||||
name: name,
|
||||
fileName: typeof fileName === 'function' ? fileName : () => fileName,
|
||||
formats: formats
|
||||
},
|
||||
outDir: path.resolve(outDir),
|
||||
emptyOutDir: false,
|
||||
sourcemap: true,
|
||||
rollupOptions: {
|
||||
output: rollupOutput
|
||||
},
|
||||
target: 'es2015',
|
||||
minify: false // Minification is done by terser in a separate step
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
},
|
||||
esbuild: {
|
||||
target: 'es2015'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
76
.build/vite.config.helper.ts
Normal file
76
.build/vite.config.helper.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { defineConfig, type UserConfig } from 'vite'
|
||||
|
||||
interface CreateViteConfigOptions {
|
||||
entry: string
|
||||
name?: string
|
||||
fileName: string | ((format: string) => string)
|
||||
formats: ('es' | 'umd' | 'iife' | 'cjs')[]
|
||||
outDir: string
|
||||
banner?: string
|
||||
minify?: boolean | 'esbuild'
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Vite configuration for building libraries
|
||||
*/
|
||||
export function createViteConfig({
|
||||
entry,
|
||||
name,
|
||||
fileName,
|
||||
formats,
|
||||
outDir,
|
||||
banner,
|
||||
minify = false
|
||||
}: CreateViteConfigOptions): UserConfig {
|
||||
const rollupOutput: {
|
||||
generatedCode: {
|
||||
constBindings: boolean
|
||||
}
|
||||
banner?: string
|
||||
} = {
|
||||
generatedCode: {
|
||||
constBindings: true
|
||||
}
|
||||
}
|
||||
|
||||
// Add banner if provided
|
||||
if (banner) {
|
||||
rollupOutput.banner = banner
|
||||
}
|
||||
|
||||
const config: UserConfig = {
|
||||
build: {
|
||||
lib: {
|
||||
entry: path.resolve(entry),
|
||||
name: name,
|
||||
fileName: typeof fileName === 'function' ? fileName : () => fileName,
|
||||
formats: formats
|
||||
},
|
||||
outDir: path.resolve(outDir),
|
||||
emptyOutDir: false,
|
||||
sourcemap: true,
|
||||
rollupOptions: {
|
||||
output: rollupOutput
|
||||
},
|
||||
target: 'es2015',
|
||||
minify: minify
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
},
|
||||
esbuild: {
|
||||
target: 'es2015',
|
||||
tsconfigRaw: {
|
||||
compilerOptions: {
|
||||
module: 'ES2020',
|
||||
target: 'ES2015'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defineConfig(config)
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import AdmZip from 'adm-zip';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { readFileSync } from 'fs';
|
||||
|
||||
// Get __dirname in ESM
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(path.join(__dirname, '../core', 'package.json'), 'utf8')
|
||||
)
|
||||
|
||||
// Create zip instance and add folder
|
||||
const zip = new AdmZip();
|
||||
zip.addLocalFolder(path.join(__dirname, '../preview/dist'), 'dashboard');
|
||||
|
||||
zip.addLocalFile(path.join(__dirname, '../preview/static', 'og.png'), '.', 'preview.png');
|
||||
|
||||
zip.addFile("documentation.url", Buffer.from("[InternetShortcut]\nURL = https://tabler.io/docs"));
|
||||
|
||||
|
||||
// Folder to zip and output path
|
||||
const outputZipPath = path.join(__dirname, '../packages-zip', `tabler-${pkg.version}.zip`);
|
||||
|
||||
// Write the zip file
|
||||
zip.writeZip(outputZipPath);
|
||||
|
||||
console.log(`Zipped folder to ${outputZipPath}`);
|
||||
46
.build/zip-package.ts
Normal file
46
.build/zip-package.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import AdmZip from 'adm-zip'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
// Get __dirname in ESM
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
interface PackageJson {
|
||||
version: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const pkg: PackageJson = JSON.parse(
|
||||
readFileSync(path.join(__dirname, '../core', 'package.json'), 'utf8')
|
||||
)
|
||||
|
||||
// Create zip instance and add folder
|
||||
const zip = new AdmZip()
|
||||
zip.addLocalFolder(path.join(__dirname, '../preview/dist'), 'dashboard')
|
||||
|
||||
zip.addLocalFile(
|
||||
path.join(__dirname, '../preview/static', 'og.png'),
|
||||
'.',
|
||||
'preview.png'
|
||||
)
|
||||
|
||||
zip.addFile(
|
||||
'documentation.url',
|
||||
Buffer.from('[InternetShortcut]\nURL = https://tabler.io/docs')
|
||||
)
|
||||
|
||||
// Folder to zip and output path
|
||||
const outputZipPath = path.join(
|
||||
__dirname,
|
||||
'../packages-zip',
|
||||
`tabler-${pkg.version}.zip`
|
||||
)
|
||||
|
||||
// Write the zip file
|
||||
zip.writeZip(outputZipPath)
|
||||
|
||||
console.log(`Zipped folder to ${outputZipPath}`)
|
||||
|
||||
45
.github/workflows/type-check.yml
vendored
Normal file
45
.github/workflows/type-check.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: Type Check
|
||||
|
||||
on:
|
||||
pull_request: null
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
|
||||
env:
|
||||
NODE: 20
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
type-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Cache turbo build setup
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .turbo
|
||||
key: ${{ runner.os }}-turbo-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-turbo-
|
||||
|
||||
- name: Install PNPM
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "${{ env.NODE }}"
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install pnpm dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Run type-check
|
||||
run: pnpm run type-check
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -38,3 +38,7 @@ dist/
|
||||
packages-zip/
|
||||
.env
|
||||
sri.json
|
||||
|
||||
# TypeScript
|
||||
*.tsbuildinfo
|
||||
.tsbuildinfo
|
||||
@@ -1,18 +1,20 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { join, dirname, basename } from 'node:path';
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join, dirname, basename } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { sync } from 'glob';
|
||||
import banner from '../../shared/banner/index.mjs';
|
||||
import { sync } from 'glob'
|
||||
import banner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const styles = sync(join(__dirname, '..', 'dist', 'css', '*.css'))
|
||||
const styles: string[] = sync(join(__dirname, '..', 'dist', 'css', '*.css'))
|
||||
|
||||
const plugins = {
|
||||
interface Plugins {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
const plugins: Plugins = {
|
||||
'tabler-flags': 'Flags',
|
||||
'tabler-flags.rtl': 'Flags RTL',
|
||||
'tabler-marketing': 'Marketing',
|
||||
@@ -25,22 +27,24 @@ const plugins = {
|
||||
'tabler-vendors.rtl': 'Vendors RTL',
|
||||
}
|
||||
|
||||
styles.forEach((file, i) => {
|
||||
styles.forEach((file: string) => {
|
||||
const content = readFileSync(file, 'utf8')
|
||||
const filename = basename(file)
|
||||
const pluginKey = Object.keys(plugins).find(plugin => filename.includes(plugin))
|
||||
const plugin = plugins[pluginKey]
|
||||
const pluginKey = Object.keys(plugins).find((plugin: string) => filename.includes(plugin))
|
||||
const plugin = pluginKey ? plugins[pluginKey] : undefined
|
||||
const regex = /^(@charset ['"][a-zA-Z0-9-]+['"];?)\n?/i
|
||||
|
||||
let newContent = ''
|
||||
const bannerText = banner(plugin)
|
||||
|
||||
if (content.match(regex)) {
|
||||
newContent = content.replace(regex, (m, m1) => {
|
||||
return `${m1}\n${banner(plugin)}\n`
|
||||
newContent = content.replace(regex, (m: string, m1: string) => {
|
||||
return `${m1}\n${bannerText}\n`
|
||||
})
|
||||
} else {
|
||||
newContent = `${banner(plugin)}\n${content}`
|
||||
newContent = `${bannerText}\n${content}`
|
||||
}
|
||||
|
||||
writeFileSync(file, newContent, 'utf8')
|
||||
})
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// Get __dirname in ES modules
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// File paths (relative to core/.build directory)
|
||||
const bootstrapPath = path.join(__dirname, '../node_modules/bootstrap/scss/_variables.scss');
|
||||
const tablerPath = path.join(__dirname, '../scss/_variables.scss');
|
||||
|
||||
// Function to extract variable names from SCSS file
|
||||
function extractVariables(filePath) {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const variables = new Set();
|
||||
|
||||
// Regex to find SCSS variables
|
||||
// Looks for patterns like: $variable-name: value
|
||||
// Includes variables in maps and lists
|
||||
const variableRegex = /\$([a-zA-Z0-9_-]+)\s*[:=]/g;
|
||||
|
||||
let match;
|
||||
while ((match = variableRegex.exec(content)) !== null) {
|
||||
const varName = match[1];
|
||||
variables.add(varName);
|
||||
}
|
||||
|
||||
return variables;
|
||||
}
|
||||
|
||||
// Main function
|
||||
function compareVariables() {
|
||||
console.log('Analyzing Bootstrap variables...');
|
||||
const bootstrapVars = extractVariables(bootstrapPath);
|
||||
console.log(`Found ${bootstrapVars.size} variables in Bootstrap\n`);
|
||||
|
||||
console.log('Analyzing Tabler variables...');
|
||||
const tablerVars = extractVariables(tablerPath);
|
||||
console.log(`Found ${tablerVars.size} variables in Tabler\n`);
|
||||
|
||||
// Find variables that are in Bootstrap but not in Tabler
|
||||
const missingInTabler = [];
|
||||
for (const varName of bootstrapVars) {
|
||||
if (!tablerVars.has(varName)) {
|
||||
missingInTabler.push(varName);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort alphabetically
|
||||
missingInTabler.sort();
|
||||
|
||||
console.log('='.repeat(60));
|
||||
console.log(`Variables in Bootstrap that are missing in Tabler: ${missingInTabler.length}`);
|
||||
console.log('='.repeat(60));
|
||||
|
||||
if (missingInTabler.length === 0) {
|
||||
console.log('All Bootstrap variables are present in Tabler!');
|
||||
} else {
|
||||
console.log('\nList of missing variables:\n');
|
||||
missingInTabler.forEach((varName, index) => {
|
||||
console.log(`${(index + 1).toString().padStart(4)}. $${varName}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Optionally: show statistics
|
||||
console.log('\n' + '='.repeat(60));
|
||||
console.log('Statistics:');
|
||||
console.log(` Bootstrap: ${bootstrapVars.size} variables`);
|
||||
console.log(` Tabler: ${tablerVars.size} variables`);
|
||||
console.log(` Missing: ${missingInTabler.length} variables`);
|
||||
console.log(` Coverage: ${((1 - missingInTabler.length / bootstrapVars.size) * 100).toFixed(1)}%`);
|
||||
console.log('='.repeat(60));
|
||||
}
|
||||
|
||||
// Run analysis
|
||||
try {
|
||||
compareVariables();
|
||||
} catch (error) {
|
||||
console.error('Error during analysis:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
84
core/.build/compare-variables.ts
Normal file
84
core/.build/compare-variables.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
// Get __dirname in ES modules
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
|
||||
// File paths (relative to core/.build directory)
|
||||
const bootstrapPath = path.join(__dirname, '../node_modules/bootstrap/scss/_variables.scss')
|
||||
const tablerPath = path.join(__dirname, '../scss/_variables.scss')
|
||||
|
||||
// Function to extract variable names from SCSS file
|
||||
function extractVariables(filePath: string): Set<string> {
|
||||
const content = readFileSync(filePath, 'utf8')
|
||||
const variables = new Set<string>()
|
||||
|
||||
// Regex to find SCSS variables
|
||||
// Looks for patterns like: $variable-name: value
|
||||
// Includes variables in maps and lists
|
||||
const variableRegex = /\$([a-zA-Z0-9_-]+)\s*[:=]/g
|
||||
|
||||
let match: RegExpExecArray | null
|
||||
while ((match = variableRegex.exec(content)) !== null) {
|
||||
const varName = match[1]
|
||||
variables.add(varName)
|
||||
}
|
||||
|
||||
return variables
|
||||
}
|
||||
|
||||
// Main function
|
||||
function compareVariables(): void {
|
||||
console.log('Analyzing Bootstrap variables...')
|
||||
const bootstrapVars = extractVariables(bootstrapPath)
|
||||
console.log(`Found ${bootstrapVars.size} variables in Bootstrap\n`)
|
||||
|
||||
console.log('Analyzing Tabler variables...')
|
||||
const tablerVars = extractVariables(tablerPath)
|
||||
console.log(`Found ${tablerVars.size} variables in Tabler\n`)
|
||||
|
||||
// Find variables that are in Bootstrap but not in Tabler
|
||||
const missingInTabler: string[] = []
|
||||
for (const varName of bootstrapVars) {
|
||||
if (!tablerVars.has(varName)) {
|
||||
missingInTabler.push(varName)
|
||||
}
|
||||
}
|
||||
|
||||
// Sort alphabetically
|
||||
missingInTabler.sort()
|
||||
|
||||
console.log('='.repeat(60))
|
||||
console.log(`Variables in Bootstrap that are missing in Tabler: ${missingInTabler.length}`)
|
||||
console.log('='.repeat(60))
|
||||
|
||||
if (missingInTabler.length === 0) {
|
||||
console.log('All Bootstrap variables are present in Tabler!')
|
||||
} else {
|
||||
console.log('\nList of missing variables:\n')
|
||||
missingInTabler.forEach((varName: string, index: number) => {
|
||||
console.log(`${(index + 1).toString().padStart(4)}. $${varName}`)
|
||||
})
|
||||
}
|
||||
|
||||
// Optionally: show statistics
|
||||
console.log('\n' + '='.repeat(60))
|
||||
console.log('Statistics:')
|
||||
console.log(` Bootstrap: ${bootstrapVars.size} variables`)
|
||||
console.log(` Tabler: ${tablerVars.size} variables`)
|
||||
console.log(` Missing: ${missingInTabler.length} variables`)
|
||||
console.log(` Coverage: ${((1 - missingInTabler.length / bootstrapVars.size) * 100).toFixed(1)}%`)
|
||||
console.log('='.repeat(60))
|
||||
}
|
||||
|
||||
// Run analysis
|
||||
try {
|
||||
compareVariables()
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error during analysis:', errorMessage)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,30 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
import { existsSync, mkdirSync, lstatSync } from 'fs'
|
||||
import { existsSync, mkdirSync } from 'node:fs'
|
||||
import { emptyDirSync, copySync } from 'fs-extra/esm'
|
||||
import libs from '../libs.json' with { type: 'json' }
|
||||
import { fileURLToPath } from 'url'
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join, dirname } from 'node:path'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
interface LibConfig {
|
||||
npm?: string
|
||||
js?: string[]
|
||||
css?: string[]
|
||||
head?: boolean
|
||||
}
|
||||
|
||||
interface Libs {
|
||||
[key: string]: LibConfig
|
||||
}
|
||||
|
||||
const libsData = libs as Libs
|
||||
|
||||
emptyDirSync(join(__dirname, '..', 'dist/libs'))
|
||||
|
||||
for(const name in libs) {
|
||||
const { npm } = libs[name]
|
||||
for (const name in libsData) {
|
||||
const { npm } = libsData[name]
|
||||
|
||||
if (npm) {
|
||||
const from = join(__dirname, '..', `node_modules/${npm}`)
|
||||
@@ -31,3 +42,4 @@ for(const name in libs) {
|
||||
console.log(`Successfully copied ${npm}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
const crypto = require('node:crypto');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
import * as crypto from 'node:crypto'
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const configFile = path.join(__dirname, '../../shared/data/sri.json')
|
||||
|
||||
const files = [
|
||||
interface FileConfig {
|
||||
file: string
|
||||
configPropertyName: string
|
||||
}
|
||||
|
||||
const files: FileConfig[] = [
|
||||
{
|
||||
file: 'dist/css/tabler.min.css',
|
||||
configPropertyName: 'css'
|
||||
@@ -79,13 +87,13 @@ const files = [
|
||||
},
|
||||
]
|
||||
|
||||
function generateSRI() {
|
||||
const sriData = {}
|
||||
function generateSRI(): void {
|
||||
const sriData: Record<string, string> = {}
|
||||
|
||||
for (const { file, configPropertyName } of files) {
|
||||
try {
|
||||
const filePath = path.join(__dirname, '..', file)
|
||||
const data = fs.readFileSync(filePath, 'utf8')
|
||||
const data = readFileSync(filePath, 'utf8')
|
||||
|
||||
const algorithm = 'sha384'
|
||||
const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64')
|
||||
@@ -95,12 +103,13 @@ function generateSRI() {
|
||||
|
||||
sriData[configPropertyName] = integrity
|
||||
} catch (error) {
|
||||
console.error(`Error processing ${file}:`, error.message)
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error(`Error processing ${file}:`, errorMessage)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(configFile, JSON.stringify(sriData, null, 2) + '\n', 'utf8')
|
||||
writeFileSync(configFile, JSON.stringify(sriData, null, 2) + '\n', 'utf8')
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -109,3 +118,4 @@ try {
|
||||
console.error('Failed to generate SRI:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
import { existsSync, mkdirSync } from 'fs'
|
||||
import { existsSync, mkdirSync } from 'node:fs'
|
||||
import { copySync } from 'fs-extra/esm'
|
||||
import { fileURLToPath } from 'url'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join, dirname } from 'node:path'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
@@ -1,7 +1,8 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper.mjs'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper'
|
||||
import getBanner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
@@ -9,18 +10,24 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const ESM = process.env.ESM === 'true'
|
||||
const THEME = process.env.THEME === 'true'
|
||||
|
||||
const MINIFY = process.env.MINIFY === 'true'
|
||||
const destinationFile = `tabler${THEME ? '-theme' : ''}${ESM ? '.esm' : ''}`
|
||||
const entryFile = `tabler${THEME ? '-theme' : ''}`
|
||||
const libraryName = `tabler${THEME ? '-theme' : ''}`
|
||||
|
||||
const bannerText = getBanner()
|
||||
|
||||
// Try .ts first, fallback to .js for gradual migration
|
||||
const entryPath = path.resolve(__dirname, `../js/${entryFile}`)
|
||||
const entry = existsSync(`${entryPath}.ts`) ? `${entryPath}.ts` : `${entryPath}.js`
|
||||
|
||||
export default createViteConfig({
|
||||
entry: path.resolve(__dirname, `../js/${entryFile}.js`),
|
||||
entry: entry,
|
||||
name: ESM ? undefined : libraryName,
|
||||
fileName: () => `${destinationFile}.js`,
|
||||
fileName: () => MINIFY ? `${destinationFile}.min.js` : `${destinationFile}.js`,
|
||||
formats: [ESM ? 'es' : 'umd'],
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: bannerText
|
||||
banner: bannerText,
|
||||
minify: MINIFY ? true : false
|
||||
})
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
// Autosize plugin
|
||||
const elements = document.querySelectorAll('[data-bs-toggle="autosize"]')
|
||||
|
||||
if (elements.length) {
|
||||
elements.forEach(function (element) {
|
||||
window.autosize && window.autosize(element)
|
||||
})
|
||||
}
|
||||
10
core/js/src/autosize.ts
Normal file
10
core/js/src/autosize.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
// Autosize plugin
|
||||
const autosizeElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>('[data-bs-toggle="autosize"]')
|
||||
|
||||
if (autosizeElements.length) {
|
||||
autosizeElements.forEach(function (element: HTMLElement) {
|
||||
if (window.autosize) {
|
||||
window.autosize(element)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,17 +1,19 @@
|
||||
const elements = document.querySelectorAll('[data-countup]')
|
||||
const countupElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>('[data-countup]')
|
||||
|
||||
if (elements.length) {
|
||||
elements.forEach(function (element) {
|
||||
let options = {}
|
||||
if (countupElements.length) {
|
||||
countupElements.forEach(function (element: HTMLElement) {
|
||||
let options: Record<string, any> = {}
|
||||
try {
|
||||
const dataOptions = element.getAttribute('data-countup') ? JSON.parse(element.getAttribute('data-countup')) : {}
|
||||
const dataOptions = element.getAttribute('data-countup') ? JSON.parse(element.getAttribute('data-countup')!) : {}
|
||||
options = Object.assign(
|
||||
{
|
||||
enableScrollSpy: true,
|
||||
},
|
||||
dataOptions,
|
||||
)
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
// ignore invalid JSON
|
||||
}
|
||||
|
||||
const value = parseInt(element.innerHTML, 10)
|
||||
|
||||
@@ -3,9 +3,9 @@ import { Dropdown } from './bootstrap'
|
||||
/*
|
||||
Core dropdowns
|
||||
*/
|
||||
let dropdownTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="dropdown"]'))
|
||||
dropdownTriggerList.map(function (dropdownTriggerEl) {
|
||||
let options = {
|
||||
const dropdownTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="dropdown"]'))
|
||||
dropdownTriggerList.map(function (dropdownTriggerEl: HTMLElement) {
|
||||
const options = {
|
||||
boundary: dropdownTriggerEl.getAttribute('data-bs-boundary') === 'viewport' ? document.querySelector('.btn') : 'clippingParents',
|
||||
}
|
||||
return new Dropdown(dropdownTriggerEl, options)
|
||||
14
core/js/src/global.d.ts
vendored
Normal file
14
core/js/src/global.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// Global type declarations for window properties
|
||||
|
||||
interface Window {
|
||||
autosize?: (element: HTMLElement | HTMLTextAreaElement) => void
|
||||
countUp?: {
|
||||
CountUp: new (target: HTMLElement, endVal: number, options?: any) => {
|
||||
error: boolean
|
||||
start: () => void
|
||||
}
|
||||
}
|
||||
IMask?: new (element: HTMLElement, options: { mask: string; lazy?: boolean }) => any
|
||||
Sortable?: new (element: HTMLElement, options?: any) => any
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Input mask plugin
|
||||
|
||||
var maskElementList = [].slice.call(document.querySelectorAll('[data-mask]'))
|
||||
maskElementList.map(function (maskEl) {
|
||||
const maskElementList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-mask]'))
|
||||
maskElementList.map(function (maskEl: HTMLElement) {
|
||||
window.IMask &&
|
||||
new window.IMask(maskEl, {
|
||||
mask: maskEl.dataset.mask,
|
||||
@@ -3,9 +3,9 @@ import { Popover } from './bootstrap'
|
||||
/*
|
||||
Core popovers
|
||||
*/
|
||||
let popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
|
||||
popoverTriggerList.map(function (popoverTriggerEl) {
|
||||
let options = {
|
||||
const popoverTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="popover"]'))
|
||||
popoverTriggerList.map(function (popoverTriggerEl: HTMLElement) {
|
||||
const options = {
|
||||
delay: { show: 50, hide: 50 },
|
||||
html: popoverTriggerEl.getAttribute('data-bs-html') === 'true',
|
||||
placement: popoverTriggerEl.getAttribute('data-bs-placement') ?? 'auto',
|
||||
@@ -2,11 +2,11 @@
|
||||
// Initializes Sortable on elements marked with [data-sortable]
|
||||
// Allows options via JSON in data attribute: data-sortable='{"animation":150}'
|
||||
|
||||
const sortableElements = document.querySelectorAll('[data-sortable]')
|
||||
const sortableElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>('[data-sortable]')
|
||||
|
||||
if (sortableElements.length) {
|
||||
sortableElements.forEach(function (element) {
|
||||
let options = {}
|
||||
sortableElements.forEach(function (element: HTMLElement) {
|
||||
let options: Record<string, any> = {}
|
||||
|
||||
try {
|
||||
const rawOptions = element.getAttribute('data-sortable')
|
||||
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
Switch icons
|
||||
*/
|
||||
let switchesTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="switch-icon"]'))
|
||||
switchesTriggerList.map(function (switchTriggerEl) {
|
||||
switchTriggerEl.addEventListener('click', (e) => {
|
||||
e.stopPropagation()
|
||||
|
||||
switchTriggerEl.classList.toggle('active')
|
||||
})
|
||||
})
|
||||
11
core/js/src/switch-icon.ts
Normal file
11
core/js/src/switch-icon.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Switch icons
|
||||
*/
|
||||
const switchesTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="switch-icon"]'))
|
||||
switchesTriggerList.map(function (switchTriggerEl: HTMLElement) {
|
||||
switchTriggerEl.addEventListener('click', (e: MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
|
||||
switchTriggerEl.classList.toggle('active')
|
||||
})
|
||||
})
|
||||
@@ -1,16 +0,0 @@
|
||||
import { Tab } from './bootstrap'
|
||||
|
||||
export const EnableActivationTabsFromLocationHash = () => {
|
||||
const locationHash = window.location.hash
|
||||
|
||||
if (locationHash) {
|
||||
const tabsList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tab"]'))
|
||||
const matchedTabs = tabsList.filter((tab) => tab.hash === locationHash)
|
||||
|
||||
matchedTabs.map((tab) => {
|
||||
new Tab(tab).show()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
EnableActivationTabsFromLocationHash()
|
||||
16
core/js/src/tab.ts
Normal file
16
core/js/src/tab.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Tab } from './bootstrap'
|
||||
|
||||
export const EnableActivationTabsFromLocationHash = (): void => {
|
||||
const locationHash: string = window.location.hash
|
||||
|
||||
if (locationHash) {
|
||||
const tabsList: HTMLAnchorElement[] = [].slice.call(document.querySelectorAll<HTMLAnchorElement>('[data-bs-toggle="tab"]'))
|
||||
const matchedTabs = tabsList.filter((tab: HTMLAnchorElement) => tab.hash === locationHash)
|
||||
|
||||
matchedTabs.map((tab: HTMLAnchorElement) => {
|
||||
new Tab(tab).show()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
EnableActivationTabsFromLocationHash()
|
||||
@@ -1,12 +1,12 @@
|
||||
export const prefix = 'tblr-'
|
||||
export const prefix: string = 'tblr-'
|
||||
|
||||
export const hexToRgba = (hex, opacity) => {
|
||||
export const hexToRgba = (hex: string, opacity: number): string | null => {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
||||
|
||||
return result ? `rgba(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}, ${opacity})` : null
|
||||
}
|
||||
|
||||
export const getColor = (color, opacity = 1) => {
|
||||
export const getColor = (color: string, opacity: number = 1): string | null => {
|
||||
const c = getComputedStyle(document.body).getPropertyValue(`--${prefix}${color}`).trim()
|
||||
|
||||
if (opacity !== 1) {
|
||||
@@ -1,17 +0,0 @@
|
||||
import { Toast } from './bootstrap'
|
||||
|
||||
/*
|
||||
Toasts
|
||||
*/
|
||||
let toastsTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="toast"]'))
|
||||
toastsTriggerList.map(function (toastTriggerEl) {
|
||||
if (!toastTriggerEl.hasAttribute('data-bs-target')) {
|
||||
return
|
||||
}
|
||||
|
||||
const toastEl = new Toast(toastTriggerEl.getAttribute('data-bs-target'))
|
||||
|
||||
toastTriggerEl.addEventListener('click', () => {
|
||||
toastEl.show()
|
||||
})
|
||||
})
|
||||
18
core/js/src/toast.ts
Normal file
18
core/js/src/toast.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Toast } from './bootstrap'
|
||||
|
||||
/*
|
||||
Toasts
|
||||
*/
|
||||
const toastsTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="toast"]'))
|
||||
toastsTriggerList.map(function (toastTriggerEl: HTMLElement) {
|
||||
const target = toastTriggerEl.getAttribute('data-bs-target')
|
||||
if (target === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const toastEl = new Toast(target)
|
||||
|
||||
toastTriggerEl.addEventListener('click', () => {
|
||||
toastEl.show()
|
||||
})
|
||||
})
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Tooltip } from './bootstrap'
|
||||
|
||||
let tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
let options = {
|
||||
const tooltipTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="tooltip"]'))
|
||||
tooltipTriggerList.map(function (tooltipTriggerEl: HTMLElement) {
|
||||
const options = {
|
||||
delay: { show: 50, hide: 50 },
|
||||
html: tooltipTriggerEl.getAttribute('data-bs-html') === 'true',
|
||||
placement: tooltipTriggerEl.getAttribute('data-bs-placement') ?? 'auto',
|
||||
@@ -3,7 +3,15 @@
|
||||
* to ensure we switch to the chosen dark/light theme as fast as possible.
|
||||
* This will prevent any flashes of the light theme (default) before switching.
|
||||
*/
|
||||
const themeConfig = {
|
||||
interface ThemeConfig {
|
||||
'theme': string
|
||||
'theme-base': string
|
||||
'theme-font': string
|
||||
'theme-primary': string
|
||||
'theme-radius': string
|
||||
}
|
||||
|
||||
const themeConfig: ThemeConfig = {
|
||||
'theme': 'light',
|
||||
'theme-base': 'gray',
|
||||
'theme-font': 'sans-serif',
|
||||
@@ -12,22 +20,22 @@ const themeConfig = {
|
||||
}
|
||||
|
||||
const params = new Proxy(new URLSearchParams(window.location.search), {
|
||||
get: (searchParams, prop) => searchParams.get(prop),
|
||||
get: (searchParams: URLSearchParams, prop: string): string | null => searchParams.get(prop),
|
||||
})
|
||||
|
||||
for (const key in themeConfig) {
|
||||
const param = params[key]
|
||||
let selectedValue
|
||||
let selectedValue: string
|
||||
|
||||
if (!!param) {
|
||||
localStorage.setItem('tabler-' + key, param)
|
||||
selectedValue = param
|
||||
} else {
|
||||
const storedTheme = localStorage.getItem('tabler-' + key)
|
||||
selectedValue = storedTheme ? storedTheme : themeConfig[key]
|
||||
selectedValue = storedTheme ? storedTheme : themeConfig[key as keyof ThemeConfig]
|
||||
}
|
||||
|
||||
if (selectedValue !== themeConfig[key]) {
|
||||
if (selectedValue !== themeConfig[key as keyof ThemeConfig]) {
|
||||
document.documentElement.setAttribute('data-bs-' + key, selectedValue)
|
||||
} else {
|
||||
document.documentElement.removeAttribute('data-bs-' + key)
|
||||
@@ -9,7 +9,7 @@ import './src/tab'
|
||||
import './src/toast'
|
||||
import './src/sortable'
|
||||
|
||||
// Re-export everything from bootstrap.js (single source of truth)
|
||||
// Re-export everything from bootstrap.ts (single source of truth)
|
||||
export * from './src/bootstrap'
|
||||
|
||||
// Re-export tabler namespace
|
||||
@@ -8,9 +8,9 @@
|
||||
"build": "pnpm run clean && pnpm run build-assets && pnpm run copy && pnpm run generate-sri",
|
||||
"build-assets": "concurrently \"pnpm run css\" \"pnpm run js\"",
|
||||
"clean": "shx rm -rf dist demo",
|
||||
"css": "pnpm run css-compile && pnpm run css-prefix && pnpm run css-rtl && pnpm run css-minify && pnpm run css-banner",
|
||||
"css-compile": "sass --no-source-map --load-path=node_modules --style expanded scss/:dist/css/",
|
||||
"css-banner": "node .build/add-banner.mjs",
|
||||
"css": "pnpm run css-build && pnpm run css-prefix && pnpm run css-rtl && pnpm run css-minify && pnpm run css-banner",
|
||||
"css-build": "sass --no-source-map --load-path=node_modules --style expanded scss/:dist/css/",
|
||||
"css-banner": "tsx .build/add-banner.ts",
|
||||
"css-prefix": "postcss --config .build/postcss.config.mjs --replace \"dist/css/*.css\" \"!dist/css/*.rtl*.css\" \"!dist/css/*.min.css\"",
|
||||
"css-rtl": "cross-env NODE_ENV=RTL postcss --config .build/postcss.config.mjs --dir \"dist/css\" --ext \".rtl.css\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*.rtl.css\"",
|
||||
"css-minify": "concurrently \"pnpm run css-minify-main\" \"pnpm run css-minify-rtl\"",
|
||||
@@ -18,29 +18,30 @@
|
||||
"css-minify-rtl": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/css/ --batch --batch-suffix \".min\" \"dist/css/*rtl.css\" \"!dist/css/*.min.css\"",
|
||||
"css-lint": "pnpm run css-lint-variables",
|
||||
"css-lint-variables": "find-unused-sass-variables scss/ node_modules/bootstrap/scss/",
|
||||
"js": "pnpm run js-compile && pnpm run js-minify",
|
||||
"js-compile": "concurrently \"pnpm run js-compile-standalone\" \"pnpm run js-compile-standalone-esm\" \"pnpm run js-compile-theme\" \"pnpm run js-compile-theme-esm\"",
|
||||
"js-compile-theme-esm": "cross-env THEME=true ESM=true vite build --config .build/vite.config.mjs",
|
||||
"js-compile-theme": "cross-env THEME=true vite build --config .build/vite.config.mjs",
|
||||
"js-compile-standalone": "vite build --config .build/vite.config.mjs",
|
||||
"js-compile-standalone-esm": "cross-env ESM=true vite build --config .build/vite.config.mjs",
|
||||
"js-minify": "concurrently \"pnpm run js-minify-standalone\" \"pnpm run js-minify-standalone-esm\" \"pnpm run js-minify-theme\" \"pnpm run js-minify-theme-esm\"",
|
||||
"js-minify-standalone": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler.js.map,includeSources,url=tabler.min.js.map\" --output dist/js/tabler.min.js dist/js/tabler.js",
|
||||
"js-minify-standalone-esm": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler.esm.js.map,includeSources,url=tabler.esm.min.js.map\" --output dist/js/tabler.esm.min.js dist/js/tabler.esm.js",
|
||||
"js-minify-theme": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler-theme.js.map,includeSources,url=tabler-theme.min.js.map\" --output dist/js/tabler-theme.min.js dist/js/tabler-theme.js",
|
||||
"js-minify-theme-esm": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler-theme.esm.js.map,includeSources,url=tabler-theme.esm.min.js.map\" --output dist/js/tabler-theme.esm.min.js dist/js/tabler-theme.esm.js",
|
||||
"js": "pnpm run js-build && pnpm run js-build-min",
|
||||
"js-build": "concurrently \"pnpm run js-build-standalone\" \"pnpm run js-build-standalone-esm\" \"pnpm run js-build-theme\" \"pnpm run js-build-theme-esm\"",
|
||||
"js-build-theme-esm": "cross-env THEME=true ESM=true vite build --config .build/vite.config.ts",
|
||||
"js-build-theme": "cross-env THEME=true vite build --config .build/vite.config.ts",
|
||||
"js-build-standalone": "vite build --config .build/vite.config.ts",
|
||||
"js-build-standalone-esm": "cross-env ESM=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min": "concurrently \"pnpm run js-build-min-standalone\" \"pnpm run js-build-min-standalone-esm\" \"pnpm run js-build-min-theme\" \"pnpm run js-build-min-theme-esm\"",
|
||||
"js-build-min-standalone": "cross-env MINIFY=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-standalone-esm": "cross-env MINIFY=true ESM=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-theme": "cross-env MINIFY=true THEME=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-theme-esm": "cross-env MINIFY=true THEME=true ESM=true vite build --config .build/vite.config.ts",
|
||||
"copy": "concurrently \"pnpm run copy-img\" \"pnpm run copy-libs\" \"pnpm run copy-fonts\"",
|
||||
"copy-img": "shx mkdir -p dist/img && shx cp -rf img/* dist/img",
|
||||
"copy-libs": "node .build/copy-libs.mjs",
|
||||
"copy-libs": "tsx .build/copy-libs.ts",
|
||||
"copy-fonts": "shx mkdir -p dist/fonts && shx cp -rf fonts/* dist/fonts",
|
||||
"import-fonts": "node .build/import-fonts.mjs",
|
||||
"import-fonts": "tsx .build/import-fonts.ts",
|
||||
"watch": "concurrently \"pnpm run watch-css\" \"pnpm run watch-js\"",
|
||||
"watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css-compile && pnpm run css-prefix\"",
|
||||
"watch-js": "nodemon --watch js/ --ext js --exec \"pnpm run js-compile\"",
|
||||
"watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css-build && pnpm run css-prefix\"",
|
||||
"watch-js": "nodemon --watch js/ --ext ts,js --exec \"pnpm run js-build\"",
|
||||
"bundlewatch": "bundlewatch",
|
||||
"generate-sri": "node .build/generate-sri.js",
|
||||
"format:check": "prettier --check \"scss/**/*.scss\" \"js/**/*.js\" --cache",
|
||||
"format:write": "prettier --write \"scss/**/*.scss\" \"js/**/*.js\" --cache"
|
||||
"generate-sri": "tsx .build/generate-sri.ts",
|
||||
"format:check": "prettier --check \"scss/**/*.scss\" \"js/**/*.{js,ts}\" --cache",
|
||||
"format:write": "prettier --write \"scss/**/*.scss\" \"js/**/*.{js,ts}\" --cache",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -70,7 +71,7 @@
|
||||
"files": [
|
||||
"docs/**/*",
|
||||
"dist/**/*",
|
||||
"js/**/*.{js,map}",
|
||||
"js/**/*.{ts,js,map}",
|
||||
"img/**/*.{svg}",
|
||||
"scss/**/*.scss",
|
||||
"libs.json"
|
||||
@@ -156,6 +157,7 @@
|
||||
"devDependencies": {
|
||||
"@hotwired/turbo": "^8.0.18",
|
||||
"@melloware/coloris": "^0.25.0",
|
||||
"@types/node": "^22.0.0",
|
||||
"apexcharts": "^5.3.6",
|
||||
"autosize": "^6.0.1",
|
||||
"choices.js": "^11.1.0",
|
||||
@@ -179,6 +181,7 @@
|
||||
"star-rating.js": "^4.3.1",
|
||||
"tom-select": "^2.4.3",
|
||||
"typed.js": "^2.1.0",
|
||||
"typescript": "^5.9.3",
|
||||
"driver.js": "^1.0.0"
|
||||
},
|
||||
"directories": {
|
||||
|
||||
30
core/tsconfig.json
Normal file
30
core/tsconfig.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2015",
|
||||
"module": "ES2020",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"moduleResolution": "bundler",
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": false,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"sourceMap": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"js/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
export default createViteConfig({
|
||||
entry: path.resolve(__dirname, '../js/docs.js'),
|
||||
name: 'docs',
|
||||
fileName: () => 'docs.js',
|
||||
formats: ['es'],
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: undefined
|
||||
})
|
||||
|
||||
25
docs/.build/vite.config.ts
Normal file
25
docs/.build/vite.config.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper'
|
||||
import getBanner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const MINIFY = process.env.MINIFY === 'true'
|
||||
|
||||
// Try .ts first, fallback to .js for gradual migration
|
||||
const entryPath = path.resolve(__dirname, '../js/docs')
|
||||
const entry = existsSync(`${entryPath}.ts`) ? `${entryPath}.ts` : `${entryPath}.js`
|
||||
|
||||
export default createViteConfig({
|
||||
entry: entry,
|
||||
name: 'docs',
|
||||
fileName: () => MINIFY ? 'docs.min.js' : 'docs.js',
|
||||
formats: ['es'],
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: undefined,
|
||||
minify: MINIFY
|
||||
})
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import docsearch from '@docsearch/js';
|
||||
import docsearch from '@docsearch/js'
|
||||
|
||||
docsearch({
|
||||
container: '#docsearch',
|
||||
appId: "NE1EGTYLS9",
|
||||
indexName: "tabler",
|
||||
apiKey: "016353235ef1dd32a6c392be0e939058",
|
||||
});
|
||||
})
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
"build": "pnpm run clean && pnpm run build-assets && pnpm run html",
|
||||
"build-assets": "concurrently \"pnpm run js\" \"pnpm run css\"",
|
||||
"html": "eleventy",
|
||||
"js": "pnpm run js-compile && pnpm run js-minify",
|
||||
"js-compile": "vite build --config .build/vite.config.mjs",
|
||||
"js-minify": "pnpm run js-minify-docs",
|
||||
"js-minify-docs": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/docs.js.map,includeSources,url=docs.min.js.map\" --output dist/js/docs.min.js dist/js/docs.js",
|
||||
"css": "pnpm run css-compile && pnpm run css-prefix && pnpm run css-minify",
|
||||
"css-compile": "sass scss/:dist/css/ --no-source-map --load-path=./node_modules",
|
||||
"js": "pnpm run js-build && pnpm run js-build-min",
|
||||
"js-build": "vite build --config .build/vite.config.ts",
|
||||
"js-build-min": "pnpm run js-build-min-docs",
|
||||
"js-build-min-docs": "cross-env MINIFY=true vite build --config .build/vite.config.ts",
|
||||
"css": "pnpm run css-build && pnpm run css-prefix && pnpm run css-minify",
|
||||
"css-build": "sass scss/:dist/css/ --no-source-map --load-path=./node_modules",
|
||||
"css-prefix": "postcss --config .build/postcss.config.mjs --replace \"dist/css/*.css\" \"!dist/css/*.rtl*.css\" \"!dist/css/*.min.css\"",
|
||||
"css-minify": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/css/ --batch --batch-suffix \".min\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*rtl*.css\"",
|
||||
"dev": "pnpm run clean && pnpm run watch",
|
||||
|
||||
@@ -7,13 +7,14 @@
|
||||
"dev": "turbo dev",
|
||||
"clean": "turbo clean",
|
||||
"bundlewatch": "turbo bundlewatch",
|
||||
"type-check": "turbo type-check",
|
||||
"version": "changeset version",
|
||||
"publish": "changeset publish",
|
||||
"playwright": "pnpm run build && pnpm run vt",
|
||||
"reformat-md": "node .build/reformat-md.mjs",
|
||||
"reformat-md": "tsx .build/reformat-mdx.ts",
|
||||
"lint": "pnpm run lint-md",
|
||||
"lint-md": "markdownlint docs/content/**/*.md",
|
||||
"zip-package": "node .build/zip-package.mjs",
|
||||
"zip-package": "tsx .build/zip-package.ts",
|
||||
"start": "pnpm dev"
|
||||
},
|
||||
"packageManager": "pnpm@10.27.0",
|
||||
@@ -45,6 +46,7 @@
|
||||
"shelljs": "^0.10.0",
|
||||
"terser": "^5.44.1",
|
||||
"turbo": "^2.7.3",
|
||||
"tsx": "^4.21.0",
|
||||
"vite": "^7.3.0"
|
||||
}
|
||||
}
|
||||
77
pnpm-lock.yaml
generated
77
pnpm-lock.yaml
generated
@@ -20,7 +20,7 @@ importers:
|
||||
version: 0.5.2
|
||||
'@changesets/cli':
|
||||
specifier: ^2.29.8
|
||||
version: 2.29.8
|
||||
version: 2.29.8(@types/node@22.19.3)
|
||||
'@playwright/test':
|
||||
specifier: ^1.57.0
|
||||
version: 1.57.0
|
||||
@@ -65,7 +65,7 @@ importers:
|
||||
version: 8.5.6
|
||||
postcss-cli:
|
||||
specifier: ^11.0.1
|
||||
version: 11.0.1(postcss@8.5.6)
|
||||
version: 11.0.1(postcss@8.5.6)(tsx@4.21.0)
|
||||
prettier:
|
||||
specifier: ^3.7.4
|
||||
version: 3.7.4
|
||||
@@ -81,12 +81,15 @@ importers:
|
||||
terser:
|
||||
specifier: ^5.44.1
|
||||
version: 5.44.1
|
||||
tsx:
|
||||
specifier: ^4.21.0
|
||||
version: 4.21.0
|
||||
turbo:
|
||||
specifier: ^2.7.3
|
||||
version: 2.7.3
|
||||
vite:
|
||||
specifier: ^7.3.0
|
||||
version: 7.3.0(sass@1.97.2)(terser@5.44.1)(yaml@2.7.1)
|
||||
version: 7.3.0(@types/node@22.19.3)(sass@1.97.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.1)
|
||||
|
||||
core:
|
||||
dependencies:
|
||||
@@ -103,6 +106,9 @@ importers:
|
||||
'@melloware/coloris':
|
||||
specifier: ^0.25.0
|
||||
version: 0.25.0
|
||||
'@types/node':
|
||||
specifier: ^22.0.0
|
||||
version: 22.19.3
|
||||
apexcharts:
|
||||
specifier: ^5.3.6
|
||||
version: 5.3.6
|
||||
@@ -175,6 +181,9 @@ importers:
|
||||
typed.js:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
typescript:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
|
||||
docs:
|
||||
dependencies:
|
||||
@@ -1207,6 +1216,9 @@ packages:
|
||||
'@types/node@12.20.55':
|
||||
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
|
||||
|
||||
'@types/node@22.19.3':
|
||||
resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==}
|
||||
|
||||
'@types/normalize-package-data@2.4.4':
|
||||
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
|
||||
|
||||
@@ -1961,6 +1973,9 @@ packages:
|
||||
resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
get-tsconfig@4.13.0:
|
||||
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
|
||||
|
||||
getpass@0.1.7:
|
||||
resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
|
||||
|
||||
@@ -2943,6 +2958,9 @@ packages:
|
||||
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
resolve-pkg-maps@1.0.0:
|
||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||
|
||||
resolve@1.22.10:
|
||||
resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -3289,6 +3307,11 @@ packages:
|
||||
tslib@2.8.1:
|
||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||
|
||||
tsx@4.21.0:
|
||||
resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
tunnel-agent@0.6.0:
|
||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
|
||||
@@ -3340,12 +3363,20 @@ packages:
|
||||
typed.js@2.1.0:
|
||||
resolution: {integrity: sha512-bDuXEf7YcaKN4g08NMTUM6G90XU25CK3bh6U0THC/Mod/QPKlEt9g/EjvbYB8x2Qwr2p6J6I3NrsoYaVnY6wsQ==}
|
||||
|
||||
typescript@5.9.3:
|
||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
|
||||
uc.micro@2.1.0:
|
||||
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
|
||||
|
||||
undefsafe@2.0.5:
|
||||
resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
|
||||
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
unist-util-is@6.0.0:
|
||||
resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==}
|
||||
|
||||
@@ -3813,7 +3844,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
'@changesets/cli@2.29.8':
|
||||
'@changesets/cli@2.29.8(@types/node@22.19.3)':
|
||||
dependencies:
|
||||
'@changesets/apply-release-plan': 7.0.14
|
||||
'@changesets/assemble-release-plan': 6.0.9
|
||||
@@ -3829,7 +3860,7 @@ snapshots:
|
||||
'@changesets/should-skip-package': 0.1.2
|
||||
'@changesets/types': 6.1.0
|
||||
'@changesets/write': 0.4.0
|
||||
'@inquirer/external-editor': 1.0.2
|
||||
'@inquirer/external-editor': 1.0.2(@types/node@22.19.3)
|
||||
'@manypkg/get-packages': 1.1.3
|
||||
ansi-colors: 4.1.3
|
||||
ci-info: 3.9.0
|
||||
@@ -4170,10 +4201,12 @@ snapshots:
|
||||
'@img/sharp-win32-x64@0.34.5':
|
||||
optional: true
|
||||
|
||||
'@inquirer/external-editor@1.0.2':
|
||||
'@inquirer/external-editor@1.0.2(@types/node@22.19.3)':
|
||||
dependencies:
|
||||
chardet: 2.1.0
|
||||
iconv-lite: 0.7.0
|
||||
optionalDependencies:
|
||||
'@types/node': 22.19.3
|
||||
|
||||
'@isaacs/balanced-match@4.0.1': {}
|
||||
|
||||
@@ -4508,6 +4541,10 @@ snapshots:
|
||||
|
||||
'@types/node@12.20.55': {}
|
||||
|
||||
'@types/node@22.19.3':
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/normalize-package-data@2.4.4': {}
|
||||
|
||||
'@types/unist@2.0.11': {}
|
||||
@@ -5265,6 +5302,10 @@ snapshots:
|
||||
|
||||
get-stream@6.0.1: {}
|
||||
|
||||
get-tsconfig@4.13.0:
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
|
||||
getpass@0.1.7:
|
||||
dependencies:
|
||||
assert-plus: 1.0.0
|
||||
@@ -6124,14 +6165,14 @@ snapshots:
|
||||
|
||||
pnpm@10.6.5: {}
|
||||
|
||||
postcss-cli@11.0.1(postcss@8.5.6):
|
||||
postcss-cli@11.0.1(postcss@8.5.6)(tsx@4.21.0):
|
||||
dependencies:
|
||||
chokidar: 3.6.0
|
||||
dependency-graph: 1.0.0
|
||||
fs-extra: 11.3.3
|
||||
picocolors: 1.1.1
|
||||
postcss: 8.5.6
|
||||
postcss-load-config: 5.1.0(postcss@8.5.6)
|
||||
postcss-load-config: 5.1.0(postcss@8.5.6)(tsx@4.21.0)
|
||||
postcss-reporter: 7.1.0(postcss@8.5.6)
|
||||
pretty-hrtime: 1.0.3
|
||||
read-cache: 1.0.0
|
||||
@@ -6142,12 +6183,13 @@ snapshots:
|
||||
- jiti
|
||||
- tsx
|
||||
|
||||
postcss-load-config@5.1.0(postcss@8.5.6):
|
||||
postcss-load-config@5.1.0(postcss@8.5.6)(tsx@4.21.0):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
yaml: 2.7.1
|
||||
optionalDependencies:
|
||||
postcss: 8.5.6
|
||||
tsx: 4.21.0
|
||||
|
||||
postcss-reporter@7.1.0(postcss@8.5.6):
|
||||
dependencies:
|
||||
@@ -6317,6 +6359,8 @@ snapshots:
|
||||
|
||||
resolve-from@5.0.0: {}
|
||||
|
||||
resolve-pkg-maps@1.0.0: {}
|
||||
|
||||
resolve@1.22.10:
|
||||
dependencies:
|
||||
is-core-module: 2.16.1
|
||||
@@ -6692,6 +6736,13 @@ snapshots:
|
||||
|
||||
tslib@2.8.1: {}
|
||||
|
||||
tsx@4.21.0:
|
||||
dependencies:
|
||||
esbuild: 0.27.2
|
||||
get-tsconfig: 4.13.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
tunnel-agent@0.6.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
@@ -6731,10 +6782,14 @@ snapshots:
|
||||
|
||||
typed.js@2.1.0: {}
|
||||
|
||||
typescript@5.9.3: {}
|
||||
|
||||
uc.micro@2.1.0: {}
|
||||
|
||||
undefsafe@2.0.5: {}
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
unist-util-is@6.0.0:
|
||||
dependencies:
|
||||
'@types/unist': 3.0.3
|
||||
@@ -6801,7 +6856,7 @@ snapshots:
|
||||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.2
|
||||
|
||||
vite@7.3.0(sass@1.97.2)(terser@5.44.1)(yaml@2.7.1):
|
||||
vite@7.3.0(@types/node@22.19.3)(sass@1.97.2)(terser@5.44.1)(tsx@4.21.0)(yaml@2.7.1):
|
||||
dependencies:
|
||||
esbuild: 0.27.2
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
@@ -6810,9 +6865,11 @@ snapshots:
|
||||
rollup: 4.52.5
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 22.19.3
|
||||
fsevents: 2.3.3
|
||||
sass: 1.97.2
|
||||
terser: 5.44.1
|
||||
tsx: 4.21.0
|
||||
yaml: 2.7.1
|
||||
|
||||
webidl-conversions@3.0.1: {}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const pkgJson = path.join(__dirname, '../package.json')
|
||||
const pkg = JSON.parse(await fs.readFile(pkgJson, 'utf8'))
|
||||
|
||||
const year = new Date().getFullYear()
|
||||
|
||||
function getBanner(pluginFilename) {
|
||||
return `/*!
|
||||
* Tabler${pluginFilename ? ` ${pluginFilename}` : ''} v${pkg.version} (${pkg.homepage})
|
||||
* Copyright 2018-${year} The Tabler Authors
|
||||
* Copyright 2018-${year} codecalm.net Paweł Kuna
|
||||
* Licensed under MIT (https://github.com/tabler/tabler/blob/master/LICENSE)
|
||||
*/`
|
||||
}
|
||||
|
||||
export default getBanner
|
||||
@@ -1,18 +0,0 @@
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper.mjs'
|
||||
import getBanner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const bannerText = getBanner('Demo')
|
||||
|
||||
export default createViteConfig({
|
||||
entry: path.resolve(__dirname, '../js/demo.js'),
|
||||
name: 'demo',
|
||||
fileName: () => 'demo.js',
|
||||
formats: ['es'],
|
||||
outDir: path.resolve(__dirname, '../dist/preview/js'),
|
||||
banner: bannerText
|
||||
})
|
||||
|
||||
26
preview/.build/vite.config.ts
Normal file
26
preview/.build/vite.config.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper'
|
||||
import getBanner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const MINIFY = process.env.MINIFY === 'true'
|
||||
const bannerText = getBanner('Demo')
|
||||
|
||||
// Try .ts first, fallback to .js for gradual migration
|
||||
const entryPath = path.resolve(__dirname, '../js/demo')
|
||||
const entry = existsSync(`${entryPath}.ts`) ? `${entryPath}.ts` : `${entryPath}.js`
|
||||
|
||||
export default createViteConfig({
|
||||
entry: entry,
|
||||
name: 'demo',
|
||||
fileName: () => MINIFY ? 'demo.min.js' : 'demo.js',
|
||||
formats: ['es'],
|
||||
outDir: path.resolve(__dirname, '../dist/preview/js'),
|
||||
banner: bannerText,
|
||||
minify: MINIFY
|
||||
})
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
// Setting items
|
||||
const items = {
|
||||
interface SettingItem {
|
||||
localStorage: string
|
||||
default: string
|
||||
}
|
||||
|
||||
interface SettingsItems {
|
||||
[key: string]: SettingItem
|
||||
}
|
||||
|
||||
const items: SettingsItems = {
|
||||
"menu-position": { localStorage: "tablerMenuPosition", default: "top" },
|
||||
"menu-behavior": { localStorage: "tablerMenuBehavior", default: "sticky" },
|
||||
"container-layout": {
|
||||
@@ -9,14 +18,14 @@ const items = {
|
||||
}
|
||||
|
||||
// Theme config
|
||||
const config = {}
|
||||
const config: Record<string, string> = {}
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
const lsParams = localStorage.getItem(params.localStorage)
|
||||
config[key] = lsParams ? lsParams : params.default
|
||||
}
|
||||
|
||||
// Parse url params
|
||||
const parseUrl = () => {
|
||||
const parseUrl = (): void => {
|
||||
const search = window.location.search.substring(1)
|
||||
const params = search.split("&")
|
||||
|
||||
@@ -36,11 +45,11 @@ const parseUrl = () => {
|
||||
}
|
||||
|
||||
// Toggle form controls
|
||||
const toggleFormControls = (form) => {
|
||||
const toggleFormControls = (form: HTMLFormElement): void => {
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
const elem = form.querySelector(
|
||||
`[name="settings-${key}"][value="${config[key]}"]`,
|
||||
)
|
||||
) as HTMLInputElement | null
|
||||
|
||||
if (elem) {
|
||||
elem.checked = true
|
||||
@@ -49,27 +58,34 @@ const toggleFormControls = (form) => {
|
||||
}
|
||||
|
||||
// Submit form
|
||||
const submitForm = (form) => {
|
||||
const submitForm = (form: HTMLFormElement): void => {
|
||||
// Save data to localStorage
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
// Save to localStorage
|
||||
const value = form.querySelector(`[name="settings-${key}"]:checked`).value
|
||||
const checkedInput = form.querySelector(`[name="settings-${key}"]:checked`) as HTMLInputElement
|
||||
if (checkedInput) {
|
||||
const value = checkedInput.value
|
||||
localStorage.setItem(params.localStorage, value)
|
||||
|
||||
// Update local variables
|
||||
config[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
window.dispatchEvent(new Event("resize"))
|
||||
|
||||
// Bootstrap is available globally
|
||||
const bootstrap = (window as any).bootstrap
|
||||
if (bootstrap) {
|
||||
new bootstrap.Offcanvas(form).hide()
|
||||
}
|
||||
}
|
||||
|
||||
// Parse url
|
||||
parseUrl()
|
||||
|
||||
// Elements
|
||||
const form = document.querySelector("#offcanvas-settings")
|
||||
const form = document.querySelector("#offcanvas-settings") as HTMLFormElement | null
|
||||
|
||||
// Toggle form controls
|
||||
if (form) {
|
||||
@@ -81,3 +97,4 @@ if (form) {
|
||||
|
||||
toggleFormControls(form)
|
||||
}
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
"watch-html": "cross-env NODE_ENV=development eleventy --serve --port=3000 --watch --incremental",
|
||||
"watch-js": "nodemon --watch js/ --ext js --exec \"pnpm run js\"",
|
||||
"watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css\"",
|
||||
"css": "pnpm run css-compile && pnpm run css-prefix && pnpm run css-minify",
|
||||
"css-compile": "sass scss/:dist/preview/css/ --no-source-map --load-path=node_modules",
|
||||
"css": "pnpm run css-build && pnpm run css-prefix && pnpm run css-minify",
|
||||
"css-build": "sass scss/:dist/preview/css/ --no-source-map --load-path=node_modules",
|
||||
"css-prefix": "postcss --config .build/postcss.config.mjs --replace \"dist/preview/css/*.css\" \"!dist/preview/css/*.rtl*.css\" \"!dist/preview/css/*.min.css\"",
|
||||
"css-minify": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/preview/css/ --batch --batch-suffix \".min\" \"dist/preview/css/*.css\" \"!dist/preview/css/*.min.css\" \"!dist/preview/css/*rtl*.css\"",
|
||||
"js": "pnpm run js-compile && pnpm run js-minify",
|
||||
"js-compile": "vite build --config .build/vite.config.mjs",
|
||||
"js-minify": "pnpm run js-minify-demo",
|
||||
"js-minify-demo": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/preview/js/demo.js.map,includeSources,url=demo.min.js.map\" --output dist/preview/js/demo.min.js dist/preview/js/demo.js",
|
||||
"js": "pnpm run js-build && pnpm run js-build-min",
|
||||
"js-build": "vite build --config .build/vite.config.ts",
|
||||
"js-build-min": "pnpm run js-build-min-demo",
|
||||
"js-build-min-demo": "cross-env MINIFY=true vite build --config .build/vite.config.ts",
|
||||
"clean": "shx rm -rf dist demo",
|
||||
"html": "pnpm run html-build && pnpm run html-prettify && pnpm run html-remove-prettier-ignore",
|
||||
"html-build": "eleventy",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const pkgJson = path.join(__dirname, '../../core/package.json')
|
||||
const pkg = JSON.parse(await fs.readFile(pkgJson, 'utf8'))
|
||||
const pkg = JSON.parse(readFileSync(pkgJson, 'utf8'))
|
||||
|
||||
const year = new Date().getFullYear()
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
const elements = document.querySelectorAll('[data-countup]');
|
||||
|
||||
if (elements.length) {
|
||||
elements.forEach(function (element) {
|
||||
let options = {};
|
||||
try {
|
||||
options = element.getAttribute('data-countup') ? JSON.parse(element.getAttribute('data-countup')) : {};
|
||||
} catch (error) {}
|
||||
|
||||
const value = parseInt(element.innerHTML, 10);
|
||||
|
||||
const countUp = new window.countUp.CountUp(element, value, options);
|
||||
if (!countUp.error) {
|
||||
countUp.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import test, { expect } from '@playwright/test';
|
||||
import { argosScreenshot } from "@argos-ci/playwright"
|
||||
import fs from "fs"
|
||||
import { readdirSync } from "fs"
|
||||
import path from "path"
|
||||
|
||||
const previewDir = path.join(__dirname, "../preview/dist")
|
||||
|
||||
const htmlFiles = fs.readdirSync(previewDir).filter((file) => file.endsWith(".html"))
|
||||
const htmlFiles = readdirSync(previewDir).filter((file) => file.endsWith(".html"))
|
||||
|
||||
for (const file of htmlFiles) {
|
||||
test(`Compare ${file}`, async ({ page }) => {
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
"build"
|
||||
],
|
||||
"cache": true
|
||||
},
|
||||
"type-check": {
|
||||
"dependsOn": [
|
||||
"^type-check"
|
||||
],
|
||||
"cache": true
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user