mirror of
https://github.com/tabler/tabler.git
synced 2026-01-25 12:26:30 +00:00
Compare commits
7 Commits
dev-docs-i
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4e1ff40c1 | ||
|
|
938e9d35cc | ||
|
|
82e3c39585 | ||
|
|
eac69eb35b | ||
|
|
684f40e7c1 | ||
|
|
f6414b3c94 | ||
|
|
c3e6aa1bd3 |
5
.changeset/docs-css-variables-font-sizes.md
Normal file
5
.changeset/docs-css-variables-font-sizes.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Updated documentation to explain font sizing and system color CSS variables (`--tblr-primary-rgb`, `--tblr-secondary`, `--tblr-tertiary`, `--tblr-link-color`, `--tblr-gray-*`).
|
||||
38
.cursor/rules/branch-naming.mdc
Normal file
38
.cursor/rules/branch-naming.mdc
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
description: Git Branch Naming Rules
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
## Branch naming
|
||||
|
||||
- Use lowercase branch names.
|
||||
- Use a type prefix and a short description in kebab-case.
|
||||
- Format: `<type>/<short-description>` or `<type>/<issue-id>-<short-description>`
|
||||
- Use `gh-123` as the issue id format (avoid `#` in branch names).
|
||||
|
||||
### Allowed types
|
||||
|
||||
- `feat` - new features
|
||||
- `fix` - bug fixes
|
||||
- `docs` - documentation changes
|
||||
- `chore` - maintenance / tooling
|
||||
- `refactor` - code refactoring (no behavior change)
|
||||
- `test` - tests only
|
||||
- `build` - build system changes
|
||||
- `ci` - CI changes
|
||||
- `perf` - performance improvements
|
||||
- `style` - formatting / lint-only changes
|
||||
- `revert` - reverting prior changes
|
||||
|
||||
### Examples
|
||||
|
||||
- `feat/gh-123-add-stepper-component`
|
||||
- `fix/markdown-table-overflow`
|
||||
- `docs/gh-45-update-contributing`
|
||||
- `chore/update-pnpm-lock`
|
||||
|
||||
### Notes
|
||||
|
||||
- Branch off `dev` by default (unless maintainers request otherwise).
|
||||
- Avoid spaces, uppercase letters, and special characters other than `/` and `-`.
|
||||
39
.cursor/rules/pull-request.mdc
Normal file
39
.cursor/rules/pull-request.mdc
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
description: Pull Request Title & Description Rules
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
## Pull request title
|
||||
|
||||
- Write PR titles in **English**.
|
||||
- Start the title with a **capital letter**.
|
||||
- Use **present tense** and keep it concise (ideally <= 72 chars).
|
||||
- Avoid a trailing period.
|
||||
|
||||
### Examples
|
||||
|
||||
- `Improve markdown table overflow handling`
|
||||
- `Clarify contributing branch naming`
|
||||
- `Add onboarding stepper page`
|
||||
|
||||
## Pull request description
|
||||
|
||||
- Write PR descriptions in **English**.
|
||||
- Focus on **why** the change is needed and what user-visible effect it has.
|
||||
- Keep it skimmable: bullets, short paragraphs, clear headings.
|
||||
|
||||
### Recommended template
|
||||
|
||||
```md
|
||||
## Summary
|
||||
- <1–3 bullets describing the change and why>
|
||||
|
||||
## Changes
|
||||
- <key implementation notes, non-obvious decisions>
|
||||
```
|
||||
|
||||
### Notes
|
||||
|
||||
- If you changed SCSS or any package behavior, add a **changeset** describing it (one sentence, with backticks for code elements).
|
||||
- If a PR is WIP, mark it as draft and prefix the title with `WIP:` only while it is not ready for review.
|
||||
@@ -1 +0,0 @@
|
||||
../../..
|
||||
14
README.md
14
README.md
@@ -28,13 +28,13 @@ A premium and open source dashboard template with a responsive and high-quality
|
||||
<p align="center">Browser testing via:</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.lambdatest.com/" target="_blank">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/14dd2a0a-bafe-436e-a6cb-29636278c781">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/d3dede5a-d702-47c3-bb66-4d887948ed83">
|
||||
<img src="https://github.com/user-attachments/assets/d3dede5a-d702-47c3-bb66-4d887948ed83" alt="labmdatest" width="296">
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://www.testmu.ai" target="_blank">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/f0967860-31ad-4078-850b-40b0abc95582" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/user-attachments/assets/55ac290a-6729-44aa-bbc3-4c5e909facbf" />
|
||||
<img src="https://github.com/user-attachments/assets/86bcbe29-eb8d-4273-a381-5ce17d4ca92d" alt="TestMu AI" width="296">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🔎 Preview
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
import { existsSync, mkdirSync } from 'fs'
|
||||
import { copySync } from 'fs-extra/esm'
|
||||
import { fileURLToPath } from '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}`)
|
||||
}
|
||||
|
||||
30
core/.build/vite.config.mts
Normal file
30
core/.build/vite.config.mts
Normal 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,33 +0,0 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper'
|
||||
import getBanner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const ESM = process.env.ESM === 'true'
|
||||
const THEME = process.env.THEME === 'true'
|
||||
|
||||
const MINIFY = process.env.MINIFY === 'true'
|
||||
const destinationFile = `tabler${THEME ? '-theme' : ''}${ESM ? '.esm' : ''}`
|
||||
const entryFile = `tabler${THEME ? '-theme' : ''}`
|
||||
const libraryName = `tabler${THEME ? '-theme' : ''}`
|
||||
|
||||
const bannerText = getBanner()
|
||||
|
||||
// Try .ts first, fallback to .js for gradual migration
|
||||
const entryPath = path.resolve(__dirname, `../js/${entryFile}`)
|
||||
const entry = existsSync(`${entryPath}.ts`) ? `${entryPath}.ts` : `${entryPath}.js`
|
||||
|
||||
export default createViteConfig({
|
||||
entry: entry,
|
||||
name: ESM ? undefined : libraryName,
|
||||
fileName: () => MINIFY ? `${destinationFile}.min.js` : `${destinationFile}.js`,
|
||||
formats: [ESM ? 'es' : 'umd'],
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: bannerText,
|
||||
minify: MINIFY ? true : false
|
||||
})
|
||||
|
||||
@@ -19,16 +19,12 @@
|
||||
"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-standalone-esm\" \"pnpm run js-build-theme\" \"pnpm run js-build-theme-esm\"",
|
||||
"js-build-theme-esm": "cross-env THEME=true ESM=true vite build --config .build/vite.config.ts",
|
||||
"js-build-theme": "cross-env THEME=true vite build --config .build/vite.config.ts",
|
||||
"js-build-standalone": "vite build --config .build/vite.config.ts",
|
||||
"js-build-standalone-esm": "cross-env ESM=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min": "concurrently \"pnpm run js-build-min-standalone\" \"pnpm run js-build-min-standalone-esm\" \"pnpm run js-build-min-theme\" \"pnpm run js-build-min-theme-esm\"",
|
||||
"js-build-min-standalone": "cross-env MINIFY=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-standalone-esm": "cross-env MINIFY=true ESM=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-theme": "cross-env MINIFY=true THEME=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-theme-esm": "cross-env MINIFY=true THEME=true ESM=true vite build --config .build/vite.config.ts",
|
||||
"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": "tsx .build/copy-libs.ts",
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
/** Theme colors */
|
||||
@each $name, $color in map.merge($theme-colors, $social-colors) {
|
||||
@debug contrast-ratio($color, white), $name, $min-contrast-ratio;
|
||||
--#{$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))};
|
||||
|
||||
@@ -495,6 +495,11 @@ $line-heights: (
|
||||
h4: $h4-line-height,
|
||||
h5: $h5-line-height,
|
||||
h6: $h6-line-height,
|
||||
|
||||
base: $line-height-base,
|
||||
sm: $line-height-sm,
|
||||
lg: $line-height-lg,
|
||||
xl: $line-height-xl,
|
||||
) !default;
|
||||
|
||||
$display-font-sizes: (
|
||||
@@ -797,8 +802,8 @@ $icon-color: var(--#{$prefix}gray-400) !default;
|
||||
// Code
|
||||
$code-color: light-dark(var(--#{$prefix}gray-600), var(--#{$prefix}gray-400)) !default;
|
||||
$code-bg: light-dark(var(--#{$prefix}gray-100), var(--#{$prefix}gray-900)) !default;
|
||||
$code-font-size: $font-size-reative-md !default;
|
||||
$code-line-height: 1.7142857em !default;
|
||||
$code-font-size: $font-size-reative-sm !default;
|
||||
$code-line-height: 1.25rem !default;
|
||||
|
||||
$pre-padding: 1rem !default;
|
||||
$pre-bg: var(--#{$prefix}bg-surface-dark) !default;
|
||||
|
||||
@@ -138,8 +138,6 @@
|
||||
|
||||
// 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,8 +1,12 @@
|
||||
$markdown-font-size: var(--#{$prefix}font-size-h3) !default;
|
||||
$markdown-line-height: var(--#{$prefix}line-height-lg) !default;
|
||||
|
||||
/**
|
||||
Markdown
|
||||
*/
|
||||
.markdown {
|
||||
line-height: $line-height-xl;
|
||||
line-height: $markdown-line-height;
|
||||
font-size: $markdown-font-size;
|
||||
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
&.nav-pills {
|
||||
margin: 0 calc(-1 * var(--#{$prefix}nav-link-padding-x));
|
||||
margin: 0 calc(-1 * $nav-link-padding-x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ pre {
|
||||
background: $pre-bg;
|
||||
color: $pre-color;
|
||||
border-radius: var(--#{$prefix}border-radius);
|
||||
line-height: $code-line-height;
|
||||
line-height: $line-height-base;
|
||||
|
||||
@include scrollbar;
|
||||
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper'
|
||||
import getBanner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const MINIFY = process.env.MINIFY === 'true'
|
||||
|
||||
// Try .ts first, fallback to .js for gradual migration
|
||||
const entryPath = path.resolve(__dirname, '../js/docs')
|
||||
const entry = existsSync(`${entryPath}.ts`) ? `${entryPath}.ts` : `${entryPath}.js`
|
||||
const entry = `${entryPath}.ts`
|
||||
|
||||
export default createViteConfig({
|
||||
entry: entry,
|
||||
name: 'docs',
|
||||
fileName: () => MINIFY ? 'docs.min.js' : 'docs.js',
|
||||
fileName: () => 'docs.js',
|
||||
formats: ['es'],
|
||||
outDir: path.resolve(__dirname, '../dist/js'),
|
||||
banner: undefined,
|
||||
minify: MINIFY
|
||||
minify: false
|
||||
})
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Tabler Emails
|
||||
menu-title: Emails
|
||||
seoTitle: Tabler Emails - premium email templates
|
||||
icon: mail
|
||||
order: 4
|
||||
description: Customizable email templates for over 90 clients and devices.
|
||||
summary: Tabler Emails is a set of 80 eye-catching, customizable HTML templates. They are compatible with over 90 email clients and devices.
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Tabler Icons
|
||||
menu-title: Icons
|
||||
summary: Tabler Icons is a powerful and versatile icon library that offers a huge collection of high quality icons suitable for a wide range of applications. With its clean and modern aesthetic, extensive customization options, and user-friendly website and plugins, Tabler Icons is an excellent resource for designers and developers looking to enhance their projects with high-quality icons.
|
||||
icon: ghost
|
||||
order: 2
|
||||
description: Over 5000 pixel-perfect icons for web design and development
|
||||
---
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Tabler Illustrations
|
||||
menu-title: Illustrations
|
||||
order: 3
|
||||
icon: paint
|
||||
description: Customizable illustrations for modern web and mobile designs.
|
||||
summary: Tabler Illustrations is a collection of customizable SVG illustrations for your web project. Explore our library of illustrations to enhance your web development experience.
|
||||
---
|
||||
|
||||
@@ -27,6 +27,35 @@ Now you just need to tell Tabler to use your favorite font:
|
||||
</style>
|
||||
```
|
||||
|
||||
## Custom font sizes
|
||||
|
||||
Tabler exposes typography settings as CSS variables. You can override them by setting variables on `:root` (global) or on any container (scoped).
|
||||
|
||||
### Base font size
|
||||
|
||||
To change the default font size used by body text and many components, override `--tblr-body-font-size`:
|
||||
|
||||
```html
|
||||
<style>
|
||||
:root {
|
||||
--tblr-body-font-size: 1rem;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Headings
|
||||
|
||||
Headings use `--tblr-font-size-h1` … `--tblr-font-size-h6` and `--tblr-line-height-h1` … `--tblr-line-height-h6`:
|
||||
|
||||
```html
|
||||
<style>
|
||||
:root {
|
||||
--tblr-font-size-h1: 2rem;
|
||||
--tblr-line-height-h1: 2.5rem;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## Custom primary color
|
||||
|
||||
To change the primary color of Tabler you need to set the `--tblr-primary` variable in your CSS. You can use any color format you like (hex, rgb, hsl, etc). In this example we will use a custom red color:
|
||||
@@ -34,7 +63,56 @@ To change the primary color of Tabler you need to set the `--tblr-primary` varia
|
||||
```html
|
||||
<style>
|
||||
:root {
|
||||
--tblr-primary: #F11D46;
|
||||
--tblr-primary: #f11d46;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
```
|
||||
|
||||
If you use `--tblr-primary` in `rgba()` contexts (or see inconsistent colors), also override `--tblr-primary-rgb` (as comma-separated RGB values) and optionally `--tblr-primary-fg` (text/icon color used on primary backgrounds):
|
||||
|
||||
```html
|
||||
<style>
|
||||
:root {
|
||||
--tblr-primary: #f11d46;
|
||||
--tblr-primary-rgb: 241, 29, 70;
|
||||
--tblr-primary-fg: #fff;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## Other system colors
|
||||
|
||||
Tabler also exposes a few "system" colors you can customize globally:
|
||||
|
||||
```html
|
||||
<style>
|
||||
:root {
|
||||
--tblr-secondary: #6b7280;
|
||||
--tblr-tertiary: #9ca3af;
|
||||
--tblr-link-color: #066fd1;
|
||||
--tblr-link-hover-color: #045db0;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### Gray scale
|
||||
|
||||
You can override the full gray palette (`--tblr-gray-50` … `--tblr-gray-950`) to match your brand:
|
||||
|
||||
```html
|
||||
<style>
|
||||
:root {
|
||||
--tblr-gray-50: #f9fafb;
|
||||
--tblr-gray-100: #f3f4f6;
|
||||
--tblr-gray-200: #e5e7eb;
|
||||
--tblr-gray-300: #d1d5db;
|
||||
--tblr-gray-400: #9ca3af;
|
||||
--tblr-gray-500: #6b7280;
|
||||
--tblr-gray-600: #4b5563;
|
||||
--tblr-gray-700: #374151;
|
||||
--tblr-gray-800: #1f2937;
|
||||
--tblr-gray-900: #111827;
|
||||
--tblr-gray-950: #030712;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
@@ -30,7 +30,8 @@ Follow these steps to set up Tabler for development:
|
||||
3. Create a new branch for your changes:
|
||||
|
||||
```bash
|
||||
git checkout -b your-branch-name
|
||||
# Use the project branch naming convention, e.g.:
|
||||
git checkout -b fix/markdown-table-overflow
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: Tabler UI
|
||||
menu-title: Admin Template
|
||||
order: 1
|
||||
icon: layout
|
||||
description: Free and open source web application UI kit based on Bootstrap
|
||||
summary: Tabler UI is a carefully crafted collection of modern and responsive user interface components. Built on top of Bootstrap, it helps developers create stunning and functional web applications quickly and efficiently.
|
||||
---
|
||||
|
||||
@@ -94,9 +94,9 @@ export default function (eleventyConfig) {
|
||||
eleventyConfig.addGlobalData("posthogHost", process.env.POSTHOG_HOST || "https://us.i.posthog.com");
|
||||
|
||||
const data = {
|
||||
iconsCount: () => 5963,
|
||||
emailsCount: () => 80,
|
||||
illustrationsCount: () => 105
|
||||
iconsCount: () => 123,
|
||||
emailsCount: () => 123,
|
||||
illustrationsCount: () => 123
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(data)) {
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
"build-assets": "concurrently \"pnpm run js\" \"pnpm run css\"",
|
||||
"html": "eleventy",
|
||||
"js": "pnpm run js-build && pnpm run js-build-min",
|
||||
"js-build": "vite build --config .build/vite.config.ts",
|
||||
"js-build": "vite build --config .build/vite.config.mts",
|
||||
"js-build-min": "pnpm run js-build-min-docs",
|
||||
"js-build-min-docs": "cross-env MINIFY=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-docs": "terser dist/js/docs.js --module --compress --mangle --comments '/@license|@preserve|^!/' --source-map \"content=dist/js/docs.js.map,filename=dist/js/docs.min.js.map,url=docs.min.js.map\" -o dist/js/docs.min.js",
|
||||
"css": "pnpm run css-build && pnpm run css-prefix && pnpm run css-minify",
|
||||
"css-build": "sass scss/:dist/css/ --no-source-map --load-path=./node_modules",
|
||||
"css-prefix": "postcss --config .build/postcss.config.mjs --replace \"dist/css/*.css\" \"!dist/css/*.rtl*.css\" \"!dist/css/*.min.css\"",
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
:root {
|
||||
--docsearch-primary-color: var(--tblr-primary);
|
||||
--docsearch-searchbox-background: var(--tblr-bg-surface-secondary);
|
||||
--docsearch-searchbox-focus-background: var(--tblr-bg-surface-secondary);
|
||||
--docsearch-searchbox-background: var(--tblr-bg-surface);
|
||||
--docsearch-searchbox-focus-background: var(--tblr-bg-surface);
|
||||
--docsearch-text-color: var(--tblr-body-text);
|
||||
--docsearch-key-shadow: none;
|
||||
--docsearch-key-shadow: 0 0 0 1px var(--tblr-border-color);
|
||||
--docsearch-key-gradient: var(--tblr-bg-surface-secondary);
|
||||
--docsearch-searchbox-shadow: 0 0 0 1px var(--tblr-border-color);
|
||||
--docsearch-searchbox-focus-background: var(--tblr-bg-surface-tertiary);
|
||||
}
|
||||
|
||||
.col-docs {
|
||||
@@ -26,11 +24,6 @@
|
||||
box-shadow: 0 0 0 1px var(--tblr-border-color);
|
||||
font-weight: var(--tblr-font-weight-normal);
|
||||
transition: all 0.2s ease-in-out;
|
||||
border-radius: var(--tblr-border-radius);
|
||||
}
|
||||
|
||||
.DocSearch-Button-Placeholder {
|
||||
font-size: var(--tblr-font-size);
|
||||
}
|
||||
|
||||
.DocSearch-SearchBar {
|
||||
@@ -39,11 +32,6 @@
|
||||
background-color: var(--tblr-bg-surface) !important;
|
||||
}
|
||||
|
||||
.DocSearch-Search-Icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.DocSearch-Hit-source {
|
||||
background: none !important;
|
||||
}
|
||||
@@ -57,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;
|
||||
@@ -100,7 +88,7 @@
|
||||
|
||||
.DocSearch-Input {
|
||||
color: var(--tblr-body-color) !important;
|
||||
|
||||
|
||||
&::placeholder {
|
||||
color: var(--tblr-muted) !important;
|
||||
}
|
||||
@@ -112,20 +100,8 @@
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.DocSearch-Button-Keys {
|
||||
min-width: 0;
|
||||
gap: .25rem;
|
||||
margin-right: .25rem;
|
||||
}
|
||||
|
||||
.DocSearch-Button-Key {
|
||||
top: 0;
|
||||
box-shadow: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: auto;
|
||||
font-size: var(--tblr-font-size);
|
||||
}
|
||||
|
||||
.DocSearch-Container {
|
||||
@@ -138,13 +114,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.example>.modal,
|
||||
.example>.offcanvas {
|
||||
.example > .modal,
|
||||
.example > .offcanvas {
|
||||
display: block !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.example>.offcanvas-backdrop {
|
||||
.example > .offcanvas-backdrop {
|
||||
position: absolute !important;
|
||||
}
|
||||
|
||||
@@ -157,4 +133,4 @@ code {
|
||||
::selection {
|
||||
background: var(--tblr-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
{
|
||||
"trailingSlash": false,
|
||||
"redirects": [
|
||||
{
|
||||
"source": "/",
|
||||
"destination": "/ui",
|
||||
"permanent": false
|
||||
}
|
||||
],
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "/stats/js/script.js",
|
||||
@@ -24,7 +17,6 @@
|
||||
"source": "/eat/:path(.*)",
|
||||
"destination": "https://eu.i.posthog.com/:path*"
|
||||
},
|
||||
|
||||
{
|
||||
"source": "/(.*)",
|
||||
"destination": "/error-404.html"
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"js-beautify": "^1.15.4",
|
||||
"markdownlint-cli": "^0.47.0",
|
||||
"nodemon": "^3.1.11",
|
||||
"pnpm": "^10.6.5",
|
||||
"pnpm": "^10.27.0",
|
||||
"postcss": "^8.5.6",
|
||||
"postcss-cli": "^11.0.1",
|
||||
"prettier": "^3.7.4",
|
||||
|
||||
25
pnpm-lock.yaml
generated
25
pnpm-lock.yaml
generated
@@ -52,8 +52,8 @@ importers:
|
||||
specifier: ^3.1.11
|
||||
version: 3.1.11
|
||||
pnpm:
|
||||
specifier: ^10.6.5
|
||||
version: 10.6.5
|
||||
specifier: ^10.27.0
|
||||
version: 10.27.0
|
||||
postcss:
|
||||
specifier: ^8.5.6
|
||||
version: 8.5.6
|
||||
@@ -439,8 +439,8 @@ packages:
|
||||
search-insights:
|
||||
optional: true
|
||||
|
||||
'@emnapi/runtime@1.7.1':
|
||||
resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==}
|
||||
'@emnapi/runtime@1.8.1':
|
||||
resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==}
|
||||
|
||||
'@epic-web/invariant@1.0.0':
|
||||
resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
|
||||
@@ -1394,6 +1394,9 @@ packages:
|
||||
caniuse-lite@1.0.30001762:
|
||||
resolution: {integrity: sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==}
|
||||
|
||||
caniuse-lite@1.0.30001763:
|
||||
resolution: {integrity: sha512-mh/dGtq56uN98LlNX9qdbKnzINhX0QzhiWBFEkFfsFO4QyCvL8YegrJAazCwXIeqkIob8BlZPGM3xdnY+sgmvQ==}
|
||||
|
||||
caseless@0.12.0:
|
||||
resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
|
||||
|
||||
@@ -2711,8 +2714,8 @@ packages:
|
||||
plyr@3.8.3:
|
||||
resolution: {integrity: sha512-0+iI5uw0WRvtKBpgPCkmQQv7ucHVQKTEo6UFJjgJ8cy/JZhy0dQqshHQVitHXV6l2O3MzhgnuvQ95VSkWcWeSw==}
|
||||
|
||||
pnpm@10.6.5:
|
||||
resolution: {integrity: sha512-zfko/KIIMs1Z7FOCZJK33CXcUk1DcLa0rb9lgD0y76psHIgUfArk6NV5psnuxxV1e1DU+jXuoXnYaOraTtBDrw==}
|
||||
pnpm@10.27.0:
|
||||
resolution: {integrity: sha512-ctaZ2haxF5wUup5k3HHJpAmIy9xlwmTLDkidt96RfyDc9NZNhyNiXylpulLUt+KhFwaC2awqXcrqq3MrfhbwSg==}
|
||||
engines: {node: '>=18.12'}
|
||||
hasBin: true
|
||||
|
||||
@@ -3903,7 +3906,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- '@algolia/client-search'
|
||||
|
||||
'@emnapi/runtime@1.7.1':
|
||||
'@emnapi/runtime@1.8.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
@@ -4101,7 +4104,7 @@ snapshots:
|
||||
|
||||
'@img/sharp-wasm32@0.34.5':
|
||||
dependencies:
|
||||
'@emnapi/runtime': 1.7.1
|
||||
'@emnapi/runtime': 1.8.1
|
||||
optional: true
|
||||
|
||||
'@img/sharp-win32-arm64@0.34.5':
|
||||
@@ -4669,6 +4672,8 @@ snapshots:
|
||||
|
||||
caniuse-lite@1.0.30001762: {}
|
||||
|
||||
caniuse-lite@1.0.30001763: {}
|
||||
|
||||
caseless@0.12.0: {}
|
||||
|
||||
ccount@2.0.1: {}
|
||||
@@ -5851,7 +5856,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@next/env': 16.0.4
|
||||
'@swc/helpers': 0.5.15
|
||||
caniuse-lite: 1.0.30001762
|
||||
caniuse-lite: 1.0.30001763
|
||||
postcss: 8.4.31
|
||||
react: 19.2.0
|
||||
react-dom: 19.2.0(react@19.2.0)
|
||||
@@ -6060,7 +6065,7 @@ snapshots:
|
||||
rangetouch: 2.0.1
|
||||
url-polyfill: 1.1.13
|
||||
|
||||
pnpm@10.6.5: {}
|
||||
pnpm@10.27.0: {}
|
||||
|
||||
postcss-cli@11.0.1(postcss@8.5.6)(tsx@4.21.0):
|
||||
dependencies:
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { createViteConfig } from '../../.build/vite.config.helper'
|
||||
import getBanner from '../../shared/banner/index.mjs'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const MINIFY = process.env.MINIFY === 'true'
|
||||
const bannerText = getBanner('Demo')
|
||||
|
||||
// Try .ts first, fallback to .js for gradual migration
|
||||
const entryPath = path.resolve(__dirname, '../js/demo')
|
||||
const entry = existsSync(`${entryPath}.ts`) ? `${entryPath}.ts` : `${entryPath}.js`
|
||||
const entry = `${entryPath}.ts`
|
||||
|
||||
export default createViteConfig({
|
||||
entry: entry,
|
||||
name: 'demo',
|
||||
fileName: () => MINIFY ? 'demo.min.js' : 'demo.js',
|
||||
fileName: () => 'demo.js',
|
||||
formats: ['es'],
|
||||
outDir: path.resolve(__dirname, '../dist/preview/js'),
|
||||
banner: bannerText,
|
||||
minify: MINIFY
|
||||
minify: false
|
||||
})
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
"css-prefix": "postcss --config .build/postcss.config.mjs --replace \"dist/preview/css/*.css\" \"!dist/preview/css/*.rtl*.css\" \"!dist/preview/css/*.min.css\"",
|
||||
"css-minify": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/preview/css/ --batch --batch-suffix \".min\" \"dist/preview/css/*.css\" \"!dist/preview/css/*.min.css\" \"!dist/preview/css/*rtl*.css\"",
|
||||
"js": "pnpm run js-build && pnpm run js-build-min",
|
||||
"js-build": "vite build --config .build/vite.config.ts",
|
||||
"js-build": "vite build --config .build/vite.config.mts",
|
||||
"js-build-min": "pnpm run js-build-min-demo",
|
||||
"js-build-min-demo": "cross-env MINIFY=true vite build --config .build/vite.config.ts",
|
||||
"js-build-min-demo": "terser dist/preview/js/demo.js --module --compress --mangle --comments '/@license|@preserve|^!/' --source-map \"content=dist/preview/js/demo.js.map,filename=dist/preview/js/demo.min.js.map,url=demo.min.js.map\" -o dist/preview/js/demo.min.js",
|
||||
"clean": "shx rm -rf dist demo",
|
||||
"html": "pnpm run html-build && pnpm run html-prettify && pnpm run html-remove-prettier-ignore",
|
||||
"html-build": "eleventy",
|
||||
|
||||
@@ -35,14 +35,6 @@ export function appFilters(eleventyConfig) {
|
||||
.replace(/[\r\n]/g, ' ');
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("strip_trailing_slash", (text) => {
|
||||
return text?.replace(/\/$/, '');
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("strip_leading_slash", (text) => {
|
||||
return text?.replace(/^\//, '');
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("contains", (items, item) => {
|
||||
return items && Array.isArray(items) && items.includes(item);
|
||||
});
|
||||
@@ -152,11 +144,6 @@ export function appFilters(eleventyConfig) {
|
||||
return 0;
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("debug", function (elem) {
|
||||
console.log(elem);
|
||||
return elem;
|
||||
})
|
||||
|
||||
eleventyConfig.addFilter("first", function (elem) {
|
||||
if (elem instanceof Object) {
|
||||
return elem[Object.keys(elem)[0]];
|
||||
|
||||
@@ -1,33 +1,22 @@
|
||||
{% assign menu = collections.docs | collection-tree %}
|
||||
{% assign current-section = page.url | split: '/' | slice: 1, 1 | prepend: '/' | append: '/' %}
|
||||
{% for level1 in menu %}
|
||||
{% if current-section == level1.url %}
|
||||
{% assign current-menu = level1.children %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if current-menu %}
|
||||
<nav class="space-y space-y-5" id="menu">
|
||||
{% for level1 in current-menu %}
|
||||
{% for level1 in menu %}
|
||||
<div>
|
||||
<div class="subheader mb-2">
|
||||
{{ level1.data.title }}
|
||||
</div>
|
||||
{% if level1.children %}
|
||||
<nav class="nav nav-vertical">
|
||||
{% for level2 in level1.children %}
|
||||
<div>
|
||||
<a class="nav-link{% if page.url contains level2.url %} active{% endif %}" {% if level2.children %}
|
||||
href="{{ level2.url }}" data-bs-toggle="collapse" data-bs-target="#collapse-{{ level2.url | slug }}"
|
||||
aria-expanded="{% if page.url contains level2.url %}true{% else %}false{% endif %}" {% endif
|
||||
%}>{{ level2.data.title }}{% if level2.children %} <span class="nav-link-toggle"></span>{% endif %}</a>
|
||||
|
||||
<a class="nav-link{% if page.url contains level2.url %} active{% endif %}"{% if level2.children %} href="{{ level2.url }}" data-bs-toggle="collapse" data-bs-target="#collapse-{{ level2.url | slug }}" aria-expanded="{% if page.url contains level2.url %}true{% else %}false{% endif %}"{% endif %}>{{ level2.data.title }}{% if level2.children %} <span class="nav-link-toggle"></span>{% endif %}</a>
|
||||
|
||||
{% if level2.children %}
|
||||
<nav class="nav nav-vertical collapse{% if page.url contains level2.url %} show{% endif %}"
|
||||
id="collapse-{{ level2.url | slug }}">
|
||||
<nav class="nav nav-vertical collapse{% if page.url contains level2.url %} show{% endif %}" id="collapse-{{ level2.url | slug }}">
|
||||
{% for level3 in level2.children %}
|
||||
<div>
|
||||
<a class="nav-link{% if page.url == level3.url %} active{% endif %}"
|
||||
href="{{ level3.url }}">{{ level3.data.title }}</a>
|
||||
<a class="nav-link{% if page.url == level3.url %} active{% endif %}" href="{{ level3.url }}">{{ level3.data.title }}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</nav>
|
||||
@@ -35,7 +24,7 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
</nav>
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="navbar navbar-expand sticky-top">
|
||||
<div class="container">
|
||||
<div class="row flex-fill align-items-md-center">
|
||||
<div class="col-auto">
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
<a href="{{ page.url | relative }}" class="navbar-brand navbar-brand-autodark gap-4">
|
||||
{% include "docs/logo.html" %}
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-none d-md-block col-3">
|
||||
<div class="d-none d-md-block col">
|
||||
<div id="docsearch"></div>
|
||||
</div>
|
||||
<div class="col d-flex">
|
||||
@@ -46,42 +46,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% assign menu = collections.docs | collection-tree %}
|
||||
<div class="navbar-expand-md">
|
||||
<div class="container">
|
||||
<div class="navbar">
|
||||
<div class="row flex-column flex-md-row flex-fill align-items-center">
|
||||
<div class="col">
|
||||
<nav>
|
||||
<ul class="navbar-nav">
|
||||
{% for level1 in menu %}
|
||||
<li class="nav-item{% if page.url contains level1.url %} active{% endif %}">
|
||||
<a href="{{ level1.url }}" class="nav-link">
|
||||
{% if level1.data.icon %}<span class="nav-link-icon">{% include "ui/icon.html" icon=level1.data.icon %}</span>{% endif %}
|
||||
<span class="nav-link-title">{{ level1.data.menu-title }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<nav>
|
||||
<ul class="navbar-nav">
|
||||
{% for link in docs-links %}
|
||||
<li class="nav-item">
|
||||
<a href="{{ link.url }}" class="nav-link" target="_blank">
|
||||
<span class="nav-link-icon">{% include "ui/icon.html" icon=link.icon %}</span>
|
||||
<span class="nav-link-title">{{ link.title }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,13 +64,12 @@
|
||||
rel="stylesheet" />
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% if docs-libs -%}
|
||||
{% for lib in libs.css -%}
|
||||
{% for lib in libs -%}
|
||||
{% if docs-libs contains lib[0] -%}
|
||||
{% for file in lib[1] -%}
|
||||
{% for file in lib[1].css -%}
|
||||
<link
|
||||
href="{% if file contains 'http://' or file contains 'https://' %}{{ file }}{% else %}{{ page | relative }}/libs/{% if environment != 'development' %}{{ file | replace: '@', '' }}{% else %}{{ file }}{% endif %}{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}{% endif %}"
|
||||
href="{% if file contains 'http://' or file contains 'https://' %}{{ file }}{% else %}/dist/libs/{{ lib[1].npm }}/{% if environment != 'development' %}{{ file | replace: '@', '' }}{% else %}{{ file }}{% endif %}{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}{% endif %}"
|
||||
rel="stylesheet" />
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
@@ -81,7 +80,7 @@
|
||||
<link rel="stylesheet" href="/css/docs{% if environment != 'development' %}.min{% endif %}.css" />
|
||||
</head>
|
||||
|
||||
<body class="d-flex flex-column bg-surface">
|
||||
<body class="d-flex flex-column" style="background: var(--tblr-bg-surface)">
|
||||
<script src="/dist/js/tabler-theme{% if environment != 'development' %}.min{% endif %}.js"></script>
|
||||
<!-- BEGIN NAVBAR -->
|
||||
<header role="banner">
|
||||
@@ -93,8 +92,16 @@
|
||||
<div class="container">
|
||||
<div class="row g-0">
|
||||
<div class="col-docs d-none d-lg-block border-end">
|
||||
<div class="py-4 pe-2">
|
||||
<div class="py-4">
|
||||
<div class="space-y space-y-5">
|
||||
<div class="nav nav-vertical">
|
||||
{% for link in docs-links %}
|
||||
<a href="{{ link.url }}" class="nav-link" target="_blank">
|
||||
<span class="border me-2 rounded p-1">{% include "ui/icon.html" icon=link.icon %}</span>
|
||||
{{ link.title }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="flex-fill">
|
||||
{% include "docs/menu.html" %}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user