Exporting Styles to JSON
While many UX patterns will be rendered as HTML components, there are several abstract style patterns – like color-palettes and font-specimens – that never appear as components in the application.
Herman provides several annotations
to help visualize these abstract patterns,
but they require access to the raw Sass data.
We do that using Sass maps
(key:value
object variables)
and the export
mixin
to generate JSON out of Sass variables.
See the sass.jsonFile
configuration
to ensure that Herman has access
to your exported Sass data.
Example
@use 'utilities';
utilities.$herman: (
'colors': (
'brand-colors': (
'brand-orange': #c75000,
'brand-blue': #0d7fa5,
),
),
);
@include utilities.export(utilities.$herman);
/*! json-encode: {"colors": {"brand-colors": {"brand-orange": "#c75000", "brand-blue": "#0d7fa5"}}} */
Related
@mixin export()
$herman
$herman: () !default;
Use the $herman
map variable to collect and organize
color, font, size, and ratio values for export.
The $herman
map should be structured
with top-level keys for each type of data,
and nested maps of the individual items to preview.
Use the add
mixin to automatically populate
fonts, colors, sizes, and ratios from existing maps –
or construct your $herman
map by hand,
following these guidelines…
Map structure
Each type of preview value should be nested under a key that describes what type of data is being stored:
$herman: (
'colors': (
/* color maps */
),
'sizes': (
/* size maps */
),
'ratios': (
/* ratio maps */
),
'fonts': (
/* font maps */
),
);
Colors
Each color has an access name and value.
The key will be used to identify the correct data
for a given color-palette,
and the data includes color name:value
pairs,
both in string format.
'brand-colors': (
'brand-orange': #c75000,
'brand-blue': #0d7fa5,
)
Color values can be in any valid web-color format – hex, hsl/a, rgba/a, etc.
Sizes & Ratios
Size and ratio data is similar to colors,
organized into top-level groups that may contain
one or more name:value
pairs:
'font-ratios': (
'line-height': 1.4,
'minor-seventh': 16/9,
),
'text-sizes': (
'root': 18px,
'large': calc(1rem + 1.5vw),
)
Ratio values can be in any valid number, and size values should be valid CSS lengths.
Fonts
Each font should have a top-level key of its own, since font-previews display a single font at a time. The data map accepts:
name
: how the font should be referenced in CSS (if omitted, defaults to top-level key)stack
: optional string or list of font-stack fallbackssource
: link to more information on the font, or typekit/googlefonts as usefulformats
: font format (or space-separated list of font formats) for locally-hosted fonts – valid format options arettf
,otf
,woff
,woff2
,svg
,svgz
, andeot
<variant>
: describe any number of relative paths to locally-hosted font-files, or embeddeddata:...
font strings per variant (e.g.normal
,bold italic
, etc.). Multi-word variants can be space-separated or comma-separated (e.g.bold italic
orbold, italic
orbold,italic
), and non-standard variants are also accepted (e.g.extra-bold
,thin
,light
, etc.). Optionally, the value can also be a nested object with the following variant-specific keys:path
: variant-specific relative path to locally-hosted font-fileslocal
: font name (or space-separated list of font names) used to look for local user fontssvgid
: optional suffix value for local SVG fontsrc
, e.g.font-file.svg#svgid
(if omitted, defaults toname
)<format>
: describe any number of relative paths to locally-hosted font-files, or embeddeddata:...
font strings per format (e.g.ttf
,otf
,woff2
, etc.)
'body-font': (
'name': 'Source Sans Pro',
'stack': ('Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'),
'formats': 'woff' 'woff2' 'ttf',
'normal': 'sans/sourcesanspro-regular-webfont',
'italic': 'sans/sourcesanspro-italic-webfont',
'bold': (
'path': 'sans/sourcesanspro-bold-webfont',
'local': 'source-sans-pro-bold',
'ttf': 'sans-ttf/sourcesanspro-bold-webfont',
'woff': 'data:application/x-font-woff;charset=utf-8;base64...',
),
)
Example
@use 'utilities';
utilities.$herman: (
'colors': (
'brand-colors': (
'brand-orange': '#c75000',
'brand-blue': '#0d7fa5',
),
'status-colors': (
'go': '#657e1b',
'yield': '#c75000',
),
),
'fonts': (
'body-font': (
'name': 'Source Sans Pro',
'stack': ('Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'),
'formats': 'woff' 'woff2' 'ttf',
'normal': 'sans/sourcesanspro-regular-webfont',
'italic': 'sans/sourcesanspro-italic-webfont',
'bold': (
'path': 'sans/sourcesanspro-bold-webfont',
'local': 'source-sans-pro-bold',
'ttf': 'sans-ttf/sourcesanspro-bold-webfont',
'woff': 'data:application/x-font-woff;charset=utf-8;base64...',
),
),
),
'sizes': (
'text-sizes': (
'root': '18px',
'large': 'calc(1rem + 1.5vw)',
),
),
);
Used By
@mixin add()
@mixin export()
Encode a Sass map as a JSON-ready string, and print to CSS output as a persistent comment.
Since 4.0.0
:
Name changed from herman-export
Parameters
$map: $herman (map)
Map to be encoded for JSON exporting
Example
@use 'utilities';
// Export to JSON
@include utilities.export;
/*! json-encode: {"colors": {"brand-colors": {"brand-orange": "hsl(24deg, 100%, 39%)", "brand-blue": "hsl(195deg, 85%, 35%)", "brand-pink": "#aa0e5c"}, "neutral-colors": {"light-gray": "#dedede", "gray": "#555b5e", "contrast-light": "#fff", "contrast-dark": "#3b4042"}, "theme-colors": {"theme-dark": "hsl(195deg, 85%, 35%)", "theme-light": "#cfe5ed", "background": "#fff", "text": "#3b4042", "text-light": "#555b5e", "action": "#b81e6c", "focus": "hsl(195deg, 85%, 35%)", "underline": "#edc7da", "border": "#555b5e", "border-light": "#dedede", "shadow": "rgba(85, 91, 94, 0.5)", "callout": "#cfe5ed", "slight": "#fafcfd", "code": "hsl(195deg, 85%, 35%)", "code-shadow": "rgba(13, 127, 165, 0.2)"}, "hljs-colors": {"hljs-comment": "#93a1a1", "hljs-green": "#859900", "hljs-cyan": "#2aa198", "hljs-blue": "#268bd2", "hljs-yellow": "#b58900", "hljs-orange": "#cb4b16", "hljs-red": "#dc322f", "hljs-formula": "#eee8d5"}, "custom-property-colors": {"link": "var(--brand-blue)", "link-action": "var(--brand-pink)"}, "demo-colors": {"brand-blue": "hsl(195deg, 85%, 35%)", "brand-pink": "hsl(330deg, 85%, 48%)"}, "demo-noncolors": {"light-gray": "#dedede", "gray": "#555b5e", "contrast-dark": "#3b4042"}}, "ratios": {"text-ratios": {"line-height": 1.4}, "demo-ratios": {"line-height": 1.4}}, "sizes": {"root-sizes": {"root": "18px", "responsive": "calc(1em + 0.125vw)", "large": "calc(1rem + 0.5vw)", "small": "0.9rem"}, "text-sizes": {"reset": "1rem", "h1": "calc(1rem + 2vw)", "h2": "calc(1rem + 1vw)", "h3": "calc(1rem + 0.5vw)", "quote": "calc(1rem + 0.5vw)", "code": "0.9rem", "footer": "0.9rem", "search": "0.9rem"}, "spacing-sizes": {"rhythm": "1.4rem", "gutter": "1.4rem", "gutter-plus": "2.1rem", "double-gutter": "2.8rem", "triple-gutter": "4.2rem", "flex-gutter": "calc(0.7rem + 2.5vw)", "spacer": "calc(4.2rem + 2.5vw)", "gutter-minus": "1.05rem", "shim": "0.7rem", "half-shim": "0.35rem", "quarter-shim": "0.175rem"}, "pattern-sizes": {"nav-underline": "4px", "nav-icon": "28px", "arrow-border": "8px", "arrow-depth": "0.7rem", "arrow-side": "1.4rem", "font-preview": "24em", "specimen-aa": "4.2rem", "color-preview": "16em", "color-swatch": "5.6rem", "footer-logo": "2.8rem"}, "layout-sizes": {"page": "50rem", "item-break": "40em", "page-break": "50em", "nav-break": "65em"}, "demo-sizes-text": {"root": "18px", "responsive": "calc(1.5em + 1vw)", "xlarge": "3rem"}, "demo-sizes-theme": {"icon": "1rem", "card": "30vw", "quote": "50%", "outline": "thin", "border": "medium", "separator": "thick"}, "demo-sizes-large": {"box": "20em", "page": "75ch"}}, "fonts": {"sans": {"name": "Source Sans Pro", "source": "https://fonts.google.com/specimen/Source+Sans+Pro", "stack": ["Source Sans Pro", "Helvetica Neue", "Helvetica", "Arial", "sans-serif"]}, "code": {"name": "Source Code Pro", "source": "https://fonts.google.com/specimen/Source+Code+Pro", "stack": ["Source Code Pro", "Consolas", "Menlo", "Monaco", "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", "monospace", "sans-serif"]}, "demo-cdn": {"name": "Source Code Pro", "source": "https://fonts.google.com/specimen/Source+Code+Pro", "stack": ["Consolas", "Menlo", "Courier New", "monospace", "sans-serif"]}, "demo-local": {"name": "rockingham", "normal": {"path": "rockingham/rockingham-regular-webfont", "local": "rockingham-regular-webfont"}, "bold": "rockingham/rockingham-bold-webfont", "italic": "rockingham/rockingham-italic-webfont", "bold italic": "rockingham/rockingham-bolditalic-webfont", "stack": "fantasy", "formats": ["woff2", "woff", "ttf"]}}} */
Requires
@function encode()
@mixin add()
Add a map of colors, fonts, sizes, ratios, etc
to the $herman
map for JSON-export,
converting values to JSON-ready strings.
Since 4.0.0
:
Name changed from herman-add
Since 4.1.0
:
Data supplied to utilities.add()
is deeply merged instead of overridden
Since 5.0.0
:
No longer accepts map-compile arguments,
since there is not an obvious default between
running compilation on keys vs values.
Use each-value
or each-key
to handle compilations manually.
Parameters & Output
$type: (String)
The type of map being added,
e.g. colors
, fonts
,
sizes
, or ratios
.
$key: (String)
A key name for accessing this data in JSON –
should match the variable name,
unless key
is otherwise set in the @font
/@colors
/@ratios
/@sizes
annotation
$map: (Map)
A map of name/value pairs
$args…: (Arglist)
A function to use for compiling values before export, and any additional arguments for the function
{CSS output} (code block)
Updated $herman
map, ready for JSON export
Example
@use 'sass:meta';
@use '~accoutrement/sass/tools';
@use 'utilities';
utilities.$herman: ();
$brand-colors: (
'brand-blue': hsl(195, 85%, 35%),
'light-gray': '#brand-blue' ('tint': 80%, 'desaturate': 80%),
);
$brand-compiled: utilities.each-key(
$brand-colors,
meta.get-function('color', $module: 'tools'),
);
@include utilities.add('colors', 'brand-colors', $brand-compiled);
@each $key, $value in utilities.$herman {
/* #{$key}: #{meta.inspect($value)} */
}
/* colors: ("brand-colors": ("brand-blue": hsl(195deg, 85%, 35%), "light-gray": #dedede)) */
@function each-value()
Pass the values of any map through a given function
(with optional arguments)
and return the compiled map.
This is used by add
,
but can also be accessed directly.
Since 4.0.0
:
Name changed from herman-map-compile
to compile
Since 5.0.0
:
Name changed from compile
to each-value
Parameters & Return
$map: (Map)
A sass map with values that need to be compiled, by running each value through a given function.
$function: (String | Function)
The function (or function name) to use in compiling values,
such as Accoutrement color
and size
functions
$args…: (Arglist)
Pass in any additional arguments for the function
@return (String | Any)
An updated map, with values compiled by a third-party function, and converted to json-ready strings
@function each-key()
Pass the keys of any map through a given function
(with optional arguments)
and return the compiled map.
This is used by add
,
but can also be accessed directly.
Since 4.0.0
:
Name changed from herman-map-compile
to compile
Since 5.0.0
:
Name changed from compile
to each-value
Parameters & Return
$map: (Map)
A sass map with values that need to be compiled, by running each key through a given function.
$function: (String | Function)
The function (or function name) to use in compiling values,
such as Accoutrement color
and size
functions
$args…: (Arglist)
Pass in any additional arguments for the function
@return (String | Any)
An updated map, with values compiled by a third-party function, and converted to json-ready strings
Example
@use 'sass:meta';
@use '~accoutrement/sass/tools';
@use 'utilities';
$brand-colors: (
'brand-orange': hsl(24, 100%, 39%),
'brand-blue': hsl(195, 85%, 35%),
'light-gray': 'brand-blue' ('tint': 80%, 'desaturate': 80%),
);
$compiled: utilities.each-key($brand-colors, meta.get-function('color', $module: 'tools'));
@each $key, $value in $compiled {
/* #{$key}: #{$value} */
}
/* brand-orange: hsl(24deg, 100%, 39%) */
/* brand-blue: hsl(195deg, 85%, 35%) */
/* light-gray: #dedede */