mirror of
https://github.com/tabler/tabler.git
synced 2026-10-13 21:57:00 +04:00
Add .btn-outline-gradient buttons and use one for the All Package navbar link
- `$gradients` map shared by `.card-gradient-*` and `.btn-outline-gradient-*` - All Package link also renders on the local dev server
This commit is contained in:
1 parent
9cebb7a185
commit
0eea8b7e2b
11 files changed
+216
-39
No files matched your search
@@ -30,6 +30,7 @@ const TOKENS = [
|
||||
{ name: 'aspectRatios', type: 'AspectRatio', module: 'v', variable: '$aspect-ratios', kind: 'map', source: 'core/scss/_variables.scss' },
|
||||
{ name: 'breakpoints', type: 'Breakpoint', module: 's', variable: '$grid-breakpoints', kind: 'map', source: 'core/scss/_settings.scss' },
|
||||
{ name: 'breadcrumbVariants', type: 'BreadcrumbVariant', module: 'v', variable: '$breadcrumb-variants', kind: 'map', source: 'core/scss/_variables.scss' },
|
||||
{ name: 'gradients', type: 'Gradient', module: 'v', variable: '$gradients', kind: 'map', source: 'core/scss/_variables.scss' },
|
||||
{ name: 'formValidationStates', type: 'FormValidationState', module: 'v', variable: '$form-validation-states', kind: 'map', source: 'core/scss/_variables.scss' },
|
||||
{ name: 'paymentProviders', type: 'PaymentProvider', module: 'v', variable: '$payment-providers', kind: 'list', source: 'core/scss/_variables.scss' },
|
||||
{ name: 'flagCountries', type: 'FlagCountry', module: 'v', variable: '$flag-countries', kind: 'list', source: 'core/scss/_variables.scss' },
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@tabler/core": minor
|
||||
"@tabler/preview": minor
|
||||
"@tabler/docs": minor
|
||||
---
|
||||
|
||||
Added `.btn-outline-gradient` buttons with a gradient border, using the named gradients shared with `.card-gradient`.
|
||||
@@ -1207,6 +1207,63 @@ $otp-slot-box-shadow: var(--shadow-input) !default;
|
||||
$otp-separator-color: var(--secondary) !default;
|
||||
// scss-docs-end otp-variables
|
||||
|
||||
// Gradients
|
||||
// Multi-color presets shared by `.card-gradient-*` and `.btn-outline-gradient-*`.
|
||||
// Each value is a comma-separated list of color stops.
|
||||
// scss-docs-start gradients
|
||||
$gradients: (
|
||||
'rainbow': (
|
||||
#78c5d6,
|
||||
#459ba8,
|
||||
#79c267,
|
||||
#c5d647,
|
||||
#f5d63d,
|
||||
#f08b33,
|
||||
#e868a2,
|
||||
#be61a5,
|
||||
),
|
||||
'sun': (
|
||||
#fd1d1d,
|
||||
#fcb045,
|
||||
),
|
||||
'snow': (
|
||||
#333,
|
||||
#e9ecef,
|
||||
),
|
||||
'ocean': (
|
||||
#1cb5e0,
|
||||
#000851,
|
||||
),
|
||||
'mellow': (
|
||||
#f8ff00,
|
||||
#3ad59f,
|
||||
),
|
||||
'disco': (
|
||||
#fc466b,
|
||||
#3f5efb,
|
||||
),
|
||||
'psychedelic': (
|
||||
#fcc5e4,
|
||||
#fda34b,
|
||||
#ff7882,
|
||||
#c8699e,
|
||||
#7046aa,
|
||||
#0c1db8,
|
||||
#020f75,
|
||||
),
|
||||
'love': (
|
||||
#f235e6,
|
||||
#bc0707,
|
||||
),
|
||||
'gold': (
|
||||
#9d4100,
|
||||
#bf7122,
|
||||
#f59f00,
|
||||
#ffd700,
|
||||
),
|
||||
) !default;
|
||||
// scss-docs-end gradients
|
||||
|
||||
// Cards
|
||||
// scss-docs-start card-variables
|
||||
$card-spacer-y: 1.25rem !default;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// `.btn-outline-gradient-*` presets share one selector list with the base
|
||||
// class, so a preset works without `.btn-outline-gradient` next to it. The
|
||||
// stops come from the shared `$gradients` map, so a card and a button with the
|
||||
// same name show the same gradient.
|
||||
@use 'sass:list';
|
||||
@use 'sass:map';
|
||||
@use '../config' as *;
|
||||
@use '../ui/buttons' as buttons;
|
||||
|
||||
@include describe('btn-outline-gradient') {
|
||||
@include it('shares the named gradient stops with .card-gradient') {
|
||||
@include assert-equal(map.get($gradients, 'sun'), (#fd1d1d, #fcb045));
|
||||
@include assert-true(map.has-key($gradients, 'rainbow'));
|
||||
}
|
||||
|
||||
@include it('lists the base class and every color and gradient preset') {
|
||||
$selectors: buttons.btn-gradient-selectors();
|
||||
@include assert-equal(list.nth($selectors, 1), '.btn-outline-gradient');
|
||||
@include assert-true(list.index($selectors, '.btn-outline-gradient-primary') != null);
|
||||
@include assert-true(list.index($selectors, '.btn-outline-gradient-rainbow') != null);
|
||||
@include assert-equal(list.length($selectors), 1 + list.length(map.keys($theme-colors)) + list.length(map.keys($gradients)));
|
||||
}
|
||||
}
|
||||
@@ -175,6 +175,66 @@ $btn-colors: map.keys(map.merge($theme-colors, $social-colors));
|
||||
--btn-box-shadow: none;
|
||||
}
|
||||
|
||||
// Gradient ring: a surface-colored layer clipped to the padding box sits on a
|
||||
// gradient layer that fills the border box, so only the border shows the
|
||||
// gradient — the same trick as `.card-gradient`. Presets share the `.btn-outline-gradient`
|
||||
// base through one selector list, so a preset class works on its own.
|
||||
$btn-gradient-names: list.join(map.keys($theme-colors), map.keys($gradients));
|
||||
|
||||
@function btn-gradient-selectors() {
|
||||
$selectors: '.btn-outline-gradient';
|
||||
@each $name in $btn-gradient-names {
|
||||
$selectors: list.append($selectors, '.btn-outline-gradient-#{$name}', $separator: comma);
|
||||
}
|
||||
@return $selectors;
|
||||
}
|
||||
|
||||
$btn-gradient-selectors: btn-gradient-selectors();
|
||||
|
||||
#{$btn-gradient-selectors} {
|
||||
// scss-docs-start btn-gradient-css-vars
|
||||
--btn-gradient: var(--primary), var(--primary);
|
||||
--btn-gradient-direction: 135deg;
|
||||
// scss-docs-end btn-gradient-css-vars
|
||||
--btn-border-color: transparent;
|
||||
--btn-hover-border-color: transparent;
|
||||
--btn-active-border-color: transparent;
|
||||
--btn-disabled-border-color: transparent;
|
||||
--btn-box-shadow: none;
|
||||
// The hover and active fills are translucent tints, so a solid surface layer
|
||||
// sits under them — otherwise the gradient would bleed through on hover.
|
||||
background:
|
||||
linear-gradient(var(--btn-bg), var(--btn-bg)) padding-box,
|
||||
linear-gradient(var(--bg-surface), var(--bg-surface)) padding-box,
|
||||
linear-gradient(var(--btn-gradient-direction), var(--btn-gradient)) border-box;
|
||||
}
|
||||
|
||||
// `.btn:hover` only sets `background-color`, which sits under the two opaque
|
||||
// image layers, so the hover and active fills go through the token instead.
|
||||
// `:is()` keeps the state rules to one selector list each.
|
||||
:is(#{$btn-gradient-selectors}):hover,
|
||||
.btn-check + :is(#{$btn-gradient-selectors}):hover {
|
||||
--btn-bg: var(--btn-hover-bg);
|
||||
}
|
||||
|
||||
:is(#{$btn-gradient-selectors}):active,
|
||||
:is(#{$btn-gradient-selectors}).active,
|
||||
.btn-check:checked + :is(#{$btn-gradient-selectors}) {
|
||||
--btn-bg: var(--btn-active-bg);
|
||||
}
|
||||
|
||||
@each $color in map.keys($theme-colors) {
|
||||
.btn-outline-gradient-#{$color} {
|
||||
--btn-gradient: var(--#{$color}), var(--#{$color}-darken);
|
||||
}
|
||||
}
|
||||
|
||||
@each $name, $stops in $gradients {
|
||||
.btn-outline-gradient-#{$name} {
|
||||
--btn-gradient: #{$stops};
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Button sizes
|
||||
//
|
||||
|
||||
@@ -734,40 +734,10 @@ Card gradient
|
||||
}
|
||||
}
|
||||
|
||||
.card-gradient-rainbow {
|
||||
--card-gradient: #78c5d6, #459ba8, #79c267, #c5d647, #f5d63d, #f08b33, #e868a2, #be61a5;
|
||||
}
|
||||
|
||||
.card-gradient-sun {
|
||||
--card-gradient: #fd1d1d, #fcb045;
|
||||
}
|
||||
|
||||
.card-gradient-snow {
|
||||
--card-gradient: #333, #e9ecef;
|
||||
}
|
||||
|
||||
.card-gradient-ocean {
|
||||
--card-gradient: #1cb5e0, #000851;
|
||||
}
|
||||
|
||||
.card-gradient-mellow {
|
||||
--card-gradient: #f8ff00, #3ad59f;
|
||||
}
|
||||
|
||||
.card-gradient-disco {
|
||||
--card-gradient: #fc466b, #3f5efb;
|
||||
}
|
||||
|
||||
.card-gradient-psychedelic {
|
||||
--card-gradient: #fcc5e4, #fda34b, #ff7882, #c8699e, #7046aa, #0c1db8, #020f75;
|
||||
}
|
||||
|
||||
.card-gradient-love {
|
||||
--card-gradient: #f235e6, #bc0707;
|
||||
}
|
||||
|
||||
.card-gradient-gold {
|
||||
--card-gradient: #9d4100, #bf7122, #f59f00, #ffd700;
|
||||
@each $name, $stops in $gradients {
|
||||
.card-gradient-#{$name} {
|
||||
--card-gradient: #{$stops};
|
||||
}
|
||||
}
|
||||
|
||||
.card-gradient-animated {
|
||||
|
||||
@@ -25,6 +25,8 @@ classnames:
|
||||
style:
|
||||
- class: btn-outline
|
||||
desc: Transparent fill with a colored border
|
||||
- class: btn-outline-gradient
|
||||
desc: Gradient ring on the border; btn-outline-gradient-{color} and the named gradients change the colors
|
||||
- class: btn-ghost
|
||||
desc: No fill and no border until hovered
|
||||
- class: btn-link
|
||||
@@ -187,6 +189,30 @@ The `.btn-outline-*` classes keep the color on the border and the text and leave
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Outline gradient buttons
|
||||
|
||||
`.btn-outline-gradient` keeps the fill empty, like an outline button, but draws the border as a gradient. Add a theme color, such as `.btn-outline-gradient-purple`, or one of the named gradients shared with [card gradients](/ui/components/card-gradient). The fill still follows the theme, so the ring works in dark mode without extra classes.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-outline-gradient">Default</a>
|
||||
<a href="#" class="btn btn-outline-gradient-purple">Purple</a>
|
||||
<a href="#" class="btn btn-outline-gradient-rainbow">Rainbow</a>
|
||||
<a href="#" class="btn btn-outline-gradient-sun">Sun</a>
|
||||
<a href="#" class="btn btn-outline-gradient-ocean">Ocean</a>
|
||||
<a href="#" class="btn btn-outline-gradient-disco">Disco</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
Set `--tblr-btn-gradient` on the button to use your own color stops, and `--tblr-btn-gradient-direction` to change the angle.
|
||||
|
||||
<Example centered>
|
||||
<div class="btn-list">
|
||||
<a href="#" class="btn btn-outline-gradient" style="--tblr-btn-gradient: #066fd1, #ae3ec9, #f76707">Custom stops</a>
|
||||
<a href="#" class="btn btn-outline-gradient-rainbow" style="--tblr-btn-gradient-direction: 90deg">Left to right</a>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
## Button sizes
|
||||
|
||||
Add `.btn-sm`, `.btn-lg` or `.btn-xl` to change the size. A larger button draws the eye to the main action, and a smaller one fits into toolbars and table rows.
|
||||
|
||||
@@ -29,7 +29,7 @@ classnames:
|
||||
---
|
||||
|
||||
import Example from '@components/Example.astro'
|
||||
export const gradients = ['rainbow', 'sun', 'snow', 'ocean', 'mellow', 'disco', 'psychedelic', 'love', 'gold']
|
||||
import { gradients } from '@shared/lib/tokens'
|
||||
|
||||
## Default markup
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import CardBody from '@ui/CardBody.astro'
|
||||
import CardTitle from '@ui/CardTitle.astro'
|
||||
import CardSubtitle from '@ui/CardSubtitle.astro'
|
||||
import site from '@data/site.json'
|
||||
import { gradients } from '@shared/lib/tokens'
|
||||
import DocsLink from '@ui/DocsLink.astro'
|
||||
|
||||
type ColorEntry = [string, { title: string; icon?: string }]
|
||||
@@ -170,6 +171,33 @@ const sizes = ['sm', 'md', 'lg', 'xl'] as const
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<Card>
|
||||
<CardBody>
|
||||
<CardTitle>Outline gradient</CardTitle>
|
||||
<CardSubtitle>Only the border carries the gradient. Use a theme color or one of the named gradients shared with <code>.card-gradient</code>.</CardSubtitle>
|
||||
<ButtonList>
|
||||
<button type="button" class="btn btn-outline-gradient">Default</button>
|
||||
{
|
||||
themeColors.slice(0, 6).map(([name, color]) => (
|
||||
<button type="button" class={`btn btn-outline-gradient-${name}`}>
|
||||
{color.icon && <Icon name={color.icon} />} {color.title}
|
||||
</button>
|
||||
))
|
||||
}
|
||||
</ButtonList>
|
||||
<ButtonList class="mt-3">
|
||||
{
|
||||
gradients.map((name) => (
|
||||
<button type="button" class={`btn btn-outline-gradient-${name}`}>
|
||||
{ucFirst(name)}
|
||||
</button>
|
||||
))
|
||||
}
|
||||
</ButtonList>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<Card>
|
||||
<CardBody>
|
||||
|
||||
@@ -40,18 +40,19 @@ const {
|
||||
} = Astro.props
|
||||
|
||||
// The All Package link is an ad for tabler.io, so it only renders on the hosted demo
|
||||
// (Vercel deploys), never in local builds or the packaged template (VERCEL_ENV is unset there).
|
||||
const isVercelDeploy = !!process.env.VERCEL_ENV
|
||||
// (Vercel deploys) and on the local dev server, never in a local build or the
|
||||
// packaged template (VERCEL_ENV is unset and DEV is false there).
|
||||
const showAllPackage = !!process.env.VERCEL_ENV || import.meta.env.DEV
|
||||
const allPackageUrl = 'https://tabler.io/pricing?ref=tabler-preview-navbar#bundle'
|
||||
---
|
||||
|
||||
<!-- BEGIN NAVBAR ACTIONS -->
|
||||
<div class:list={['navbar-nav flex-row', className]}>
|
||||
{
|
||||
!condensed && isVercelDeploy && (
|
||||
!condensed && showAllPackage && (
|
||||
<div class={`nav-item d-none d-${breakpoint}-flex me-3`}>
|
||||
<ButtonList>
|
||||
<Button icon="package" iconColor="blue" text="All Package" href={allPackageUrl} external />
|
||||
<Button icon="package" iconColor="purple" variant="outline" color="gradient-rainbow" text="All Package" href={allPackageUrl} external />
|
||||
</ButtonList>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -33,6 +33,10 @@ export type Breakpoint = (typeof breakpoints)[number]
|
||||
export const breadcrumbVariants = ['dots', 'arrows', 'bullets'] as const
|
||||
export type BreadcrumbVariant = (typeof breadcrumbVariants)[number]
|
||||
|
||||
/** Keys of `$gradients` (core/scss/_variables.scss). */
|
||||
export const gradients = ['rainbow', 'sun', 'snow', 'ocean', 'mellow', 'disco', 'psychedelic', 'love', 'gold'] as const
|
||||
export type Gradient = (typeof gradients)[number]
|
||||
|
||||
/** Keys of `$form-validation-states` (core/scss/_variables.scss). */
|
||||
export const formValidationStates = ['valid', 'invalid'] as const
|
||||
export type FormValidationState = (typeof formValidationStates)[number]
|
||||
|
||||
Reference in new issue
Block a user