mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Add quality gates: Prettier for Astro, astro check for shared, unused SCSS variable lint (#2749)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
4d04c102d3
commit
8962710163
552 files changed
+17998
-19543
No files matched your search
+39
-50
@@ -11,69 +11,58 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const docs: string[] = sync(join(__dirname, '..', 'docs', 'pages', '**', '*.mdx'))
|
||||
|
||||
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
|
||||
}
|
||||
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)]
|
||||
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))
|
||||
)
|
||||
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])
|
||||
})
|
||||
let result = str
|
||||
matches.forEach((match: RegExpMatchArray, i: number) => {
|
||||
result = result.replace(match[0], replacements[i])
|
||||
})
|
||||
|
||||
return result
|
||||
return result
|
||||
}
|
||||
|
||||
async function processFiles(): Promise<void> {
|
||||
for (const file of docs) {
|
||||
const oldContent = readFileSync(file, 'utf8')
|
||||
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)
|
||||
// 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, '')
|
||||
// remove empty lines
|
||||
formattedHtml = formattedHtml.replace(/^\s*[\r\n]/gm, '')
|
||||
|
||||
return m1 + formattedHtml.trim() + '\n' + m4
|
||||
}
|
||||
return m.trim()
|
||||
}
|
||||
)
|
||||
return m1 + formattedHtml.trim() + '\n' + m4
|
||||
}
|
||||
return m.trim()
|
||||
})
|
||||
|
||||
if (content !== oldContent) {
|
||||
writeFileSync(file, content, 'utf8')
|
||||
console.log(`Reformatted ${file}`)
|
||||
}
|
||||
}
|
||||
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)
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error processing files:', errorMessage)
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
@@ -3,72 +3,63 @@ 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'
|
||||
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 {
|
||||
// Vite 8 (Rolldown) always emits const bindings and no longer accepts the
|
||||
// Rollup-only generatedCode.constBindings option
|
||||
const rollupOutput: { banner?: string } = {}
|
||||
export function createViteConfig({ entry, name, fileName, formats, outDir, banner, minify = false }: CreateViteConfigOptions): UserConfig {
|
||||
// Vite 8 (Rolldown) always emits const bindings and no longer accepts the
|
||||
// Rollup-only generatedCode.constBindings option
|
||||
const rollupOutput: { banner?: string } = {}
|
||||
|
||||
// Add banner if provided
|
||||
if (banner) {
|
||||
rollupOutput.banner = banner
|
||||
}
|
||||
// Add banner if provided
|
||||
if (banner) {
|
||||
rollupOutput.banner = banner
|
||||
}
|
||||
|
||||
const config: UserConfig = {
|
||||
// These are library (JS bundle) builds, not app builds — Vite's default
|
||||
// behavior of copying <root>/public into outDir on every build is not wanted
|
||||
// here (and in @tabler/preview, where public/ is itself generated from this
|
||||
// same outDir, caused unbounded growth across repeated builds).
|
||||
publicDir: false,
|
||||
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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const config: UserConfig = {
|
||||
// These are library (JS bundle) builds, not app builds — Vite's default
|
||||
// behavior of copying <root>/public into outDir on every build is not wanted
|
||||
// here (and in @tabler/preview, where public/ is itself generated from this
|
||||
// same outDir, caused unbounded growth across repeated builds).
|
||||
publicDir: false,
|
||||
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)
|
||||
return defineConfig(config)
|
||||
}
|
||||
|
||||
+6
-20
@@ -9,38 +9,24 @@ import { readFileSync } from 'node:fs'
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
interface PackageJson {
|
||||
version: string
|
||||
[key: string]: unknown
|
||||
version: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
const pkg: PackageJson = JSON.parse(
|
||||
readFileSync(path.join(__dirname, '../core', 'package.json'), 'utf8')
|
||||
)
|
||||
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, '../shared/static', 'og.png'),
|
||||
'.',
|
||||
'preview.png'
|
||||
)
|
||||
zip.addLocalFile(path.join(__dirname, '../shared/static', 'og.png'), '.', 'preview.png')
|
||||
|
||||
zip.addFile(
|
||||
'documentation.url',
|
||||
Buffer.from('[InternetShortcut]\nURL = https://tabler.io/docs')
|
||||
)
|
||||
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`
|
||||
)
|
||||
const outputZipPath = path.join(__dirname, '../packages-zip', `tabler-${pkg.version}.zip`)
|
||||
|
||||
// Write the zip file
|
||||
zip.writeZip(outputZipPath)
|
||||
|
||||
console.log(`Zipped folder to ${outputZipPath}`)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@tabler/core': major
|
||||
---
|
||||
|
||||
Remove unused SCSS `!default` variables (deprecated Bootstrap leftovers such as `$variable-prefix`, `$alert-*-scale`, accordion icon/button variables, `$popover-arrow-*`, numbered `$font-size-*` / `$line-height-*` scales and others). Configuring any of the removed variables via `@use ... with (...)` now raises a Sass error — they had no effect on the compiled CSS before. The color shade ladders (`$blue-100`…`$cyan-900`) and per-color maps (`$blues`…`$cyans`) are kept as configurable API. Compiled CSS output is unchanged.
|
||||
@@ -3,3 +3,28 @@ dist
|
||||
.vscode
|
||||
.cache
|
||||
node_modules
|
||||
# generated / build outputs
|
||||
.astro
|
||||
coverage
|
||||
demo
|
||||
packages-zip
|
||||
preview/public
|
||||
preview/tmp-assets
|
||||
docs/public
|
||||
|
||||
# prettier-plugin-astro cannot parse HTML comments or <script> tags inside
|
||||
# JSX expressions ({cond && (<Fragment><!-- ... --><script>...)}) — these files
|
||||
# use those constructs on purpose (BEGIN/END markers emitted into demo HTML,
|
||||
# conditional inline scripts). Re-check when the plugin gains support.
|
||||
docs/layouts/DocsLayout.astro
|
||||
shared/components/cards/Card.astro
|
||||
shared/components/layout/PageHeader.astro
|
||||
shared/components/navbar/Navbar.astro
|
||||
shared/ui/Chart.astro
|
||||
shared/ui/ChartSparkline.astro
|
||||
shared/ui/Datepicker.astro
|
||||
shared/ui/InlinePlayer.astro
|
||||
shared/ui/Map.astro
|
||||
shared/ui/MapVector.astro
|
||||
shared/ui/Range.astro
|
||||
shared/ui/Select.astro
|
||||
@@ -9,12 +9,19 @@
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"trailingComma": "all",
|
||||
"plugins": ["prettier-plugin-astro"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.scss",
|
||||
"options": {
|
||||
"parser": "scss"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": "*.astro",
|
||||
"options": {
|
||||
"parser": "astro"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+26
-27
@@ -11,40 +11,39 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const styles: string[] = sync(join(__dirname, '..', 'dist', 'css', '*.css'))
|
||||
|
||||
interface Plugins {
|
||||
[key: string]: string
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
const plugins: Plugins = {
|
||||
'tabler-flags': 'Flags',
|
||||
'tabler-flags.rtl': 'Flags RTL',
|
||||
'tabler-marketing': 'Marketing',
|
||||
'tabler-marketing.rtl': 'Marketing RTL',
|
||||
'tabler-payments': 'Payments',
|
||||
'tabler-payments.rtl': 'Payments RTL',
|
||||
'tabler-socials': 'Socials',
|
||||
'tabler-socials.rtl': 'Socials RTL',
|
||||
'tabler-vendors': 'Vendors',
|
||||
'tabler-vendors.rtl': 'Vendors RTL',
|
||||
'tabler-flags': 'Flags',
|
||||
'tabler-flags.rtl': 'Flags RTL',
|
||||
'tabler-marketing': 'Marketing',
|
||||
'tabler-marketing.rtl': 'Marketing RTL',
|
||||
'tabler-payments': 'Payments',
|
||||
'tabler-payments.rtl': 'Payments RTL',
|
||||
'tabler-socials': 'Socials',
|
||||
'tabler-socials.rtl': 'Socials RTL',
|
||||
'tabler-vendors': 'Vendors',
|
||||
'tabler-vendors.rtl': 'Vendors RTL',
|
||||
}
|
||||
|
||||
styles.forEach((file: string) => {
|
||||
const content = readFileSync(file, 'utf8')
|
||||
const filename = basename(file)
|
||||
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
|
||||
const content = readFileSync(file, 'utf8')
|
||||
const filename = basename(file)
|
||||
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)
|
||||
let newContent = ''
|
||||
const bannerText = banner(plugin)
|
||||
|
||||
if (content.match(regex)) {
|
||||
newContent = content.replace(regex, (m: string, m1: string) => {
|
||||
return `${m1}\n${bannerText}\n`
|
||||
})
|
||||
} else {
|
||||
newContent = `${bannerText}\n${content}`
|
||||
}
|
||||
if (content.match(regex)) {
|
||||
newContent = content.replace(regex, (m: string, m1: string) => {
|
||||
return `${m1}\n${bannerText}\n`
|
||||
})
|
||||
} else {
|
||||
newContent = `${bannerText}\n${content}`
|
||||
}
|
||||
|
||||
writeFileSync(file, newContent, 'utf8')
|
||||
writeFileSync(file, newContent, 'utf8')
|
||||
})
|
||||
|
||||
@@ -12,73 +12,72 @@ 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>()
|
||||
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
|
||||
// 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)
|
||||
}
|
||||
let match: RegExpExecArray | null
|
||||
while ((match = variableRegex.exec(content)) !== null) {
|
||||
const varName = match[1]
|
||||
variables.add(varName)
|
||||
}
|
||||
|
||||
return variables
|
||||
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 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`)
|
||||
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)
|
||||
}
|
||||
}
|
||||
// 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()
|
||||
// Sort alphabetically
|
||||
missingInTabler.sort()
|
||||
|
||||
console.log('='.repeat(60))
|
||||
console.log(`Variables in Bootstrap that are missing in Tabler: ${missingInTabler.length}`)
|
||||
console.log('='.repeat(60))
|
||||
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}`)
|
||||
})
|
||||
}
|
||||
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))
|
||||
// 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()
|
||||
compareVariables()
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error during analysis:', errorMessage)
|
||||
process.exit(1)
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error('Error during analysis:', errorMessage)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
+18
-19
@@ -9,14 +9,14 @@ import { join, dirname } from 'node:path'
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
interface LibConfig {
|
||||
npm?: string
|
||||
js?: string[]
|
||||
css?: string[]
|
||||
head?: boolean
|
||||
npm?: string
|
||||
js?: string[]
|
||||
css?: string[]
|
||||
head?: boolean
|
||||
}
|
||||
|
||||
interface Libs {
|
||||
[key: string]: LibConfig
|
||||
[key: string]: LibConfig
|
||||
}
|
||||
|
||||
const libsData = libs as Libs
|
||||
@@ -24,22 +24,21 @@ const libsData = libs as Libs
|
||||
emptyDirSync(join(__dirname, '..', 'dist/libs'))
|
||||
|
||||
for (const name in libsData) {
|
||||
const { npm } = libsData[name]
|
||||
const { npm } = libsData[name]
|
||||
|
||||
if (npm) {
|
||||
const from = join(__dirname, '..', `node_modules/${npm}`)
|
||||
const to = join(__dirname, '..', `dist/libs/${npm}`)
|
||||
if (npm) {
|
||||
const from = join(__dirname, '..', `node_modules/${npm}`)
|
||||
const to = join(__dirname, '..', `dist/libs/${npm}`)
|
||||
|
||||
// create dir in dist/libs
|
||||
if (!existsSync(to)) {
|
||||
mkdirSync(to, { recursive: true })
|
||||
}
|
||||
// create dir in dist/libs
|
||||
if (!existsSync(to)) {
|
||||
mkdirSync(to, { recursive: true })
|
||||
}
|
||||
|
||||
copySync(from, to, {
|
||||
dereference: true,
|
||||
})
|
||||
copySync(from, to, {
|
||||
dereference: true,
|
||||
})
|
||||
|
||||
console.log(`Successfully copied ${npm}`)
|
||||
}
|
||||
console.log(`Successfully copied ${npm}`)
|
||||
}
|
||||
}
|
||||
|
||||
+94
-95
@@ -8,114 +8,113 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const configFile = path.join(__dirname, '../../shared/data/sri.json')
|
||||
|
||||
interface FileConfig {
|
||||
file: string
|
||||
configPropertyName: string
|
||||
file: string
|
||||
configPropertyName: string
|
||||
}
|
||||
|
||||
const files: FileConfig[] = [
|
||||
{
|
||||
file: 'dist/css/tabler.min.css',
|
||||
configPropertyName: 'css'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler.rtl.min.css',
|
||||
configPropertyName: 'css-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-flags.min.css',
|
||||
configPropertyName: 'css-flags'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-flags.rtl.min.css',
|
||||
configPropertyName: 'css-flags-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-marketing.min.css',
|
||||
configPropertyName: 'css-marketing'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-marketing.rtl.min.css',
|
||||
configPropertyName: 'css-marketing-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-payments.min.css',
|
||||
configPropertyName: 'css-payments'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-payments.rtl.min.css',
|
||||
configPropertyName: 'css-payments-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-props.min.css',
|
||||
configPropertyName: 'css-props'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-props.rtl.min.css',
|
||||
configPropertyName: 'css-props-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-themes.min.css',
|
||||
configPropertyName: 'css-themes'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-themes.rtl.min.css',
|
||||
configPropertyName: 'css-themes-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-socials.min.css',
|
||||
configPropertyName: 'css-socials'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-socials.rtl.min.css',
|
||||
configPropertyName: 'css-socials-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-vendors.min.css',
|
||||
configPropertyName: 'css-vendors'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-vendors.rtl.min.css',
|
||||
configPropertyName: 'css-vendors-rtl'
|
||||
},
|
||||
{
|
||||
file: 'dist/js/tabler.min.js',
|
||||
configPropertyName: 'js'
|
||||
},
|
||||
{
|
||||
file: 'dist/js/tabler-theme.min.js',
|
||||
configPropertyName: 'js-theme'
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler.min.css',
|
||||
configPropertyName: 'css',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler.rtl.min.css',
|
||||
configPropertyName: 'css-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-flags.min.css',
|
||||
configPropertyName: 'css-flags',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-flags.rtl.min.css',
|
||||
configPropertyName: 'css-flags-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-marketing.min.css',
|
||||
configPropertyName: 'css-marketing',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-marketing.rtl.min.css',
|
||||
configPropertyName: 'css-marketing-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-payments.min.css',
|
||||
configPropertyName: 'css-payments',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-payments.rtl.min.css',
|
||||
configPropertyName: 'css-payments-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-props.min.css',
|
||||
configPropertyName: 'css-props',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-props.rtl.min.css',
|
||||
configPropertyName: 'css-props-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-themes.min.css',
|
||||
configPropertyName: 'css-themes',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-themes.rtl.min.css',
|
||||
configPropertyName: 'css-themes-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-socials.min.css',
|
||||
configPropertyName: 'css-socials',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-socials.rtl.min.css',
|
||||
configPropertyName: 'css-socials-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-vendors.min.css',
|
||||
configPropertyName: 'css-vendors',
|
||||
},
|
||||
{
|
||||
file: 'dist/css/tabler-vendors.rtl.min.css',
|
||||
configPropertyName: 'css-vendors-rtl',
|
||||
},
|
||||
{
|
||||
file: 'dist/js/tabler.min.js',
|
||||
configPropertyName: 'js',
|
||||
},
|
||||
{
|
||||
file: 'dist/js/tabler-theme.min.js',
|
||||
configPropertyName: 'js-theme',
|
||||
},
|
||||
]
|
||||
|
||||
function generateSRI(): void {
|
||||
const sriData: Record<string, string> = {}
|
||||
const sriData: Record<string, string> = {}
|
||||
|
||||
for (const { file, configPropertyName } of files) {
|
||||
try {
|
||||
const filePath = path.join(__dirname, '..', file)
|
||||
const data = readFileSync(filePath, 'utf8')
|
||||
for (const { file, configPropertyName } of files) {
|
||||
try {
|
||||
const filePath = path.join(__dirname, '..', file)
|
||||
const data = readFileSync(filePath, 'utf8')
|
||||
|
||||
const algorithm = 'sha384'
|
||||
const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64')
|
||||
const integrity = `${algorithm}-${hash}`
|
||||
const algorithm = 'sha384'
|
||||
const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64')
|
||||
const integrity = `${algorithm}-${hash}`
|
||||
|
||||
console.log(`${configPropertyName}: ${integrity}`)
|
||||
console.log(`${configPropertyName}: ${integrity}`)
|
||||
|
||||
sriData[configPropertyName] = integrity
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error(`Error processing ${file}:`, errorMessage)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
sriData[configPropertyName] = integrity
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
console.error(`Error processing ${file}:`, errorMessage)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
writeFileSync(configFile, JSON.stringify(sriData, null, 2) + '\n', 'utf8')
|
||||
writeFileSync(configFile, JSON.stringify(sriData, null, 2) + '\n', 'utf8')
|
||||
}
|
||||
|
||||
try {
|
||||
generateSRI()
|
||||
generateSRI()
|
||||
} catch (error) {
|
||||
console.error('Failed to generate SRI:', error)
|
||||
process.exit(1)
|
||||
console.error('Failed to generate SRI:', error)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
+17
-18
@@ -12,7 +12,7 @@ const toDir = join(__dirname, '..', 'fonts')
|
||||
|
||||
// Create fonts directory if it doesn't exist
|
||||
if (!existsSync(toDir)) {
|
||||
mkdirSync(toDir, { recursive: true })
|
||||
mkdirSync(toDir, { recursive: true })
|
||||
}
|
||||
|
||||
// Copy geist-mono fonts
|
||||
@@ -20,17 +20,17 @@ const monoFrom = join(fromDir, 'geist-mono')
|
||||
const monoTo = join(toDir, 'geist-mono')
|
||||
|
||||
if (existsSync(monoFrom)) {
|
||||
if (!existsSync(monoTo)) {
|
||||
mkdirSync(monoTo, { recursive: true })
|
||||
}
|
||||
if (!existsSync(monoTo)) {
|
||||
mkdirSync(monoTo, { recursive: true })
|
||||
}
|
||||
|
||||
copySync(monoFrom, monoTo, {
|
||||
dereference: true,
|
||||
})
|
||||
copySync(monoFrom, monoTo, {
|
||||
dereference: true,
|
||||
})
|
||||
|
||||
console.log(`Successfully copied geist-mono fonts`)
|
||||
console.log(`Successfully copied geist-mono fonts`)
|
||||
} else {
|
||||
console.warn(`Warning: geist-mono fonts not found at ${monoFrom}`)
|
||||
console.warn(`Warning: geist-mono fonts not found at ${monoFrom}`)
|
||||
}
|
||||
|
||||
// Copy geist-sans fonts
|
||||
@@ -38,16 +38,15 @@ const sansFrom = join(fromDir, 'geist-sans')
|
||||
const sansTo = join(toDir, 'geist-sans')
|
||||
|
||||
if (existsSync(sansFrom)) {
|
||||
if (!existsSync(sansTo)) {
|
||||
mkdirSync(sansTo, { recursive: true })
|
||||
}
|
||||
if (!existsSync(sansTo)) {
|
||||
mkdirSync(sansTo, { recursive: true })
|
||||
}
|
||||
|
||||
copySync(sansFrom, sansTo, {
|
||||
dereference: true,
|
||||
})
|
||||
copySync(sansFrom, sansTo, {
|
||||
dereference: true,
|
||||
})
|
||||
|
||||
console.log(`Successfully copied geist-sans fonts`)
|
||||
console.log(`Successfully copied geist-sans fonts`)
|
||||
} else {
|
||||
console.warn(`Warning: geist-sans fonts not found at ${sansFrom}`)
|
||||
console.warn(`Warning: geist-sans fonts not found at ${sansFrom}`)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
export default context => {
|
||||
return {
|
||||
map: {
|
||||
inline: false,
|
||||
annotation: true,
|
||||
sourcesContent: true
|
||||
},
|
||||
plugins: {
|
||||
autoprefixer: {
|
||||
cascade: false
|
||||
},
|
||||
rtlcss: context.env === 'RTL'
|
||||
}
|
||||
}
|
||||
export default (context) => {
|
||||
return {
|
||||
map: {
|
||||
inline: false,
|
||||
annotation: true,
|
||||
sourcesContent: true,
|
||||
},
|
||||
plugins: {
|
||||
autoprefixer: {
|
||||
cascade: false,
|
||||
},
|
||||
rtlcss: context.env === 'RTL',
|
||||
},
|
||||
}
|
||||
}
|
||||
+10
-11
@@ -16,15 +16,14 @@ const entryPath = path.resolve(__dirname, `../js/${entryFile}`)
|
||||
const entry = `${entryPath}.ts`
|
||||
|
||||
export default createViteConfig({
|
||||
entry: entry,
|
||||
name: libraryName,
|
||||
fileName: (format) => {
|
||||
const esmSuffix = format === 'es' ? '.esm' : ''
|
||||
return `${baseName}${esmSuffix}.js`
|
||||
},
|
||||
formats: ['es', 'umd'],
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: bannerText,
|
||||
minify: false
|
||||
entry: entry,
|
||||
name: libraryName,
|
||||
fileName: (format) => {
|
||||
const esmSuffix = format === 'es' ? '.esm' : ''
|
||||
return `${baseName}${esmSuffix}.js`
|
||||
},
|
||||
formats: ['es', 'umd'],
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: bannerText,
|
||||
minify: false,
|
||||
})
|
||||
|
||||
@@ -88,12 +88,6 @@ $form-invalid-border-color-dark: tint-color($red, 40%) !default;
|
||||
// Accordion dark
|
||||
//
|
||||
|
||||
$accordion-icon-color-dark: $primary-text-emphasis-dark !default;
|
||||
$accordion-icon-active-color-dark: $primary-text-emphasis-dark !default;
|
||||
|
||||
$accordion-button-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/></svg>") !default;
|
||||
$accordion-button-active-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-active-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/></svg>") !default;
|
||||
|
||||
//
|
||||
// Carousel dark
|
||||
//
|
||||
|
||||
@@ -7,13 +7,11 @@
|
||||
|
||||
// Prefixes
|
||||
// $prefix moved to `_settings.scss`
|
||||
$variable-prefix: bs- !default; // Deprecated in v5.2.0 for the shorter `$prefix`
|
||||
|
||||
// Assets Base
|
||||
$assets-base: '..' !default;
|
||||
|
||||
// Base Config
|
||||
$enable-social-colors: true !default;
|
||||
$enable-extra-colors: true !default;
|
||||
$enable-gradients: false !default;
|
||||
$enable-shadows: true !default;
|
||||
@@ -22,7 +20,6 @@ $enable-dark-mode: true !default;
|
||||
$enable-negative-margins: true !default;
|
||||
// $enable-rfs is declared in `_mixins.scss` (forwarded from rfs with `false !default`)
|
||||
$enable-cssgrid: true !default;
|
||||
$enable-caret: true !default;
|
||||
$enable-rounded: true !default;
|
||||
$enable-transitions: true !default;
|
||||
$enable-reduced-motion: true !default;
|
||||
@@ -104,6 +101,10 @@ $colors: (
|
||||
|
||||
// $min-contrast-ratio, $color-contrast-dark and $color-contrast-light moved to `_settings.scss`
|
||||
|
||||
// Color shade ladders and per-color maps (Bootstrap parity). Nothing in the
|
||||
// build consumes them yet, but they are kept as configurable API — hence
|
||||
// excluded from the unused-variable lint.
|
||||
// fusv-disable
|
||||
$blue-100: tint-color($blue, 80%) !default;
|
||||
$blue-200: tint-color($blue, 60%) !default;
|
||||
$blue-300: tint-color($blue, 40%) !default;
|
||||
@@ -323,9 +324,9 @@ $cyans: (
|
||||
'cyan-800': $cyan-800,
|
||||
'cyan-900': $cyan-900,
|
||||
) !default;
|
||||
// fusv-enable
|
||||
|
||||
// Spacers
|
||||
$spacer-0: 0 !default;
|
||||
$spacer-1: 0.25rem !default;
|
||||
$spacer-2: 0.5rem !default;
|
||||
$spacer-3: 1rem !default;
|
||||
@@ -380,7 +381,6 @@ $body-emphasis-color: $black !default;
|
||||
// Typography
|
||||
$font-google: null !default;
|
||||
$font-google-monospaced: null !default;
|
||||
$font-local: null !default;
|
||||
$font-icons: () !default;
|
||||
|
||||
$font-family-sans-serif: ('Geist', -apple-system, BlinkMacSystemFont, San Francisco, Segoe UI, Roboto, Helvetica Neue, sans-serif) !default;
|
||||
@@ -400,23 +400,6 @@ $icon-sm-size: 1rem !default;
|
||||
$icon-md-size: 2.5rem !default;
|
||||
$icon-lg-size: 3.5rem !default;
|
||||
|
||||
$font-size-75: 0.75rem !default;
|
||||
$font-size-100: 0.875rem !default;
|
||||
$font-size-200: 1rem !default;
|
||||
$font-size-300: 1.25rem !default;
|
||||
$font-size-400: 1.5rem !default;
|
||||
$font-size-500: 1.75rem !default;
|
||||
$font-size-600: 2rem !default;
|
||||
$font-size-700: 2.5rem !default;
|
||||
|
||||
$line-height-100: 1rem !default;
|
||||
$line-height-200: 1.25rem !default;
|
||||
$line-height-300: 1.5rem !default;
|
||||
$line-height-400: 1.75rem !default;
|
||||
$line-height-500: 2rem !default;
|
||||
$line-height-600: 2.5rem !default;
|
||||
$line-height-700: 3rem !default;
|
||||
|
||||
$font-size-root: null !default;
|
||||
$font-size-base: 0.875rem !default;
|
||||
$font-size-sm: $font-size-base * 0.875 !default;
|
||||
@@ -561,13 +544,6 @@ $zindex-levels: (
|
||||
) !default;
|
||||
|
||||
$text-secondary-opacity: 0.7 !default;
|
||||
$text-secondary-light-opacity: 0.4 !default;
|
||||
$text-secondary-dark-opacity: 0.8 !default;
|
||||
|
||||
$bg-surface: var(--#{$prefix}white) !default;
|
||||
$bg-surface-secondary: var(--#{$prefix}gray-100) !default;
|
||||
$bg-surface-tertiary: var(--#{$prefix}gray-50) !default;
|
||||
$bg-surface-dark: var(--#{$prefix}dark) !default;
|
||||
|
||||
$body-text-align: null !default;
|
||||
$body-bg: $gray-50 !default;
|
||||
@@ -578,7 +554,6 @@ $body-emphasis-color: $gray-700 !default;
|
||||
// Note: they were already no-ops here — the `!default` definitions earlier
|
||||
// in this file always won, so their effective values were $black / $white.
|
||||
|
||||
$text-muted: $gray-500 !default;
|
||||
$text-secondary: $gray-500 !default;
|
||||
$text-secondary-light: $gray-400 !default;
|
||||
$text-secondary-dark: $gray-600 !default;
|
||||
@@ -622,15 +597,8 @@ $link-color: $primary !default;
|
||||
$link-shade-percentage: 20% !default;
|
||||
$link-hover-color: shift-color($link-color, $link-shade-percentage) !default;
|
||||
$link-hover-decoration: null !default;
|
||||
$stretched-link-pseudo-element: after !default;
|
||||
$stretched-link-z-index: 1 !default;
|
||||
|
||||
// Icon links
|
||||
$icon-link-gap: 0.375rem !default;
|
||||
$icon-link-underline-offset: 0.25em !default;
|
||||
$icon-link-icon-size: 1em !default;
|
||||
$icon-link-icon-transition: 0.2s ease-in-out transform !default;
|
||||
$icon-link-icon-transform: translate3d(0.25em, 0, 0) !default;
|
||||
|
||||
// Paragraphs
|
||||
$paragraph-margin-bottom: 1rem !default;
|
||||
@@ -787,7 +755,6 @@ $border-radius: 6px !default;
|
||||
$border-radius-lg: 8px !default;
|
||||
$border-radius-xl: 1rem !default;
|
||||
$border-radius-xxl: 2rem !default;
|
||||
$border-radius-2xl: $border-radius-xxl !default; // Deprecated in v5.3.0
|
||||
$border-radius-pill: 100rem !default;
|
||||
|
||||
$border-radiuses: (
|
||||
@@ -812,7 +779,6 @@ $icon-color: var(--#{$prefix}gray-400) !default;
|
||||
$code-color: light-dark(var(--#{$prefix}gray-600), var(--#{$prefix}gray-400)) !default;
|
||||
$code-bg: light-dark(var(--#{$prefix}gray-100), var(--#{$prefix}gray-900)) !default;
|
||||
$code-font-size: $font-size-reative-sm !default;
|
||||
$code-line-height: 1.25rem !default;
|
||||
|
||||
$pre-padding: 1rem !default;
|
||||
$pre-bg: var(--#{$prefix}bg-surface-dark) !default;
|
||||
@@ -893,7 +859,6 @@ $avatar-sizes: (
|
||||
) !default;
|
||||
$avatar-border-radius: var(--#{$prefix}border-radius-pill) !default;
|
||||
$avatar-font-size: $h4-font-size !default;
|
||||
$avatar-box-shadow: var(--#{$prefix}shadow-border) !default;
|
||||
$avatar-list-spacing: -0.5;
|
||||
|
||||
$link-decoration: none !default;
|
||||
@@ -902,8 +867,6 @@ $link-hover-decoration: underline !default;
|
||||
// Horizontal rules
|
||||
$hr-margin-y: 2rem !default;
|
||||
$hr-color: inherit !default;
|
||||
$hr-bg-color: null !default;
|
||||
$hr-height: null !default;
|
||||
$hr-border-color: null !default;
|
||||
$hr-border-width: var(--#{$prefix}border-width) !default;
|
||||
$hr-opacity: $border-opacity !default;
|
||||
@@ -1065,15 +1028,10 @@ $overlay-gradient: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.
|
||||
$alert-padding-y: 0.75rem !default;
|
||||
$alert-padding-x: 1rem !default;
|
||||
$alert-margin-bottom: 1rem !default;
|
||||
$alert-border-radius: var(--#{$prefix}border-radius) !default;
|
||||
$alert-link-font-weight: var(--#{$prefix}font-weight-semibold) !default;
|
||||
$alert-border-width: var(--#{$prefix}border-width) !default;
|
||||
$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side
|
||||
$alert-border-color: var(--#{$prefix}border-color-translucent) !default;
|
||||
$alert-shadow: rgba($dark, 0.04) 0 2px 4px 0 !default;
|
||||
$alert-bg-scale: -80% !default; // Deprecated in v5.2.0, to be removed in v6
|
||||
$alert-border-scale: -70% !default; // Deprecated in v5.2.0, to be removed in v6
|
||||
$alert-color-scale: 40% !default; // Deprecated in v5.2.0, to be removed in v6
|
||||
$alert-heading-margin-bottom: 0.25rem !default;
|
||||
$alert-icon-size: 1.25rem !default;
|
||||
$alert-padding-inline-end: 3rem !default;
|
||||
@@ -1089,7 +1047,6 @@ $breadcrumb-bg: null !default;
|
||||
$breadcrumb-divider-color: var(--#{$prefix}gray-500) !default;
|
||||
$breadcrumb-active-color: inherit !default;
|
||||
$breadcrumb-divider: string.quote('/') !default;
|
||||
$breadcrumb-divider-flipped: $breadcrumb-divider !default;
|
||||
$breadcrumb-border-radius: null !default;
|
||||
$breadcrumb-link-color: var(--#{$prefix}link-color) !default;
|
||||
$breadcrumb-active-font-weight: var(--#{$prefix}font-weight-semibold) !default;
|
||||
@@ -1105,7 +1062,6 @@ $breadcrumb-variants: (
|
||||
$badge-font-size: $font-size-reative-sm !default;
|
||||
$badge-font-size-sm: $font-size-reative-xs !default;
|
||||
$badge-font-size-lg: $font-size-reative-md !default;
|
||||
$badge-line-height: $code-line-height !default;
|
||||
$badge-font-weight: var(--#{$prefix}font-weight-medium) !default;
|
||||
$badge-padding-y: 0.25em !default;
|
||||
$badge-padding-x: 0.5em !default;
|
||||
@@ -1156,7 +1112,6 @@ $btn-border-width: $input-btn-border-width !default;
|
||||
$btn-font-weight: var(--#{$prefix}font-weight-medium) !default;
|
||||
$btn-box-shadow: var(--#{$prefix}shadow-input) !default;
|
||||
$btn-focus-width: $input-btn-focus-width !default;
|
||||
$btn-focus-box-shadow: $input-btn-focus-box-shadow !default;
|
||||
$btn-disabled-opacity: 0.4 !default;
|
||||
$btn-active-box-shadow: inset 0 3px 5px rgba($black, 0.125) !default;
|
||||
|
||||
@@ -1267,7 +1222,6 @@ $card-border-color: var(--#{$prefix}border-color-translucent) !default;
|
||||
$card-border-radius: var(--#{$prefix}border-radius-lg) !default;
|
||||
$card-box-shadow: var(--#{$prefix}shadow-card) !default;
|
||||
$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default;
|
||||
$card-hover-box-shadow: var(--#{$prefix}shadow-card-hover) !default;
|
||||
|
||||
$card-cap-padding-y: $card-spacer-y !default;
|
||||
$card-cap-padding-x: $card-spacer-x !default;
|
||||
@@ -1276,7 +1230,6 @@ $card-cap-color: inherit !default;
|
||||
$card-height: null !default;
|
||||
$card-color: inherit !default;
|
||||
$card-bg: var(--#{$prefix}bg-surface) !default;
|
||||
$card-bg-hover: $white !default;
|
||||
$card-img-overlay-padding: $spacer !default;
|
||||
$card-group-margin: 1.5rem !default;
|
||||
|
||||
@@ -1324,10 +1277,7 @@ $ribbon-bookmark-notch-width: 0.5rem !default;
|
||||
// Accordion
|
||||
$accordion-padding-y: 1rem !default;
|
||||
$accordion-padding-x: 1.25rem !default;
|
||||
$accordion-color: var(--#{$prefix}body-color) !default;
|
||||
$accordion-bg: transparent !default;
|
||||
$accordion-border-width: var(--#{$prefix}border-width) !default;
|
||||
$accordion-border-color: var(--#{$prefix}border-color-translucent) !default;
|
||||
$accordion-border-radius: var(--#{$prefix}border-radius) !default;
|
||||
$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default;
|
||||
$accordion-btn-toggle-width: $icon-size !default;
|
||||
@@ -1336,25 +1286,8 @@ $accordion-body-padding-y: $accordion-padding-y !default;
|
||||
$accordion-body-padding-x: $accordion-padding-x !default;
|
||||
|
||||
$accordion-button-padding-y: $accordion-padding-y !default;
|
||||
$accordion-button-padding-x: $accordion-padding-x !default;
|
||||
$accordion-button-color: var(--#{$prefix}body-color) !default;
|
||||
$accordion-button-bg: transparent !default;
|
||||
$accordion-transition:
|
||||
$btn-transition,
|
||||
border-radius 0.15s ease !default;
|
||||
$accordion-button-active-bg: transparent !default;
|
||||
$accordion-button-active-color: inherit !default;
|
||||
$accordion-button-focus-border-color: $accordion-border-color !default; // Deprecated in v5.3.3
|
||||
$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default;
|
||||
|
||||
$accordion-icon-width: 1rem !default;
|
||||
$accordion-icon-color: $body-color !default;
|
||||
$accordion-icon-active-color: $primary-text-emphasis !default;
|
||||
$accordion-icon-transition: transform 0.2s ease-in-out !default;
|
||||
$accordion-icon-transform: rotate(-180deg) !default;
|
||||
|
||||
$accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-color}' stroke-linecap='round' stroke-linejoin='round'><path d='m2 5 6 6 6-6'/></svg>") !default;
|
||||
$accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-active-color}' stroke-linecap='round' stroke-linejoin='round'><path d='m2 5 6 6 6-6'/></svg>") !default;
|
||||
$accordion-btn-gap: 0.75rem !default;
|
||||
$accordion-header-gap: 1rem !default;
|
||||
$accordion-tabs-gap: 0.75rem !default;
|
||||
@@ -1398,7 +1331,6 @@ $carousel-indicators-vertical-margin-inline-end: 1rem !default;
|
||||
|
||||
// Close
|
||||
$btn-close-width: 1em !default;
|
||||
$btn-close-height: $btn-close-width !default;
|
||||
$btn-close-padding-x: 0.25em !default;
|
||||
$btn-close-padding-y: $btn-close-padding-x !default;
|
||||
$btn-close-color: $body-color !default;
|
||||
@@ -1456,7 +1388,6 @@ $dropdown-item-padding-x: 0.75rem !default;
|
||||
$dropdown-header-color: $gray-600 !default;
|
||||
$dropdown-header-padding-x: $dropdown-item-padding-x !default;
|
||||
$dropdown-header-padding-y: $dropdown-padding-y !default;
|
||||
$dropdown-header-padding: $dropdown-header-padding-y $dropdown-header-padding-x !default; // Deprecated in v5.2.0
|
||||
|
||||
$dropdown-max-width: 25rem !default;
|
||||
$dropdown-scrollable-height: 13rem !default;
|
||||
@@ -1495,7 +1426,6 @@ $tooltip-margin: null !default; // TODO: remove this in v6
|
||||
|
||||
$tooltip-arrow-width: 0.8rem !default;
|
||||
$tooltip-arrow-height: 0.4rem !default;
|
||||
$tooltip-arrow-color: null !default;
|
||||
|
||||
// Loader
|
||||
$loader-size: 2.5rem !default;
|
||||
@@ -1565,7 +1495,6 @@ $nav-link-transition:
|
||||
border-color 0.15s ease-in-out !default;
|
||||
$nav-link-disabled-color: var(--#{$prefix}disabled-color) !default;
|
||||
$nav-link-focus-box-shadow: $focus-ring-box-shadow !default;
|
||||
$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default;
|
||||
$nav-link-icon-size: $icon-size !default;
|
||||
$nav-link-icon-color: color-transparent(var(--#{$prefix}nav-link-color), 0.5) !default;
|
||||
$nav-link-hover-icon-color: color-transparent(var(--#{$prefix}nav-link-color), 0.8) !default;
|
||||
@@ -1588,7 +1517,6 @@ $nav-tabs-link-hover-border-color: $nav-tabs-border-color $nav-tabs-border-color
|
||||
$nav-tabs-link-active-color: var(--#{$prefix}body-color) !default;
|
||||
$nav-tabs-link-active-bg: var(--#{$prefix}body-bg) !default;
|
||||
$nav-tabs-link-active-border-color: $nav-tabs-link-hover-border-color !default;
|
||||
$nav-tabs-bg: var(--#{$prefix}bg-surface-tertiary) !default;
|
||||
|
||||
$nav-underline-gap: 1rem !default;
|
||||
$nav-underline-border-width: 0.125rem !default;
|
||||
@@ -1626,17 +1554,14 @@ $navbar-dark-hover-color: rgba($white, 0.75) !default;
|
||||
$navbar-dark-brand-color: $white !default;
|
||||
$navbar-dark-active-color: $white !default;
|
||||
$navbar-dark-disabled-color: var(--#{$prefix}disabled-color) !default;
|
||||
$navbar-dark-active-bg: rgba(255, 255, 255, 0.06) !default;
|
||||
$navbar-dark-icon-color: $navbar-dark-color !default;
|
||||
$navbar-dark-toggler-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke='#{$navbar-dark-icon-color}' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg>") !default;
|
||||
$navbar-dark-toggler-border-color: rgba($white, 0.1) !default;
|
||||
$navbar-dark-brand-hover-color: $navbar-dark-active-color !default;
|
||||
|
||||
$navbar-brand-font-size: $h2-font-size !default;
|
||||
$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default;
|
||||
$navbar-brand-padding-y: $nav-link-padding-y !default;
|
||||
$navbar-brand-image-height: 2rem !default;
|
||||
$navbar-brand-margin-right: 0 !default;
|
||||
$navbar-brand-margin-end: 1rem !default;
|
||||
$navbar-brand-font-weight: var(--#{$prefix}font-weight-semibold) !default;
|
||||
|
||||
@@ -1683,8 +1608,6 @@ $popover-body-padding-x: 0.5rem !default;
|
||||
|
||||
$popover-arrow-width: 1rem !default;
|
||||
$popover-arrow-height: 0.5rem !default;
|
||||
$popover-arrow-color: $popover-bg !default;
|
||||
$popover-arrow-outer-color: var(--#{$prefix}border-color-translucent) !default;
|
||||
|
||||
// Footer
|
||||
$footer-padding-y: 2rem !default;
|
||||
@@ -1754,7 +1677,6 @@ $status-circle-size: 0.75rem !default;
|
||||
$steps-border-width: 2px !default;
|
||||
$steps-color: var(--#{$prefix}primary) !default;
|
||||
$steps-inactive-color: var(--#{$prefix}border-color) !default;
|
||||
$steps-margin: 2rem 0 !default;
|
||||
$steps-dot-size: 0.5rem !default;
|
||||
$step-item-min-height: 1rem !default;
|
||||
$steps-counter-dot-size: 1.5rem !default;
|
||||
@@ -1777,7 +1699,6 @@ $spinner-border-width-sm: 1px !default;
|
||||
|
||||
// Tables
|
||||
$table-bg: transparent !default;
|
||||
$table-bg-scale-dark: 40% !default;
|
||||
$table-color: inherit !default;
|
||||
$table-accent-bg: transparent !default;
|
||||
|
||||
@@ -1791,11 +1712,9 @@ $table-border-factor: 0.2 !default;
|
||||
$table-border-width: var(--#{$prefix}border-width) !default;
|
||||
$table-border-color: var(--#{$prefix}border-color-translucent) !default;
|
||||
|
||||
$table-th-border-color: var(--#{$prefix}border-color-translucent) !default;
|
||||
$table-th-padding-x: $table-cell-padding-x !default;
|
||||
$table-th-padding-y: 0.5rem !default;
|
||||
$table-th-font-weight: null !default;
|
||||
$table-th-color: var(--#{$prefix}gray-500) !default;
|
||||
$table-th-bg: var(--#{$prefix}bg-surface-tertiary) !default;
|
||||
|
||||
$table-striped-color: $table-color !default;
|
||||
@@ -1887,8 +1806,6 @@ $list-group-border-radius: var(--#{$prefix}border-radius) !default;
|
||||
|
||||
$list-group-item-padding-y: $card-cap-padding-y !default;
|
||||
$list-group-item-padding-x: $card-cap-padding-x !default;
|
||||
$list-group-item-bg-scale: -80% !default; // Deprecated in v5.3.0
|
||||
$list-group-item-color-scale: 40% !default; // Deprecated in v5.3.0
|
||||
|
||||
$list-group-hover-bg: $hover-bg !default;
|
||||
$list-group-active-color: inherit !default;
|
||||
@@ -1941,7 +1858,6 @@ $form-check-input-box-shadow: $input-box-shadow !default;
|
||||
|
||||
$form-check-input-checked-bg-size: 1.25rem !default;
|
||||
$form-check-input-checked-bg-color: var(--#{$prefix}primary) !default;
|
||||
$form-check-input-checked-color: var(--#{$prefix}bg-forms) !default;
|
||||
$form-check-input-checked-bg-repeat: repeat !default;
|
||||
$form-check-input-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'><path fill='none' stroke='#{$white}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/></svg>") !default;
|
||||
$form-check-input-checked-bg-image-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'><path fill='none' stroke='#{$body-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/></svg>") !default;
|
||||
@@ -2006,7 +1922,6 @@ $form-switch-focus-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.o
|
||||
$form-switch-checked-color: white !default;
|
||||
$form-switch-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-checked-color}'/></svg>") !default;
|
||||
$form-switch-checked-bg-position: right center !default;
|
||||
$form-switch-bg-size: auto !default;
|
||||
|
||||
// Form range
|
||||
$form-range-track-width: 100% !default;
|
||||
@@ -2070,8 +1985,6 @@ $form-feedback-font-style: $form-text-font-style !default;
|
||||
$form-feedback-valid-color: $success !default;
|
||||
$form-feedback-invalid-color: $danger !default;
|
||||
|
||||
$form-feedback-icon-valid-color: $form-feedback-valid-color !default;
|
||||
$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;
|
||||
$form-feedback-icon-valid: str-replace(
|
||||
url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='" + $green + "' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'></polyline></svg>"),
|
||||
'#',
|
||||
|
||||
Vendored
-2
@@ -1,7 +1,5 @@
|
||||
@use '../config' as *;
|
||||
|
||||
$select-color-dropdown: #fff;
|
||||
$select-color-dropdown-border-top: red;
|
||||
$input-border-width: 1px;
|
||||
|
||||
:root {
|
||||
|
||||
+70
-47
@@ -1,55 +1,78 @@
|
||||
// Rebuild Astro's public directory from source and generated workspace assets.
|
||||
import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { setTimeout as sleep } from 'node:timers/promises'
|
||||
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const repo = join(root, '..');
|
||||
const publicDir = join(root, 'public');
|
||||
const root = join(dirname(fileURLToPath(import.meta.url)), '..')
|
||||
const repo = join(root, '..')
|
||||
const publicDir = join(root, 'public')
|
||||
|
||||
const copies = [
|
||||
{
|
||||
from: join(root, 'assets'),
|
||||
to: publicDir,
|
||||
packageName: '@tabler/docs',
|
||||
requiredFile: join(root, 'assets', 'css', 'docs.css'),
|
||||
},
|
||||
{
|
||||
from: join(repo, 'core', 'dist'),
|
||||
to: join(publicDir, 'dist'),
|
||||
packageName: '@tabler/core',
|
||||
requiredFile: join(repo, 'core', 'dist', 'css', 'tabler.css'),
|
||||
},
|
||||
{
|
||||
// Sourced from preview's isolated tmp-assets/ (not dist/) — dist/ is Astro's own
|
||||
// build output there, and reading demo assets from it caused unbounded growth
|
||||
// across repeated builds. See preview/.build/copy-assets.mjs.
|
||||
from: join(repo, 'preview', 'tmp-assets'),
|
||||
to: join(publicDir, 'preview'),
|
||||
packageName: '@tabler/preview',
|
||||
requiredFile: join(repo, 'preview', 'tmp-assets', 'css', 'demo.css'),
|
||||
},
|
||||
{
|
||||
from: join(repo, 'shared', 'static'),
|
||||
to: join(publicDir, 'static'),
|
||||
packageName: 'shared assets',
|
||||
requiredFile: join(repo, 'shared', 'static', 'logo.svg'),
|
||||
},
|
||||
];
|
||||
{
|
||||
from: join(root, 'assets'),
|
||||
to: publicDir,
|
||||
packageName: '@tabler/docs',
|
||||
requiredFile: join(root, 'assets', 'css', 'docs.css'),
|
||||
},
|
||||
{
|
||||
// core's own `dev` builds this asynchronously (nodemon-driven watch), so in
|
||||
// `pnpm run dev` this script can start before it exists — wait for it instead
|
||||
// of failing outright. See preview/.build/copy-assets.mjs for the same race.
|
||||
from: join(repo, 'core', 'dist'),
|
||||
to: join(publicDir, 'dist'),
|
||||
packageName: '@tabler/core',
|
||||
requiredFile: join(repo, 'core', 'dist', 'css', 'tabler.css'),
|
||||
waitForBuild: true,
|
||||
},
|
||||
{
|
||||
// Sourced from preview's isolated tmp-assets/ (not dist/) — dist/ is Astro's own
|
||||
// build output there, and reading demo assets from it caused unbounded growth
|
||||
// across repeated builds. See preview/.build/copy-assets.mjs.
|
||||
from: join(repo, 'preview', 'tmp-assets'),
|
||||
to: join(publicDir, 'preview'),
|
||||
packageName: '@tabler/preview',
|
||||
requiredFile: join(repo, 'preview', 'tmp-assets', 'css', 'demo.css'),
|
||||
waitForBuild: true,
|
||||
},
|
||||
{
|
||||
from: join(repo, 'shared', 'static'),
|
||||
to: join(publicDir, 'static'),
|
||||
packageName: 'shared assets',
|
||||
requiredFile: join(repo, 'shared', 'static', 'logo.svg'),
|
||||
},
|
||||
]
|
||||
|
||||
rmSync(publicDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });
|
||||
mkdirSync(publicDir, { recursive: true });
|
||||
const BUILD_WAIT_TIMEOUT_MS = 120_000
|
||||
const BUILD_WAIT_POLL_MS = 200
|
||||
|
||||
for (const { from, to, packageName, requiredFile } of copies) {
|
||||
if (!existsSync(from) || !existsSync(requiredFile)) {
|
||||
throw new Error(`copy-assets: missing ${requiredFile} — build ${packageName} first`);
|
||||
}
|
||||
|
||||
cpSync(from, to, {
|
||||
recursive: true,
|
||||
dereference: true,
|
||||
filter: src => !src.includes('/.vscode') && !src.includes('\\.vscode'),
|
||||
});
|
||||
async function waitForBuildOutput(requiredFile, packageName) {
|
||||
if (existsSync(requiredFile)) return
|
||||
console.log(`copy-assets: waiting for ${packageName} to finish its first build (${requiredFile})...`)
|
||||
const deadline = Date.now() + BUILD_WAIT_TIMEOUT_MS
|
||||
while (!existsSync(requiredFile)) {
|
||||
if (Date.now() > deadline) {
|
||||
throw new Error(`copy-assets: timed out waiting for ${requiredFile} — is ${packageName}'s dev/build running?`)
|
||||
}
|
||||
await sleep(BUILD_WAIT_POLL_MS)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('copy-assets: done');
|
||||
rmSync(publicDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 })
|
||||
mkdirSync(publicDir, { recursive: true })
|
||||
|
||||
for (const { from, to, packageName, requiredFile, waitForBuild } of copies) {
|
||||
if (waitForBuild) {
|
||||
await waitForBuildOutput(requiredFile, packageName)
|
||||
} else if (!existsSync(from) || !existsSync(requiredFile)) {
|
||||
throw new Error(`copy-assets: missing ${requiredFile} — build ${packageName} first`)
|
||||
}
|
||||
|
||||
cpSync(from, to, {
|
||||
recursive: true,
|
||||
dereference: true,
|
||||
filter: (src) => !src.includes('/.vscode') && !src.includes('\\.vscode'),
|
||||
})
|
||||
}
|
||||
|
||||
console.log('copy-assets: done')
|
||||
@@ -25,6 +25,8 @@ export default defineConfig({
|
||||
'@ui': fileURLToPath(new URL('../shared/ui', import.meta.url)),
|
||||
// docs-only components (Example, DocsMenu, …)
|
||||
'@components': fileURLToPath(new URL('./components', import.meta.url)),
|
||||
// docs-only layouts (DocsLayout + the MDX adapter, referenced by `layout:` front matter)
|
||||
'@layouts': fileURLToPath(new URL('./layouts', import.meta.url)),
|
||||
// this package's pages dir — used by @shared/lib/docs-children's glob
|
||||
'@pages': fileURLToPath(new URL('./pages', import.meta.url)),
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ import { site } from '@shared/lib/site.ts'
|
||||
---
|
||||
|
||||
<Code
|
||||
lang="html"
|
||||
code={`<link rel="stylesheet" href="${site.cdnUrl}/dist/css/tabler.min.css" />
|
||||
lang="html"
|
||||
code={`<link rel="stylesheet" href="${site.cdnUrl}/dist/css/tabler.min.css" />
|
||||
<script src="${site.cdnUrl}/dist/js/tabler.min.js"></script>`}
|
||||
/>
|
||||
@@ -3,15 +3,17 @@ import { Code } from 'astro:components'
|
||||
import { site } from '@shared/lib/site.ts'
|
||||
|
||||
interface Props {
|
||||
plugins: string[],
|
||||
plugins: string[]
|
||||
}
|
||||
|
||||
const { plugins }: Props = Astro.props
|
||||
---
|
||||
|
||||
<Code
|
||||
lang="html"
|
||||
code={plugins.map(plugin => {
|
||||
return `<link rel="stylesheet" href="${site.cdnUrl}/dist/css/tabler-${plugin}.min.css" />`
|
||||
}).join('\n')}
|
||||
lang="html"
|
||||
code={plugins
|
||||
.map((plugin) => {
|
||||
return `<link rel="stylesheet" href="${site.cdnUrl}/dist/css/tabler-${plugin}.min.css" />`
|
||||
})
|
||||
.join('\n')}
|
||||
/>
|
||||
@@ -1,18 +1,20 @@
|
||||
---
|
||||
interface Props {
|
||||
colors: Record<string, { prop: string; title: string }>;
|
||||
colors: Record<string, { prop: string; title: string }>
|
||||
}
|
||||
|
||||
const { colors }: Props = Astro.props;
|
||||
const { colors }: Props = Astro.props
|
||||
---
|
||||
|
||||
<div class="row row-cols-4 row-cols-md-6 g-3 g-md-4">
|
||||
{Object.values(colors).map((color) => {
|
||||
return (
|
||||
<div class="col-2 text-center">
|
||||
<div class="p-6 rounded border" style={{ backgroundColor: `var(${color.prop})` }}></div>
|
||||
<div class="small">{color.title}</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{
|
||||
Object.values(colors).map((color) => {
|
||||
return (
|
||||
<div class="col-2 text-center">
|
||||
<div class="p-6 rounded border" style={{ backgroundColor: `var(${color.prop})` }} />
|
||||
<div class="small">{color.title}</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
@@ -1,36 +1,38 @@
|
||||
---
|
||||
import Icon from "@ui/Icon.astro";
|
||||
import Icon from '@ui/Icon.astro'
|
||||
|
||||
interface Props {
|
||||
/** When omitted, the card renders as a non-interactive "Coming soon" tile. */
|
||||
href?: string;
|
||||
icon?: string;
|
||||
title: string;
|
||||
description: string;
|
||||
/** When omitted, the card renders as a non-interactive "Coming soon" tile. */
|
||||
href?: string
|
||||
icon?: string
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const { href, icon, title, description }: Props = Astro.props;
|
||||
const { href, icon, title, description }: Props = Astro.props
|
||||
|
||||
const Tag = href ? 'a' : 'div';
|
||||
const Tag = href ? 'a' : 'div'
|
||||
---
|
||||
|
||||
<div class="col-md-6">
|
||||
<Tag href={href} class:list={['card', !href && 'bg-surface-tertiary']}>
|
||||
<div class="card-body">
|
||||
<div class="position-relative">
|
||||
{ !href && <span class="badge position-absolute top-0 end-0">Coming soon</span> }
|
||||
<div class="row">
|
||||
{ icon && (
|
||||
<div class="col-auto">
|
||||
<Icon name={icon} class="text-secondary" />
|
||||
</div>
|
||||
)}
|
||||
<div class="col">
|
||||
<div class="h3">{ title }</div>
|
||||
<p class="text-secondary m-0 fs-4 lh-base">{ description }</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tag>
|
||||
<Tag href={href} class:list={['card', !href && 'bg-surface-tertiary']}>
|
||||
<div class="card-body">
|
||||
<div class="position-relative">
|
||||
{!href && <span class="badge position-absolute top-0 end-0">Coming soon</span>}
|
||||
<div class="row">
|
||||
{
|
||||
icon && (
|
||||
<div class="col-auto">
|
||||
<Icon name={icon} class="text-secondary" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div class="col">
|
||||
<div class="h3">{title}</div>
|
||||
<p class="text-secondary m-0 fs-4 lh-base">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tag>
|
||||
</div>
|
||||
@@ -3,16 +3,13 @@
|
||||
---
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="32" fill="none">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M78.263 10.957a5.96 5.96 0 0 1 3.158.895c.947.632 1.737 1.474 2.21 2.474.58 1.105.843 2.368.843 3.631 0 1.369-.264 2.527-.79 3.632-.474 1-1.263 1.895-2.21 2.526-.948.58-2 .895-3.106.895a5.45 5.45 0 0 1-2.263-.474c-.684-.316-1.263-.684-1.79-1.21v.158c0 .42-.157.79-.42 1.105-.263.316-.632.421-1.105.421-.79 0-1.474-.632-1.527-1.421V7.536c0-.42.158-.79.421-1.105a1.24 1.24 0 0 1 1.106-.421c.42 0 .789.158 1.105.421.263.316.42.684.42 1.105V12.8c.475-.579 1.053-1 1.685-1.315.684-.369 1.474-.527 2.263-.527ZM51.737 21.852a.82.82 0 0 1 .631.316c.21.21.316.526.316.895 0 .473-.263.842-.737 1.158-.473.315-1.052.473-1.684.473-.947.053-1.842-.21-2.631-.684-.737-.421-1.053-1.421-1.053-2.842V14.22H45.42c-.737.052-1.368-.58-1.421-1.316v-.106c0-.368.158-.736.421-1 .263-.263.632-.368 1-.368h1.158V9.799c0-.42.158-.789.421-1.105a1.24 1.24 0 0 1 1.105-.42c.421 0 .79.157 1.053.42.263.316.42.684.42 1.105v1.632h1.79c.737-.053 1.369.579 1.421 1.316v.105c0 .737-.631 1.368-1.368 1.368h-1.84v6.843c0 .368.105.631.263.79.21.157.421.262.737.262.108 0 .217-.024.359-.057.065-.015.137-.032.22-.048.21-.105.368-.158.579-.158Zm14.737-10.895c.79 0 1.473.632 1.526 1.421v10.79c0 .42-.158.79-.421 1.105-.263.316-.632.421-1.105.421a1.47 1.47 0 0 1-1.053-.42c-.263-.317-.421-.685-.421-1.106a5.664 5.664 0 0 1-1.684 1.263c-.684.316-1.474.526-2.263.526a5.959 5.959 0 0 1-3.158-.894c-.948-.632-1.737-1.474-2.21-2.474a7.842 7.842 0 0 1-.843-3.632c0-1.368.263-2.526.79-3.631.473-1 1.263-1.895 2.21-2.527.947-.579 2-.894 3.105-.894 1.527 0 2.948.526 4.053 1.579 0-.421.158-.79.421-1.106a1.144 1.144 0 0 1 1.053-.42Zm-2.421 10a4.737 4.737 0 0 0 1.052-3c0-1.21-.368-2.21-1.052-3.052a3.316 3.316 0 0 0-2.685-1.21c-1.105 0-1.947.42-2.631 1.21-.684.842-1.053 1.947-1.053 3.052 0 1.21.369 2.21 1 3 .684.79 1.684 1.264 2.684 1.21 1.106 0 2-.42 2.685-1.21Zm16.473 0c.684-.842 1.053-1.947 1.053-3.052 0-1.21-.316-2.21-1-3a3.405 3.405 0 0 0-2.684-1.21c-1.105 0-2 .42-2.684 1.21a4.842 4.842 0 0 0-1.053 3c0 1.21.316 2.21 1.052 3.052.685.79 1.685 1.264 2.685 1.21 1.105 0 1.947-.42 2.631-1.21Zm9.79 2.21c0 .422-.158.79-.421 1.106-.263.316-.684.421-1.105.421a1.47 1.47 0 0 1-1.053-.42c-.263-.317-.421-.685-.421-1.106V7.536c0-.42.158-.79.42-1.105.317-.316.685-.474 1.106-.421.421 0 .79.158 1.053.421.316.316.42.684.42 1.105v15.632Zm14.947-4.525c.316-.264.474-.58.474-1 0-2.369-1.263-4.58-3.105-5.843-1-.579-2.053-.894-3.158-.894-1.158 0-2.21.316-3.21.894a6.563 6.563 0 0 0-2.422 2.527c-.579 1.052-.895 2.316-.895 3.79a6.729 6.729 0 0 0 .843 3.526c.578 1 1.368 1.842 2.42 2.42 1.053.58 2.264.895 3.685.895.842 0 1.631-.158 2.421-.42a6.38 6.38 0 0 0 1.895-1c.473-.316.684-.738.684-1.211 0-.369-.106-.632-.369-.895a1.153 1.153 0 0 0-.894-.368 1.67 1.67 0 0 0-.843.21l-.473.263c-.316.21-.632.316-.948.421-.421.158-.947.21-1.631.21a3.805 3.805 0 0 1-3.842-3.157h8.316c.421 0 .736-.105 1.052-.368Zm-5.947-4.948c.789 0 1.526.263 2.105.737s1 1.105 1.053 1.842v.158h-6.632c.368-1.842 1.526-2.737 3.474-2.737Zm17.21-2.316c-.315-.263-.737-.42-1.263-.42-.789 0-1.579.157-2.263.526-.737.368-1.316.894-1.684 1.579v-.316c0-.421-.105-.79-.421-1.105a1.695 1.695 0 0 0-1.106-.421 1.239 1.239 0 0 0-1.105.42c-.263.316-.421.685-.421 1.106v10.368c0 .421.158.79.421 1.106.316.263.632.42 1.105.42.474 0 .843-.105 1.106-.42.263-.316.421-.685.421-1.106v-6c-.053-.684.105-1.316.368-1.947.211-.474.579-.895 1-1.21.527-.37 1.211-.474 1.842-.316l.316.105c.316.105.579.158.842.158.369.052.684-.106.948-.369.315-.263.421-.631.421-1.158 0-.368-.211-.736-.527-1Z"
|
||||
/>
|
||||
<path
|
||||
fill="#066FD1"
|
||||
d="M31.288 7.107A8.833 8.833 0 0 0 24.893.712a55.899 55.899 0 0 0-17.786 0A8.833 8.833 0 0 0 .712 7.107a55.899 55.899 0 0 0 0 17.786 8.833 8.833 0 0 0 6.395 6.395c5.895.95 11.89.95 17.786 0a8.833 8.833 0 0 0 6.395-6.395c.95-5.895.95-11.89 0-17.786Z"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M10.019 22.452a17.5 17.5 0 0 0 5.498-5.449 2.193 2.193 0 0 0 0-2.328c-1.436-2.18-3.27-4.013-5.498-5.4-1.09-.693-2.527-.297-3.22.793-.05 0-.05.05-.05.05a2.278 2.278 0 0 0 .842 3.12c1.14.743 2.13 1.585 3.022 2.626a11.782 11.782 0 0 1-3.022 2.625c-.743.396-1.189 1.189-1.189 2.031a2.397 2.397 0 0 0 3.617 1.932Zm7.727-.644h5.647c1.04 0 1.883-.495 1.883-1.486 0-.99-.843-1.486-1.883-1.486h-5.647c-1.04 0-1.882.495-1.882 1.486 0 .99.842 1.486 1.882 1.486Z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M78.263 10.957a5.96 5.96 0 0 1 3.158.895c.947.632 1.737 1.474 2.21 2.474.58 1.105.843 2.368.843 3.631 0 1.369-.264 2.527-.79 3.632-.474 1-1.263 1.895-2.21 2.526-.948.58-2 .895-3.106.895a5.45 5.45 0 0 1-2.263-.474c-.684-.316-1.263-.684-1.79-1.21v.158c0 .42-.157.79-.42 1.105-.263.316-.632.421-1.105.421-.79 0-1.474-.632-1.527-1.421V7.536c0-.42.158-.79.421-1.105a1.24 1.24 0 0 1 1.106-.421c.42 0 .789.158 1.105.421.263.316.42.684.42 1.105V12.8c.475-.579 1.053-1 1.685-1.315.684-.369 1.474-.527 2.263-.527ZM51.737 21.852a.82.82 0 0 1 .631.316c.21.21.316.526.316.895 0 .473-.263.842-.737 1.158-.473.315-1.052.473-1.684.473-.947.053-1.842-.21-2.631-.684-.737-.421-1.053-1.421-1.053-2.842V14.22H45.42c-.737.052-1.368-.58-1.421-1.316v-.106c0-.368.158-.736.421-1 .263-.263.632-.368 1-.368h1.158V9.799c0-.42.158-.789.421-1.105a1.24 1.24 0 0 1 1.105-.42c.421 0 .79.157 1.053.42.263.316.42.684.42 1.105v1.632h1.79c.737-.053 1.369.579 1.421 1.316v.105c0 .737-.631 1.368-1.368 1.368h-1.84v6.843c0 .368.105.631.263.79.21.157.421.262.737.262.108 0 .217-.024.359-.057.065-.015.137-.032.22-.048.21-.105.368-.158.579-.158Zm14.737-10.895c.79 0 1.473.632 1.526 1.421v10.79c0 .42-.158.79-.421 1.105-.263.316-.632.421-1.105.421a1.47 1.47 0 0 1-1.053-.42c-.263-.317-.421-.685-.421-1.106a5.664 5.664 0 0 1-1.684 1.263c-.684.316-1.474.526-2.263.526a5.959 5.959 0 0 1-3.158-.894c-.948-.632-1.737-1.474-2.21-2.474a7.842 7.842 0 0 1-.843-3.632c0-1.368.263-2.526.79-3.631.473-1 1.263-1.895 2.21-2.527.947-.579 2-.894 3.105-.894 1.527 0 2.948.526 4.053 1.579 0-.421.158-.79.421-1.106a1.144 1.144 0 0 1 1.053-.42Zm-2.421 10a4.737 4.737 0 0 0 1.052-3c0-1.21-.368-2.21-1.052-3.052a3.316 3.316 0 0 0-2.685-1.21c-1.105 0-1.947.42-2.631 1.21-.684.842-1.053 1.947-1.053 3.052 0 1.21.369 2.21 1 3 .684.79 1.684 1.264 2.684 1.21 1.106 0 2-.42 2.685-1.21Zm16.473 0c.684-.842 1.053-1.947 1.053-3.052 0-1.21-.316-2.21-1-3a3.405 3.405 0 0 0-2.684-1.21c-1.105 0-2 .42-2.684 1.21a4.842 4.842 0 0 0-1.053 3c0 1.21.316 2.21 1.052 3.052.685.79 1.685 1.264 2.685 1.21 1.105 0 1.947-.42 2.631-1.21Zm9.79 2.21c0 .422-.158.79-.421 1.106-.263.316-.684.421-1.105.421a1.47 1.47 0 0 1-1.053-.42c-.263-.317-.421-.685-.421-1.106V7.536c0-.42.158-.79.42-1.105.317-.316.685-.474 1.106-.421.421 0 .79.158 1.053.421.316.316.42.684.42 1.105v15.632Zm14.947-4.525c.316-.264.474-.58.474-1 0-2.369-1.263-4.58-3.105-5.843-1-.579-2.053-.894-3.158-.894-1.158 0-2.21.316-3.21.894a6.563 6.563 0 0 0-2.422 2.527c-.579 1.052-.895 2.316-.895 3.79a6.729 6.729 0 0 0 .843 3.526c.578 1 1.368 1.842 2.42 2.42 1.053.58 2.264.895 3.685.895.842 0 1.631-.158 2.421-.42a6.38 6.38 0 0 0 1.895-1c.473-.316.684-.738.684-1.211 0-.369-.106-.632-.369-.895a1.153 1.153 0 0 0-.894-.368 1.67 1.67 0 0 0-.843.21l-.473.263c-.316.21-.632.316-.948.421-.421.158-.947.21-1.631.21a3.805 3.805 0 0 1-3.842-3.157h8.316c.421 0 .736-.105 1.052-.368Zm-5.947-4.948c.789 0 1.526.263 2.105.737s1 1.105 1.053 1.842v.158h-6.632c.368-1.842 1.526-2.737 3.474-2.737Zm17.21-2.316c-.315-.263-.737-.42-1.263-.42-.789 0-1.579.157-2.263.526-.737.368-1.316.894-1.684 1.579v-.316c0-.421-.105-.79-.421-1.105a1.695 1.695 0 0 0-1.106-.421 1.239 1.239 0 0 0-1.105.42c-.263.316-.421.685-.421 1.106v10.368c0 .421.158.79.421 1.106.316.263.632.42 1.105.42.474 0 .843-.105 1.106-.42.263-.316.421-.685.421-1.106v-6c-.053-.684.105-1.316.368-1.947.211-.474.579-.895 1-1.21.527-.37 1.211-.474 1.842-.316l.316.105c.316.105.579.158.842.158.369.052.684-.106.948-.369.315-.263.421-.631.421-1.158 0-.368-.211-.736-.527-1Z"
|
||||
></path>
|
||||
<path fill="#066FD1" d="M31.288 7.107A8.833 8.833 0 0 0 24.893.712a55.899 55.899 0 0 0-17.786 0A8.833 8.833 0 0 0 .712 7.107a55.899 55.899 0 0 0 0 17.786 8.833 8.833 0 0 0 6.395 6.395c5.895.95 11.89.95 17.786 0a8.833 8.833 0 0 0 6.395-6.395c.95-5.895.95-11.89 0-17.786Z"></path>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M10.019 22.452a17.5 17.5 0 0 0 5.498-5.449 2.193 2.193 0 0 0 0-2.328c-1.436-2.18-3.27-4.013-5.498-5.4-1.09-.693-2.527-.297-3.22.793-.05 0-.05.05-.05.05a2.278 2.278 0 0 0 .842 3.12c1.14.743 2.13 1.585 3.022 2.626a11.782 11.782 0 0 1-3.022 2.625c-.743.396-1.189 1.189-1.189 2.031a2.397 2.397 0 0 0 3.617 1.932Zm7.727-.644h5.647c1.04 0 1.883-.495 1.883-1.486 0-.99-.843-1.486-1.883-1.486h-5.647c-1.04 0-1.882.495-1.882 1.486 0 .99.842 1.486 1.882 1.486Z"
|
||||
></path>
|
||||
</svg>
|
||||
@@ -4,87 +4,75 @@
|
||||
// the tree is frozen in shared/data/docs.json (extracted from the reference
|
||||
// development docs build).
|
||||
|
||||
import Subheader from '@ui/Subheader.astro';
|
||||
import docs from '@data/docs.json';
|
||||
import { pathSlug as slug } from '@shared/lib/string-format';
|
||||
import Subheader from '@ui/Subheader.astro'
|
||||
import docs from '@data/docs.json'
|
||||
import { pathSlug as slug } from '@shared/lib/string-format'
|
||||
|
||||
interface MenuLeaf {
|
||||
title: string;
|
||||
url: string;
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface MenuGroup extends MenuLeaf {
|
||||
children?: MenuLeaf[];
|
||||
children?: MenuLeaf[]
|
||||
}
|
||||
|
||||
interface MenuSection {
|
||||
title: string;
|
||||
children?: MenuGroup[];
|
||||
title: string
|
||||
children?: MenuGroup[]
|
||||
}
|
||||
|
||||
interface Props {
|
||||
/** Page URL in the docs namespace (equivalent of page.url), e.g. "/ui/components/alert/". */
|
||||
url: string;
|
||||
/** Page URL in the docs namespace (equivalent of page.url), e.g. "/ui/components/alert/". */
|
||||
url: string
|
||||
}
|
||||
|
||||
const { url } = Astro.props;
|
||||
const menu = docs.menu as MenuSection[];
|
||||
const { url } = Astro.props
|
||||
const menu = docs.menu as MenuSection[]
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS MENU -->
|
||||
<nav class="space-y space-y-5" id="menu">
|
||||
{
|
||||
menu.map((level1) => (
|
||||
<div>
|
||||
<Subheader class="mb-2">{level1.title}</Subheader>
|
||||
{level1.children && level1.children.length > 0 && (
|
||||
<nav class="nav nav-vertical">
|
||||
{level1.children.map((level2) => {
|
||||
const hasChildren = Boolean(level2.children && level2.children.length > 0);
|
||||
// Expanded only for the group's own page or one of its direct children —
|
||||
// a prefix check would also expand "Introduction" on /ui/getting-started/frameworks/* pages.
|
||||
const expanded = url === level2.url || Boolean(level2.children?.some((child) => child.url === url));
|
||||
return (
|
||||
<div>
|
||||
{/* as in Liquid: href/data-bs-* only when the element has children */}
|
||||
{hasChildren ? (
|
||||
<a
|
||||
class={`nav-link${expanded ? ' active' : ''}`}
|
||||
href={level2.url}
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target={`#collapse-${slug(level2.url)}`}
|
||||
aria-expanded={expanded ? 'true' : 'false'}
|
||||
>
|
||||
{level2.title} <span class="nav-link-toggle" />
|
||||
</a>
|
||||
) : (
|
||||
<a class={`nav-link${expanded ? ' active' : ''}`}>{level2.title}</a>
|
||||
)}
|
||||
{
|
||||
menu.map((level1) => (
|
||||
<div>
|
||||
<Subheader class="mb-2">{level1.title}</Subheader>
|
||||
{level1.children && level1.children.length > 0 && (
|
||||
<nav class="nav nav-vertical">
|
||||
{level1.children.map((level2) => {
|
||||
const hasChildren = Boolean(level2.children && level2.children.length > 0)
|
||||
// Expanded only for the group's own page or one of its direct children —
|
||||
// a prefix check would also expand "Introduction" on /ui/getting-started/frameworks/* pages.
|
||||
const expanded = url === level2.url || Boolean(level2.children?.some((child) => child.url === url))
|
||||
return (
|
||||
<div>
|
||||
{/* as in Liquid: href/data-bs-* only when the element has children */}
|
||||
{hasChildren ? (
|
||||
<a class={`nav-link${expanded ? ' active' : ''}`} href={level2.url} data-bs-toggle="collapse" data-bs-target={`#collapse-${slug(level2.url)}`} aria-expanded={expanded ? 'true' : 'false'}>
|
||||
{level2.title} <span class="nav-link-toggle" />
|
||||
</a>
|
||||
) : (
|
||||
<a class={`nav-link${expanded ? ' active' : ''}`}>{level2.title}</a>
|
||||
)}
|
||||
|
||||
{hasChildren && (
|
||||
<nav
|
||||
class={`nav nav-vertical collapse${expanded ? ' show' : ''}`}
|
||||
id={`collapse-${slug(level2.url)}`}
|
||||
>
|
||||
{level2.children!.map((level3) => (
|
||||
<div>
|
||||
<a
|
||||
class={`nav-link${url === level3.url ? ' active' : ''}`}
|
||||
href={level3.url}
|
||||
>
|
||||
{level3.title}
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{hasChildren && (
|
||||
<nav class={`nav nav-vertical collapse${expanded ? ' show' : ''}`} id={`collapse-${slug(level2.url)}`}>
|
||||
{level2.children!.map((level3) => (
|
||||
<div>
|
||||
<a class={`nav-link${url === level3.url ? ' active' : ''}`} href={level3.url}>
|
||||
{level3.title}
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
<!-- END DOCS MENU -->
|
||||
@@ -1,63 +1,63 @@
|
||||
---
|
||||
// Equivalent of docs/navbar.html.
|
||||
import Icon from '@ui/Icon.astro';
|
||||
import DocsLogo from './DocsLogo.astro';
|
||||
import { site } from '@shared/lib/site';
|
||||
import Icon from '@ui/Icon.astro'
|
||||
import DocsLogo from './DocsLogo.astro'
|
||||
import { site } from '@shared/lib/site'
|
||||
|
||||
// Eventually belongs in src/lib/site.ts (out of scope for this task).
|
||||
const previewUrl = 'https://preview.tabler.io';
|
||||
const changelogUrl = 'https://tabler.io/changelog';
|
||||
const previewUrl = 'https://preview.tabler.io'
|
||||
const changelogUrl = 'https://tabler.io/changelog'
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS NAVBAR -->
|
||||
<div class="navbar navbar-expand sticky-top">
|
||||
<div class="container">
|
||||
<div class="row flex-fill align-items-md-center">
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
{/* href=".": Liquid `page.url | relative` receives a string, so the filter always returns "." */}
|
||||
<a href="." class="navbar-brand navbar-brand-autodark gap-4">
|
||||
<DocsLogo />
|
||||
</a>
|
||||
<div>
|
||||
<span class="badge">v{site.version}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-none d-md-block col">
|
||||
<div id="docsearch"></div>
|
||||
</div>
|
||||
<div class="col d-flex">
|
||||
<ul class="navbar-nav ms-auto gap-2 align-items-center">
|
||||
<div class="nav-item d-none d-md-block">
|
||||
<a href={previewUrl} class="nav-link">Preview</a>
|
||||
</div>
|
||||
<div class="nav-item d-none d-md-block">
|
||||
<a href={changelogUrl} class="nav-link">Changelog</a>
|
||||
</div>
|
||||
<li class="nav-item hide-theme-dark">
|
||||
<a href="?theme=dark" class="btn btn-icon">
|
||||
<Icon name="moon" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item hide-theme-light">
|
||||
<a href="?theme=light" class="btn btn-icon">
|
||||
<Icon name="sun" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href={site.githubUrl} class="btn btn-icon" target="_blank">
|
||||
<Icon name="brand-github" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href={previewUrl} class="btn btn-primary" target="_blank">
|
||||
<Icon name="eye" /> Preview
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="row flex-fill align-items-md-center">
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
{/* href=".": Liquid `page.url | relative` receives a string, so the filter always returns "." */}
|
||||
<a href="." class="navbar-brand navbar-brand-autodark gap-4">
|
||||
<DocsLogo />
|
||||
</a>
|
||||
<div>
|
||||
<span class="badge">v{site.version}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-none d-md-block col">
|
||||
<div id="docsearch"></div>
|
||||
</div>
|
||||
<div class="col d-flex">
|
||||
<ul class="navbar-nav ms-auto gap-2 align-items-center">
|
||||
<div class="nav-item d-none d-md-block">
|
||||
<a href={previewUrl} class="nav-link">Preview</a>
|
||||
</div>
|
||||
<div class="nav-item d-none d-md-block">
|
||||
<a href={changelogUrl} class="nav-link">Changelog</a>
|
||||
</div>
|
||||
<li class="nav-item hide-theme-dark">
|
||||
<a href="?theme=dark" class="btn btn-icon">
|
||||
<Icon name="moon" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item hide-theme-light">
|
||||
<a href="?theme=light" class="btn btn-icon">
|
||||
<Icon name="sun" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href={site.githubUrl} class="btn btn-icon" target="_blank">
|
||||
<Icon name="brand-github" />
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href={previewUrl} class="btn btn-primary" target="_blank">
|
||||
<Icon name="eye" /> Preview
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END DOCS NAVBAR -->
|
||||
@@ -1,120 +1,114 @@
|
||||
---
|
||||
// Equivalent of docs/pagination.html: child-page cards or next/prev siblings.
|
||||
import DocsCard from './DocsCard.astro';
|
||||
import docs from '@data/docs.json';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
import { getDocsChildren } from '@shared/lib/docs-children';
|
||||
import type { DocsChildPage } from '@shared/lib/docs-children';
|
||||
import DocsCard from './DocsCard.astro'
|
||||
import docs from '@data/docs.json'
|
||||
import Icon from '@ui/Icon.astro'
|
||||
import { getDocsChildren } from '@shared/lib/docs-children'
|
||||
import type { DocsChildPage } from '@shared/lib/docs-children'
|
||||
|
||||
interface MenuLeaf {
|
||||
title: string;
|
||||
url: string;
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
|
||||
interface MenuNode {
|
||||
title: string;
|
||||
url?: string;
|
||||
children?: MenuNode[];
|
||||
title: string
|
||||
url?: string
|
||||
children?: MenuNode[]
|
||||
}
|
||||
|
||||
interface Props {
|
||||
/** Page URL in the docs namespace (equivalent of page.url), e.g. "/ui/components/alert/". */
|
||||
url: string;
|
||||
/** Page URL in the docs namespace (equivalent of page.url), e.g. "/ui/components/alert/". */
|
||||
url: string
|
||||
}
|
||||
|
||||
const { url } = Astro.props;
|
||||
const { url } = Astro.props
|
||||
|
||||
const children = getDocsChildren(url);
|
||||
const children = getDocsChildren(url)
|
||||
|
||||
type Pagination = {
|
||||
prev: MenuLeaf | null;
|
||||
next: MenuLeaf | null;
|
||||
found: boolean;
|
||||
};
|
||||
prev: MenuLeaf | null
|
||||
next: MenuLeaf | null
|
||||
found: boolean
|
||||
}
|
||||
|
||||
function findPage(nodes: MenuNode[]): Pagination | null {
|
||||
const index = nodes.findIndex((item) => item.url === url);
|
||||
const index = nodes.findIndex((item) => item.url === url)
|
||||
|
||||
if (index !== -1) {
|
||||
const previousNode = index > 0 ? nodes[index - 1] : null;
|
||||
const nextNode = index < nodes.length - 1 ? nodes[index + 1] : null;
|
||||
if (index !== -1) {
|
||||
const previousNode = index > 0 ? nodes[index - 1] : null
|
||||
const nextNode = index < nodes.length - 1 ? nodes[index + 1] : null
|
||||
|
||||
return {
|
||||
prev: previousNode?.url ? { title: previousNode.title, url: previousNode.url } : null,
|
||||
next: nextNode?.url ? { title: nextNode.title, url: nextNode.url } : null,
|
||||
found: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
prev: previousNode?.url ? { title: previousNode.title, url: previousNode.url } : null,
|
||||
next: nextNode?.url ? { title: nextNode.title, url: nextNode.url } : null,
|
||||
found: true,
|
||||
}
|
||||
}
|
||||
|
||||
for (const node of nodes) {
|
||||
const result = node.children ? findPage(node.children) : null;
|
||||
if (result) return result;
|
||||
}
|
||||
for (const node of nodes) {
|
||||
const result = node.children ? findPage(node.children) : null
|
||||
if (result) return result
|
||||
}
|
||||
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const { prev, next, found } = findPage(docs.menu as MenuNode[]) ?? {
|
||||
prev: null,
|
||||
next: null,
|
||||
found: false,
|
||||
};
|
||||
prev: null,
|
||||
next: null,
|
||||
found: false,
|
||||
}
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS PAGINATION -->
|
||||
{
|
||||
children.length > 0 && (
|
||||
<div class="mt-6 pt-6">
|
||||
<div class="row row-deck row-cards">
|
||||
{children.map((child: DocsChildPage) => (
|
||||
<DocsCard
|
||||
href={child.url}
|
||||
title={child.title}
|
||||
description={child.description}
|
||||
icon={child.icon}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
<!-- BEGIN DOCS PAGINATION -->{
|
||||
children.length > 0 && (
|
||||
<div class="mt-6 pt-6">
|
||||
<div class="row row-deck row-cards">
|
||||
{children.map((child: DocsChildPage) => (
|
||||
<DocsCard href={child.url} title={child.title} description={child.description} icon={child.icon} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
children.length === 0 && found && (
|
||||
<div class="mt-6 pt-6">
|
||||
<ul class="pagination">
|
||||
{prev && (
|
||||
<li class="page-item page-prev">
|
||||
<a class="page-link" href={prev.url}>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<Icon name="chevron-left" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="page-item-subtitle">previous</div>
|
||||
<div class="page-item-title">{prev.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{next && (
|
||||
<li class="page-item page-next">
|
||||
<a class="page-link" href={next.url}>
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<div class="page-item-subtitle">next</div>
|
||||
<div class="page-item-title">{next.title}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<Icon name="chevron-right" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
children.length === 0 && found && (
|
||||
<div class="mt-6 pt-6">
|
||||
<ul class="pagination">
|
||||
{prev && (
|
||||
<li class="page-item page-prev">
|
||||
<a class="page-link" href={prev.url}>
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<Icon name="chevron-left" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="page-item-subtitle">previous</div>
|
||||
<div class="page-item-title">{prev.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{next && (
|
||||
<li class="page-item page-next">
|
||||
<a class="page-link" href={next.url}>
|
||||
<div class="row align-items-center">
|
||||
<div class="col">
|
||||
<div class="page-item-subtitle">next</div>
|
||||
<div class="page-item-title">{next.title}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<Icon name="chevron-right" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<!-- END DOCS PAGINATION -->
|
||||
@@ -4,44 +4,43 @@
|
||||
// here it comes in as a prop from the consuming page.
|
||||
|
||||
export interface TocItem {
|
||||
/** 2 or 3 (h2/h3); h3 gets the ms-3 indent */
|
||||
level: number;
|
||||
text: string;
|
||||
/** anchor without '#', e.g. "default-markup" */
|
||||
id: string;
|
||||
/** 2 or 3 (h2/h3); h3 gets the ms-3 indent */
|
||||
level: number
|
||||
text: string
|
||||
/** anchor without '#', e.g. "default-markup" */
|
||||
id: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
toc?: TocItem[];
|
||||
toc?: TocItem[]
|
||||
}
|
||||
|
||||
const { toc = [] } = Astro.props;
|
||||
const { toc = [] } = Astro.props
|
||||
|
||||
// Equivalent of `illustrations | size` (shared/data/illustrations.json has 100 entries).
|
||||
const illustrationsCount = 100;
|
||||
const illustrationsCount = 100
|
||||
---
|
||||
|
||||
<!-- BEGIN DOCS TOC -->
|
||||
{
|
||||
toc.length > 0 && (
|
||||
<Fragment>
|
||||
<h3>Table of Contents</h3>
|
||||
<div class="nav nav-vertical" id="toc">
|
||||
{toc.map((item) => (
|
||||
<a href={`#${item.id}`} class={`nav-link${item.level === 3 ? ' ms-3' : ''}`}>
|
||||
{item.text}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
<!-- BEGIN DOCS TOC -->{
|
||||
toc.length > 0 && (
|
||||
<Fragment>
|
||||
<h3>Table of Contents</h3>
|
||||
<div class="nav nav-vertical" id="toc">
|
||||
{toc.map((item) => (
|
||||
<a href={`#${item.id}`} class={`nav-link${item.level === 3 ? ' ms-3' : ''}`}>
|
||||
{item.text}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
<a href="https://r.tabler.io/illustrations" class="card card-sm mt-6 shadow-none" target="_blank">
|
||||
<div class="card-body">
|
||||
<img src="/img/banner-carbon.png" class="mb-3" alt="" />
|
||||
<div class="card-body">
|
||||
<img src="/img/banner-carbon.png" class="mb-3" alt="" />
|
||||
|
||||
<h4>{illustrationsCount} sleek illustrations for your startup's visual identity.</h4>
|
||||
</div>
|
||||
<h4>{illustrationsCount} sleek illustrations for your startup's visual identity.</h4>
|
||||
</div>
|
||||
</a>
|
||||
<!-- END DOCS TOC -->
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
interface Props {
|
||||
href: string
|
||||
title: string
|
||||
href: string
|
||||
title: string
|
||||
}
|
||||
|
||||
const { href, title }: Props = Astro.props;
|
||||
const { href, title }: Props = Astro.props
|
||||
---
|
||||
|
||||
<div class="my-6 text-center">
|
||||
<a href={href} class="btn btn btn-primary" target="_blank">{title}</a>
|
||||
<a href={href} class="btn btn btn-primary" target="_blank">{title}</a>
|
||||
</div>
|
||||
@@ -1,99 +1,68 @@
|
||||
---
|
||||
// copy button with data-clipboard-text (equivalent of escape_attribute).
|
||||
// The example code comes from the `html` prop or from the rendered slot.
|
||||
import Icon from '@ui/Icon.astro';
|
||||
import { beautifyHtml, highlightCode, removeHref } from '@shared/lib/code-example';
|
||||
import Icon from '@ui/Icon.astro'
|
||||
import { beautifyHtml, highlightCode, removeHref } from '@shared/lib/code-example'
|
||||
|
||||
interface Props {
|
||||
/** raw HTML of the example; when absent — the slot is rendered */
|
||||
html?: string;
|
||||
/** code shown in the panel instead of html (the code param in Liquid) */
|
||||
code?: string;
|
||||
raw?: boolean;
|
||||
overflow?: string;
|
||||
bg?: string;
|
||||
class?: string;
|
||||
height?: string;
|
||||
column?: boolean;
|
||||
centered?: boolean;
|
||||
vertical?: boolean;
|
||||
columnFullWidth?: boolean;
|
||||
hideCode?: boolean;
|
||||
codeOnly?: boolean;
|
||||
/** raw HTML of the example; when absent — the slot is rendered */
|
||||
html?: string
|
||||
/** code shown in the panel instead of html (the code param in Liquid) */
|
||||
code?: string
|
||||
raw?: boolean
|
||||
overflow?: string
|
||||
bg?: string
|
||||
class?: string
|
||||
height?: string
|
||||
column?: boolean
|
||||
centered?: boolean
|
||||
vertical?: boolean
|
||||
columnFullWidth?: boolean
|
||||
hideCode?: boolean
|
||||
codeOnly?: boolean
|
||||
}
|
||||
|
||||
const {
|
||||
html: htmlProp,
|
||||
code,
|
||||
raw,
|
||||
overflow = 'auto',
|
||||
bg,
|
||||
class: className,
|
||||
height,
|
||||
column,
|
||||
centered,
|
||||
vertical,
|
||||
columnFullWidth,
|
||||
hideCode,
|
||||
codeOnly,
|
||||
} = Astro.props;
|
||||
const { html: htmlProp, code, raw, overflow = 'auto', bg, class: className, height, column, centered, vertical, columnFullWidth, hideCode, codeOnly } = Astro.props
|
||||
|
||||
// equivalent of {% removeemptylines %} around include output (e.g. ui/alert.html)
|
||||
let html = (htmlProp ?? (await Astro.slots.render('default'))).replace(/^\s*[\r\n]/gm, '');
|
||||
let html = (htmlProp ?? (await Astro.slots.render('default'))).replace(/^\s*[\r\n]/gm, '')
|
||||
|
||||
// JSX reserializes the slot markup: empty SVG elements get explicit closing
|
||||
// tags, and apostrophes in text are escaped. We restore the source form so the
|
||||
// code in the panel looks like hand-written HTML.
|
||||
html = html
|
||||
.replace(/<(path|circle|line|polyline|polygon|rect|ellipse)([^>]*?)\s*><\/\1>/g, '<$1$2 />')
|
||||
.replace(/'/g, "'");
|
||||
html = html.replace(/<(path|circle|line|polyline|polygon|rect|ellipse)([^>]*?)\s*><\/\1>/g, '<$1$2 />').replace(/'/g, "'")
|
||||
|
||||
const exampleClasses = [
|
||||
'example fs-base border rounded my-5',
|
||||
!raw && 'd-flex flex-wrap justify-content-center',
|
||||
`overflow-${overflow}`,
|
||||
'position-relative',
|
||||
bg ? `bg-${bg}` : 'bg-pattern-rectangles',
|
||||
className,
|
||||
]
|
||||
const exampleClasses = ['example fs-base border rounded my-5', !raw && 'd-flex flex-wrap justify-content-center', `overflow-${overflow}`, 'position-relative', bg ? `bg-${bg}` : 'bg-pattern-rectangles', className]
|
||||
|
||||
const innerClasses = [
|
||||
'p-6 w-full',
|
||||
column && 'd-flex gap-3 flex-column',
|
||||
!column && centered && `d-flex flex-fill flex-wrap gap-2 justify-content-center${vertical ? ' align-items-center flex-column' : ' justify-content-center'}`,
|
||||
columnFullWidth && 'd-flex flex-fill flex-column gap-2',
|
||||
]
|
||||
const innerClasses = ['p-6 w-full', column && 'd-flex gap-3 flex-column', !column && centered && `d-flex flex-fill flex-wrap gap-2 justify-content-center${vertical ? ' align-items-center flex-column' : ' justify-content-center'}`, columnFullWidth && 'd-flex flex-fill flex-column gap-2']
|
||||
|
||||
const highlighted = hideCode ? '' : await highlightCode(beautifyHtml(code ?? html), 'html');
|
||||
const highlighted = hideCode ? '' : await highlightCode(beautifyHtml(code ?? html), 'html')
|
||||
---
|
||||
|
||||
<!--EXAMPLE-->
|
||||
{
|
||||
!codeOnly && (
|
||||
<div class:list={exampleClasses} style={height ? `height: ${height}` : undefined}>
|
||||
{
|
||||
raw ? (
|
||||
<Fragment set:html={removeHref(html)} />
|
||||
) : (
|
||||
<div class:list={innerClasses} style={column ? 'max-width: 25rem;' : undefined}>
|
||||
<Fragment set:html={removeHref(html)} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
<!--EXAMPLE-->{
|
||||
!codeOnly && (
|
||||
<div class:list={exampleClasses} style={height ? `height: ${height}` : undefined}>
|
||||
{raw ? (
|
||||
<Fragment set:html={removeHref(html)} />
|
||||
) : (
|
||||
<div class:list={innerClasses} style={column ? 'max-width: 25rem;' : undefined}>
|
||||
<Fragment set:html={removeHref(html)} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
!hideCode && (
|
||||
<div class="position-relative">
|
||||
{/* Astro escapes the attribute value itself (equivalent of escape_attribute) */}
|
||||
<a class="btn btn-icon btn-dark position-absolute m-2 top-0 end-0 z-3" data-clipboard-text={html}>
|
||||
<Icon name="clipboard" />
|
||||
<Icon name="check" class="d-none" />
|
||||
</a>
|
||||
<Fragment set:html={highlighted} />
|
||||
</div>
|
||||
)
|
||||
!hideCode && (
|
||||
<div class="position-relative">
|
||||
{/* Astro escapes the attribute value itself (equivalent of escape_attribute) */}
|
||||
<a class="btn btn-icon btn-dark position-absolute m-2 top-0 end-0 z-3" data-clipboard-text={html}>
|
||||
<Icon name="clipboard" />
|
||||
<Icon name="check" class="d-none" />
|
||||
</a>
|
||||
<Fragment set:html={highlighted} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<!--/EXAMPLE-->
|
||||
+23
-17
@@ -3,24 +3,30 @@ import flags from '@data/flags.json'
|
||||
---
|
||||
|
||||
<table class="table table-vcenter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">Flag</th>
|
||||
<th>Name</th>
|
||||
<th class="w-1">Country code</th>
|
||||
<th>CSS class</th>
|
||||
</tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">Flag</th>
|
||||
<th>Name</th>
|
||||
<th class="w-1">Country code</th>
|
||||
<th>CSS class</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{flags.map((flag) => (
|
||||
<tr>
|
||||
<td>
|
||||
<div class={`flag flag-sm flag-country-${ flag.flag }`}></div>
|
||||
</td>
|
||||
<td>{ flag.name }</td>
|
||||
<td><code>{ flag.flag }</code></td>
|
||||
<td><code>.flag-country-{ flag.flag }</code></td>
|
||||
</tr>
|
||||
))}
|
||||
{
|
||||
flags.map((flag) => (
|
||||
<tr>
|
||||
<td>
|
||||
<div class={`flag flag-sm flag-country-${flag.flag}`} />
|
||||
</td>
|
||||
<td>{flag.name}</td>
|
||||
<td>
|
||||
<code>{flag.flag}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>.flag-country-{flag.flag}</code>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1,30 +1,26 @@
|
||||
---
|
||||
import openSources from '@data/open-source.json';
|
||||
import openSources from '@data/open-source.json'
|
||||
---
|
||||
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>
|
||||
Name
|
||||
</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
<th>
|
||||
License
|
||||
</th>
|
||||
</tr>
|
||||
{ openSources.map((el) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<a href={el.url} target="_blank">
|
||||
{el.name}
|
||||
</a>
|
||||
</td>
|
||||
<td>{el.description}</td>
|
||||
<td>{el.license}</td>
|
||||
</tr>
|
||||
)
|
||||
}) }
|
||||
<tr>
|
||||
<th> Name </th>
|
||||
<th> Description </th>
|
||||
<th> License </th>
|
||||
</tr>
|
||||
{
|
||||
openSources.map((el) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<a href={el.url} target="_blank">
|
||||
{el.name}
|
||||
</a>
|
||||
</td>
|
||||
<td>{el.description}</td>
|
||||
<td>{el.license}</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
}
|
||||
</table>
|
||||
@@ -1,33 +1,38 @@
|
||||
---
|
||||
import payments from '@data/payments.json';
|
||||
import payments from '@data/payments.json'
|
||||
---
|
||||
|
||||
<table class="table table-vcenter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">Icon light</th>
|
||||
<th class="w-1">Icon dark</th>
|
||||
<th>Provider name</th>
|
||||
<th>CSS class</th>
|
||||
</tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">Icon light</th>
|
||||
<th class="w-1">Icon dark</th>
|
||||
<th>Provider name</th>
|
||||
<th>CSS class</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{payments.map((payment) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<div class={`payment payment-sm payment-provider-${ payment.logo }`}></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class={`payment payment-sm payment-provider-${ payment.logo }-dark`}></div>
|
||||
</td>
|
||||
<td>{ payment.name }</td>
|
||||
<td>
|
||||
<code>.payment-provider-{ payment.logo }</code><br>
|
||||
<code>.payment-provider-{ payment.logo }-dark</code>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
{
|
||||
payments.map((payment) => {
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<div class={`payment payment-sm payment-provider-${payment.logo}`} />
|
||||
</td>
|
||||
<td>
|
||||
<div class={`payment payment-sm payment-provider-${payment.logo}-dark`} />
|
||||
</td>
|
||||
<td>{payment.name}</td>
|
||||
<td>
|
||||
<>
|
||||
<code>.payment-provider-{payment.logo}</code>
|
||||
<br />
|
||||
</>
|
||||
<code>.payment-provider-{payment.logo}-dark</code>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1,26 +1,31 @@
|
||||
---
|
||||
import socials from '@data/socials.json';
|
||||
import socials from '@data/socials.json'
|
||||
---
|
||||
|
||||
<table class="table table-vcenter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">App</th>
|
||||
<th>Name</th>
|
||||
<th>CSS class</th>
|
||||
</tr>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1">App</th>
|
||||
<th>Name</th>
|
||||
<th>CSS class</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{socials.map((social) => (
|
||||
<tr>
|
||||
<td>
|
||||
<div class={`social social-sm social-app-${ social.file }`}></div>
|
||||
</td>
|
||||
<td>{ social.name }</td>
|
||||
<td>
|
||||
<code>.social-app-{ social.file }</code><br>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{
|
||||
socials.map((social) => (
|
||||
<tr>
|
||||
<td>
|
||||
<div class={`social social-sm social-app-${social.file}`} />
|
||||
</td>
|
||||
<td>{social.name}</td>
|
||||
<td>
|
||||
<>
|
||||
<code>.social-app-{social.file}</code>
|
||||
<br />
|
||||
</>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -4,5 +4,5 @@
|
||||
---
|
||||
|
||||
<div class="steps steps-vertical">
|
||||
<slot />
|
||||
<slot />
|
||||
</div>
|
||||
@@ -1,45 +1,36 @@
|
||||
---
|
||||
import { Code } from 'astro:components';
|
||||
import packageManagers from '@data/package-managers.json';
|
||||
import { Code } from 'astro:components'
|
||||
import packageManagers from '@data/package-managers.json'
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
name: string
|
||||
}
|
||||
|
||||
const { name }: Props = Astro.props;
|
||||
const { name }: Props = Astro.props
|
||||
---
|
||||
|
||||
<ul class="nav nav-bordered mb-2" role="tablist">
|
||||
{packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
class={`nav-link${i === 0 ? ' active' : ''}`}
|
||||
id={`${manager.name}-tab`}
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target={`#${manager.name}`}
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="home"
|
||||
aria-selected={i === 0 ? 'true' : 'false'}>
|
||||
<span set:html={manager.icon.replace('<svg ', '<svg class="me-2" ')} />
|
||||
{manager.name}
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
{
|
||||
packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class={`nav-link${i === 0 ? ' active' : ''}`} id={`${manager.name}-tab`} data-bs-toggle="tab" data-bs-target={`#${manager.name}`} type="button" role="tab" aria-controls="home" aria-selected={i === 0 ? 'true' : 'false'}>
|
||||
<span set:html={manager.icon.replace('<svg ', '<svg class="me-2" ')} />
|
||||
{manager.name}
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
{packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<div
|
||||
class={`tab-pane${i === 0 ? ' show active' : ''}`}
|
||||
id={`${manager.name}`}
|
||||
role="tabpanel"
|
||||
aria-labelledby={`${manager.name}-tab`}
|
||||
>
|
||||
<Code code={`${manager.command} ${manager.install} ${name}`} lang="bash" />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
{
|
||||
packageManagers.map((manager, i) => {
|
||||
return (
|
||||
<div class={`tab-pane${i === 0 ? ' show active' : ''}`} id={`${manager.name}`} role="tabpanel" aria-labelledby={`${manager.name}-tab`}>
|
||||
<Code code={`${manager.command} ${manager.install} ${name}`} lang="bash" />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
File renamed without changes.
@@ -0,0 +1,65 @@
|
||||
---
|
||||
// Adapter: MDX (layout in frontmatter) → DocsLayout.
|
||||
// Astro passes { frontmatter, headings, url, file } to the MDX layout — we map it
|
||||
// onto DocsLayout props, computing the TOC from the headings (equivalent of the `toc` filter).
|
||||
import DocsLayout from './DocsLayout.astro'
|
||||
|
||||
interface MdxHeading {
|
||||
depth: number
|
||||
slug: string
|
||||
text: string
|
||||
}
|
||||
|
||||
interface MdxFrontmatter {
|
||||
'title'?: string
|
||||
'seoTitle'?: string
|
||||
'summary'?: string
|
||||
'description'?: string
|
||||
'seoDescription'?: string
|
||||
'added-in'?: string;
|
||||
'docs-libs'?: string[]
|
||||
'hide-pagination'?: boolean
|
||||
}
|
||||
|
||||
const {
|
||||
frontmatter,
|
||||
headings = [],
|
||||
url,
|
||||
file,
|
||||
} = Astro.props as {
|
||||
frontmatter: MdxFrontmatter
|
||||
headings: MdxHeading[]
|
||||
url?: string
|
||||
file?: string
|
||||
}
|
||||
|
||||
// Repo-relative source path for the "Edit this page" link, e.g.
|
||||
// "docs/pages/ui/components/alert.mdx" (`file` is the absolute path of the MDX page).
|
||||
const editPath = file?.includes('/docs/pages/') ? file.replace(/^.*\/docs\/pages\//, 'docs/pages/') : undefined
|
||||
|
||||
const docsLibs = frontmatter['docs-libs'] ?? []
|
||||
|
||||
const toc = headings
|
||||
.filter((heading) => heading.depth === 2 || heading.depth === 3)
|
||||
.map((heading) => ({
|
||||
level: heading.depth as 2 | 3,
|
||||
text: heading.text,
|
||||
id: heading.slug,
|
||||
}))
|
||||
---
|
||||
|
||||
<DocsLayout
|
||||
title={frontmatter.title ?? ''}
|
||||
seoTitle={frontmatter.seoTitle}
|
||||
summary={frontmatter.summary}
|
||||
description={frontmatter.description}
|
||||
seoDescription={frontmatter.seoDescription}
|
||||
addedIn={frontmatter['added-in']}
|
||||
docsLibs={docsLibs}
|
||||
hidePagination={frontmatter['hide-pagination']}
|
||||
editPath={editPath}
|
||||
toc={toc}
|
||||
url={url ? `${url.replace(/\.html$/, '').replace(/\/$/, '')}/` : undefined}
|
||||
>
|
||||
<slot />
|
||||
</DocsLayout>
|
||||
@@ -5,5 +5,5 @@ order: 4
|
||||
description: Customizable email templates for over 90 clients and devices.
|
||||
summary: Tabler Emails is a set of 80 eye-catching, customizable HTML templates. They are compatible with over 90 email clients and devices.
|
||||
seoDescription: Tabler Emails is a collection of 80 premium, customizable HTML templates. They are compatible with over 90 email clients and devices.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -5,7 +5,7 @@ seoTitle: Tabler Emails - How to use the compiled HTML email templates
|
||||
description: Learn how to use the compiled HTML email templates from the Tabler Emails package.
|
||||
summary: The compiled HTML files from the Tabler Emails package are ready to use in your email marketing campaigns. This guide explains how to use them effectively.
|
||||
seoDescription: The compiled HTML files from the Tabler Emails package are ready to use in your email marketing campaigns. This guide explains how to use them effectively.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ seoTitle: Tabler Emails - Content of the package
|
||||
description: Content of the Tabler Emails package.
|
||||
summary: The Tabler Emails package contains files which can be used by everyone, even without great knowledge of HTML.
|
||||
seoDescription: todo
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@ seoTitle: Introduction to Tabler Emails
|
||||
description: Base information about Tabler Emails package.
|
||||
summary: Tabler Emails is a set of 80 eye-catching, customizable HTML templates. They are compatible with over 90 email clients and devices.
|
||||
seoDescription: Tabler Emails is a collection of 80 premium, customizable HTML templates. They are compatible with over 90 email clients and devices.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -5,7 +5,7 @@ seoTitle: Tabler Emails - How to use the source HTML email templates
|
||||
description: Learn how to use the source HTML email templates from the Tabler Emails package.
|
||||
summary: The source HTML files from the Tabler Emails package need a bit more work than the compiled ones. Learn how to use them.
|
||||
seoDescription: The source HTML files from the Tabler Emails package need a bit more work than the compiled ones. Learn how to use them.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ summary:
|
||||
developers looking to enhance their projects with high-quality icons.
|
||||
order: 2
|
||||
description: Over 5000 pixel-perfect icons for web design and development
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import { site } from '@shared/lib/site'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Astro
|
||||
description: Tabler Icons library for Astro framework.
|
||||
summary: Tabler Icons for Astro provides an optimized collection of icons specifically designed for use with Astro. These lightweight and scalable icons are easy to integrate into Astro-based projects.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
title: Libraries
|
||||
description: Explore Tabler Icons libraries.
|
||||
summary: The libraries section offers various integrations of Tabler Icons for popular frameworks and technologies, making it easy to incorporate icons into any project.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Preact
|
||||
description: Tabler Icons library for Preact framework.
|
||||
summary: Tabler Icons for Preact provides an optimized collection of icons specifically designed for use with Preact. These lightweight and scalable icons are easy to integrate into Preact-based projects.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: React
|
||||
description: Tabler Icons library for React framework.
|
||||
summary: Tabler Icons for React offers a robust set of icons tailored for React applications, providing developers with a seamless way to enhance their user interfaces with high-quality, scalable graphics.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: SolidJS
|
||||
description: Tabler Icons library for SolidJS framework.
|
||||
summary: Tabler Icons for SolidJS is a lightweight library offering a vast selection of high-quality icons. It is designed for seamless integration with SolidJS, enabling developers to build visually appealing interfaces.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Svelte
|
||||
description: Tabler Icons library for Svelte framework.
|
||||
summary: Tabler Icons for Svelte provides a clean and efficient way to use Tabler's comprehensive icon set in Svelte applications, helping developers deliver polished, user-friendly designs.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Vue
|
||||
description: Tabler Icons library for Vue framework.
|
||||
summary: Tabler Icons for Vue offers a collection of customizable and scalable icons designed for use in Vue applications, providing a powerful tool for creating modern and engaging interfaces.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Webfont
|
||||
description: Tabler Icons as a webfont.
|
||||
summary: Tabler Icons as a webfont allows you to easily include icons in your projects using simple CSS classes, offering a lightweight and scalable solution for web development.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Figma plugin
|
||||
description: Use Tabler Icons directly in Figma.
|
||||
summary: The Tabler Figma plugin allows designers to seamlessly integrate Tabler Icons into their Figma projects, providing quick access to a vast library of customizable icons that enhance the design workflow.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import DownloadButton from '@components/DownloadButton.astro'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Plugins
|
||||
description: Icon plugins for seamless integration.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: EPS version
|
||||
description: Download Tabler Icons in EPS format.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
title: Static files
|
||||
description: Download static file formats of icons.
|
||||
summary: Static files provide multiple formats of Tabler Icons, including EPS, PDF, PNG, and SVG, offering flexibility for different design and development workflows.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: PDF version
|
||||
description: Download Tabler Icons in PDF format.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: PNG version
|
||||
description: Download Tabler Icons in PNG format.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: SVG version
|
||||
description: Download Tabler Icons in SVG format.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import TabsPackage from '@components/TabsPackage.astro'
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Tabler Illustrations
|
||||
order: 3
|
||||
description: Customizable illustrations for modern web and mobile designs.
|
||||
summary: Tabler Illustrations is a collection of customizable SVG illustrations for your web project. Explore our library of illustrations to enhance your web development experience.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
# Tabler Illustrations
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Contents
|
||||
description: Explore Tabler Illustrations folder structure
|
||||
summary: The Tabler Illustrations package is thoughtfully structured to provide designers and developers with an array of high-quality assets. This guide explores the various folders and their contents, helping users make the most of these resources.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Customization
|
||||
description: Customize the illustrations to match your brand.
|
||||
summary: Learn how to tailor Tabler Illustrations by adjusting colors, sizes, and formats. This section provides insights into seamlessly integrating illustrations to align with your design and branding.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
title: Introduction
|
||||
description: Introduction to Tabler Illustrations and their key features.
|
||||
summary: Tabler Illustrations is a collection of high-quality, customizable illustrations designed to enhance the visual appeal of your projects. These illustrations align seamlessly with the Tabler design system, making it easy to create engaging and cohesive designs for websites, apps, and presentations
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Tabler Illustrations License
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Preview
|
||||
summary: 'Tabler Illustrations offers 80 illustrations in two themes: light and dark. You can use them in your projects to enhance the visual appeal and convey messages effectively.'
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import illustrations from '@data/illustrations.json'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Welcome to Tabler Documentation
|
||||
summary: Tabler Docs provides a comprehensive guide to help you get started with the Tabler ecosystem, including its UI components, plugins, and icons. Explore detailed documentation to understand and leverage the full potential of Tabler in your projects.
|
||||
description: Find comprehensive guides, examples, and resources to help you use Tabler UI components, plugins, icons, and tools effectively in your projects.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import Card from '@components/DocsCard.astro'
|
||||
|
||||
@@ -4,7 +4,7 @@ summary:
|
||||
The choice of colors for a website or app interface has a big influence on how users interact with the product and what decisions they make. Harmonious colors can contribute to a nice first impression and encourage users to engage with your product, so it's a very important aspect of a successful design, which needs
|
||||
to be well thought out.
|
||||
description: Impact of colors on user interface design.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import Colors from '@components/Colors.astro'
|
||||
|
||||
@@ -3,5 +3,5 @@ title: Base
|
||||
order: 2
|
||||
description: Foundational elements for UI design.
|
||||
summary: The base section includes foundational elements such as colors, typography, and spacing that form the building blocks of a cohesive and consistent user interface.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -4,7 +4,7 @@
|
||||
// so the include gets an empty url and the target collapses to `{{ page | relative }}`.
|
||||
// For this 3-deep page that is "../../..", which is exactly what the reference
|
||||
// build (ui/base/markdown/index.html) redirects to.
|
||||
import RedirectLayout from '@shared/layouts/RedirectLayout.astro';
|
||||
import RedirectLayout from '@shared/layouts/RedirectLayout.astro'
|
||||
---
|
||||
|
||||
<RedirectLayout base="../../.." />
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Prose
|
||||
summary: Use the `.prose` wrapper to style long-form content without adding classes to every element.
|
||||
description: Long-form content styles for markdown-like HTML.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Prose from '@ui/Prose.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Typography
|
||||
summary: Typography plays an important role in creating an attractive and clear interface design. Good typography will make the content easy to follow and improve the usability of your website.
|
||||
description: Role of typography in interface design.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Prose from '@ui/Prose.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Accordion
|
||||
summary: Use accordion panels to group related content and show one section at a time.
|
||||
description: Build collapsible content sections with accordion classes and modifiers.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Alert
|
||||
summary: An alert message is used to inform users about the status of their action and help them solve problems that may occur. Good alert design is important for the overall user experience of a website or app.
|
||||
description: An alert message for user notification.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Alert from '@ui/Alert.astro';
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Autosize
|
||||
summary: The autosize element will automatically adjust the textarea height and make it easier for users to follow as they type.
|
||||
docs-libs: autosize
|
||||
description: Auto-adjusting textarea for better usability.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Avatar
|
||||
summary: An avatar helps customize interface elements and make the product experience more personalized. It is often used in communication apps, collaboration tools, and social media.
|
||||
description: Personalize UI with a user avatar.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Badge
|
||||
summary: A badge is a small count and labeling component used to add extra information to an interface element. You can use it to draw user attention to a new element, notify about unread messages, or provide additional context.
|
||||
description: Add extra information with a badge.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import BadgesList from '@ui/BadgesList.astro';
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Breadcrumb
|
||||
summary: A breadcrumb is used to show the current website or app location and reduce the number of actions users need to take. It helps users navigate the website hierarchy and better understand its structure.
|
||||
description: A navigation aid for better structure.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Breadcrumb from '@ui/Breadcrumb.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Button
|
||||
summary: Use a button style that best suits your design and encourages users to take the desired action. You can customize button properties to improve user experience by changing size, shape, color, and more.
|
||||
description: A customizable button for user actions.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import ButtonGroup from '@ui/ButtonGroup.astro';
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Card gradient
|
||||
summary: Card gradients add rich color backgrounds to cards and help emphasize key information in dashboards and marketing sections.
|
||||
description: Build eye-catching cards with gradient variants, directions, and animated backgrounds.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import Example from '@components/Example.astro'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Card
|
||||
summary: A card is a flexible user interface element that helps organize content into meaningful sections and display it across different screen sizes. It can contain smaller elements such as images, text, links, and buttons, and can act as an entry point to more detailed information.
|
||||
description: Organize content with a flexible card.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Carousel
|
||||
summary: A carousel is used to display multiple pieces of visual content without taking up too much space. It eliminates the need to scroll down the page to see all content and is a popular method of presenting marketing information.
|
||||
description: Display visual content with a carousel.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Chart
|
||||
docs-libs: [apexcharts]
|
||||
summary: Tabler uses ApexCharts - a free and open-source modern charting library that helps developers to create beautiful and interactive visualizations for web pages.
|
||||
description: Interactive data visualizations with ApexCharts.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
|
||||
import Example from '@components/Example.astro'
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Countup
|
||||
summary: A countup element is used to display numerical data in an interesting way and make the interface more interactive.
|
||||
docs-libs: countup
|
||||
description: Display numbers dynamically with a countup.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Data grid
|
||||
summary: Use the data grid component to display detailed information about your product. The data is displayed as a column of items consisting of a title and content.
|
||||
description: Detailed product information in grids.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Divider
|
||||
summary: Dividers help organize content and make the interface layout clear and uncluttered. Greater clarity adds up to better user experience and enhanced interaction with a website or app.
|
||||
description: Separate content with clear dividers.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Dropdown
|
||||
summary: A dropdown is used to display a list of options or include more items in a menu without overwhelming users with too many buttons and long lists. It improves interaction with your website or software and keeps the interface clear.
|
||||
description: Organize options with a dropdown menu.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Dropzone
|
||||
summary: Dropzone is a simple JavaScript library that helps you add file drag and drop functionality to your web forms. It is one of the most popular drag and drop libraries on the web and is used by millions of people.
|
||||
description: Drag-and-drop file upload tool.
|
||||
docs-libs: dropzone
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Empty State
|
||||
summary: An empty state or blank page is commonly used as a placeholder for first-use, empty data, or an error screen. Its goal is to engage users when there is no content to display, which makes its design important for the overall user experience of your website or app.
|
||||
description: Engage users in an empty or error screen.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Illustration from '@ui/Illustration.astro';
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Icon
|
||||
summary: Use an icon from over 5000 options created specifically for Tabler to make your dashboard more attractive. Each icon is available under the MIT license, so it can be used in both private and commercial projects.
|
||||
banner: icons
|
||||
description: Enhance a dashboard with a custom icon.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
|
||||
@@ -3,5 +3,5 @@ title: Components
|
||||
order: 4
|
||||
description: Various components to enhance UI.
|
||||
summary: Tabler UI includes a variety of components to help you build web applications that are both functional and visually appealing. From buttons and cards to modals and navigation, these components provide a wide range of features to enhance your site.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
@@ -3,7 +3,7 @@ title: Inline player
|
||||
docs-libs: plyr
|
||||
summary: A simple, lightweight, accessible and customizable HTML5, YouTube and Vimeo media player that supports modern browsers.
|
||||
description: Lightweight media player for websites.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import { Code } from 'astro:components';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Modal
|
||||
summary: Use Bootstrap’s JavaScript modal plugin to add dialogs to your site for lightboxes, user notifications, or completely custom content.
|
||||
description: Dialogs for notifications and content.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Offcanvas
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Pagination
|
||||
summary: Pagination is a user interface element that allows users to navigate through a set of data or content that is divided into multiple pages. It is commonly used in web applications, blogs, and e-commerce sites to display large amounts of information in a manageable way.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Pagination from '@ui/Pagination.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Placeholder
|
||||
summary: Placeholder is used to reserve space for content that will soon appear in a layout.
|
||||
description: Reserve space for upcoming content.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Popover
|
||||
summary: A popover is used to provide additional information for elements where a simple tooltip is not sufficient.
|
||||
description: Provide extra information with a popover.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Progress Steps
|
||||
summary: A progress step helps users track their place in a short process by breaking it into clear, simple steps. This makes flows like setup or onboarding easier to follow and finish.
|
||||
new: true
|
||||
description: Use progress steps to display compact onboarding, checkout, and setup progress.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import ProgressSteps from '@ui/ProgressSteps.astro';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Progress Bar
|
||||
summary: A progress bar is used to provide feedback on an action status and inform users about current progress. Although it is a small interface element, it is extremely helpful in managing user expectations and preventing abandonment of an initiated process.
|
||||
description: Track and display progress with a progress bar.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import ProgressBg from '@ui/ProgressBg.astro';
|
||||
|
||||
@@ -3,7 +3,7 @@ title: Range slider
|
||||
docs-libs: nouislider
|
||||
description: Adjust values with a range slider.
|
||||
summary: A range slider allows users to select a range of values by adjusting two handles along a track, providing an intuitive and space-efficient input method.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: Ribbon
|
||||
summary: A ribbon is a graphical element that attracts user attention to a given interface element and makes it stand out.
|
||||
description: Highlight an element with a graphical ribbon.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Segmented Control
|
||||
summary: A segmented control is a set of two or more segments, each of which functions as a mutually exclusive button. A segmented control is used to display a set of mutually exclusive options.
|
||||
layout: '@shared/layouts/DocsMdxLayout.astro'
|
||||
layout: '@layouts/DocsMdxLayout.astro'
|
||||
---
|
||||
import Example from '@components/Example.astro';
|
||||
import Icon from '@ui/Icon.astro';
|
||||
|
||||
Loaded 100 of 552 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user