Last active
September 16, 2024 14:38
-
-
Save lukaskleinschmidt/f4c10d15d013fec8f8b8a341d9ade859 to your computer and use it in GitHub Desktop.
Utility class generator like tailwindcss but in pure Sass.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@use 'sass:map'; | |
@use 'variants' as * with ( | |
$breakpoints: ( | |
'small': 640px, | |
'medium': 768px, | |
'large': 1024px, | |
'wide': 1280px, | |
) | |
); | |
// ASCII Art Generator | |
// http://www.patorjk.com/software/taag/#p=display&v=0&f=ANSI%20Shadow&t=variant | |
// ██████╗ █████╗ ███╗ ██╗ █████╗ ███╗ ██╗ █████╗ | |
// ██╔══██╗██╔══██╗████╗ ██║██╔══██╗████╗ ██║██╔══██╗ | |
// ██████╔╝███████║██╔██╗ ██║███████║██╔██╗ ██║███████║ | |
// ██╔══██╗██╔══██║██║╚██╗██║██╔══██║██║╚██╗██║██╔══██║ | |
// ██████╔╝██║ ██║██║ ╚████║██║ ██║██║ ╚████║██║ ██║ | |
// ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝ | |
.banana { | |
@include variants('responsive' 'hover' 'group-hover') { | |
color: #FFE135; | |
} | |
} | |
// ████████╗███████╗██╗ ██╗████████╗ | |
// ╚══██╔══╝██╔════╝╚██╗██╔╝╚══██╔══╝ | |
// ██║ █████╗ ╚███╔╝ ██║ | |
// ██║ ██╔══╝ ██╔██╗ ██║ | |
// ██║ ███████╗██╔╝ ██╗ ██║ | |
// ╚═╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ | |
$text: ( | |
'left': left, | |
'right': right, | |
'center': center, | |
'justify': justify, | |
); | |
.text { | |
@include options($text, 'responsive') using ($value) { | |
text-align: $value; | |
} | |
} | |
// ███████╗██████╗ █████╗ ██████╗██╗███╗ ██╗ ██████╗ | |
// ██╔════╝██╔══██╗██╔══██╗██╔════╝██║████╗ ██║██╔════╝ | |
// ███████╗██████╔╝███████║██║ ██║██╔██╗ ██║██║ ███╗ | |
// ╚════██║██╔═══╝ ██╔══██║██║ ██║██║╚██╗██║██║ ██║ | |
// ███████║██║ ██║ ██║╚██████╗██║██║ ╚████║╚██████╔╝ | |
// ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ | |
$spacing: ( | |
'px': 1px, | |
'0': 0, | |
'1': .25rem, | |
'2': .5rem, | |
'3': .75rem, | |
'4': 1rem, | |
'5': 1.25rem, | |
'6': 1.5rem, | |
'8': 2rem, | |
'10': 2.5rem, | |
'12': 3rem, | |
'16': 4rem, | |
'20': 5rem, | |
'24': 6rem, | |
'32': 8rem, | |
'40': 10rem, | |
'48': 12rem, | |
'56': 14rem, | |
'64': 16rem, | |
); | |
// Add auto to the positive margin classes | |
$margin: map.merge(( | |
'auto': auto | |
), $spacing); | |
@include variants('responsive') using ($props...) { | |
// ██████╗ █████╗ ██████╗ ██████╗ ██╗███╗ ██╗ ██████╗ | |
// ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██║████╗ ██║██╔════╝ | |
// ██████╔╝███████║██║ ██║██║ ██║██║██╔██╗ ██║██║ ███╗ | |
// ██╔═══╝ ██╔══██║██║ ██║██║ ██║██║██║╚██╗██║██║ ██║ | |
// ██║ ██║ ██║██████╔╝██████╔╝██║██║ ╚████║╚██████╔╝ | |
// ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ | |
.p { | |
@include options($spacing, $props...) using ($value) { | |
padding: $value; | |
} | |
} | |
.px { | |
@include options($spacing, $props...) using ($value) { | |
padding-right: $value; | |
padding-left: $value; | |
} | |
} | |
.py { | |
@include options($spacing, $props...) using ($value) { | |
padding-bottom: $value; | |
padding-top: $value; | |
} | |
} | |
.pt { | |
@include options($spacing, $props...) using ($value) { | |
padding-top: $value; | |
} | |
} | |
.pr { | |
@include options($spacing, $props...) using ($value) { | |
padding-right: $value; | |
} | |
} | |
.pb { | |
@include options($spacing, $props...) using ($value) { | |
padding-bottom: $value; | |
} | |
} | |
.pl { | |
@include options($spacing, $props...) using ($value) { | |
padding-left: $value; | |
} | |
} | |
// ███╗ ███╗ █████╗ ██████╗ ██████╗ ██╗███╗ ██╗ | |
// ████╗ ████║██╔══██╗██╔══██╗██╔════╝ ██║████╗ ██║ | |
// ██╔████╔██║███████║██████╔╝██║ ███╗██║██╔██╗ ██║ | |
// ██║╚██╔╝██║██╔══██║██╔══██╗██║ ██║██║██║╚██╗██║ | |
// ██║ ╚═╝ ██║██║ ██║██║ ██║╚██████╔╝██║██║ ╚████║ | |
// ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ | |
.m { | |
@include options($margin, $props...) using ($value) { | |
margin: $value; | |
} | |
} | |
.mx { | |
@include options($margin, $props...) using ($value) { | |
margin-right: $value; | |
margin-left: $value; | |
} | |
} | |
.my { | |
@include options($margin, $props...) using ($value) { | |
margin-bottom: $value; | |
margin-top: $value; | |
} | |
} | |
.mt { | |
@include options($margin, $props...) using ($value) { | |
margin-top: $value; | |
} | |
} | |
.mr { | |
@include options($margin, $props...) using ($value) { | |
margin-right: $value; | |
} | |
} | |
.mb { | |
@include options($margin, $props...) using ($value) { | |
margin-bottom: $value; | |
} | |
} | |
.ml { | |
@include options($margin, $props...) using ($value) { | |
margin-left: $value; | |
} | |
} | |
// ███╗ ███╗ █████╗ ██████╗ ██████╗ ██╗███╗ ██╗ | |
// ████╗ ████║██╔══██╗██╔══██╗██╔════╝ ██║████╗ ██║ | |
// █████╗██╔████╔██║███████║██████╔╝██║ ███╗██║██╔██╗ ██║ | |
// ╚════╝██║╚██╔╝██║██╔══██║██╔══██╗██║ ██║██║██║╚██╗██║ | |
// ██║ ╚═╝ ██║██║ ██║██║ ██║╚██████╔╝██║██║ ╚████║ | |
// ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ | |
.-m { | |
@include options($spacing, $props...) using ($value) { | |
margin: -$value; | |
} | |
} | |
.-mx { | |
@include options($spacing, $props...) using ($value) { | |
margin-right: -$value; | |
margin-left: -$value; | |
} | |
} | |
.-my { | |
@include options($spacing, $props...) using ($value) { | |
margin-bottom: -$value; | |
margin-top: -$value; | |
} | |
} | |
.-mt { | |
@include options($spacing, $props...) using ($value) { | |
margin-top: -$value; | |
} | |
} | |
.-mr { | |
@include options($spacing, $props...) using ($value) { | |
margin-right: -$value; | |
} | |
} | |
.-mb { | |
@include options($spacing, $props...) using ($value) { | |
margin-bottom: -$value; | |
} | |
} | |
.-ml { | |
@include options($spacing, $props...) using ($value) { | |
margin-left: -$value; | |
} | |
} | |
} | |
// ██╗ █████╗ ██╗ ██╗ ██████╗ ██╗ ██╗████████╗ | |
// ██║ ██╔══██╗╚██╗ ██╔╝██╔═══██╗██║ ██║╚══██╔══╝ | |
// ██║ ███████║ ╚████╔╝ ██║ ██║██║ ██║ ██║ | |
// ██║ ██╔══██║ ╚██╔╝ ██║ ██║██║ ██║ ██║ | |
// ███████╗██║ ██║ ██║ ╚██████╔╝╚██████╔╝ ██║ | |
// ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ | |
$display: ( | |
'block': block, | |
'inline-block': inline-block, | |
'inline': inline, | |
'flex': flex, | |
'inline-flex': inline-flex, | |
'grid': grid, | |
'inline-grid': inline-grid, | |
'hidden': none, | |
) !default; | |
@include options($display, 'responsive') using ($value) { | |
display: $value; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@use 'sass:list' | |
@use 'sass:meta' | |
@use 'sass:selector' | |
@use 'sass:string' | |
/// List of available breakpoints. | |
/// | |
/// @type Map | |
$breakpoints: () !default | |
/// The position of the breakpoint to the selector. | |
/// | |
/// @type String | |
$breakpoint-position: 'before' !default | |
/// The string used to attach breakpoints. | |
/// | |
/// @type String | |
$breakpoint-glue: '\\:' !default | |
/// The position of the variant to the selector. | |
/// | |
/// @type String | |
$variant-position: 'before' !default | |
/// The string used to attach variants. | |
/// | |
/// @type String | |
$variant-glue: '\\:' !default | |
/// The string used to attach options. | |
/// | |
/// @type String | |
$option-glue: '-' !default | |
/// Unset a given value from a list. | |
/// | |
/// @param {List} $list - The string that will be trimmed. | |
/// @param {String} $value - Value that you want to be removed. | |
/// @return {List} Returns the filtered list. | |
@function _remove($list, $value) | |
$result: () | |
@for $i from 1 through list.length($list) | |
@if list.nth($list, $i) != $value | |
$result: list.append($result, list.nth($list, $i)) | |
@return $result | |
/// Generates the selector depending on the current variant and breakpoint. | |
/// | |
/// @param {String} $variant [null] | |
/// @param {String} $breakpoint [null] | |
/// @return {List} Returns the updated selector. | |
@function _selector($variant: null, $breakpoint: null) | |
$selectors: () | |
@each $selector in & | |
$selector: list.nth($selector, 1) | |
@if meta.type-of($selector) == 'string' | |
$selector: string.slice($selector, 2) | |
// Add the variant to the current selector | |
@if $variant | |
@if $variant-position == 'after' | |
$selector: '#{$selector}#{$variant-glue}#{$variant}' | |
@else | |
$selector: '#{$variant}#{$variant-glue}#{$selector}' | |
// Add the breakpoint to the current selector | |
@if $breakpoint | |
@if $breakpoint-position == 'after' | |
$selector: '#{$selector}#{$breakpoint-glue}#{$breakpoint}' | |
@else | |
$selector: '#{$breakpoint}#{$breakpoint-glue}#{$selector}' | |
// Convert back to a class | |
@if $selector | |
$selectors: list.append($selectors, '.#{$selector}', comma) | |
@return $selectors | |
/// Appends a pseudo-class to a selector. | |
/// | |
/// @param {String} $selector | |
/// @param {String} $pseudo-class [null] | |
/// @return {String} Returns the updated selector. | |
@function _pseudo-class($selector, $pseudo-class: null) | |
@if $pseudo-class | |
$selector: selector.nest($selector, '&:#{$pseudo-class}') | |
@return $selector | |
/// Generates the css for a variant and breakpoint. | |
/// | |
/// @param {String} $variant | |
/// @param {String} $breakpoint | |
@mixin _variant($variant, $breakpoint) | |
$pseudo-class: $variant | |
$group: null | |
// Handle group variants | |
@if meta.type-of($variant) == 'string' and string.index($variant, 'group-') | |
$pseudo-class: string.slice($pseudo-class, 7) | |
$group: '.group' | |
// Get the selector depending on the current variant and breakpoint | |
$selector: _selector($variant, $breakpoint) | |
@if $group | |
#{_pseudo-class($group, $pseudo-class)} | |
#{$selector} | |
@content | |
@else | |
#{_pseudo-class($selector, $pseudo-class)} | |
@content | |
/// Distributes the input to the correct output. | |
/// | |
/// @param {List} $variants | |
/// @param {String} $breakpoint | |
@mixin _io($variants, $breakpoint) | |
@if & | |
@include _variant(null, $breakpoint) | |
@content | |
@each $variant in $variants | |
@include _variant($variant, $breakpoint) | |
@content | |
@else | |
@content($variants, $breakpoint) | |
/// Generates the css for the given variants. | |
/// | |
/// @param {List} $variants [()] | |
/// @param {String} $breakpoint [null] | |
@mixin variants($variants: (), $breakpoint: null) | |
// Check for the responsive variant | |
$responsive: list.index($variants, 'responsive') | |
@if $responsive | |
$variants: _remove($variants, 'responsive') | |
@at-root | |
@include _io($variants, $breakpoint) using ($data...) | |
@content($data...) | |
@if $responsive | |
@each $breakpoint, $value in $breakpoints | |
@media screen and (min-width: #{$value}) | |
@include _io($variants, $breakpoint) using ($data...) | |
@content($data...) | |
/// Responsive alias. | |
/// | |
/// @see {Mixin} variants | |
/// @param {List} $variants [()] | |
@mixin responsive($variants: ()) | |
// Make responsive by default | |
$variants: list.append($variants, 'responsive', space) | |
@include variants($variants) using ($data...) | |
@content($data...) | |
/// Helper for creating option based modifiers or classes. | |
/// | |
/// @param {Map} $options | |
/// @param {List} $variants [()] | |
/// @param {List} $breakpoint [null] | |
@mixin options($options, $variants: (), $breakpoint: null) | |
@if & | |
// Render options as a class modifier | |
@each $key, $value in $options | |
&#{$option-glue}#{$key} | |
@include variants($variants, $breakpoint) | |
@content($value) | |
@else | |
// Render options as seperate classes | |
@include variants($variants, $breakpoint) using ($props...) | |
@each $key, $value in $options | |
.#{$key} | |
@include variants($props...) | |
@content($value) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The url is 404