css - 如何将 json 转换为样式字典中的 css 类?
问题描述
我有以下 button.json
{
"component": {
"button": {
"padding": { "value": "{size.padding.medium.value}" },
"font-size": { "value": 2 },
"text-align": { "value": "center" },
"primary": {
"background-color": { "value": "hsl(10, 80, 50)" },
"color": { "value": "{color.font.inverse.value}" }
},
"secondary": {
"background-color": { "value": "{color.background.primary.value}" },
"color": { "value": "{color.font.link.value}" }
}
}
}
我能够使用亚马逊风格词典生成风格标记。我想要生成的是一个完整的 sass css 来自 json。
例如:
.component-button {
padding: " ";
font-size: " ";
& .primary {
background-color: "",
color: ""
}
}
解决方案
一种方法是使用自定义模板创建自定义格式来呈现.scss
文件。我在下面包含了执行此操作的基本代码。
首先,这是我使用的button.json文件:
{
"color": {
"background": {
"primary": { "value": "hsl(10, 80, 50)" },
"secondary": { "value": "hsl(10, 80, 90)" }
},
"font": {
"inverse": { "value": "#fff" },
"link": { "value": "#00f" }
}
},
"size": {
"2": { "value": 16 },
"padding": {
"medium": { "value": 16 }
}
},
"component": {
"button": {
"padding": { "value": "{size.padding.medium.value}" },
"font-size": { "value": "{size.2.value}" },
"text-align": { "value": "center" },
"primary": {
"background-color": { "value": "{color.background.primary.value}" },
"color": { "value": "{color.font.inverse.value}" }
},
"secondary": {
"background-color": { "value": "{color.background.secondary.value}" },
"color": { "value": "{color.font.link.value}" }
}
}
}
}
我添加了一个附加对象color
,size
以便指针可以适当地解析。我还对你的令牌的结构做了一些假设(例如size.2
for the font-size
),但希望那里的整体想法很清楚。
这是主要的 JavaScript 代码。我已经加入了评论,试图解释一切。
const _ = require('lodash')
/*
This is formatted oddly in order to get a nice final shape
in `button.scss`.
Essentially what the template is doing is looping through
the props object and outputting the top-level properties
as the parent classnames, then for each child props of
"classname" it looks to see if the child prop is an object,
if it is, then it outputs the Sass `&.` operator with the
child prop rule as the sub classname and then each child
prop of the value as the final CSS style rule and value.
If it's not an object then it outputs the rule and value
as the CSS style rule and value.
*/
const template = _.template(`<% _.each(props, function(prop, classname) { %>.<%= classname %> {
<% _.each(prop, (value, rule) => { %><% if (typeof value === 'object') { %> &.<%= rule %> {<% _.each(value, (subvalue, subrule) => { %>
<%= subrule %>: <%= subvalue %>;<% }) %>
}<% } else { %> <%= rule %>: <%= value %>;<% } %>
<% }) %><% }) %>}
`)
const StyleDictionary = require('style-dictionary')
.registerFormat({
name: 'scss/button',
formatter: function(dictionary, config) {
/*
allProperties is an array containing all the matched
tokens based on the filter.
*/
const { allProperties } = dictionary
/*
Set up an empty object to hold the final shape to pass
to the custom template.
After the allProperties.map(), props will look like this:
{
'component-button': {
padding: '16px',
'font-size': '16px',
'text-align': 'center',
primary: { 'background-color': '#e63c19', color: '#ffffff' },
secondary: { 'background-color': '#fad8d1', color: '#0000ff' }
}
}
*/
const props = {}
// go through properties and structure final props object
allProperties.map(prop => {
/*
Extract the attributes object created by the 'attribute/cti'
transform and the transformed token value.
*/
const { attributes, value } = prop
// extract attributes to build custom class and style rules
const { category, type, item, subitem } = attributes
// build main classname for .scss file
const classname = `${category}-${type}`
/*
Add to the props object if it doesn't already exist.
We run the check to see if the classname exists already as an
object property because in our case, `classname` will be the
same for each token object in allProperties because each token
is under the same category and type.
*/
if (!props.hasOwnProperty(classname)) {
props[classname] = {}
}
/*
If the token object has a subitem, use the item as the subclass.
Run the same check to see if this particular subclass (item) has
been added yet.
*/
if (subitem) {
if (!props[classname].hasOwnProperty(item)) {
props[classname][item] = {}
}
// add the subitem and value as final CSS rule
props[classname][item][subitem] = value
}
else {
// add the item as a CSS rule, not a subclass
props[classname][item] = value
}
})
/*
Pass the final `props` object to our custom template to render
the contents for the final button.scss file.
*/
return template({ props })
}
})
.extend({
source: ['button.json'],
platforms: {
scss: {
buildPath: 'build/',
transforms: [
'attribute/cti', // setup attributes object
'color/css', // transform color values to hex
'name/cti/kebab', // prevent name collisions
'size/px' // transform size values to px
],
files: [
{
destination: 'button.scss',
format: 'scss/button',
filter: {
attributes: {
category: 'component',
type: 'button'
}
}
}
]
}
}
})
// run Style Dictionary
StyleDictionary.buildAllPlatforms()
如果你运行它,你应该得到一个看起来像这样的最终文件( build/button.scss ):
.component-button {
padding: 16px;
font-size: 16px;
text-align: center;
&.primary {
background-color: #e63c19;
color: #ffffff;
}
&.secondary {
background-color: #fad8d1;
color: #0000ff;
}
}
推荐阅读
- tfs - 将 TFS 中的评论解析限制为仅作者
- c# - 没有装箱值实例的接口的泛型和使用
- c# - 如何有效地编辑数据库中的数据?
- python - Python mock 返回一个 MagicMock 对象而不是指定的结果值
- java - 对 url 的 GET 请求(接受条款和条件)返回与响应正文相同的页面,但在 POSTMAN 中有效
- git - 我可以在 GitHub Enterprise 中跟踪 repo 克隆活动吗?
- python - 根据python中的条件制作列表以创建唯一列表
- javascript - 如何使用 jquery/javascript 设置弹出宽度最大宽度
- c++ - 从 lineEdit QT 获取 unicode 并将其写入文件
- spotfire - 对于满足特定条件的值,同一列中的行之间的差异