mirror of
https://github.com/tabler/tabler.git
synced 2026-01-25 12:26:30 +00:00
Compare commits
3 Commits
changeset-
...
chore/qual
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6aae2ecce7 | ||
|
|
55c307d1d1 | ||
|
|
d4857c89ce |
5
.github/workflows/lint.yml
vendored
5
.github/workflows/lint.yml
vendored
@@ -28,5 +28,8 @@ jobs:
|
||||
- name: Install pnpm dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Lint Markdown
|
||||
- name: Lint
|
||||
run: pnpm run lint
|
||||
|
||||
- name: Type Check
|
||||
run: pnpm run type-check
|
||||
|
||||
7
core/js/src/global.d.ts
vendored
7
core/js/src/global.d.ts
vendored
@@ -3,7 +3,11 @@
|
||||
interface Window {
|
||||
autosize?: (element: HTMLElement | HTMLTextAreaElement) => void
|
||||
countUp?: {
|
||||
CountUp: new (target: HTMLElement, endVal: number, options?: any) => {
|
||||
CountUp: new (
|
||||
target: HTMLElement,
|
||||
endVal: number,
|
||||
options?: any,
|
||||
) => {
|
||||
error: boolean
|
||||
start: () => void
|
||||
}
|
||||
@@ -11,4 +15,3 @@ interface Window {
|
||||
IMask?: new (element: HTMLElement, options: { mask: string; lazy?: boolean }) => any
|
||||
Sortable?: new (element: HTMLElement, options?: any) => any
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
"watch-js": "nodemon --watch js/ --ext ts,js --exec \"pnpm run js-build\"",
|
||||
"bundlewatch": "bundlewatch",
|
||||
"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": {
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
// Colors
|
||||
@function to-rgb($value) {
|
||||
@debug $value;
|
||||
|
||||
|
||||
@return color.channel($value, 'red', $space: rgb), color.channel($value, 'green', $space: rgb), color.channel($value, 'blue', $space: rgb);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import docsearch from '@docsearch/js'
|
||||
|
||||
docsearch({
|
||||
container: '#docsearch',
|
||||
appId: "NE1EGTYLS9",
|
||||
indexName: "tabler",
|
||||
apiKey: "016353235ef1dd32a6c392be0e939058",
|
||||
container: '#docsearch',
|
||||
appId: 'NE1EGTYLS9',
|
||||
indexName: 'tabler',
|
||||
apiKey: '016353235ef1dd32a6c392be0e939058',
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@use "@docsearch/css/dist/style.css";
|
||||
@use '@docsearch/css/dist/style.css';
|
||||
|
||||
:root {
|
||||
--docsearch-primary-color: var(--tblr-primary);
|
||||
@@ -45,7 +45,7 @@
|
||||
border: 1px solid var(--tblr-border-color) !important;
|
||||
color: var(--tblr-body-color) !important;
|
||||
box-shadow: none !important;
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: var(--tblr-bg-surface-tertiary) !important;
|
||||
border-color: var(--tblr-border-color-active) !important;
|
||||
@@ -64,15 +64,15 @@
|
||||
color: var(--tblr-muted) !important;
|
||||
}
|
||||
|
||||
.DocSearch-Hit[aria-selected="true"] a {
|
||||
.DocSearch-Hit[aria-selected='true'] a {
|
||||
background-color: var(--tblr-primary) !important;
|
||||
border-color: var(--tblr-primary) !important;
|
||||
color: var(--tblr-primary-fg) !important;
|
||||
}
|
||||
|
||||
.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-Container,
|
||||
.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-title,
|
||||
.DocSearch-Hit[aria-selected="true"] .DocSearch-Hit-path {
|
||||
.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-Container,
|
||||
.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-title,
|
||||
.DocSearch-Hit[aria-selected='true'] .DocSearch-Hit-path {
|
||||
color: var(--tblr-primary-fg) !important;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
|
||||
.DocSearch-Input {
|
||||
color: var(--tblr-body-color) !important;
|
||||
|
||||
|
||||
&::placeholder {
|
||||
color: var(--tblr-muted) !important;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,13 @@
|
||||
"version": "changeset version",
|
||||
"publish": "changeset publish",
|
||||
"reformat-md": "tsx .build/reformat-mdx.ts",
|
||||
"lint": "pnpm run lint-md",
|
||||
"lint": "pnpm run lint-md && pnpm run lint-prettier",
|
||||
"lint-prettier": "prettier --check --config core/.prettierrc \"core/scss/**/*.scss\" \"core/js/**/*.{js,ts}\" \"docs/scss/**/*.scss\" \"docs/js/**/*.{js,ts}\" \"preview/scss/**/*.scss\" \"preview/js/**/*.{js,ts}\" \"shared/**/*.{js,mjs,ts}\" --cache",
|
||||
"lint-md": "markdownlint docs/content/**/*.md",
|
||||
"format": "pnpm run format-prettier && pnpm run format-md",
|
||||
"format-prettier": "prettier --write --config core/.prettierrc \"core/scss/**/*.scss\" \"core/js/**/*.{js,ts}\" \"docs/scss/**/*.scss\" \"docs/js/**/*.{js,ts}\" \"preview/scss/**/*.scss\" \"preview/js/**/*.{js,ts}\" \"shared/**/*.{js,mjs,ts}\" --cache",
|
||||
"format-md": "markdownlint --fix docs/content/**/*.md",
|
||||
"check": "pnpm run lint && pnpm run type-check",
|
||||
"zip-package": "tsx .build/zip-package.ts",
|
||||
"start": "pnpm dev"
|
||||
},
|
||||
|
||||
@@ -1,100 +1,97 @@
|
||||
// Setting items
|
||||
interface SettingItem {
|
||||
localStorage: string
|
||||
default: string
|
||||
localStorage: string
|
||||
default: string
|
||||
}
|
||||
|
||||
interface SettingsItems {
|
||||
[key: string]: SettingItem
|
||||
[key: string]: SettingItem
|
||||
}
|
||||
|
||||
const items: SettingsItems = {
|
||||
"menu-position": { localStorage: "tablerMenuPosition", default: "top" },
|
||||
"menu-behavior": { localStorage: "tablerMenuBehavior", default: "sticky" },
|
||||
"container-layout": {
|
||||
localStorage: "tablerContainerLayout",
|
||||
default: "boxed",
|
||||
},
|
||||
'menu-position': { localStorage: 'tablerMenuPosition', default: 'top' },
|
||||
'menu-behavior': { localStorage: 'tablerMenuBehavior', default: 'sticky' },
|
||||
'container-layout': {
|
||||
localStorage: 'tablerContainerLayout',
|
||||
default: 'boxed',
|
||||
},
|
||||
}
|
||||
|
||||
// Theme config
|
||||
const config: Record<string, string> = {}
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
const lsParams = localStorage.getItem(params.localStorage)
|
||||
config[key] = lsParams ? lsParams : params.default
|
||||
const lsParams = localStorage.getItem(params.localStorage)
|
||||
config[key] = lsParams ? lsParams : params.default
|
||||
}
|
||||
|
||||
// Parse url params
|
||||
const parseUrl = (): void => {
|
||||
const search = window.location.search.substring(1)
|
||||
const params = search.split("&")
|
||||
const search = window.location.search.substring(1)
|
||||
const params = search.split('&')
|
||||
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const arr = params[i].split("=")
|
||||
const key = arr[0]
|
||||
const value = arr[1]
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const arr = params[i].split('=')
|
||||
const key = arr[0]
|
||||
const value = arr[1]
|
||||
|
||||
if (!!items[key]) {
|
||||
// Save to localStorage
|
||||
localStorage.setItem(items[key].localStorage, value)
|
||||
if (!!items[key]) {
|
||||
// Save to localStorage
|
||||
localStorage.setItem(items[key].localStorage, value)
|
||||
|
||||
// Update local variables
|
||||
config[key] = value
|
||||
}
|
||||
}
|
||||
// Update local variables
|
||||
config[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle form controls
|
||||
const toggleFormControls = (form: HTMLFormElement): void => {
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
const elem = form.querySelector(
|
||||
`[name="settings-${key}"][value="${config[key]}"]`,
|
||||
) as HTMLInputElement | null
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
const elem = form.querySelector(`[name="settings-${key}"][value="${config[key]}"]`) as HTMLInputElement | null
|
||||
|
||||
if (elem) {
|
||||
elem.checked = true
|
||||
}
|
||||
}
|
||||
if (elem) {
|
||||
elem.checked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Submit form
|
||||
const submitForm = (form: HTMLFormElement): void => {
|
||||
// Save data to localStorage
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
// Save to localStorage
|
||||
const checkedInput = form.querySelector(`[name="settings-${key}"]:checked`) as HTMLInputElement
|
||||
if (checkedInput) {
|
||||
const value = checkedInput.value
|
||||
localStorage.setItem(params.localStorage, value)
|
||||
// Save data to localStorage
|
||||
for (const [key, params] of Object.entries(items)) {
|
||||
// Save to localStorage
|
||||
const checkedInput = form.querySelector(`[name="settings-${key}"]:checked`) as HTMLInputElement
|
||||
if (checkedInput) {
|
||||
const value = checkedInput.value
|
||||
localStorage.setItem(params.localStorage, value)
|
||||
|
||||
// Update local variables
|
||||
config[key] = value
|
||||
}
|
||||
}
|
||||
// Update local variables
|
||||
config[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
window.dispatchEvent(new Event("resize"))
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
|
||||
// Bootstrap is available globally
|
||||
const bootstrap = (window as any).bootstrap
|
||||
if (bootstrap) {
|
||||
new bootstrap.Offcanvas(form).hide()
|
||||
}
|
||||
// Bootstrap is available globally
|
||||
const bootstrap = (window as any).bootstrap
|
||||
if (bootstrap) {
|
||||
new bootstrap.Offcanvas(form).hide()
|
||||
}
|
||||
}
|
||||
|
||||
// Parse url
|
||||
parseUrl()
|
||||
|
||||
// Elements
|
||||
const form = document.querySelector("#offcanvas-settings") as HTMLFormElement | null
|
||||
const form = document.querySelector('#offcanvas-settings') as HTMLFormElement | null
|
||||
|
||||
// Toggle form controls
|
||||
if (form) {
|
||||
form.addEventListener("submit", function (e) {
|
||||
e.preventDefault()
|
||||
form.addEventListener('submit', function (e) {
|
||||
e.preventDefault()
|
||||
|
||||
submitForm(form)
|
||||
})
|
||||
submitForm(form)
|
||||
})
|
||||
|
||||
toggleFormControls(form)
|
||||
toggleFormControls(form)
|
||||
}
|
||||
|
||||
|
||||
@@ -40,10 +40,5 @@
|
||||
"dependencies": {
|
||||
"@tabler/core": "workspace:*",
|
||||
"@tabler/icons": "^3.36.1"
|
||||
},
|
||||
"prettier": {
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"printWidth": 160
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,29 @@ pre.highlight,
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.c, .c1 { color: $color-highlight-gray; }
|
||||
.nt, .nc, .nx { color: $color-highlight-red; }
|
||||
.na, .p { color: $color-highlight-yellow; }
|
||||
.s, .dl, .s2 { color: $color-highlight-green; }
|
||||
.k { color: $color-highlight-blue; }
|
||||
.s1, .mi { color: $color-highlight-purple; }
|
||||
.c,
|
||||
.c1 {
|
||||
color: $color-highlight-gray;
|
||||
}
|
||||
.nt,
|
||||
.nc,
|
||||
.nx {
|
||||
color: $color-highlight-red;
|
||||
}
|
||||
.na,
|
||||
.p {
|
||||
color: $color-highlight-yellow;
|
||||
}
|
||||
.s,
|
||||
.dl,
|
||||
.s2 {
|
||||
color: $color-highlight-green;
|
||||
}
|
||||
.k {
|
||||
color: $color-highlight-blue;
|
||||
}
|
||||
.s1,
|
||||
.mi {
|
||||
color: $color-highlight-purple;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
$prefix: "tblr-";
|
||||
$prefix: 'tblr-';
|
||||
|
||||
@import "highlight";
|
||||
@import 'highlight';
|
||||
|
||||
.dropdown-menu-demo {
|
||||
display: inline-block;
|
||||
@@ -70,10 +70,8 @@ $demo-icon-size: 4rem;
|
||||
aspect-ratio: 1;
|
||||
text-align: center;
|
||||
padding: 0.5rem;
|
||||
border-right: var(--#{$prefix}border-width) var(--#{$prefix}border-style)
|
||||
var(--#{$prefix}border-color);
|
||||
border-bottom: var(--#{$prefix}border-width) var(--#{$prefix}border-style)
|
||||
var(--#{$prefix}border-color);
|
||||
border-right: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color);
|
||||
border-bottom: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color);
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -86,4 +84,4 @@ $demo-icon-size: 4rem;
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ const pkg = JSON.parse(readFileSync(pkgJson, 'utf8'))
|
||||
const year = new Date().getFullYear()
|
||||
|
||||
function getBanner(pluginFilename) {
|
||||
return `/*!
|
||||
return `/*!
|
||||
* Tabler${pluginFilename ? ` ${pluginFilename}` : ''} v${pkg.version} (${pkg.homepage})
|
||||
* Copyright 2018-${year} The Tabler Authors
|
||||
* Copyright 2018-${year} codecalm.net Paweł Kuna
|
||||
@@ -18,4 +18,4 @@ function getBanner(pluginFilename) {
|
||||
*/`
|
||||
}
|
||||
|
||||
export default getBanner
|
||||
export default getBanner
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
export function appConfig(eleventyConfig) {
|
||||
eleventyConfig.setOutputDirectory("dist");
|
||||
eleventyConfig.setInputDirectory("pages");
|
||||
eleventyConfig.setOutputDirectory('dist')
|
||||
eleventyConfig.setInputDirectory('pages')
|
||||
|
||||
eleventyConfig.setLayoutsDirectory("../../shared/layouts");
|
||||
eleventyConfig.setIncludesDirectory("../../shared/includes");
|
||||
eleventyConfig.setDataDirectory("../../shared/data");
|
||||
eleventyConfig.setLayoutsDirectory('../../shared/layouts')
|
||||
eleventyConfig.setIncludesDirectory('../../shared/includes')
|
||||
eleventyConfig.setDataDirectory('../../shared/data')
|
||||
|
||||
eleventyConfig.addWatchTarget("../shared/**/*.html");
|
||||
eleventyConfig.addWatchTarget("./pages/**/*.html");
|
||||
eleventyConfig.addWatchTarget('../shared/**/*.html')
|
||||
eleventyConfig.addWatchTarget('./pages/**/*.html')
|
||||
|
||||
eleventyConfig.setLiquidOptions({
|
||||
timezoneOffset: 0,
|
||||
jekyllInclude: true,
|
||||
dynamicPartials: true,
|
||||
jekyllWhere: true,
|
||||
});
|
||||
eleventyConfig.setLiquidOptions({
|
||||
timezoneOffset: 0,
|
||||
jekyllInclude: true,
|
||||
dynamicPartials: true,
|
||||
jekyllWhere: true,
|
||||
})
|
||||
|
||||
eleventyConfig.setServerPassthroughCopyBehavior("passthrough");
|
||||
|
||||
}
|
||||
eleventyConfig.setServerPassthroughCopyBehavior('passthrough')
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { readFileSync } from "fs";
|
||||
import { join, dirname } from "path";
|
||||
import { readFileSync } from 'fs'
|
||||
import { join, dirname } from 'path'
|
||||
|
||||
import { fileURLToPath } from "url";
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
export function appData(eleventyConfig) {
|
||||
const currentDir = dirname(fileURLToPath(import.meta.url));
|
||||
const currentDir = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
console.log('currentDir', currentDir);
|
||||
console.log('currentDir', currentDir)
|
||||
|
||||
eleventyConfig.addGlobalData("package", JSON.parse(readFileSync(join(currentDir, "..", "..", "core", "package.json"), "utf-8"))) ;
|
||||
eleventyConfig.addGlobalData("changelog", readFileSync(join(currentDir, "..", "..", "core", "CHANGELOG.md"), "utf-8"));
|
||||
eleventyConfig.addGlobalData("libs", JSON.parse(readFileSync(join(currentDir, "..", "..", "core", "libs.json"), "utf-8")));
|
||||
eleventyConfig.addGlobalData('package', JSON.parse(readFileSync(join(currentDir, '..', '..', 'core', 'package.json'), 'utf-8')))
|
||||
eleventyConfig.addGlobalData('changelog', readFileSync(join(currentDir, '..', '..', 'core', 'CHANGELOG.md'), 'utf-8'))
|
||||
eleventyConfig.addGlobalData('libs', JSON.parse(readFileSync(join(currentDir, '..', '..', 'core', 'libs.json'), 'utf-8')))
|
||||
|
||||
// Analytics Environment Variables
|
||||
eleventyConfig.addGlobalData("posthogApiKey", process.env.NEXT_PUBLIC_POSTHOG_KEY);
|
||||
eleventyConfig.addGlobalData("posthogHost", process.env.NEXT_PUBLIC_POSTHOG_HOST);
|
||||
}
|
||||
// Analytics Environment Variables
|
||||
eleventyConfig.addGlobalData('posthogApiKey', process.env.NEXT_PUBLIC_POSTHOG_KEY)
|
||||
eleventyConfig.addGlobalData('posthogHost', process.env.NEXT_PUBLIC_POSTHOG_HOST)
|
||||
}
|
||||
|
||||
@@ -1,446 +1,444 @@
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { readFileSync, existsSync } from 'node:fs'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join, dirname } from 'node:path'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
export function appFilters(eleventyConfig) {
|
||||
/**
|
||||
* Filters
|
||||
*/
|
||||
eleventyConfig.addFilter("miliseconds_to_minutes", function (value) {
|
||||
// Raturn 3:45 time format
|
||||
const minutes = Math.floor(value / 60000);
|
||||
const seconds = ((value % 60000) / 1000).toFixed(0);
|
||||
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("relative", (page) => {
|
||||
const segments = (page.url || '').replace(/^\//).split('/');
|
||||
if (segments.length === 1) {
|
||||
return '.';
|
||||
} else {
|
||||
return '../'.repeat(segments.length - 1).slice(0, -1);
|
||||
}
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("escape_attribute", (text) => {
|
||||
return text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\r\n/g, ' ')
|
||||
.replace(/[\r\n]/g, ' ');
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("contains", (items, item) => {
|
||||
return items && Array.isArray(items) && items.includes(item);
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("concat_objects", function (object, object2) {
|
||||
if (
|
||||
object &&
|
||||
object2 &&
|
||||
typeof object === 'object' &&
|
||||
typeof object2 === 'object' &&
|
||||
!Array.isArray(object) &&
|
||||
!Array.isArray(object2)
|
||||
) {
|
||||
return { ...object, ...object2 };
|
||||
}
|
||||
return object;
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("replace_regex", function (input, regStr, replStr) {
|
||||
const regex = new RegExp(regStr, 'gm');
|
||||
return input.replace(regex, replStr);
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("timestamp_to_date", function (timestamp) {
|
||||
const date = new Date(timestamp * 1000); // Convert timestamp to milliseconds
|
||||
return date.toISOString().split('T')[0]; // Extract the date in 'YYYY-MM-DD' format
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("split_to_n", function (arr, n) {
|
||||
const chunkSize = Math.round(arr.length / n);
|
||||
const result = [];
|
||||
for (let i = 0; i < arr.length; i += chunkSize) {
|
||||
result.push(arr.slice(i, i + chunkSize));
|
||||
}
|
||||
return result;
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("format_number", function (value) {
|
||||
return value.toString()
|
||||
.split('')
|
||||
.reverse()
|
||||
.reduce((acc, char, index) => {
|
||||
if (index > 0 && index % 3 === 0) {
|
||||
acc.push(',');
|
||||
}
|
||||
acc.push(char);
|
||||
return acc;
|
||||
}, [])
|
||||
.reverse()
|
||||
.join('');
|
||||
});
|
||||
|
||||
function randomNumber(x, min = 0, max = 100, round = 0) {
|
||||
let value = ((x * x * Math.PI * Math.E * (max + 1) * (Math.sin(x) / Math.cos(x * x))) % (max + 1 - min)) + min;
|
||||
|
||||
value = value > max ? max : value;
|
||||
value = value < min ? min : value;
|
||||
|
||||
if (round !== 0) {
|
||||
value = parseFloat(value.toFixed(round));
|
||||
} else {
|
||||
value = Math.floor(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
eleventyConfig.addFilter("random_date_ago", function (x, daysAgo = 100) {
|
||||
const today = new Date();
|
||||
const randomDaysAgo = randomNumber(x, 0, daysAgo);
|
||||
today.setDate(today.getDate() - randomDaysAgo);
|
||||
return today;
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("random_date", function (x, startDate = null, endDate = null) {
|
||||
const start = new Date(startDate ? startDate : '2024-01-01').getTime() / 1000;
|
||||
const end = new Date(endDate ? endDate : '2024-12-30').getTime() / 1000;
|
||||
|
||||
const randomTimestamp = randomNumber(x, start, end);
|
||||
return new Date(randomTimestamp * 1000);
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("random_item", function (x, items) {
|
||||
const index = randomNumber(x, 0, items.length - 1);
|
||||
return items[index];
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("random_number", randomNumber);
|
||||
|
||||
eleventyConfig.addFilter("first_letters", function capitalizeFirstLetter(string) {
|
||||
return (string || '').split(' ').map(word => word.charAt(0)).join('');
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("uc_first", function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("size", function (elem) {
|
||||
if (elem instanceof Object) {
|
||||
return Object.keys(elem).length;
|
||||
}
|
||||
|
||||
if (elem) {
|
||||
return elem.length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("first", function (elem) {
|
||||
if (elem instanceof Object) {
|
||||
return elem[Object.keys(elem)[0]];
|
||||
}
|
||||
|
||||
return elem ? elem[0] : null;
|
||||
})
|
||||
|
||||
// Convert a URL path to an absolute URL
|
||||
eleventyConfig.addFilter("absolute_url", function (url) {
|
||||
const baseUrl = "https://docs.tabler.io";
|
||||
|
||||
// Ensure url starts with a slash
|
||||
if (!url.startsWith('/')) {
|
||||
url = '/' + url;
|
||||
}
|
||||
|
||||
return baseUrl + url;
|
||||
})
|
||||
|
||||
// time ago from today
|
||||
eleventyConfig.addFilter("timeago", function (date) {
|
||||
let seconds;
|
||||
if (typeof date === 'number') {
|
||||
seconds = date;
|
||||
} else {
|
||||
seconds = Math.floor((new Date() - date) / 1000);
|
||||
}
|
||||
|
||||
let interval = Math.floor(seconds / 31536000);
|
||||
|
||||
if (interval >= 1) {
|
||||
return `${interval} year${interval > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
interval = Math.floor(seconds / 2592000);
|
||||
if (interval >= 1) {
|
||||
return `${interval} month${interval > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
interval = Math.floor(seconds / 86400);
|
||||
if (interval >= 1) {
|
||||
return `${interval} day${interval > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
interval = Math.floor(seconds / 3600);
|
||||
if (interval >= 1) {
|
||||
return `${interval} hour${interval > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval >= 1) {
|
||||
return `${interval} minute${interval > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
if (seconds > 0) {
|
||||
return `${Math.floor(seconds)} second${Math.floor(seconds) > 1 ? 's' : ''} ago`;
|
||||
}
|
||||
|
||||
return "now";
|
||||
})
|
||||
|
||||
function buildCollectionTree(flatData) {
|
||||
const tree = [];
|
||||
const lookup = {};
|
||||
|
||||
flatData
|
||||
.filter(item => item.url !== '/')
|
||||
.forEach(item => {
|
||||
lookup[item.url] = { ...item, children: [] };
|
||||
});
|
||||
|
||||
flatData.forEach(item => {
|
||||
const parts = item.url.split('/').filter(Boolean);
|
||||
if (parts.length === 1) {
|
||||
tree.push(lookup[item.url]);
|
||||
} else {
|
||||
const parentUrl = '/' + parts.slice(0, -1).join('/') + '/';
|
||||
if (lookup[parentUrl]) {
|
||||
lookup[parentUrl].children.push(lookup[item.url]);
|
||||
} else {
|
||||
tree.push(lookup[item.url]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
eleventyConfig.addFilter("collection-tree", function (collection) {
|
||||
const a = collection.map(item => {
|
||||
return {
|
||||
data: item.data,
|
||||
page: item.page,
|
||||
url: item.url,
|
||||
children: []
|
||||
}
|
||||
}).sort((a, b) => {
|
||||
const orderA = a.data.order ?? 999;
|
||||
const orderB = b.data.order ?? 999;
|
||||
|
||||
if (orderA !== orderB) {
|
||||
return orderA - orderB;
|
||||
}
|
||||
|
||||
const titleA = a.data.title ?? '';
|
||||
const titleB = b.data.title ?? '';
|
||||
|
||||
return titleA.localeCompare(titleB);
|
||||
});
|
||||
|
||||
return buildCollectionTree(a);
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("collection-children", function (collection, page) {
|
||||
const url = page.url.split('/').filter(Boolean).join('/');
|
||||
|
||||
const filteredCollection = collection.filter(item => {
|
||||
const parts = item.url.split('/').filter(Boolean);
|
||||
return parts.length > 1 && parts.slice(0, -1).join('/') === url;
|
||||
});
|
||||
|
||||
return filteredCollection.sort((a, b) => {
|
||||
return (a.data?.order || 999) - (b.data?.order || 999);
|
||||
});
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("next-prev", function (collection, page) {
|
||||
const items = collection
|
||||
.filter(item => {
|
||||
const parts = item.url.split('/').filter(Boolean);
|
||||
return parts.length > 1 && parts.slice(0, -1).join('/') === page.url.split('/').filter(Boolean).slice(0, -1).join('/');
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.data.title.localeCompare(b.data.title);
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return (a.data?.order || 999) - (b.data?.order || 999);
|
||||
});
|
||||
const index = items.findIndex(item => item.url === page.url);
|
||||
|
||||
const prevPost = index > 0 ? items[index - 1] : null;
|
||||
const nextPost = index < items.length - 1 ? items[index + 1] : null;
|
||||
|
||||
return {
|
||||
prev: prevPost ? prevPost : null,
|
||||
next: nextPost ? nextPost : null,
|
||||
};
|
||||
});
|
||||
|
||||
const generateUniqueId = (text) => {
|
||||
let id = text
|
||||
.replace(/<[^>]+>/g, "")
|
||||
.replace(/\s/g, "-")
|
||||
.replace(/[^\w-]+/g, "")
|
||||
.replace(/--+/g, "-")
|
||||
.replace(/^-+|-+$/g, "")
|
||||
.toLowerCase();
|
||||
|
||||
// Ensure ID doesn't start with a number (invalid HTML)
|
||||
if (/^[0-9]/.test(id)) {
|
||||
id = "h" + id;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
eleventyConfig.addFilter("headings-id", function (content) {
|
||||
return content.replace(/<h([1-6])>([^<]+)<\/h\1>/g, (match, level, text) => {
|
||||
const headingId = generateUniqueId(text);
|
||||
|
||||
return `<h${level} id="${headingId}">${text}</h${level}>`;
|
||||
});
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("toc", function (name) {
|
||||
const toc = [];
|
||||
|
||||
const contentWithoutExamples = name.replace(/<!--EXAMPLE-->[\s\S]*?<!--\/EXAMPLE-->/g, '');
|
||||
const headings = contentWithoutExamples.match(/<h([23])>([^<]+)<\/h\1>/g);
|
||||
|
||||
if (headings) {
|
||||
headings.forEach(heading => {
|
||||
const level = parseInt(heading.match(/<h([1-6])>/)[1]);
|
||||
const text = heading.replace(/<[^>]+>/g, "");
|
||||
const id = generateUniqueId(text);
|
||||
|
||||
toc.push({ level, text, id });
|
||||
});
|
||||
}
|
||||
|
||||
return toc;
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("remove-href", function (content) {
|
||||
return content.replace(/href="#"/g, 'href="javascript:void(0)"');
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Shortcodes
|
||||
*/
|
||||
eleventyConfig.addShortcode('scss-docs', function (name, filename) {
|
||||
const file = join(__dirname, `../../core/scss/${filename}`)
|
||||
|
||||
if (existsSync(file)) {
|
||||
const content = readFileSync(file, 'utf8');
|
||||
const regex = new RegExp(`\/\/\\sscss-docs-start\\s${name}\\n(.+?)\/\/\\sscss-docs-end`, 'gs')
|
||||
|
||||
const m = content.matchAll(regex)
|
||||
|
||||
if (m) {
|
||||
const matches = [...m]
|
||||
|
||||
if (matches[0] && matches[0][1]) {
|
||||
const lines = matches[0][1].split('\n');
|
||||
|
||||
// Find minimum number of leading spaces in non-empty lines
|
||||
const minIndent = lines
|
||||
.filter(line => line.trim().length > 0)
|
||||
.reduce((min, line) => {
|
||||
const match = line.match(/^(\s*)/);
|
||||
const leadingSpaces = match ? match[1].length : 0;
|
||||
return Math.min(min, leadingSpaces);
|
||||
}, Infinity);
|
||||
|
||||
// Remove that many spaces from the start of each line
|
||||
const result = lines.map(line => line.startsWith(' '.repeat(minIndent))
|
||||
? line.slice(minIndent)
|
||||
: line).join('\n');
|
||||
|
||||
return "\n```scss\n" + result.trimRight() + "\n```\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
const tags = ["capture_global", "endcapture_global", "highlight", "endhighlight"];
|
||||
tags.forEach(tag => {
|
||||
eleventyConfig.addLiquidTag(tag, function (liquidEngine) {
|
||||
return {
|
||||
parse: function (tagToken, remainingTokens) {
|
||||
this.str = tagToken.args;
|
||||
},
|
||||
render: function (scope, hash) {
|
||||
return "";
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
let _CAPTURES = {};
|
||||
eleventyConfig.on('beforeBuild', () => {
|
||||
_CAPTURES = {};
|
||||
});
|
||||
|
||||
['script', 'modal'].forEach((tag) => {
|
||||
eleventyConfig.addPairedShortcode(`capture_${tag}`, function (content, inline) {
|
||||
if (inline) {
|
||||
return content;
|
||||
}
|
||||
|
||||
if (!_CAPTURES[tag]) {
|
||||
_CAPTURES[tag] = []
|
||||
}
|
||||
|
||||
if (!_CAPTURES[tag][this.page.inputPath]) {
|
||||
_CAPTURES[tag][this.page.inputPath] = [];
|
||||
}
|
||||
|
||||
_CAPTURES[tag][this.page.inputPath].push(content);
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
eleventyConfig.addShortcode(`${tag}s`, function () {
|
||||
if (_CAPTURES[tag] && _CAPTURES[tag][this.page.inputPath]) {
|
||||
return _CAPTURES[tag][this.page.inputPath] ? `<!-- BEGIN PAGE ${tag.toUpperCase()}S -->\n${_CAPTURES[tag][this.page.inputPath].join('\n').trim()}\n<!-- END PAGE ${tag.toUpperCase()}S -->` : '';
|
||||
}
|
||||
|
||||
return ''
|
||||
});
|
||||
});
|
||||
|
||||
eleventyConfig.addPairedShortcode(`removeemptylines`, function (content) {
|
||||
if (content) {
|
||||
return content.split('\n').filter(line => line.trim() !== '').join('\n');
|
||||
}
|
||||
|
||||
return '';
|
||||
})
|
||||
|
||||
|
||||
eleventyConfig.addPairedShortcode(`callout`, function (content) {
|
||||
if (content) {
|
||||
return `<div class="callout">\n${content}\n</div>`;
|
||||
}
|
||||
|
||||
return '';
|
||||
})
|
||||
|
||||
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);
|
||||
/**
|
||||
* Filters
|
||||
*/
|
||||
eleventyConfig.addFilter('miliseconds_to_minutes', function (value) {
|
||||
// Raturn 3:45 time format
|
||||
const minutes = Math.floor(value / 60000)
|
||||
const seconds = ((value % 60000) / 1000).toFixed(0)
|
||||
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('relative', (page) => {
|
||||
const segments = (page.url || '').replace(/^\//).split('/')
|
||||
if (segments.length === 1) {
|
||||
return '.'
|
||||
} else {
|
||||
return '../'.repeat(segments.length - 1).slice(0, -1)
|
||||
}
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('escape_attribute', (text) => {
|
||||
return text
|
||||
.replace(/&/g, '&')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/\r\n/g, ' ')
|
||||
.replace(/[\r\n]/g, ' ')
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('contains', (items, item) => {
|
||||
return items && Array.isArray(items) && items.includes(item)
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('concat_objects', function (object, object2) {
|
||||
if (object && object2 && typeof object === 'object' && typeof object2 === 'object' && !Array.isArray(object) && !Array.isArray(object2)) {
|
||||
return { ...object, ...object2 }
|
||||
}
|
||||
return object
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('replace_regex', function (input, regStr, replStr) {
|
||||
const regex = new RegExp(regStr, 'gm')
|
||||
return input.replace(regex, replStr)
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('timestamp_to_date', function (timestamp) {
|
||||
const date = new Date(timestamp * 1000) // Convert timestamp to milliseconds
|
||||
return date.toISOString().split('T')[0] // Extract the date in 'YYYY-MM-DD' format
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('split_to_n', function (arr, n) {
|
||||
const chunkSize = Math.round(arr.length / n)
|
||||
const result = []
|
||||
for (let i = 0; i < arr.length; i += chunkSize) {
|
||||
result.push(arr.slice(i, i + chunkSize))
|
||||
}
|
||||
return result
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('format_number', function (value) {
|
||||
return value
|
||||
.toString()
|
||||
.split('')
|
||||
.reverse()
|
||||
.reduce((acc, char, index) => {
|
||||
if (index > 0 && index % 3 === 0) {
|
||||
acc.push(',')
|
||||
}
|
||||
acc.push(char)
|
||||
return acc
|
||||
}, [])
|
||||
.reverse()
|
||||
.join('')
|
||||
})
|
||||
|
||||
function randomNumber(x, min = 0, max = 100, round = 0) {
|
||||
let value = ((x * x * Math.PI * Math.E * (max + 1) * (Math.sin(x) / Math.cos(x * x))) % (max + 1 - min)) + min
|
||||
|
||||
value = value > max ? max : value
|
||||
value = value < min ? min : value
|
||||
|
||||
if (round !== 0) {
|
||||
value = parseFloat(value.toFixed(round))
|
||||
} else {
|
||||
value = Math.floor(value)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
eleventyConfig.addFilter('random_date_ago', function (x, daysAgo = 100) {
|
||||
const today = new Date()
|
||||
const randomDaysAgo = randomNumber(x, 0, daysAgo)
|
||||
today.setDate(today.getDate() - randomDaysAgo)
|
||||
return today
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('random_date', function (x, startDate = null, endDate = null) {
|
||||
const start = new Date(startDate ? startDate : '2024-01-01').getTime() / 1000
|
||||
const end = new Date(endDate ? endDate : '2024-12-30').getTime() / 1000
|
||||
|
||||
const randomTimestamp = randomNumber(x, start, end)
|
||||
return new Date(randomTimestamp * 1000)
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('random_item', function (x, items) {
|
||||
const index = randomNumber(x, 0, items.length - 1)
|
||||
return items[index]
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('random_number', randomNumber)
|
||||
|
||||
eleventyConfig.addFilter('first_letters', function capitalizeFirstLetter(string) {
|
||||
return (string || '')
|
||||
.split(' ')
|
||||
.map((word) => word.charAt(0))
|
||||
.join('')
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('uc_first', function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('size', function (elem) {
|
||||
if (elem instanceof Object) {
|
||||
return Object.keys(elem).length
|
||||
}
|
||||
|
||||
if (elem) {
|
||||
return elem.length
|
||||
}
|
||||
|
||||
return 0
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('first', function (elem) {
|
||||
if (elem instanceof Object) {
|
||||
return elem[Object.keys(elem)[0]]
|
||||
}
|
||||
|
||||
return elem ? elem[0] : null
|
||||
})
|
||||
|
||||
// Convert a URL path to an absolute URL
|
||||
eleventyConfig.addFilter('absolute_url', function (url) {
|
||||
const baseUrl = 'https://docs.tabler.io'
|
||||
|
||||
// Ensure url starts with a slash
|
||||
if (!url.startsWith('/')) {
|
||||
url = '/' + url
|
||||
}
|
||||
|
||||
return baseUrl + url
|
||||
})
|
||||
|
||||
// time ago from today
|
||||
eleventyConfig.addFilter('timeago', function (date) {
|
||||
let seconds
|
||||
if (typeof date === 'number') {
|
||||
seconds = date
|
||||
} else {
|
||||
seconds = Math.floor((new Date() - date) / 1000)
|
||||
}
|
||||
|
||||
let interval = Math.floor(seconds / 31536000)
|
||||
|
||||
if (interval >= 1) {
|
||||
return `${interval} year${interval > 1 ? 's' : ''} ago`
|
||||
}
|
||||
interval = Math.floor(seconds / 2592000)
|
||||
if (interval >= 1) {
|
||||
return `${interval} month${interval > 1 ? 's' : ''} ago`
|
||||
}
|
||||
interval = Math.floor(seconds / 86400)
|
||||
if (interval >= 1) {
|
||||
return `${interval} day${interval > 1 ? 's' : ''} ago`
|
||||
}
|
||||
interval = Math.floor(seconds / 3600)
|
||||
if (interval >= 1) {
|
||||
return `${interval} hour${interval > 1 ? 's' : ''} ago`
|
||||
}
|
||||
interval = Math.floor(seconds / 60)
|
||||
if (interval >= 1) {
|
||||
return `${interval} minute${interval > 1 ? 's' : ''} ago`
|
||||
}
|
||||
if (seconds > 0) {
|
||||
return `${Math.floor(seconds)} second${Math.floor(seconds) > 1 ? 's' : ''} ago`
|
||||
}
|
||||
|
||||
return 'now'
|
||||
})
|
||||
|
||||
function buildCollectionTree(flatData) {
|
||||
const tree = []
|
||||
const lookup = {}
|
||||
|
||||
flatData
|
||||
.filter((item) => item.url !== '/')
|
||||
.forEach((item) => {
|
||||
lookup[item.url] = { ...item, children: [] }
|
||||
})
|
||||
|
||||
flatData.forEach((item) => {
|
||||
const parts = item.url.split('/').filter(Boolean)
|
||||
if (parts.length === 1) {
|
||||
tree.push(lookup[item.url])
|
||||
} else {
|
||||
const parentUrl = '/' + parts.slice(0, -1).join('/') + '/'
|
||||
if (lookup[parentUrl]) {
|
||||
lookup[parentUrl].children.push(lookup[item.url])
|
||||
} else {
|
||||
tree.push(lookup[item.url])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return tree
|
||||
}
|
||||
|
||||
eleventyConfig.addFilter('collection-tree', function (collection) {
|
||||
const a = collection
|
||||
.map((item) => {
|
||||
return {
|
||||
data: item.data,
|
||||
page: item.page,
|
||||
url: item.url,
|
||||
children: [],
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const orderA = a.data.order ?? 999
|
||||
const orderB = b.data.order ?? 999
|
||||
|
||||
if (orderA !== orderB) {
|
||||
return orderA - orderB
|
||||
}
|
||||
|
||||
const titleA = a.data.title ?? ''
|
||||
const titleB = b.data.title ?? ''
|
||||
|
||||
return titleA.localeCompare(titleB)
|
||||
})
|
||||
|
||||
return buildCollectionTree(a)
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('collection-children', function (collection, page) {
|
||||
const url = page.url.split('/').filter(Boolean).join('/')
|
||||
|
||||
const filteredCollection = collection.filter((item) => {
|
||||
const parts = item.url.split('/').filter(Boolean)
|
||||
return parts.length > 1 && parts.slice(0, -1).join('/') === url
|
||||
})
|
||||
|
||||
return filteredCollection.sort((a, b) => {
|
||||
return (a.data?.order || 999) - (b.data?.order || 999)
|
||||
})
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('next-prev', function (collection, page) {
|
||||
const items = collection
|
||||
.filter((item) => {
|
||||
const parts = item.url.split('/').filter(Boolean)
|
||||
return parts.length > 1 && parts.slice(0, -1).join('/') === page.url.split('/').filter(Boolean).slice(0, -1).join('/')
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return a.data.title.localeCompare(b.data.title)
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return (a.data?.order || 999) - (b.data?.order || 999)
|
||||
})
|
||||
const index = items.findIndex((item) => item.url === page.url)
|
||||
|
||||
const prevPost = index > 0 ? items[index - 1] : null
|
||||
const nextPost = index < items.length - 1 ? items[index + 1] : null
|
||||
|
||||
return {
|
||||
prev: prevPost ? prevPost : null,
|
||||
next: nextPost ? nextPost : null,
|
||||
}
|
||||
})
|
||||
|
||||
const generateUniqueId = (text) => {
|
||||
let id = text
|
||||
.replace(/<[^>]+>/g, '')
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^\w-]+/g, '')
|
||||
.replace(/--+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.toLowerCase()
|
||||
|
||||
// Ensure ID doesn't start with a number (invalid HTML)
|
||||
if (/^[0-9]/.test(id)) {
|
||||
id = 'h' + id
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
eleventyConfig.addFilter('headings-id', function (content) {
|
||||
return content.replace(/<h([1-6])>([^<]+)<\/h\1>/g, (match, level, text) => {
|
||||
const headingId = generateUniqueId(text)
|
||||
|
||||
return `<h${level} id="${headingId}">${text}</h${level}>`
|
||||
})
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('toc', function (name) {
|
||||
const toc = []
|
||||
|
||||
const contentWithoutExamples = name.replace(/<!--EXAMPLE-->[\s\S]*?<!--\/EXAMPLE-->/g, '')
|
||||
const headings = contentWithoutExamples.match(/<h([23])>([^<]+)<\/h\1>/g)
|
||||
|
||||
if (headings) {
|
||||
headings.forEach((heading) => {
|
||||
const level = parseInt(heading.match(/<h([1-6])>/)[1])
|
||||
const text = heading.replace(/<[^>]+>/g, '')
|
||||
const id = generateUniqueId(text)
|
||||
|
||||
toc.push({ level, text, id })
|
||||
})
|
||||
}
|
||||
|
||||
return toc
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter('remove-href', function (content) {
|
||||
return content.replace(/href="#"/g, 'href="javascript:void(0)"')
|
||||
})
|
||||
|
||||
/**
|
||||
* Shortcodes
|
||||
*/
|
||||
eleventyConfig.addShortcode('scss-docs', function (name, filename) {
|
||||
const file = join(__dirname, `../../core/scss/${filename}`)
|
||||
|
||||
if (existsSync(file)) {
|
||||
const content = readFileSync(file, 'utf8')
|
||||
const regex = new RegExp(`\/\/\\sscss-docs-start\\s${name}\\n(.+?)\/\/\\sscss-docs-end`, 'gs')
|
||||
|
||||
const m = content.matchAll(regex)
|
||||
|
||||
if (m) {
|
||||
const matches = [...m]
|
||||
|
||||
if (matches[0] && matches[0][1]) {
|
||||
const lines = matches[0][1].split('\n')
|
||||
|
||||
// Find minimum number of leading spaces in non-empty lines
|
||||
const minIndent = lines
|
||||
.filter((line) => line.trim().length > 0)
|
||||
.reduce((min, line) => {
|
||||
const match = line.match(/^(\s*)/)
|
||||
const leadingSpaces = match ? match[1].length : 0
|
||||
return Math.min(min, leadingSpaces)
|
||||
}, Infinity)
|
||||
|
||||
// Remove that many spaces from the start of each line
|
||||
const result = lines.map((line) => (line.startsWith(' '.repeat(minIndent)) ? line.slice(minIndent) : line)).join('\n')
|
||||
|
||||
return '\n```scss\n' + result.trimRight() + '\n```\n'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
const tags = ['capture_global', 'endcapture_global', 'highlight', 'endhighlight']
|
||||
tags.forEach((tag) => {
|
||||
eleventyConfig.addLiquidTag(tag, function (liquidEngine) {
|
||||
return {
|
||||
parse: function (tagToken, remainingTokens) {
|
||||
this.str = tagToken.args
|
||||
},
|
||||
render: function (scope, hash) {
|
||||
return ''
|
||||
},
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let _CAPTURES = {}
|
||||
eleventyConfig.on('beforeBuild', () => {
|
||||
_CAPTURES = {}
|
||||
})
|
||||
|
||||
;['script', 'modal'].forEach((tag) => {
|
||||
eleventyConfig.addPairedShortcode(`capture_${tag}`, function (content, inline) {
|
||||
if (inline) {
|
||||
return content
|
||||
}
|
||||
|
||||
if (!_CAPTURES[tag]) {
|
||||
_CAPTURES[tag] = []
|
||||
}
|
||||
|
||||
if (!_CAPTURES[tag][this.page.inputPath]) {
|
||||
_CAPTURES[tag][this.page.inputPath] = []
|
||||
}
|
||||
|
||||
_CAPTURES[tag][this.page.inputPath].push(content)
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
eleventyConfig.addShortcode(`${tag}s`, function () {
|
||||
if (_CAPTURES[tag] && _CAPTURES[tag][this.page.inputPath]) {
|
||||
return _CAPTURES[tag][this.page.inputPath] ? `<!-- BEGIN PAGE ${tag.toUpperCase()}S -->\n${_CAPTURES[tag][this.page.inputPath].join('\n').trim()}\n<!-- END PAGE ${tag.toUpperCase()}S -->` : ''
|
||||
}
|
||||
|
||||
return ''
|
||||
})
|
||||
})
|
||||
|
||||
eleventyConfig.addPairedShortcode(`removeemptylines`, function (content) {
|
||||
if (content) {
|
||||
return content
|
||||
.split('\n')
|
||||
.filter((line) => line.trim() !== '')
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
eleventyConfig.addPairedShortcode(`callout`, function (content) {
|
||||
if (content) {
|
||||
return `<div class="callout">\n${content}\n</div>`
|
||||
}
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
eleventyConfig.addShortcode('year', () => `${new Date().getFullYear()}`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user