diff --git a/docs/pages/components/button.md b/docs/pages/components/button.md index 1d62e9b..b0d2df3 100644 --- a/docs/pages/components/button.md +++ b/docs/pages/components/button.md @@ -12,21 +12,10 @@ Buttons indicate actions the user can trigger on click. Buttons already have a b The default button without any class is already utilizing accent coloring. In addition, you can use `neutral`, `positive` and `negative` classes for the corresponding colors.
-
- -
-
- - .neutral -
-
- - .positive -
-
- - .negative -
+ + + +
```html @@ -36,27 +25,31 @@ The default button without any class is already utilizing accent coloring. In ad ``` +Using the `disabled` attribute deactivates buttons. If you're using `onclick` event handlers, make sure this case is handled. + +
+ + + + +
+ +```html + + + + +``` + ### Secondary button For less important buttons with outline and transparent backgrounds, the `hollow` class can be used. It can be combined with all other button related classes.
-
- - .hollow -
-
- - .hollow.neutral -
-
- - .hollow.positive -
-
- - .hollow.negative -
+ + + +
```html @@ -66,19 +59,29 @@ For less important buttons with outline and transparent backgrounds, the `hollow ``` +The `disabled` attribute can be set on secondary buttons too. + +
+ + + + +
+ +```html + + + + +``` + ### Link button Use the `button` class to apply all button styles on `` tags. That way you can create button links for navigation.
-
- Go shopping - .button -
-
- Go back - .button.neutral -
+ Go shopping + Go back
```html @@ -91,36 +94,54 @@ Use the `button` class to apply all button styles on `` tags. That way you ca Use the `rounded-full` utility class to give buttons a pill form.
-
- - .rounded-full -
-
- - .neutral.rounded-full -
+ + +
```html + ``` ### Ghost button -Use the `ghost` class to keep button sizing without background color or border. +Use the `ghost` class to keep button sizing without background color or border. Works on link buttons too.
-
- - .ghost -
+ + +
GitHub
```html - + + +GitHub ``` +### Busy button + +Use the `busy` class to replace the text of a button with a loader while keeping the button size. Works with secondary buttons, link buttons and pill buttons. Busy buttons are disabled. + +
+ + + + + +
+ +```html + + + + + +``` + + ### Button group Use the `button-group` class on an element containing buttons, to group buttons to a single logical unit. diff --git a/docs/pages/components/loader.md b/docs/pages/components/loader.md new file mode 100644 index 0000000..8a69fed --- /dev/null +++ b/docs/pages/components/loader.md @@ -0,0 +1,76 @@ +--- +title: 'Components: Loader - Sloth.css' +description: Loader component of Sloth.css. +--- + +## Loader + +A loader indicates a busy state, giving visual feedback for users that a process currently takes some time. This reassures the user, that an action got triggered in the first place and is still working or progressing. + +### Loader colors + +Use the `loader` class to add a loading indicator. The loadinng indicator is in accent colors per default. Use the `neutral`, `positive` and `negative` classes to change the color accordingly. + +
+
+
+
+
+
+ +```html +
+
+
+
+``` + +### Loader sizes + +Use the `sm` or `lg` classes to reduce or increase the size of a loader. + +
+
+
+
+
+ +```html +
+
+
+``` + +### Double loader + +Use the `double` class to make the loading animation more emphasized. Double loaders support all colors and sizes too. + +
+
+
+
+
+ +```html +
+
+
+``` + +### Button loader + +Loaders are also supported on button elements. Use the `busy` class to replace the text of a button with a loader while keeping the button size. + +
+ + + + +
+ +```html + + + + +``` diff --git a/eleventy.config.js b/eleventy.config.js index 05f745e..d4f5034 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -31,6 +31,7 @@ module.exports = function(eleventyConfig) { 'breadcrumb', 'button', 'callout', + 'loader', 'separator', 'state', 'toast', diff --git a/src/_components.css b/src/_components.css index c7d4a4a..f8f3060 100644 --- a/src/_components.css +++ b/src/_components.css @@ -5,7 +5,7 @@ @import 'components/_callout.css'; /* @import 'components/_card.css'; */ /* @import 'components/_input.css'; */ -/* @import 'components/_loader.css'; */ +@import 'components/_loader.css'; /* @import 'components/_modal.css'; */ @import 'components/_separator.css'; /* @import 'components/_sequence.css'; */ diff --git a/src/_config.css b/src/_config.css index b68b5bd..b886a9a 100644 --- a/src/_config.css +++ b/src/_config.css @@ -65,5 +65,9 @@ } @keyframes pulse { 50% { box-shadow: 0 0 0 0 var(--color-bg-accent); } - 100% { box-shadow: 0 0 0 .5rem rgba(0, 0, 0, 0); } + 100% { box-shadow: 0 0 0 .5rem rgba(0, 0, 0, 0); } +} +@keyframes rotate { + 0% { transform: rotate(0); } + 100% { transform: rotate(360deg); } } diff --git a/src/components/_button.css b/src/components/_button.css index d5943ac..0943238 100644 --- a/src/components/_button.css +++ b/src/components/_button.css @@ -33,75 +33,79 @@ a.button { background-color: var(--color-negative); } - &:not(:disabled) { - cursor: pointer; - } - &:hover:not(:disabled) { - background-color: var(--color-accent); - &.neutral { - background-color: color-mix(in hsl, var(--color-neutral) 90%, white); - } - &.positive { - background-color: color-mix(in hsl, var(--color-positive) 90%, white); - } - &.negative { - background-color: color-mix(in hsl, var(--color-negative) 90%, white); - } - } - &:focus:not(:disabled), &:focus-within:not(:disabled), &:hover:not(:disabled) { - box-shadow: - color-mix(in hsl, var(--color-accent) 90%, black) var(--shadow-border), - black var(--shadow-float); - &.neutral { + &:not(:disabled):not(.busy):not(.ghost) { + &:hover { + background-color: var(--color-accent); + &.neutral { + background-color: color-mix(in hsl, var(--color-neutral) 90%, white); + } + &.positive { + background-color: color-mix(in hsl, var(--color-positive) 90%, white); + } + &.negative { + background-color: color-mix(in hsl, var(--color-negative) 90%, white); + } + } + &:focus, &:focus-within, &:hover { box-shadow: - color-mix(in hsl, var(--color-neutral) 90%, black) var(--shadow-border), + color-mix(in hsl, var(--color-accent) 90%, black) var(--shadow-border), black var(--shadow-float); - } - &.positive { + &.neutral { + box-shadow: + color-mix(in hsl, var(--color-neutral) 90%, black) var(--shadow-border), + black var(--shadow-float); + } + &.positive { + box-shadow: + color-mix(in hsl, var(--color-positive) 90%, black) var(--shadow-border), + black var(--shadow-float); + } + &.negative { + box-shadow: + color-mix(in hsl, var(--color-negative) 90%, black) var(--shadow-border), + black var(--shadow-float); + } + } + &:active { + outline: 0; box-shadow: - color-mix(in hsl, var(--color-positive) 90%, black) var(--shadow-border), - black var(--shadow-float); - } - &.negative { - box-shadow: - color-mix(in hsl, var(--color-negative) 90%, black) var(--shadow-border), - black var(--shadow-float); + var(--color-bg-accent) var(--shadow-border), + var(--color-bg-accent) var(--shadow-inset); + &.neutral { + box-shadow: + color-mix(in hsl, var(--color-neutral) 80%, black) var(--shadow-border), + color-mix(in hsl, var(--color-neutral) 80%, black) var(--shadow-inset); + } + &.positive { + box-shadow: + color-mix(in hsl, var(--color-positive) 80%, black) var(--shadow-border), + color-mix(in hsl, var(--color-positive) 80%, black) var(--shadow-inset); + } + &.negative { + box-shadow: + color-mix(in hsl, var(--color-negative) 80%, black) var(--shadow-border), + color-mix(in hsl, var(--color-negative) 80%, black) var(--shadow-inset); + } } } - &:focus:not(:disabled), &:focus-within:not(:disabled) { - outline: 4px solid var(--color-outline); - &.neutral { - outline: 4px solid color-mix(in srgb, var(--color-neutral) 35%, transparent); - } - &.positive { - outline: 4px solid color-mix(in srgb, var(--color-positive) 35%, transparent); - } - &.negative { - outline: 4px solid color-mix(in srgb, var(--color-negative) 35%, transparent); - } - } - &:active:not(:disabled) { - outline: 0; - box-shadow: - var(--color-bg-accent) var(--shadow-border), - var(--color-bg-accent) var(--shadow-inset); - &.neutral { - box-shadow: - color-mix(in hsl, var(--color-neutral) 80%, black) var(--shadow-border), - color-mix(in hsl, var(--color-neutral) 80%, black) var(--shadow-inset); - } - &.positive { - box-shadow: - color-mix(in hsl, var(--color-positive) 80%, black) var(--shadow-border), - color-mix(in hsl, var(--color-positive) 80%, black) var(--shadow-inset); - } - &.negative { - box-shadow: - color-mix(in hsl, var(--color-negative) 80%, black) var(--shadow-border), - color-mix(in hsl, var(--color-negative) 80%, black) var(--shadow-inset); + &:not(:disabled):not(.busy) { + cursor: pointer; + + &:focus, &:focus-within { + outline: 4px solid var(--color-outline); + &.neutral { + outline: 4px solid color-mix(in srgb, var(--color-neutral) 35%, transparent); + } + &.positive { + outline: 4px solid color-mix(in srgb, var(--color-positive) 35%, transparent); + } + &.negative { + outline: 4px solid color-mix(in srgb, var(--color-negative) 35%, transparent); + } } } + &.hollow { color: light-dark(var(--color-bg-accent), var(--color-accent)); background-color: color-mix(in srgb, var(--color-accent) 10%, transparent); @@ -143,16 +147,18 @@ a.button { text-underline-offset: 0; transition: var(--transition-color), var(--transition-underline); - &:hover, &:focus, &:focus-within, &:active { - color: var(--color-link-hover); - background-color: transparent; - box-shadow: none; - text-decoration: underline; - text-underline-offset: 15%; + &:not(:disabled):not(.busy) { + &:hover, &:focus, &:focus-within, &:active { + color: var(--color-link-hover); + background-color: transparent; + box-shadow: none; + text-decoration: underline; + text-underline-offset: 15%; + } } } - &:disabled { + &:disabled, &.busy { cursor: not-allowed; opacity: .5; } diff --git a/src/components/_loader.css b/src/components/_loader.css new file mode 100644 index 0000000..2d54745 --- /dev/null +++ b/src/components/_loader.css @@ -0,0 +1,102 @@ +.loader { + position: relative; + height: 2rem; + width: 2rem; + border: .25rem solid color-mix(in srgb, var(--color-accent) 10%, transparent); + border-radius: 9999px; + color: var(--color-accent); + border-top-color: currentColor; + animation: rotate 1s 0s infinite linear normal; + box-sizing: border-box; + + &.neutral { + color: var(--color-neutral); + border-color: var(--color-bg-muted); + border-top-color: currentColor; + } + &.positive { + color: var(--color-positive); + border-color: var(--color-bg-positive); + border-top-color: currentColor; + } + &.negative { + color: var(--color-negative); + border-color: var(--color-bg-negative); + border-top-color: currentColor; + } + + &.sm { + height: 1rem; + width: 1rem; + border-width: .125rem; + } + &.lg { + height: 4rem; + width: 4rem; + border-width: .3125rem; + } + + &.double::after { + content: ''; + position: absolute; + inset: .25rem; + display: block; + border: inherit; + border-radius: inherit; + border-top-color: inherit; + animation: rotate .5s 0s infinite linear reverse; + } + &.double.sm::after { + border: none; + animation: none; + background: currentColor; + } + &.double.lg::after { + inset: .5rem; + } +} + +input[type="submit"], +input[type="button"], +input[type="reset"], +button, +a.button { + &.busy { + color: transparent; + position: relative; + + &::before { + content: ''; + position: absolute; + display: block; + height: 1.5rem; + width: 1.5rem; + top: calc(50% - .75rem); + left: calc(50% - .75rem); + border: .25rem solid #ffffff88; + border-radius: 9999px; + border-top-color: transparent; + animation: rotate 1s 0s infinite linear normal; + box-sizing: border-box; + } + + &.hollow { + &, &:hover { + color: transparent; + } + + &.neutral::before { + border-color: var(--color-neutral); + border-top-color: transparent; + } + &.positive::before { + border-color: var(--color-positive); + border-top-color: transparent; + } + &.negative::before { + border-color: var(--color-negative); + border-top-color: transparent; + } + } + } +} diff --git a/src/core/_form.css b/src/core/_form.css index 2459f11..abc71ca 100644 --- a/src/core/_form.css +++ b/src/core/_form.css @@ -207,43 +207,44 @@ input[type="reset"], button { appearance: none; background-color: var(--color-bg-accent); + border-radius: .25rem; border: 0; + box-shadow: black var(--shadow-float); + box-sizing: border-box; color: white; display: inline-block; + font-family: inherit; + font-size: .875rem; + padding: .75rem 1rem; text-align: center; text-decoration: none; - user-select: none; - white-space: nowrap; - border-radius: .25rem; - padding: .75rem 1rem; - font-size: .875rem; - box-shadow: black var(--shadow-float); - font-family: inherit; - box-sizing: border-box; transition: var(--transition-outline), var(--transition-color), var(--transition-transform); + user-select: none; + white-space: nowrap; - &:not(:disabled) { + &:not(:disabled):not(.busy) { cursor: pointer; - } - &:hover:not(:disabled) { - background-color: var(--color-accent); - } - &:focus:not(:disabled), &:focus-within:not(:disabled), &:hover:not(:disabled) { - box-shadow: - color-mix(in hsl, var(--color-accent) 90%, black) var(--shadow-border), - black var(--shadow-float); - } - &:focus:not(:disabled), &:focus-within:not(:disabled) { - outline: 4px solid var(--color-outline); - } - &:active:not(:disabled) { - outline: 0; - box-shadow: - var(--color-bg-accent) var(--shadow-border), - var(--color-bg-accent) var(--shadow-inset); + + &:hover { + background-color: var(--color-accent); + } + &:focus, &:focus-within, &:hover { + box-shadow: + color-mix(in hsl, var(--color-accent) 90%, black) var(--shadow-border), + black var(--shadow-float); + } + &:focus, &:focus-within { + outline: 4px solid var(--color-outline); + } + &:active { + outline: 0; + box-shadow: + var(--color-bg-accent) var(--shadow-border), + var(--color-bg-accent) var(--shadow-inset); + } } &:disabled { cursor: not-allowed;