1
0
mirror of https://github.com/tabler/tabler.git synced 2026-07-15 10:01:41 +04:00

Merge branch 'dev' of https://github.com/tabler/tabler into fix-1927

This commit is contained in:
Bartek
2026-02-26 14:36:17 +01:00
543 changed files with 17492 additions and 8244 deletions
@@ -1,18 +1,20 @@
#!/usr/bin/env node
'use strict'
import { readFileSync, writeFileSync } from 'node:fs';
import { join, dirname, basename } from 'node:path';
import { readFileSync, writeFileSync } from 'node:fs'
import { join, dirname, basename } from 'node:path'
import { fileURLToPath } from 'node:url'
import { sync } from 'glob';
import banner from '../../shared/banner/index.mjs';
import { sync } from 'glob'
import banner from '../../shared/banner/index.mjs'
const __dirname = dirname(fileURLToPath(import.meta.url))
const styles = sync(join(__dirname, '..', 'dist', 'css', '*.css'))
const styles: string[] = sync(join(__dirname, '..', 'dist', 'css', '*.css'))
const plugins = {
interface Plugins {
[key: string]: string
}
const plugins: Plugins = {
'tabler-flags': 'Flags',
'tabler-flags.rtl': 'Flags RTL',
'tabler-marketing': 'Marketing',
@@ -25,22 +27,24 @@ const plugins = {
'tabler-vendors.rtl': 'Vendors RTL',
}
styles.forEach((file, i) => {
styles.forEach((file: string) => {
const content = readFileSync(file, 'utf8')
const filename = basename(file)
const pluginKey = Object.keys(plugins).find(plugin => filename.includes(plugin))
const plugin = plugins[pluginKey]
const pluginKey = Object.keys(plugins).find((plugin: string) => filename.includes(plugin))
const plugin = pluginKey ? plugins[pluginKey] : undefined
const regex = /^(@charset ['"][a-zA-Z0-9-]+['"];?)\n?/i
let newContent = ''
const bannerText = banner(plugin)
if (content.match(regex)) {
newContent = content.replace(regex, (m, m1) => {
return `${m1}\n${banner(plugin)}\n`
newContent = content.replace(regex, (m: string, m1: string) => {
return `${m1}\n${bannerText}\n`
})
} else {
newContent = `${banner(plugin)}\n${content}`
newContent = `${bannerText}\n${content}`
}
writeFileSync(file, newContent, 'utf8')
})
})
+84
View File
@@ -0,0 +1,84 @@
import { readFileSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
// Get __dirname in ES modules
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
// File paths (relative to core/.build directory)
const bootstrapPath = path.join(__dirname, '../node_modules/bootstrap/scss/_variables.scss')
const tablerPath = path.join(__dirname, '../scss/_variables.scss')
// Function to extract variable names from SCSS file
function extractVariables(filePath: string): Set<string> {
const content = readFileSync(filePath, 'utf8')
const variables = new Set<string>()
// Regex to find SCSS variables
// Looks for patterns like: $variable-name: value
// Includes variables in maps and lists
const variableRegex = /\$([a-zA-Z0-9_-]+)\s*[:=]/g
let match: RegExpExecArray | null
while ((match = variableRegex.exec(content)) !== null) {
const varName = match[1]
variables.add(varName)
}
return variables
}
// Main function
function compareVariables(): void {
console.log('Analyzing Bootstrap variables...')
const bootstrapVars = extractVariables(bootstrapPath)
console.log(`Found ${bootstrapVars.size} variables in Bootstrap\n`)
console.log('Analyzing Tabler variables...')
const tablerVars = extractVariables(tablerPath)
console.log(`Found ${tablerVars.size} variables in Tabler\n`)
// Find variables that are in Bootstrap but not in Tabler
const missingInTabler: string[] = []
for (const varName of bootstrapVars) {
if (!tablerVars.has(varName)) {
missingInTabler.push(varName)
}
}
// Sort alphabetically
missingInTabler.sort()
console.log('='.repeat(60))
console.log(`Variables in Bootstrap that are missing in Tabler: ${missingInTabler.length}`)
console.log('='.repeat(60))
if (missingInTabler.length === 0) {
console.log('All Bootstrap variables are present in Tabler!')
} else {
console.log('\nList of missing variables:\n')
missingInTabler.forEach((varName: string, index: number) => {
console.log(`${(index + 1).toString().padStart(4)}. $${varName}`)
})
}
// Optionally: show statistics
console.log('\n' + '='.repeat(60))
console.log('Statistics:')
console.log(` Bootstrap: ${bootstrapVars.size} variables`)
console.log(` Tabler: ${tablerVars.size} variables`)
console.log(` Missing: ${missingInTabler.length} variables`)
console.log(` Coverage: ${((1 - missingInTabler.length / bootstrapVars.size) * 100).toFixed(1)}%`)
console.log('='.repeat(60))
}
// Run analysis
try {
compareVariables()
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error)
console.error('Error during analysis:', errorMessage)
process.exit(1)
}
@@ -1,19 +1,30 @@
#!/usr/bin/env node
'use strict'
import { existsSync, mkdirSync, lstatSync } from 'fs'
import { existsSync, mkdirSync } from 'node:fs'
import { emptyDirSync, copySync } from 'fs-extra/esm'
import libs from '../libs.json' with { type: 'json' }
import { fileURLToPath } from 'url'
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url'
import { join, dirname } from 'node:path'
const __dirname = dirname(fileURLToPath(import.meta.url))
interface LibConfig {
npm?: string
js?: string[]
css?: string[]
head?: boolean
}
interface Libs {
[key: string]: LibConfig
}
const libsData = libs as Libs
emptyDirSync(join(__dirname, '..', 'dist/libs'))
for(const name in libs) {
const { npm } = libs[name]
for (const name in libsData) {
const { npm } = libsData[name]
if (npm) {
const from = join(__dirname, '..', `node_modules/${npm}`)
@@ -23,11 +34,12 @@ for(const name in libs) {
if (!existsSync(to)) {
mkdirSync(to, { recursive: true })
}
copySync(from, to, {
dereference: true,
})
console.log(`Successfully copied ${npm}`)
}
}
}
@@ -1,13 +1,18 @@
const crypto = require('node:crypto');
const fs = require('node:fs');
const path = require('node:path');
const sh = require('shelljs');
import * as crypto from 'node:crypto'
import { readFileSync, writeFileSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
sh.config.fatal = true
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const configFile = path.join(__dirname, '../../shared/data/sri.json')
const files = [
interface FileConfig {
file: string
configPropertyName: string
}
const files: FileConfig[] = [
{
file: 'dist/css/tabler.min.css',
configPropertyName: 'css'
@@ -80,28 +85,37 @@ const files = [
file: 'dist/js/tabler-theme.min.js',
configPropertyName: 'js-theme'
},
// {
// file: 'dist/preview/css/demo.min.css',
// configPropertyName: 'demo-css'
// },
// {
// file: 'dist/preview/js/demo.min.js',
// configPropertyName: 'demo-js'
// },
]
for (const { file, configPropertyName } of files) {
fs.readFile(path.join(__dirname, '..', file), 'utf8', (error, data) => {
if (error) {
function generateSRI(): void {
const sriData: Record<string, string> = {}
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}`
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
}
}
const algorithm = 'sha384'
const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64')
const integrity = `${algorithm}-${hash}`
writeFileSync(configFile, JSON.stringify(sriData, null, 2) + '\n', 'utf8')
}
console.log(`${configPropertyName}: ${integrity}`)
try {
generateSRI()
} catch (error) {
console.error('Failed to generate SRI:', error)
process.exit(1)
}
sh.sed('-i', new RegExp(`^(\\s+"${configPropertyName}":\\s+["'])\\S*(["'])`), `$1${integrity}$2`, configFile)
})
}
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env node
import { existsSync, mkdirSync } from 'node:fs'
import { copySync } from 'fs-extra/esm'
import { fileURLToPath } from 'node:url'
import { join, dirname } from 'node:path'
const __dirname = dirname(fileURLToPath(import.meta.url))
const fromDir = join(__dirname, '..', 'node_modules/geist/dist/fonts')
const toDir = join(__dirname, '..', 'fonts')
// Create fonts directory if it doesn't exist
if (!existsSync(toDir)) {
mkdirSync(toDir, { recursive: true })
}
// Copy geist-mono fonts
const monoFrom = join(fromDir, 'geist-mono')
const monoTo = join(toDir, 'geist-mono')
if (existsSync(monoFrom)) {
if (!existsSync(monoTo)) {
mkdirSync(monoTo, { recursive: true })
}
copySync(monoFrom, monoTo, {
dereference: true,
})
console.log(`Successfully copied geist-mono fonts`)
} else {
console.warn(`Warning: geist-mono fonts not found at ${monoFrom}`)
}
// Copy geist-sans fonts
const sansFrom = join(fromDir, 'geist-sans')
const sansTo = join(toDir, 'geist-sans')
if (existsSync(sansFrom)) {
if (!existsSync(sansTo)) {
mkdirSync(sansTo, { recursive: true })
}
copySync(sansFrom, sansTo, {
dereference: true,
})
console.log(`Successfully copied geist-sans fonts`)
} else {
console.warn(`Warning: geist-sans fonts not found at ${sansFrom}`)
}
-47
View File
@@ -1,47 +0,0 @@
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { babel } from '@rollup/plugin-babel'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import replace from '@rollup/plugin-replace'
import banner from '../../shared/banner/index.mjs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const ESM = process.env.ESM === 'true'
const THEME = process.env.THEME === 'true'
const external = []
const plugins = [
babel({
exclude: 'node_modules/**',
babelHelpers: 'bundled'
})
]
plugins.push(
replace({
'process.env.NODE_ENV': '"production"',
preventAssignment: true
}),
nodeResolve()
)
const destinationFile = `tabler${THEME ? '-theme' : ''}${ESM ? '.esm' : ''}`
const rollupConfig = {
input: path.resolve(__dirname, `../js/tabler${THEME ? '-theme' : ''}.js`),
output: {
banner: banner(),
file: path.resolve(__dirname, `../dist/js/${destinationFile}.js`),
format: ESM ? 'esm' : 'umd',
generatedCode: 'es2015'
},
external,
plugins
}
if (!ESM) {
rollupConfig.output.name = `tabler${THEME ? '-theme' : ''}`
}
export default rollupConfig
+30
View File
@@ -0,0 +1,30 @@
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { createViteConfig } from '../../.build/vite.config.helper'
import getBanner from '../../shared/banner/index.mjs'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const baseName = process.env.BASE_NAME || 'tabler'
const entryFile = baseName
const libraryName = baseName
const bannerText = getBanner()
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
})
-1
View File
@@ -106,7 +106,6 @@
### Minor Changes
- a2640e2: Add Playwright configuration and visual regression tests
- d3ae77c: Enable `scrollSpy` in `countup` module
- bd3d959: Refactor SCSS files to replace divide function with calc
- cb278c7: Add Segmented Control component
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="16" fill="none"><mask id="a" width="21" height="16" x="0" y="0" mask-type="alpha" maskUnits="userSpaceOnUse"><path fill="#fff" d="M.001.927h20v15h-20z"/></mask><g mask="url(#a)"><path fill="#F7FCFF" fill-rule="evenodd" d="M.001.927v15h20v-15h-20Z" clip-rule="evenodd"/><mask id="b" width="21" height="16" x="0" y="0" mask-type="alpha" maskUnits="userSpaceOnUse"><path fill="#fff" fill-rule="evenodd" d="M.001.927v15h20v-15h-20Z" clip-rule="evenodd"/></mask><g fill-rule="evenodd" clip-rule="evenodd" mask="url(#b)"><path fill="#3D58DB" d="M.001.927v15h20v-15h-20Z"/><path fill="#FFD018" d="m9.407 3.137-.14.818L10 3.57l.735.386-.14-.818.594-.64h-.821L10 1.695l-.367.804h-.822l.595.639Zm0 10.855-.14.819.734-.387.735.387-.14-.819.594-.639h-.821L10 12.55l-.367.804h-.822l.595.64ZM3.484 9.438l.14-.818-.594-.64h.822l.367-.803.367.804h.822l-.595.639.14.818-.734-.386-.735.386Zm1.352 1.77-.14.818.734-.386.735.386-.14-.818.594-.64h-.821l-.368-.803-.367.804H4.24l.595.639Zm9.009.818.14-.818-.595-.64h.822l.367-.803.368.804h.821l-.594.639.14.818-.735-.386-.734.386Zm-9.01-6.062-.14.818.735-.386.735.386-.14-.818.594-.639h-.821l-.368-.804-.367.804H4.24l.595.64Zm9.01.818.14-.818-.595-.639h.822l.367-.804.368.804h.821l-.594.64.14.817-.735-.386-.734.386ZM6.66 13.29l-.14.819.735-.387.734.386-.14-.818.595-.639h-.822l-.367-.804-.368.804h-.821l.594.64Zm5.418.819.14-.819-.594-.639h.821l.367-.804.368.804h.821l-.594.64.14.817-.735-.386-.734.386ZM6.52 4.666l.735-.387.734.387-.14-.818.595-.64h-.822l-.367-.804-.368.804h-.821l.594.64-.14.818Zm5.558 0 .14-.818-.594-.64h.821l.367-.804.368.804h.821l-.594.64.14.818-.735-.387-.734.387Zm3.062 3.879-.14.818.735-.386.735.386-.14-.818.593-.64h-.82l-.368-.803-.368.804h-.821l.594.639Z"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="15" fill="none" viewBox="0 0 20 15"><path fill="#3d58db" fill-rule="evenodd" d="M0 0v15h20V0z" clip-rule="evenodd"/><path fill="#ffd018" fill-rule="evenodd" d="m9.407 2.442-.14.818.733-.385.735.386-.14-.818.594-.64h-.821L10 1l-.367.804h-.822zm0 10.855-.14.819.734-.387.735.387-.14-.819.594-.639h-.821L10 11.855l-.367.804h-.822l.595.64zM3.484 8.743l.14-.818-.594-.64h.822l.367-.803.367.804h.822l-.595.639.14.818-.734-.386zm1.352 1.77-.14.818.734-.386.735.386-.14-.818.594-.64h-.821L5.43 9.07l-.367.804H4.24zm9.009.818.14-.818-.595-.64h.822l.367-.803.368.804h.821l-.594.639.14.818-.735-.386zm-9.01-6.062-.14.818.735-.386.735.386-.14-.818.594-.639h-.821l-.368-.804-.367.804H4.24zm9.01.818.14-.818-.595-.639h.822l.367-.804.368.804h.821l-.594.64.14.817-.735-.386zM6.66 12.595l-.14.819.735-.387.734.386-.14-.818.595-.639h-.822l-.367-.804-.368.804h-.821zm5.418.819.14-.819-.594-.639h.821l.367-.804.368.804h.821l-.594.64.14.817-.735-.386zM6.52 3.971l.735-.387.734.387-.14-.818.595-.64h-.822l-.367-.804-.368.804h-.821l.594.64zm5.558 0 .14-.818-.594-.64h.821l.367-.804.368.804h.821l-.594.64.14.818-.735-.387zM15.14 7.85l-.14.818.735-.386.735.386-.14-.818.593-.64h-.82l-.368-.803-.368.804h-.821z" clip-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

-7
View File
@@ -1,7 +0,0 @@
// Autosize plugin
const elements = document.querySelectorAll('[data-bs-toggle="autosize"]');
if (elements.length) {
elements.forEach(function (element) {
window.autosize && window.autosize(element);
});
}
+10
View File
@@ -0,0 +1,10 @@
// Autosize plugin
const autosizeElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>('[data-bs-toggle="autosize"]')
if (autosizeElements.length) {
autosizeElements.forEach(function (element: HTMLElement) {
if (window.autosize) {
window.autosize(element)
}
})
}
-3
View File
@@ -1,3 +0,0 @@
export * as Popper from '@popperjs/core';
export { Dropdown, Tooltip, Popover, Tab, Toast } from 'bootstrap';
+7
View File
@@ -0,0 +1,7 @@
export * as Popper from '@popperjs/core'
// Export all Bootstrap components directly for consistent usage
export { Alert, Button, Carousel, Collapse, Dropdown, Modal, Offcanvas, Popover, ScrollSpy, Tab, Toast, Tooltip } from 'bootstrap'
// Re-export everything as namespace for backward compatibility
export * as bootstrap from 'bootstrap'
-23
View File
@@ -1,23 +0,0 @@
const elements = document.querySelectorAll('[data-countup]');
if (elements.length) {
elements.forEach(function (element) {
let options = {};
try {
const dataOptions = element.getAttribute('data-countup') ? JSON.parse(element.getAttribute('data-countup')) : {};
options = Object.assign({
'enableScrollSpy': true
}, dataOptions);
} catch (error) {}
const value = parseInt(element.innerHTML, 10);
if (window.countUp && window.countUp.CountUp) {
const countUp = new window.countUp.CountUp(element, value, options);
if (!countUp.error) {
countUp.start();
}
}
});
}
+27
View File
@@ -0,0 +1,27 @@
const countupElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>('[data-countup]')
if (countupElements.length) {
countupElements.forEach(function (element: HTMLElement) {
let options: Record<string, any> = {}
try {
const dataOptions = element.getAttribute('data-countup') ? JSON.parse(element.getAttribute('data-countup')!) : {}
options = Object.assign(
{
enableScrollSpy: true,
},
dataOptions,
)
} catch (error) {
// ignore invalid JSON
}
const value = parseInt(element.innerHTML, 10)
if (window.countUp && window.countUp.CountUp) {
const countUp = new window.countUp.CountUp(element, value, options)
if (!countUp.error) {
countUp.start()
}
}
})
}
-12
View File
@@ -1,12 +0,0 @@
import { Dropdown } from './bootstrap';
/*
Core dropdowns
*/
let dropdownTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="dropdown"]'));
dropdownTriggerList.map(function (dropdownTriggerEl) {
let options = {
boundary: dropdownTriggerEl.getAttribute('data-bs-boundary') === 'viewport' ? document.querySelector('.btn') : 'clippingParents',
}
return new Dropdown(dropdownTriggerEl, options);
});
+12
View File
@@ -0,0 +1,12 @@
import { Dropdown } from './bootstrap'
/*
Core dropdowns
*/
const dropdownTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="dropdown"]'))
dropdownTriggerList.map(function (dropdownTriggerEl: HTMLElement) {
const options = {
boundary: dropdownTriggerEl.getAttribute('data-bs-boundary') === 'viewport' ? document.querySelector('.btn') : 'clippingParents',
}
return new Dropdown(dropdownTriggerEl, options)
})
+14
View File
@@ -0,0 +1,14 @@
// Global type declarations for window properties
interface Window {
autosize?: (element: HTMLElement | HTMLTextAreaElement) => void
countUp?: {
CountUp: new (target: HTMLElement, endVal: number, options?: any) => {
error: boolean
start: () => void
}
}
IMask?: new (element: HTMLElement, options: { mask: string; lazy?: boolean }) => any
Sortable?: new (element: HTMLElement, options?: any) => any
}
-9
View File
@@ -1,9 +0,0 @@
// Input mask plugin
var maskElementList = [].slice.call(document.querySelectorAll('[data-mask]'));
maskElementList.map(function (maskEl) {
window.IMask && new window.IMask(maskEl, {
mask: maskEl.dataset.mask,
lazy: maskEl.dataset['mask-visible'] === 'true'
})
});
+10
View File
@@ -0,0 +1,10 @@
// Input mask plugin
const maskElementList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-mask]'))
maskElementList.map(function (maskEl: HTMLElement) {
window.IMask &&
new window.IMask(maskEl, {
mask: maskEl.dataset.mask,
lazy: maskEl.dataset['mask-visible'] === 'true',
})
})
-14
View File
@@ -1,14 +0,0 @@
import { Popover } from './bootstrap';
/*
Core popovers
*/
let popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
popoverTriggerList.map(function (popoverTriggerEl) {
let options = {
delay: {show: 50, hide: 50},
html: popoverTriggerEl.getAttribute('data-bs-html') === "true" ?? false,
placement: popoverTriggerEl.getAttribute('data-bs-placement') ?? 'auto'
};
return new Popover(popoverTriggerEl, options);
});
+14
View File
@@ -0,0 +1,14 @@
import { Popover } from './bootstrap'
/*
Core popovers
*/
const popoverTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="popover"]'))
popoverTriggerList.map(function (popoverTriggerEl: HTMLElement) {
const options = {
delay: { show: 50, hide: 50 },
html: popoverTriggerEl.getAttribute('data-bs-html') === 'true',
placement: popoverTriggerEl.getAttribute('data-bs-placement') ?? 'auto',
}
return new Popover(popoverTriggerEl, options)
})
+23
View File
@@ -0,0 +1,23 @@
// SortableJS plugin
// Initializes Sortable on elements marked with [data-sortable]
// Allows options via JSON in data attribute: data-sortable='{"animation":150}'
const sortableElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>('[data-sortable]')
if (sortableElements.length) {
sortableElements.forEach(function (element: HTMLElement) {
let options: Record<string, any> = {}
try {
const rawOptions = element.getAttribute('data-sortable')
options = rawOptions ? JSON.parse(rawOptions) : {}
} catch (e) {
// ignore invalid JSON
}
if (window.Sortable) {
// eslint-disable-next-line no-new
new window.Sortable(element, options)
}
})
}
-11
View File
@@ -1,11 +0,0 @@
/*
Switch icons
*/
let switchesTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="switch-icon"]'));
switchesTriggerList.map(function (switchTriggerEl) {
switchTriggerEl.addEventListener('click', (e) => {
e.stopPropagation();
switchTriggerEl.classList.toggle('active');
});
});
+11
View File
@@ -0,0 +1,11 @@
/*
Switch icons
*/
const switchesTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="switch-icon"]'))
switchesTriggerList.map(function (switchTriggerEl: HTMLElement) {
switchTriggerEl.addEventListener('click', (e: MouseEvent) => {
e.stopPropagation()
switchTriggerEl.classList.toggle('active')
})
})
-16
View File
@@ -1,16 +0,0 @@
import { Tab } from './bootstrap';
export const EnableActivationTabsFromLocationHash = () => {
const locationHash = window.location.hash;
if (locationHash) {
const tabsList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tab"]'));
const matchedTabs = tabsList.filter(tab => tab.hash === locationHash);
matchedTabs.map(tab => {
new Tab(tab).show();
});
}
}
EnableActivationTabsFromLocationHash()
+16
View File
@@ -0,0 +1,16 @@
import { Tab } from './bootstrap'
export const EnableActivationTabsFromLocationHash = (): void => {
const locationHash: string = window.location.hash
if (locationHash) {
const tabsList: HTMLAnchorElement[] = [].slice.call(document.querySelectorAll<HTMLAnchorElement>('[data-bs-toggle="tab"]'))
const matchedTabs = tabsList.filter((tab: HTMLAnchorElement) => tab.hash === locationHash)
matchedTabs.map((tab: HTMLAnchorElement) => {
new Tab(tab).show()
})
}
}
EnableActivationTabsFromLocationHash()
@@ -1,17 +1,17 @@
export const prefix = 'tblr-'
export const prefix: string = 'tblr-'
export const hexToRgba = (hex, opacity) => {
export const hexToRgba = (hex: string, opacity: number): string | null => {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
return result ? `rgba(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}, ${opacity})` : null
}
export const getColor = (color, opacity = 1) => {
export const getColor = (color: string, opacity: number = 1): string | null => {
const c = getComputedStyle(document.body).getPropertyValue(`--${prefix}${color}`).trim()
if (opacity !== 1) {
return hexToRgba(c, opacity)
return hexToRgba(c, opacity)
}
return c
}
}
-17
View File
@@ -1,17 +0,0 @@
import { Toast } from './bootstrap';
/*
Toasts
*/
let toastsTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="toast"]'));
toastsTriggerList.map(function (toastTriggerEl) {
if (!toastTriggerEl.hasAttribute('data-bs-target')) {
return;
}
const toastEl = new Toast(toastTriggerEl.getAttribute('data-bs-target'));
toastTriggerEl.addEventListener('click', () => {
toastEl.show()
});
});
+18
View File
@@ -0,0 +1,18 @@
import { Toast } from './bootstrap'
/*
Toasts
*/
const toastsTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="toast"]'))
toastsTriggerList.map(function (toastTriggerEl: HTMLElement) {
const target = toastTriggerEl.getAttribute('data-bs-target')
if (target === null) {
return
}
const toastEl = new Toast(target)
toastTriggerEl.addEventListener('click', () => {
toastEl.show()
})
})
-11
View File
@@ -1,11 +0,0 @@
import { Tooltip } from './bootstrap';
let tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(function (tooltipTriggerEl) {
let options = {
delay: {show: 50, hide: 50},
html: tooltipTriggerEl.getAttribute("data-bs-html") === "true" ?? false,
placement: tooltipTriggerEl.getAttribute('data-bs-placement') ?? 'auto'
};
return new Tooltip(tooltipTriggerEl, options);
});
+11
View File
@@ -0,0 +1,11 @@
import { Tooltip } from './bootstrap'
const tooltipTriggerList: HTMLElement[] = [].slice.call(document.querySelectorAll<HTMLElement>('[data-bs-toggle="tooltip"]'))
tooltipTriggerList.map(function (tooltipTriggerEl: HTMLElement) {
const options = {
delay: { show: 50, hide: 50 },
html: tooltipTriggerEl.getAttribute('data-bs-html') === 'true',
placement: tooltipTriggerEl.getAttribute('data-bs-placement') ?? 'auto',
}
return new Tooltip(tooltipTriggerEl, options)
})
-35
View File
@@ -1,35 +0,0 @@
/**
* demo-theme is specifically loaded right after the body and not deferred
* to ensure we switch to the chosen dark/light theme as fast as possible.
* This will prevent any flashes of the light theme (default) before switching.
*/
const themeConfig = {
"theme": "light",
"theme-base": "gray",
"theme-font": "sans-serif",
"theme-primary": "blue",
"theme-radius": "1",
}
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
})
for (const key in themeConfig) {
const param = params[key]
let selectedValue
if (!!param) {
localStorage.setItem('tabler-' + key, param)
selectedValue = param
} else {
const storedTheme = localStorage.getItem('tabler-' + key)
selectedValue = storedTheme ? storedTheme : themeConfig[key]
}
if (selectedValue !== themeConfig[key]) {
document.documentElement.setAttribute('data-bs-' + key, selectedValue)
} else {
document.documentElement.removeAttribute('data-bs-' + key)
}
}
+43
View File
@@ -0,0 +1,43 @@
/**
* demo-theme is specifically loaded right after the body and not deferred
* to ensure we switch to the chosen dark/light theme as fast as possible.
* This will prevent any flashes of the light theme (default) before switching.
*/
interface ThemeConfig {
'theme': string
'theme-base': string
'theme-font': string
'theme-primary': string
'theme-radius': string
}
const themeConfig: ThemeConfig = {
'theme': 'light',
'theme-base': 'gray',
'theme-font': 'sans-serif',
'theme-primary': 'blue',
'theme-radius': '1',
}
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams: URLSearchParams, prop: string): string | null => searchParams.get(prop),
})
for (const key in themeConfig) {
const param = params[key]
let selectedValue: string
if (!!param) {
localStorage.setItem('tabler-' + key, param)
selectedValue = param
} else {
const storedTheme = localStorage.getItem('tabler-' + key)
selectedValue = storedTheme ? storedTheme : themeConfig[key as keyof ThemeConfig]
}
if (selectedValue !== themeConfig[key as keyof ThemeConfig]) {
document.documentElement.setAttribute('data-bs-' + key, selectedValue)
} else {
document.documentElement.removeAttribute('data-bs-' + key)
}
}
-27
View File
@@ -1,27 +0,0 @@
import "./src/autosize"
import "./src/countup"
import "./src/input-mask"
import "./src/dropdown"
import "./src/tooltip"
import "./src/popover"
import "./src/switch-icon"
import "./src/tab"
import "./src/toast"
export * as bootstrap from "bootstrap"
export * as tabler from "./src/tabler"
export {
Alert,
Modal,
Toast,
Tooltip,
Tab,
Button,
Carousel,
Collapse,
Dropdown,
Popover,
ScrollSpy,
Offcanvas
} from 'bootstrap'
+16
View File
@@ -0,0 +1,16 @@
import './src/autosize'
import './src/countup'
import './src/input-mask'
import './src/dropdown'
import './src/tooltip'
import './src/popover'
import './src/switch-icon'
import './src/tab'
import './src/toast'
import './src/sortable'
// Re-export everything from bootstrap.ts (single source of truth)
export * from './src/bootstrap'
// Re-export tabler namespace
export * as tabler from './src/tabler'
+15
View File
@@ -38,6 +38,12 @@
"dist/list.min.js"
]
},
"sortablejs": {
"npm": "sortablejs",
"js": [
"Sortable.min.js"
]
},
"masonry": {
"js": [
"https://cdnjs.cloudflare.com/ajax/libs/masonry/4.2.2/masonry.pkgd.min.js"
@@ -160,5 +166,14 @@
"dist/turbo.es2017-umd.js"
],
"head": true
},
"driver.js": {
"npm": "driver.js",
"js": [
"dist/driver.js.iife.js"
],
"css": [
"dist/driver.css"
]
}
}
+45 -37
View File
@@ -5,37 +5,39 @@
"homepage": "https://tabler.io",
"scripts": {
"dev": "pnpm run clean && pnpm run copy && pnpm run watch",
"build": "pnpm run clean && pnpm run css && pnpm run js && pnpm run copy && pnpm run generate-sri",
"build": "pnpm run clean && pnpm run build-assets && pnpm run copy && pnpm run generate-sri",
"build-assets": "concurrently \"pnpm run css\" \"pnpm run js\"",
"clean": "shx rm -rf dist demo",
"css": "pnpm run css-compile && pnpm run css-prefix && pnpm run css-rtl && pnpm run css-minify && pnpm run css-banner",
"css-compile": "sass --no-source-map --load-path=node_modules --style expanded scss/:dist/css/",
"css-banner": "node .build/add-banner.mjs",
"css": "pnpm run css-build && pnpm run css-prefix && pnpm run css-rtl && pnpm run css-minify && pnpm run css-banner",
"css-build": "sass --no-source-map --load-path=node_modules --style expanded scss/:dist/css/",
"css-banner": "tsx .build/add-banner.ts",
"css-prefix": "postcss --config .build/postcss.config.mjs --replace \"dist/css/*.css\" \"!dist/css/*.rtl*.css\" \"!dist/css/*.min.css\"",
"css-rtl": "cross-env NODE_ENV=RTL postcss --config .build/postcss.config.mjs --dir \"dist/css\" --ext \".rtl.css\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*.rtl.css\"",
"css-minify": "pnpm run css-minify-main && pnpm run css-minify-rtl",
"css-minify": "concurrently \"pnpm run css-minify-main\" \"pnpm run css-minify-rtl\"",
"css-minify-main": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/css/ --batch --batch-suffix \".min\" \"dist/css/*.css\" \"!dist/css/*.min.css\" \"!dist/css/*rtl*.css\"",
"css-minify-rtl": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/css/ --batch --batch-suffix \".min\" \"dist/css/*rtl.css\" \"!dist/css/*.min.css\"",
"js": "pnpm run js-compile && pnpm run js-minify",
"js-compile": "pnpm run js-compile-standalone && pnpm run js-compile-standalone-esm && pnpm run js-compile-theme && pnpm run js-compile-theme-esm",
"js-compile-theme-esm": "rollup --environment THEME:true --environment ESM:true --config .build/rollup.config.mjs --sourcemap",
"js-compile-theme": "rollup --environment THEME:true --config .build/rollup.config.mjs --sourcemap",
"js-compile-standalone": "rollup --config .build/rollup.config.mjs --sourcemap",
"js-compile-standalone-esm": "rollup --environment ESM:true --config .build/rollup.config.mjs --sourcemap",
"js-minify": "pnpm run js-minify-standalone && pnpm run js-minify-standalone-esm && pnpm run js-minify-theme && pnpm run js-minify-theme-esm",
"js-minify-standalone": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler.js.map,includeSources,url=tabler.min.js.map\" --output dist/js/tabler.min.js dist/js/tabler.js",
"js-minify-standalone-esm": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler.esm.js.map,includeSources,url=tabler.esm.min.js.map\" --output dist/js/tabler.esm.min.js dist/js/tabler.esm.js",
"js-minify-theme": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler-theme.js.map,includeSources,url=tabler-theme.min.js.map\" --output dist/js/tabler-theme.min.js dist/js/tabler-theme.js",
"js-minify-theme-esm": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/js/tabler-theme.esm.js.map,includeSources,url=tabler-theme.esm.min.js.map\" --output dist/js/tabler-theme.esm.min.js dist/js/tabler-theme.esm.js",
"copy": "pnpm run copy-img && pnpm run copy-libs",
"css-lint": "pnpm run css-lint-variables",
"css-lint-variables": "find-unused-sass-variables scss/ node_modules/bootstrap/scss/",
"js": "pnpm run js-build && pnpm run js-build-min",
"js-build": "concurrently \"pnpm run js-build-standalone\" \"pnpm run js-build-theme\"",
"js-build-theme": "cross-env BASE_NAME=tabler-theme vite build --config .build/vite.config.mts",
"js-build-standalone": "cross-env BASE_NAME=tabler vite build --config .build/vite.config.mts",
"js-build-min": "concurrently \"pnpm run js-build-min-standalone\" \"pnpm run js-build-min-theme\"",
"js-build-min-standalone": "concurrently \"terser dist/js/tabler.js --compress --mangle --comments '/@license|@preserve|^!/' --source-map \\\"content=dist/js/tabler.js.map,filename=dist/js/tabler.min.js.map,url=tabler.min.js.map\\\" -o dist/js/tabler.min.js\" \"terser dist/js/tabler.esm.js --module --compress --mangle --comments '/@license|@preserve|^!/' --source-map \\\"content=dist/js/tabler.esm.js.map,filename=dist/js/tabler.esm.min.js.map,url=tabler.esm.min.js.map\\\" -o dist/js/tabler.esm.min.js\"",
"js-build-min-theme": "concurrently \"terser dist/js/tabler-theme.js --compress --mangle --comments '/@license|@preserve|^!/' --source-map \\\"content=dist/js/tabler-theme.js.map,filename=dist/js/tabler-theme.min.js.map,url=tabler-theme.min.js.map\\\" -o dist/js/tabler-theme.min.js\" \"terser dist/js/tabler-theme.esm.js --module --compress --mangle --comments '/@license|@preserve|^!/' --source-map \\\"content=dist/js/tabler-theme.esm.js.map,filename=dist/js/tabler-theme.esm.min.js.map,url=tabler-theme.esm.min.js.map\\\" -o dist/js/tabler-theme.esm.min.js\"",
"copy": "concurrently \"pnpm run copy-img\" \"pnpm run copy-libs\" \"pnpm run copy-fonts\"",
"copy-img": "shx mkdir -p dist/img && shx cp -rf img/* dist/img",
"copy-libs": "node .build/copy-libs.mjs",
"copy-libs": "tsx .build/copy-libs.ts",
"copy-fonts": "shx mkdir -p dist/fonts && shx cp -rf fonts/* dist/fonts",
"import-fonts": "tsx .build/import-fonts.ts",
"watch": "concurrently \"pnpm run watch-css\" \"pnpm run watch-js\"",
"watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css-compile && pnpm run css-prefix\"",
"watch-js": "nodemon --watch js/ --ext js --exec \"pnpm run js-compile\"",
"watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css-build && pnpm run css-prefix\"",
"watch-js": "nodemon --watch js/ --ext ts,js --exec \"pnpm run js-build\"",
"bundlewatch": "bundlewatch",
"generate-sri": "node .build/generate-sri.js",
"format:check": "prettier --check src/**/*.{js,scss} --cache",
"format:write": "prettier --write src/**/*.{js,scss} --cache"
"generate-sri": "tsx .build/generate-sri.ts",
"format:check": "prettier --check \"scss/**/*.scss\" \"js/**/*.{js,ts}\" --cache",
"format:write": "prettier --write \"scss/**/*.scss\" \"js/**/*.{js,ts}\" --cache",
"type-check": "tsc --noEmit"
},
"repository": {
"type": "git",
@@ -65,7 +67,7 @@
"files": [
"docs/**/*",
"dist/**/*",
"js/**/*.{js,map}",
"js/**/*.{ts,js,map}",
"img/**/*.{svg}",
"scss/**/*.scss",
"libs.json"
@@ -80,19 +82,19 @@
"files": [
{
"path": "./dist/css/tabler.css",
"maxSize": "75 kB"
"maxSize": "77 kB"
},
{
"path": "./dist/css/tabler.min.css",
"maxSize": "70 kB"
"maxSize": "72 kB"
},
{
"path": "./dist/css/tabler.rtl.css",
"maxSize": "75 kB"
"maxSize": "77 kB"
},
{
"path": "./dist/css/tabler.rtl.min.css",
"maxSize": "70 kB"
"maxSize": "73 kB"
},
{
"path": "./dist/css/tabler-flags.css",
@@ -104,7 +106,7 @@
},
{
"path": "./dist/css/tabler-payments.css",
"maxSize": "2.2 kB"
"maxSize": "2.3 kB"
},
{
"path": "./dist/css/tabler-payments.min.css",
@@ -146,31 +148,37 @@
},
"dependencies": {
"@popperjs/core": "^2.11.8",
"bootstrap": "5.3.7"
"bootstrap": "5.3.8"
},
"devDependencies": {
"@hotwired/turbo": "^8.0.13",
"@hotwired/turbo": "^8.0.18",
"@melloware/coloris": "^0.25.0",
"apexcharts": "3.54.1",
"@types/node": "^22.0.0",
"apexcharts": "^5.3.6",
"autosize": "^6.0.1",
"choices.js": "^11.1.0",
"clipboard": "^2.0.11",
"countup.js": "^2.9.0",
"dropzone": "^6.0.0-beta.2",
"find-unused-sass-variables": "^6.1.0",
"flatpickr": "^4.6.13",
"fslightbox": "^3.6.1",
"fullcalendar": "^6.1.18",
"fslightbox": "^3.7.4",
"fullcalendar": "^6.1.19",
"geist": "^1.5.1",
"hugerte": "^1.0.9",
"imask": "^7.6.1",
"jsvectormap": "^1.7.0",
"list.js": "^2.3.1",
"litepicker": "^2.0.12",
"nouislider": "^15.8.1",
"plyr": "^3.7.8",
"signature_pad": "^5.0.10",
"plyr": "^3.8.3",
"signature_pad": "^5.1.1",
"sortablejs": "^1.15.6",
"star-rating.js": "^4.3.1",
"tom-select": "^2.4.3",
"typed.js": "^2.1.0"
"typed.js": "^2.1.0",
"typescript": "^5.9.3",
"driver.js": "^1.0.0"
},
"directories": {
"doc": "docs"
+27 -27
View File
@@ -1,30 +1,30 @@
// Layout & components
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/images";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/tables";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/transitions";
@import "bootstrap/scss/dropdown";
@import "bootstrap/scss/button-group";
@import "bootstrap/scss/nav";
@import "bootstrap/scss/navbar";
@import "bootstrap/scss/card";
@import "bootstrap/scss/pagination";
@import "bootstrap/scss/progress";
@import "bootstrap/scss/list-group";
@import "bootstrap/scss/toasts";
@import "bootstrap/scss/modal";
@import "bootstrap/scss/tooltip";
@import "bootstrap/scss/popover";
@import "bootstrap/scss/carousel";
@import "bootstrap/scss/spinners";
@import "bootstrap/scss/offcanvas";
@import "bootstrap/scss/placeholders";
@import 'bootstrap/scss/root';
@import 'bootstrap/scss/reboot';
@import 'bootstrap/scss/type';
@import 'bootstrap/scss/images';
@import 'bootstrap/scss/containers';
@import 'bootstrap/scss/grid';
@import 'bootstrap/scss/tables';
@import 'bootstrap/scss/forms';
@import 'bootstrap/scss/buttons';
@import 'bootstrap/scss/transitions';
@import 'bootstrap/scss/dropdown';
@import 'bootstrap/scss/button-group';
@import 'bootstrap/scss/nav';
@import 'bootstrap/scss/navbar';
@import 'bootstrap/scss/card';
@import 'bootstrap/scss/pagination';
@import 'bootstrap/scss/progress';
@import 'bootstrap/scss/list-group';
@import 'bootstrap/scss/toasts';
@import 'bootstrap/scss/modal';
@import 'bootstrap/scss/tooltip';
@import 'bootstrap/scss/popover';
@import 'bootstrap/scss/carousel';
@import 'bootstrap/scss/spinners';
@import 'bootstrap/scss/offcanvas';
@import 'bootstrap/scss/placeholders';
// Utilities
@import "bootstrap/scss/utilities/api";
@import 'bootstrap/scss/utilities/api';
+5 -6
View File
@@ -1,7 +1,6 @@
// Config
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
// @import "bootstrap/scss/variables";
// @import "bootstrap/scss/variables-dark";
// @import "bootstrap/scss/maps";
@import 'bootstrap/scss/mixins';
// @import "bootstrap/scss/utilities";
+33 -33
View File
@@ -1,24 +1,26 @@
@mixin caret($direction: down) {
$selector: "after";
@use 'sass:color';
@if $direction == "left" {
$selector: "before";
@mixin caret($direction: down) {
$selector: 'after';
@if $direction == 'left' {
$selector: 'before';
}
&:#{$selector} {
content: "";
content: '';
display: inline-block;
vertical-align: $caret-vertical-align;
width: $caret-width;
height: $caret-width;
border-bottom: 1px var(--#{$prefix}border-style);
border-left: 1px var(--#{$prefix}border-style);
margin-right: 0.1em;
border-inline-start: 1px var(--#{$prefix}border-style);
margin-inline-end: 0.1em;
@if $direction != "left" {
margin-left: $caret-spacing;
@if $direction != 'left' {
margin-inline-start: $caret-spacing;
} @else {
margin-right: $caret-spacing;
margin-inline-end: $caret-spacing;
}
@if $direction == down {
@@ -32,7 +34,7 @@
}
}
@if $direction == "left" {
@if $direction == 'left' {
&:after {
content: none;
}
@@ -43,30 +45,11 @@
// Override bootstrap core
}
@mixin button-variant(
$background: null,
$border: null,
$color: null,
$hover-background: null,
$hover-border: null,
$hover-color: null,
$active-background: null,
$active-border: null,
$active-color: null,
$disabled-background: null,
$disabled-border: null,
$disabled-color: null
) {
@mixin button-variant($background: null, $border: null, $color: null, $hover-background: null, $hover-border: null, $hover-color: null, $active-background: null, $active-border: null, $active-color: null, $disabled-background: null, $disabled-border: null, $disabled-color: null) {
// Override bootstrap core
}
@mixin button-outline-variant(
$color: null,
$color-hover: null,
$active-background: null,
$active-border: null,
$active-color: null
) {
@mixin button-outline-variant($color: null, $color-hover: null, $active-background: null, $active-border: null, $active-color: null) {
// Override bootstrap core
}
@@ -74,5 +57,22 @@
// TODO: remove when https://github.com/twbs/bootstrap/pull/37425/ will be released
//
@function opaque($background, $foreground) {
@return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%);
@return color.mix(rgba($foreground, 1), $background, color.alpha($foreground) * 100%);
}
@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) {
@if $enable-rounded {
border-radius: valid-radius($radius);
@if $radius != 0 {
@supports (corner-shape: squircle) {
corner-shape: squircle;
border-radius: calc(#{$radius} * 2.5) !important;
}
}
}
@else if $fallback-border-radius !=false {
border-radius: $fallback-border-radius;
}
}
+7 -8
View File
@@ -1,9 +1,8 @@
@import "bootstrap/scss/functions";
@import 'mixins';
@import 'variables';
@import 'variables-dark';
@import 'maps';
@import 'utilities';
@import "mixins";
@import "variables";
@import "variables-dark";
@import "utilities";
@import "bootstrap-config";
@import "bootstrap-override";
@import 'bootstrap-config';
@import 'bootstrap-override';
+75 -78
View File
@@ -1,84 +1,81 @@
@import "config";
@import "bootstrap-components";
@import 'config';
@import 'bootstrap-components';
@import "props";
@import 'props';
@import "fonts/webfonts";
@import 'fonts/webfonts';
@import 'fonts/geist';
@import "layout/root";
@import "layout/animations";
@import "layout/core";
@import "layout/navbar";
@import "layout/page";
@import "layout/footer";
@import "layout/dark";
@import 'layout/root';
@import 'layout/animations';
@import 'layout/core';
@import 'layout/navbar';
@import 'layout/page';
@import 'layout/footer';
@import 'layout/dark';
@import "ui/accordion";
@import "ui/alerts";
@import "ui/avatars";
@import "ui/badges";
@import "ui/breadcrumbs";
@import "ui/buttons";
@import "ui/button-group";
@import "ui/calendars";
@import "ui/carousel";
@import "ui/cards";
@import "ui/close";
@import "ui/dropdowns";
@import "ui/datagrid";
@import "ui/empty";
@import "ui/grid";
@import "ui/icons";
@import "ui/images";
@import "ui/forms";
@import "ui/forms/form-icon";
@import "ui/forms/form-colorinput";
@import "ui/forms/form-imagecheck";
@import "ui/forms/form-selectgroup";
@import "ui/forms/form-custom";
@import "ui/forms/form-check";
@import "ui/forms/validation";
@import "ui/legend";
@import "ui/lists";
@import "ui/loaders";
@import "ui/login";
@import "ui/modals";
@import "ui/nav";
@import "ui/stars";
@import "ui/pagination";
@import "ui/popovers";
@import "ui/progress";
@import "ui/ribbons";
@import "ui/markdown";
@import "ui/placeholder";
@import "ui/segmented";
@import "ui/steps";
@import "ui/status";
@import "ui/switch-icon";
@import "ui/tables";
@import "ui/tags";
@import "ui/toasts";
@import "ui/toolbar";
@import "ui/tracking";
@import "ui/timeline";
@import "ui/type";
@import "ui/charts";
@import "ui/offcanvas";
@import "ui/chat";
@import "ui/signature";
@import 'ui/accordion';
@import 'ui/alerts';
@import 'ui/avatars';
@import 'ui/badges';
@import 'ui/breadcrumbs';
@import 'ui/buttons';
@import 'ui/button-group';
@import 'ui/calendars';
@import 'ui/carousel';
@import 'ui/cards';
@import 'ui/close';
@import 'ui/dropdowns';
@import 'ui/datagrid';
@import 'ui/empty';
@import 'ui/grid';
@import 'ui/icons';
@import 'ui/images';
@import 'ui/forms';
@import 'ui/forms/form-icon';
@import 'ui/forms/form-colorinput';
@import 'ui/forms/form-imagecheck';
@import 'ui/forms/form-selectgroup';
@import 'ui/forms/form-custom';
@import 'ui/forms/form-check';
@import 'ui/forms/validation';
@import 'ui/legend';
@import 'ui/lists';
@import 'ui/loaders';
@import 'ui/login';
@import 'ui/modals';
@import 'ui/nav';
@import 'ui/stars';
@import 'ui/pagination';
@import 'ui/popovers';
@import 'ui/progress';
@import 'ui/ribbons';
@import 'ui/markdown';
@import 'ui/placeholder';
@import 'ui/segmented';
@import 'ui/steps';
@import 'ui/status';
@import 'ui/switch-icon';
@import 'ui/tables';
@import 'ui/tags';
@import 'ui/toasts';
@import 'ui/toolbar';
@import 'ui/tracking';
@import 'ui/timeline';
@import 'ui/type';
@import 'ui/charts';
@import 'ui/offcanvas';
@import 'ui/chat';
@import 'ui/signature';
@import 'ui/patterns';
@import "helpers/index";
@import 'helpers/index';
@import "utils/background";
@import "utils/colors";
@import "utils/scroll";
@import "utils/sizing";
@import "utils/opacity";
@import "utils/shadow";
@import "utils/text";
@import "utils/hover";
@import "debug";
@import "debug";
@import 'utils/background';
@import 'utils/colors';
@import 'utils/scroll';
@import 'utils/sizing';
@import 'utils/opacity';
@import 'utils/shadow';
@import 'utils/text';
@import 'utils/hover';
-49
View File
@@ -1,49 +0,0 @@
$debug: false;
@if $debug {
$colors: (
"blue": $blue,
"azure": $azure,
"indigo": $indigo,
"purple": $purple,
"pink": $pink,
"red": $red,
"orange": $orange,
"yellow": $yellow,
"lime": $lime,
"green": $green,
"teal": $teal,
"cyan": $cyan,
);
@each $name, $color in $colors {
@debug ("#{$name}: '#{$color}'");
@debug ("#{$name}-100: '#{tint-color($color, 8)}'");
@debug ("#{$name}-200: '#{tint-color($color, 6)}'");
@debug ("#{$name}-300: '#{tint-color($color, 4)}'");
@debug ("#{$name}-400: '#{tint-color($color, 2)}'");
@debug ("#{$name}-500: '#{$color}'");
@debug ("#{$name}-600: '#{shade-color($color, 2)}'");
@debug ("#{$name}-700: '#{shade-color($color, 4)}'");
@debug ("#{$name}-800: '#{shade-color($color, 6)}'");
@debug ("#{$name}-900: '#{shade-color($color, 8)}'");
}
@debug ("gray: '#{$gray-500}'");
@debug ("gray-100: '#{$gray-100}'");
@debug ("gray-200: '#{$gray-200}'");
@debug ("gray-300: '#{$gray-300}'");
@debug ("gray-400: '#{$gray-400}'");
@debug ("gray-500: '#{$gray-500}'");
@debug ("gray-600: '#{$gray-600}'");
@debug ("gray-700: '#{$gray-700}'");
@debug ("gray-800: '#{$gray-800}'");
@debug ("gray-900: '#{$gray-900}'");
@debug ("border-color: '#{$border-color}'");
@debug ("text-secondary: '#{$text-secondary}'");
@each $name, $color in $social-colors {
@debug ("#{$name}: '#{$color}'");
}
}
+155
View File
@@ -0,0 +1,155 @@
@use 'sass:map';
// Re-assigned maps
//
// Placed here so that others can override the default Sass maps and see automatic updates to utilities and more.
$theme-colors-rgb: map-loop($theme-colors, to-rgb, '$value') !default;
$theme-colors-text: (
'primary': $primary-text-emphasis,
'secondary': $secondary-text-emphasis,
'success': $success-text-emphasis,
'info': $info-text-emphasis,
'warning': $warning-text-emphasis,
'danger': $danger-text-emphasis,
'light': $light-text-emphasis,
'dark': $dark-text-emphasis,
) !default;
$theme-colors-bg-subtle: (
'primary': $primary-bg-subtle,
'secondary': $secondary-bg-subtle,
'success': $success-bg-subtle,
'info': $info-bg-subtle,
'warning': $warning-bg-subtle,
'danger': $danger-bg-subtle,
'light': $light-bg-subtle,
'dark': $dark-bg-subtle,
) !default;
$theme-colors-border-subtle: (
'primary': $primary-border-subtle,
'secondary': $secondary-border-subtle,
'success': $success-border-subtle,
'info': $info-border-subtle,
'warning': $warning-border-subtle,
'danger': $danger-border-subtle,
'light': $light-border-subtle,
'dark': $dark-border-subtle,
) !default;
$theme-colors-text-dark: null !default;
$theme-colors-bg-subtle-dark: null !default;
$theme-colors-border-subtle-dark: null !default;
@if $enable-dark-mode {
$theme-colors-text-dark: (
'primary': $primary-text-emphasis-dark,
'secondary': $secondary-text-emphasis-dark,
'success': $success-text-emphasis-dark,
'info': $info-text-emphasis-dark,
'warning': $warning-text-emphasis-dark,
'danger': $danger-text-emphasis-dark,
'light': $light-text-emphasis-dark,
'dark': $dark-text-emphasis-dark,
) !default;
$theme-colors-bg-subtle-dark: (
'primary': $primary-bg-subtle-dark,
'secondary': $secondary-bg-subtle-dark,
'success': $success-bg-subtle-dark,
'info': $info-bg-subtle-dark,
'warning': $warning-bg-subtle-dark,
'danger': $danger-bg-subtle-dark,
'light': $light-bg-subtle-dark,
'dark': $dark-bg-subtle-dark,
) !default;
$theme-colors-border-subtle-dark: (
'primary': $primary-border-subtle-dark,
'secondary': $secondary-border-subtle-dark,
'success': $success-border-subtle-dark,
'info': $info-border-subtle-dark,
'warning': $warning-border-subtle-dark,
'danger': $danger-border-subtle-dark,
'light': $light-border-subtle-dark,
'dark': $dark-border-subtle-dark,
) !default;
}
// Utilities maps
//
// Extends the default `$theme-colors` maps to help create our utilities.
// Come v6, we'll de-dupe these variables. Until then, for backward compatibility, we keep them to reassign.
$utilities-colors: $theme-colors-rgb !default;
$utilities-text: map.merge(
$utilities-colors,
(
'black': to-rgb($black),
'white': to-rgb($white),
'body': to-rgb($body-color),
)
) !default;
$utilities-text-colors: map-loop($utilities-text, rgba-css-var, '$key', 'text') !default;
$utilities-text-emphasis-colors: (
'primary-emphasis': var(--#{$prefix}primary-text-emphasis),
'secondary-emphasis': var(--#{$prefix}secondary-text-emphasis),
'success-emphasis': var(--#{$prefix}success-text-emphasis),
'info-emphasis': var(--#{$prefix}info-text-emphasis),
'warning-emphasis': var(--#{$prefix}warning-text-emphasis),
'danger-emphasis': var(--#{$prefix}danger-text-emphasis),
'light-emphasis': var(--#{$prefix}light-text-emphasis),
'dark-emphasis': var(--#{$prefix}dark-text-emphasis),
) !default;
$utilities-bg: map.merge(
$utilities-colors,
(
'black': to-rgb($black),
'white': to-rgb($white),
'body': to-rgb($body-bg),
)
) !default;
$utilities-bg-colors: map-loop($utilities-bg, rgba-css-var, '$key', 'bg') !default;
$utilities-bg-subtle: (
'primary-subtle': var(--#{$prefix}primary-bg-subtle),
'secondary-subtle': var(--#{$prefix}secondary-bg-subtle),
'success-subtle': var(--#{$prefix}success-bg-subtle),
'info-subtle': var(--#{$prefix}info-bg-subtle),
'warning-subtle': var(--#{$prefix}warning-bg-subtle),
'danger-subtle': var(--#{$prefix}danger-bg-subtle),
'light-subtle': var(--#{$prefix}light-bg-subtle),
'dark-subtle': var(--#{$prefix}dark-bg-subtle),
) !default;
$utilities-border: map.merge(
$utilities-colors,
(
'black': to-rgb($black),
'white': to-rgb($white),
)
) !default;
$utilities-border-colors: map-loop($utilities-border, rgba-css-var, '$key', 'border') !default;
$utilities-border-subtle: (
'primary-subtle': var(--#{$prefix}primary-border-subtle),
'secondary-subtle': var(--#{$prefix}secondary-border-subtle),
'success-subtle': var(--#{$prefix}success-border-subtle),
'info-subtle': var(--#{$prefix}info-border-subtle),
'warning-subtle': var(--#{$prefix}warning-border-subtle),
'danger-subtle': var(--#{$prefix}danger-border-subtle),
'light-subtle': var(--#{$prefix}light-border-subtle),
'dark-subtle': var(--#{$prefix}dark-border-subtle),
) !default;
$utilities-links-underline: map-loop($utilities-colors, rgba-css-var, '$key', 'link-underline') !default;
$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;
$gutters: $spacers !default;
+2 -2
View File
@@ -1,2 +1,2 @@
@import "mixins/mixins";
@import "mixins/functions";
@import 'mixins/mixins';
@import 'mixins/functions';
+3 -2
View File
@@ -1,4 +1,5 @@
@import "config";
@use 'sass:map';
@import 'config';
:root,
:host {
@@ -30,7 +31,7 @@
--#{$prefix}brand: #{$primary};
/** Theme colors */
@each $name, $color in map-merge($theme-colors, $social-colors) {
@each $name, $color in map.merge($theme-colors, $social-colors) {
--#{$prefix}#{$name}: #{$color};
--#{$prefix}#{$name}-rgb: #{to-rgb($color)};
--#{$prefix}#{$name}-fg: #{if(contrast-ratio($color) > $min-contrast-ratio, var(--#{$prefix}light), var(--#{$prefix}dark))};
+43 -50
View File
@@ -1,165 +1,158 @@
$negative-spacers-extra: if(
$enable-negative-margins,
negativify-map(map-merge($spacers, $spacers-extra)),
null
);
@use 'sass:map';
$negative-spacers-extra: if($enable-negative-margins, negativify-map(map.merge($spacers, $spacers-extra)), null);
$utilities: (
// Margin utilities
"margin":
(
'margin': (
responsive: true,
property: margin,
class: m,
values: $spacers-extra,
),
"margin-x": (
'margin-x': (
responsive: true,
property: margin-right margin-left,
property: margin-inline-end margin-inline-start,
class: mx,
values: $spacers-extra,
),
"margin-y": (
'margin-y': (
responsive: true,
property: margin-top margin-bottom,
class: my,
values: $spacers-extra,
),
"margin-top": (
'margin-top': (
responsive: true,
property: margin-top,
class: mt,
values: $spacers-extra,
),
"margin-end": (
'margin-end': (
responsive: true,
property: margin-right,
property: margin-inline-end,
class: me,
values: $spacers-extra,
),
"margin-bottom": (
'margin-bottom': (
responsive: true,
property: margin-bottom,
class: mb,
values: $spacers-extra,
),
"margin-start": (
'margin-start': (
responsive: true,
property: margin-left,
property: margin-inline-start,
class: ms,
values: $spacers-extra,
),
// Negative margin utilities
"negative-margin":
(
'negative-margin': (
responsive: true,
property: margin,
class: m,
values: $negative-spacers-extra,
),
"negative-margin-x": (
'negative-margin-x': (
responsive: true,
property: margin-right margin-left,
property: margin-inline-end margin-inline-start,
class: mx,
values: $negative-spacers-extra,
),
"negative-margin-y": (
'negative-margin-y': (
responsive: true,
property: margin-top margin-bottom,
class: my,
values: $negative-spacers-extra,
),
"negative-margin-top": (
'negative-margin-top': (
responsive: true,
property: margin-top,
class: mt,
values: $negative-spacers-extra,
),
"negative-margin-end": (
'negative-margin-end': (
responsive: true,
property: margin-right,
property: margin-inline-end,
class: me,
values: $negative-spacers-extra,
),
"negative-margin-bottom": (
'negative-margin-bottom': (
responsive: true,
property: margin-bottom,
class: mb,
values: $negative-spacers-extra,
),
"negative-margin-start": (
'negative-margin-start': (
responsive: true,
property: margin-left,
property: margin-inline-start,
class: ms,
values: $negative-spacers-extra,
),
// Padding utilities
"padding":
(
'padding': (
responsive: true,
property: padding,
class: p,
values: $spacers-extra,
),
"padding-x": (
'padding-x': (
responsive: true,
property: padding-right padding-left,
property: padding-inline-end padding-inline-start,
class: px,
values: $spacers-extra,
),
"padding-y": (
'padding-y': (
responsive: true,
property: padding-top padding-bottom,
class: py,
values: $spacers-extra,
),
"padding-top": (
'padding-top': (
responsive: true,
property: padding-top,
class: pt,
values: $spacers-extra,
),
"padding-end": (
'padding-end': (
responsive: true,
property: padding-right,
property: padding-inline-end,
class: pe,
values: $spacers-extra,
),
"padding-bottom": (
'padding-bottom': (
responsive: true,
property: padding-bottom,
class: pb,
values: $spacers-extra,
),
"padding-start": (
'padding-start': (
responsive: true,
property: padding-left,
property: padding-inline-start,
class: ps,
values: $spacers-extra,
),
// Gap utility
"gap":
(
'gap': (
responsive: true,
property: gap,
class: gap,
values: $spacers-extra,
),
"row-gap": (
'row-gap': (
responsive: true,
property: row-gap,
class: row-gap,
values: $spacers-extra,
),
"column-gap": (
'column-gap': (
responsive: true,
property: column-gap,
class: column-gap,
values: $spacers-extra,
),
// Letter spacing
"spacing":
(
'spacing': (
property: letter-spacing,
class: tracking,
values: (
@@ -168,38 +161,38 @@ $utilities: (
wide: $spacing-wide,
),
),
"width": (
'width': (
property: width,
class: w,
values: $spacers-extra,
),
"height": (
'height': (
property: height,
class: h,
values: $spacers-extra,
),
"filter": (
'filter': (
property: filter,
class: filter,
values: (
grayscale: grayscale(100%),
),
),
"gutter-x": (
'gutter-x': (
responsive: true,
css-var: true,
css-variable-name: gutter-x,
class: gx,
values: $spacers-extra,
),
"gutter-y": (
'gutter-y': (
responsive: true,
css-var: true,
css-variable-name: gutter-y,
class: gy,
values: $spacers-extra,
),
"gutter": (
'gutter': (
responsive: true,
css-var: true,
css-variable-name: gutter-x,
+897 -129
View File
File diff suppressed because it is too large Load Diff
+97 -4
View File
@@ -1,4 +1,4 @@
@use "sass:color";
@use 'sass:color';
//
// Dark mode
@@ -6,14 +6,107 @@
$darken-dark: color.adjust($dark, $lightness: -2%) !default;
$lighten-dark: color.adjust($dark, $lightness: 2%) !default;
$border-color-dark: color.adjust($dark, $lightness: 8%) !default;
$border-color-translucent-dark: rgba(72, 110, 149, .14) !default;
$border-color-translucent-dark: rgba(128, 150, 172, 0.2) !default;
$border-dark-color-dark: color.adjust($dark, $lightness: 4%) !default;
$border-active-color-dark: color.adjust($dark, $lightness: 12%) !default;
//new bootsrap variables
$body-color-dark: $gray-200 !default;
$body-color-dark: $gray-200 !default;
$body-emphasis-color-dark: $white !default;
$code-color-dark: var(--#{$prefix}gray-300) !default;
$text-secondary-dark: rgba(153, 159, 164, 1) !default;
// Theme text emphasis dark
$primary-text-emphasis-dark: tint-color($primary, 40%) !default;
$secondary-text-emphasis-dark: tint-color($secondary, 40%) !default;
$success-text-emphasis-dark: tint-color($success, 40%) !default;
$info-text-emphasis-dark: tint-color($info, 40%) !default;
$warning-text-emphasis-dark: tint-color($warning, 40%) !default;
$danger-text-emphasis-dark: tint-color($danger, 40%) !default;
$light-text-emphasis-dark: $gray-100 !default;
$dark-text-emphasis-dark: $gray-300 !default;
// Theme bg subtle dark
$primary-bg-subtle-dark: shade-color($primary, 80%) !default;
$secondary-bg-subtle-dark: shade-color($secondary, 80%) !default;
$success-bg-subtle-dark: shade-color($success, 80%) !default;
$info-bg-subtle-dark: shade-color($info, 80%) !default;
$warning-bg-subtle-dark: shade-color($warning, 80%) !default;
$danger-bg-subtle-dark: shade-color($danger, 80%) !default;
$light-bg-subtle-dark: $gray-800 !default;
$dark-bg-subtle-dark: color.mix($gray-800, $black) !default;
// Theme border subtle dark
$primary-border-subtle-dark: shade-color($primary, 40%) !default;
$secondary-border-subtle-dark: shade-color($secondary, 40%) !default;
$success-border-subtle-dark: shade-color($success, 40%) !default;
$info-border-subtle-dark: shade-color($info, 40%) !default;
$warning-border-subtle-dark: shade-color($warning, 40%) !default;
$danger-border-subtle-dark: shade-color($danger, 40%) !default;
$light-border-subtle-dark: $gray-700 !default;
$dark-border-subtle-dark: $gray-800 !default;
// Body dark
$body-bg-dark: $gray-900 !default;
$body-secondary-color-dark: rgba($body-color-dark, 0.75) !default;
$body-secondary-bg-dark: $gray-800 !default;
$body-tertiary-color-dark: rgba($body-color-dark, 0.5) !default;
$body-tertiary-bg-dark: color.mix($gray-800, $gray-900, 50%) !default;
// Headings dark
$headings-color-dark: inherit !default;
// Link dark
$link-color-dark: tint-color($primary, 40%) !default;
$link-hover-color-dark: shift-color($link-color-dark, -$link-shade-percentage) !default;
// Mark dark
$mark-color-dark: $body-color-dark !default;
$mark-bg-dark: shade-color($yellow, 60%) !default;
//
// Forms dark
//
$form-select-indicator-color-dark: $body-color-dark !default;
$form-select-indicator-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$form-select-indicator-color-dark}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>") !default;
$form-switch-color-dark: rgba($white, 0.25) !default;
$form-switch-bg-image-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color-dark}'/></svg>") !default;
// Form validation colors dark
$form-valid-color-dark: tint-color($green, 40%) !default;
$form-valid-border-color-dark: tint-color($green, 40%) !default;
$form-invalid-color-dark: tint-color($red, 40%) !default;
$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
//
$carousel-dark-indicator-active-bg: $black !default; // Deprecated in v5.3.4
$carousel-dark-caption-color: $black !default; // Deprecated in v5.3.4
$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default; // Deprecated in v5.3.4
$carousel-indicator-active-bg-dark: $carousel-dark-indicator-active-bg !default;
$carousel-caption-color-dark: $carousel-dark-caption-color !default;
$carousel-control-icon-filter-dark: $carousel-dark-control-icon-filter !default;
//
// Close button dark
//
$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default; // Deprecated in v5.3.4
$btn-close-filter-dark: $btn-close-white-filter !default;
+1927 -540
View File
File diff suppressed because it is too large Load Diff
+203
View File
@@ -0,0 +1,203 @@
// Geist Sans Font Family
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-Thin.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-Thin.ttf') format('truetype');
font-weight: 100;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-UltraLight.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-UltraLight.ttf') format('truetype');
font-weight: 200;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-Light.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-Light.ttf') format('truetype');
font-weight: 300;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-Regular.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-Medium.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-SemiBold.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-SemiBold.ttf') format('truetype');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-Bold.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-Bold.ttf') format('truetype');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-Black.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-Black.ttf') format('truetype');
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-UltraBlack.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-UltraBlack.ttf') format('truetype');
font-weight: 900;
font-style: normal;
font-display: swap;
}
// Geist Sans Variable Font
@font-face {
font-family: 'Geist';
src:
url('#{$assets-base}/fonts/geist-sans/Geist-Variable.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-sans/Geist-Variable.ttf') format('truetype');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
// Geist Mono Font Family
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-Thin.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-Thin.ttf') format('truetype');
font-weight: 100;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-UltraLight.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-UltraLight.ttf') format('truetype');
font-weight: 200;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-Light.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-Light.ttf') format('truetype');
font-weight: 300;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-Regular.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-Medium.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-SemiBold.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-SemiBold.ttf') format('truetype');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-Bold.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-Bold.ttf') format('truetype');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-Black.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-Black.ttf') format('truetype');
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-UltraBlack.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-UltraBlack.ttf') format('truetype');
font-weight: 900;
font-style: normal;
font-display: swap;
}
// Geist Mono Variable Font
@font-face {
font-family: 'Geist Mono';
src:
url('#{$assets-base}/fonts/geist-mono/GeistMono-Variable.woff2') format('woff2'),
url('#{$assets-base}/fonts/geist-mono/GeistMono-Variable.ttf') format('truetype');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
+2 -2
View File
@@ -1,10 +1,10 @@
@if $font-google {
$google-font-url: "https://fonts.googleapis.com/css2?family=" + str-replace($font-google, " ", "+") + ":wght@300;400;500;600;700&display=swap" !default;
$google-font-url: 'https://fonts.googleapis.com/css2?family=' + str-replace($font-google, ' ', '+') + ':wght@300;400;500;600;700&display=swap' !default;
@import url($google-font-url);
}
@if $font-google-monospaced {
$google-font-monospaced-url: "https://fonts.googleapis.com/css2?family=" + str-replace($font-google-monospaced, " ", "+") + ":wght@300;400;500;600;700&display=swap" !default;
$google-font-monospaced-url: 'https://fonts.googleapis.com/css2?family=' + str-replace($font-google-monospaced, ' ', '+') + ':wght@300;400;500;600;700&display=swap' !default;
@import url($google-font-monospaced-url);
}
+14 -13
View File
@@ -1,3 +1,5 @@
@use 'sass:map';
//
// Clearfix
//
@@ -28,14 +30,14 @@
// Stretched link
//
.stretched-link {
&::#{$stretched-link-pseudo-element} {
&::after {
position: absolute;
top: 0;
right: 0;
inset-inline-end: 0;
bottom: 0;
left: 0;
z-index: $stretched-link-z-index;
content: "";
inset-inline-start: 0;
z-index: 1;
content: '';
}
}
@@ -72,21 +74,21 @@
.fixed-top {
position: fixed;
top: 0;
right: 0;
left: 0;
inset-inline-end: 0;
inset-inline-start: 0;
z-index: $zindex-fixed;
}
.fixed-bottom {
position: fixed;
right: 0;
inset-inline-end: 0;
bottom: 0;
left: 0;
inset-inline-start: 0;
z-index: $zindex-fixed;
}
// Responsive sticky top and bottom
@each $breakpoint in map-keys($grid-breakpoints) {
@each $breakpoint in map.keys($grid-breakpoints) {
@include media-breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $grid-breakpoints);
@@ -114,13 +116,13 @@
&::before {
display: block;
padding-top: var(--#{$prefix}aspect-ratio);
content: "";
content: '';
}
> * {
position: absolute;
top: 0;
left: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
}
@@ -140,4 +142,3 @@
// By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values
box-shadow: var(--#{$prefix}focus-ring-x, 0) var(--#{$prefix}focus-ring-y, 0) var(--#{$prefix}focus-ring-blur, 0) var(--#{$prefix}focus-ring-width) var(--#{$prefix}focus-ring-color);
}
+24 -10
View File
@@ -1,9 +1,23 @@
@use 'sass:map';
html {
scrollbar-gutter: stable;
@supports not (scrollbar-gutter: stable) {
overflow-y: scroll;
}
}
// stylelint-disable property-no-vendor-prefix
body {
letter-spacing: $body-letter-spacing;
touch-action: manipulation;
text-rendering: optimizeLegibility;
font-feature-settings: "liga" 0, "cv03", "cv04", "cv11";
font-feature-settings:
'liga' 0,
'cv03',
'cv04',
'cv11';
position: relative;
min-height: 100%;
height: 100%;
@@ -12,7 +26,7 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@media print {
@include media-print {
background: transparent;
}
}
@@ -24,8 +38,8 @@ body {
//
.layout-fluid {
.container,
[class^="container-"],
[class*=" container-"] {
[class^='container-'],
[class*=' container-'] {
max-width: 100%;
}
}
@@ -35,10 +49,10 @@ body {
//
.layout-boxed {
--#{$prefix}theme-boxed-border-radius: 0;
--#{$prefix}theme-boxed-width: #{map-get($container-max-widths, xxl)};
--#{$prefix}theme-boxed-width: #{map.get($container-max-widths, xxl)};
@include media-breakpoint-up(md) {
background: $dark linear-gradient(to right, rgba(#fff, .1), transparent) fixed;
background: $dark linear-gradient(to right, rgba(#fff, 0.1), transparent) fixed;
padding: 1rem;
--#{$prefix}theme-boxed-border-radius: #{$border-radius};
}
@@ -46,7 +60,7 @@ body {
.page {
margin: 0 auto;
max-width: var(--#{$prefix}theme-boxed-width);
border-radius: var(--#{$prefix}theme-boxed-border-radius);
@include border-radius(var(--#{$prefix}theme-boxed-border-radius));
color: var(--#{$prefix}body-color);
@include media-breakpoint-up(md) {
@@ -55,8 +69,8 @@ body {
}
> .navbar:first-child {
border-top-left-radius: var(--#{$prefix}theme-boxed-border-radius);
border-top-right-radius: var(--#{$prefix}theme-boxed-border-radius);
border-start-start-radius: var(--#{$prefix}theme-boxed-border-radius);
border-start-end-radius: var(--#{$prefix}theme-boxed-border-radius);
}
}
}
}
+8 -13
View File
@@ -1,10 +1,10 @@
@use "sass:color";
@use 'sass:color';
// stylelint-disable declaration-no-important
@if $enable-dark-mode {
:root {
&:not(.theme-dark):not([data-bs-theme="dark"]) {
&:not(.theme-dark):not([data-bs-theme='dark']) {
.hide-theme-light {
display: none !important;
}
@@ -15,7 +15,7 @@
}
&.theme-dark,
&[data-bs-theme="dark"] {
&[data-bs-theme='dark'] {
.hide-theme-dark {
display: none !important;
}
@@ -26,7 +26,6 @@
}
}
@include color-mode(dark, true) {
color-scheme: dark;
--#{$prefix}body-color: var(--#{$prefix}gray-200);
@@ -48,16 +47,12 @@
--#{$prefix}link-hover-color: color-mix(in srgb, var(--#{$prefix}primary), black 20%);
--#{$prefix}active-bg: #{$lighten-dark};
--#{$prefix}disabled-color: #{color-transparent(var(--#{$prefix}body-color), .4)};
--#{$prefix}disabled-color: #{color-transparent(var(--#{$prefix}body-color), 0.4)};
--#{$prefix}border-color: var(--#{$prefix}gray-700);
--#{$prefix}border-color-translucent: var(
--#{$prefix}dark-mode-border-color-translucent
);
--#{$prefix}border-color-translucent: var(--#{$prefix}dark-mode-border-color-translucent);
--#{$prefix}border-dark-color: var(--#{$prefix}dark-mode-border-dark-color);
--#{$prefix}border-active-color: var(
--#{$prefix}dark-mode-border-active-color
);
--#{$prefix}border-active-color: var(--#{$prefix}dark-mode-border-active-color);
--#{$prefix}btn-color: #{$darken-dark};
@@ -68,7 +63,7 @@
}
}
body[data-bs-theme=dark] [data-bs-theme=light] {
@extend [data-bs-theme=dark];
body[data-bs-theme='dark'] [data-bs-theme='light'] {
@extend [data-bs-theme='dark'];
}
}
+5 -1
View File
@@ -4,9 +4,13 @@
padding: $footer-padding-y 0;
color: $footer-color;
margin-top: auto;
@include media-print {
display: none;
}
}
.footer-transparent {
background-color: transparent;
border-top: 0;
}
}
+47 -48
View File
@@ -1,20 +1,22 @@
@use 'sass:map';
@mixin navbar-vertical-nav {
.navbar-collapse {
flex-direction: column;
[class^="container"] {
[class^='container'] {
flex-direction: column;
align-items: stretch;
padding: 0;
}
.navbar-nav {
margin-left: 0;
margin-right: 0;
margin-inline-start: 0;
margin-inline-end: 0;
.nav-link {
padding: 0.5rem calc(#{$container-padding-x} / 2);
justify-content: flex-start;
justify-content: start;
}
}
@@ -36,7 +38,7 @@
min-width: 0;
display: flex;
width: auto;
padding-left: add(calc(#{$container-padding-x} / 2), 1.75rem);
padding-inline-start: add(calc(#{$container-padding-x} / 2), 1.75rem);
color: inherit;
&.disabled {
@@ -52,22 +54,22 @@
}
.dropdown-menu .dropdown-item {
padding-left: add(calc(#{$container-padding-x} / 2), 3.25rem);
padding-inline-start: add(calc(#{$container-padding-x} / 2), 3.25rem);
}
.dropdown-menu .dropdown-menu .dropdown-item {
padding-left: add(calc(#{$container-padding-x} / 2), 4.75rem);
padding-inline-start: add(calc(#{$container-padding-x} / 2), 4.75rem);
}
}
.dropdown-toggle:after {
margin-left: auto;
margin-inline-start: auto;
}
.nav-item.active:after {
border-bottom-width: 0;
border-left-width: 3px;
right: auto;
border-inline-start-width: 3px;
inset-inline-end: auto;
top: 0;
bottom: 0;
}
@@ -111,12 +113,12 @@ Navbar
min-width: 2.5rem;
min-height: 2.5rem;
justify-content: center;
border-radius: var(--#{$prefix}border-radius);
@include border-radius(var(--#{$prefix}border-radius));
.badge {
position: absolute;
top: 0.375rem;
right: 0.375rem;
top: 0.5rem;
inset-inline-end: 0.5rem;
transform: translate(50%, -50%);
}
}
@@ -124,7 +126,7 @@ Navbar
}
.navbar-expand {
@each $breakpoint in map-keys($grid-breakpoints) {
@each $breakpoint in map.keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
@@ -147,10 +149,10 @@ Navbar
}
&:after {
content: "";
content: '';
position: absolute;
left: 0;
right: 0;
inset-inline-start: 0;
inset-inline-end: 0;
bottom: -0.25rem;
border: 0 var(--#{$prefix}border-style) var(--#{$prefix}navbar-active-border-color);
border-bottom-width: 2px;
@@ -169,7 +171,7 @@ Navbar
&.navbar-vertical {
~ .navbar,
~ .page-wrapper {
margin-left: $sidebar-width;
margin-inline-start: $sidebar-width;
}
}
@@ -177,8 +179,8 @@ Navbar
&.navbar-vertical.navbar-end {
~ .navbar,
~ .page-wrapper {
margin-left: 0;
margin-right: $sidebar-width;
margin-inline-start: 0;
margin-inline-end: $sidebar-width;
}
}
}
@@ -220,25 +222,20 @@ Navbar toggler
height: 2px;
width: 1.25em;
background: currentColor;
border-radius: 10px;
@include transition(
top $navbar-toggler-animation-time $navbar-toggler-animation-time,
bottom $navbar-toggler-animation-time $navbar-toggler-animation-time,
transform $navbar-toggler-animation-time,
opacity 0s $navbar-toggler-animation-time
);
@include border-radius(var(--#{$prefix}border-radius-pill));
position: relative;
@include transition(top $navbar-toggler-animation-time $navbar-toggler-animation-time, bottom $navbar-toggler-animation-time $navbar-toggler-animation-time, transform $navbar-toggler-animation-time, opacity 0s $navbar-toggler-animation-time);
&:before,
&:after {
content: "";
content: '';
display: block;
height: inherit;
width: inherit;
border-radius: inherit;
background: inherit;
position: absolute;
left: 0;
inset-inline-start: 0;
@include transition(inherit);
}
@@ -250,7 +247,7 @@ Navbar toggler
bottom: -0.45em;
}
.navbar-toggler[aria-expanded="true"] & {
.navbar-toggler[aria-expanded='true'] & {
transform: rotate(45deg);
@include transition(top $transition-time, bottom $transition-time, transform $transition-time $transition-time, opacity 0s $transition-time);
@@ -278,7 +275,9 @@ Navbar transparent
Navbar nav
*/
.navbar-nav {
--#{$prefix}nav-link-hover-bg: #{color-transparent(var(--#{$prefix}nav-link-color), 0.04)};
--#{$prefix}nav-link-hover-bg: #{$navbar-nav-link-hover-bg};
--#{$prefix}nav-link-icon-color: #{$nav-link-icon-color};
--#{$prefix}nav-link-hover-icon-color: #{$nav-link-hover-icon-color};
margin: 0;
padding: 0;
align-items: stretch;
@@ -307,7 +306,7 @@ Navbar vertical
@if $enable-navbar-vertical {
.navbar-vertical {
&.navbar-expand {
@each $breakpoint in map-keys($grid-breakpoints) {
@each $breakpoint in map.keys($grid-breakpoints) {
$next: breakpoint-next($breakpoint, $grid-breakpoints);
$infix: breakpoint-infix($next, $grid-breakpoints);
@@ -316,18 +315,18 @@ Navbar vertical
width: $sidebar-width;
position: fixed;
top: 0;
left: 0;
inset-inline-start: 0;
bottom: 0;
z-index: $zindex-fixed;
align-items: flex-start;
@include transition(transform $transition-time);
align-items: start;
overflow-y: scroll;
padding: 0;
@include transition(transform $transition-time);
&.navbar-right,
&.navbar-end {
left: auto;
right: 0;
inset-inline-start: auto;
inset-inline-end: 0;
}
.navbar-brand {
@@ -350,27 +349,27 @@ Navbar vertical
}
}
> [class^="container"] {
> [class^='container'] {
flex-direction: column;
align-items: stretch;
min-height: 100%;
justify-content: flex-start;
justify-content: start;
padding: 0;
}
~ .page {
padding-left: $sidebar-width;
padding-inline-start: $sidebar-width;
[class^="container"] {
padding-left: 1.5rem;
padding-right: 1.5rem;
[class^='container'] {
padding-inline-start: 1.5rem;
padding-inline-end: 1.5rem;
}
}
&.navbar-right ~ .page,
&.navbar-end ~ .page {
padding-left: 0;
padding-right: $sidebar-width;
padding-inline-start: 0;
padding-inline-end: $sidebar-width;
}
@include navbar-vertical-nav;
@@ -383,12 +382,12 @@ Navbar vertical
.navbar-overlap {
&:after {
content: "";
content: '';
height: $navbar-overlap-height;
position: absolute;
top: 100%;
left: 0;
right: 0;
inset-inline-start: 0;
inset-inline-end: 0;
background: inherit;
z-index: -1;
box-shadow: inherit;
+10 -11
View File
@@ -14,7 +14,7 @@
display: flex;
flex-direction: column;
@media print {
@include media-print {
margin: 0 !important;
}
}
@@ -64,17 +64,16 @@
position: relative;
&:after {
content: "";
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
inset-inline-start: 0;
inset-inline-end: 0;
bottom: 0;
background-image: $overlay-gradient;
}
}
.page-header {
display: flex;
flex-wrap: wrap;
@@ -111,7 +110,7 @@
svg {
width: 1.5rem;
height: 1.5rem;
margin-right: .25rem;
margin-inline-end: 0.25rem;
}
}
@@ -121,7 +120,7 @@
}
.page-subtitle {
margin-top: .25rem;
margin-top: 0.25rem;
color: var(--#{$prefix}secondary);
}
@@ -140,8 +139,8 @@
.page-cover-img {
position: absolute;
top: calc(-2 * var(--#{$prefix}page-cover-blur, 0));
left: calc(-2 * var(--#{$prefix}page-cover-blur, 0));
right: calc(-2 * var(--#{$prefix}page-cover-blur, 0));
inset-inline-start: calc(-2 * var(--#{$prefix}page-cover-blur, 0));
inset-inline-end: calc(-2 * var(--#{$prefix}page-cover-blur, 0));
bottom: calc(-2 * var(--#{$prefix}page-cover-blur, 0));
pointer-events: none;
filter: blur(var(--#{$prefix}page-cover-blur));
@@ -155,7 +154,7 @@
// Page tabs
//
.page-tabs {
margin-top: .5rem;
margin-top: 0.5rem;
position: relative;
}
@@ -167,4 +166,4 @@
+ .page-body-card {
margin-top: 0;
}
}
}
+4 -6
View File
@@ -2,16 +2,11 @@
:host {
font-size: 16px;
height: 100%;
@include media-breakpoint-up(lg) {
margin-left: calc(100vw - 100%);
margin-right: 0;
}
}
:root,
:host,
[data-bs-theme="light"] {
[data-bs-theme='light'] {
color-scheme: light;
--#{$prefix}spacer: var(--#{$prefix}spacer-2);
@@ -38,7 +33,10 @@
--#{$prefix}border-color-translucent: #{$border-color-translucent};
--#{$prefix}border-dark-color: #{$border-dark-color};
--#{$prefix}border-dark-color-translucent: #{$border-dark-color-translucent};
--#{$prefix}border-light-color: #{$border-light-color};
--#{$prefix}border-light-color-translucent: #{$border-light-color-translucent};
--#{$prefix}border-active-color: #{$border-active-color};
--#{$prefix}border-active-color-translucent: #{$border-active-color-translucent};
--#{$prefix}icon-color: #{$icon-color};

Some files were not shown because too many files have changed in this diff Show More