[{"name":"Anje Keizer","avatar":"/Faces/109.jpg","location":"Bangkok","bio":"Dog lover 🐕, mahjong champion 🀄️, and traveler 🗺 ","social":{"handle":"@akeizer01","bio":"Loving life and living in Dallas, go Mavs!"}}]
第一部分非常簡單。它將每個圖層的值添加到單個對象中,並確保以不同於單個圖層的方式處理圖層組。它只會將數據值賦予(並從中提取)文字圖層、填色和符號實例的覆蓋值。對於群組,它會遞迴地呼叫 walk 函數。
constwalk=(layers,extract,initialValue)=>{varvalue=initialValuefor (constlofArray.from(layers).reverse()){// layer groups can only create nested data objects, not valuesletv=isLayerGroup(l)?walk(l.layers,extract,undefined):extract(l)if (v===undefined)continuevalue={...value,[l.name]:v}}returnvalue}
const{getSelectedDocument,Style}=require('sketch')const{message}=require('sketch/ui')functionisLayerGroup(tbc){return'type'intbc&&tbc.type=='Group'}consttoData=(layer)=>{switch (layer.type){// text layers use the valuecase'Text':returnlayer.text// symbol instances can have override valuescase'SymbolInstance':case'SymbolMaster':// ensure overrides for nested symbols won't be processed before the// actual symbol override and filter out any override values that cannot// be used with dataletsupportedProperties=['symbolID','stringValue','image']letoverrides=layer.overrides.sort((a,b)=>a.path.localeCompare(b.path)).filter((val)=>supportedProperties.includes(val.property))vardata={}vardataGroupByPath={'':data}varhasValues=falsefor (constoofoverrides){letpathComponents=o.path.split('/')pathComponents.pop()letparentPath=pathComponents.join('/')if (o.property==='symbolID'){dataGroupByPath[o.path]={}dataGroupByPath[parentPath][o.affectedLayer.name]=dataGroupByPath[o.path]continue}dataGroupByPath[parentPath][o.affectedLayer.name]=o.property==='image'?'/path/to/image.png':o.valuehasValues=true}// We need to remove the nodes that don't have any valuesdata=removeEmptyNodes(data)returnhasValues?data:undefined// other layers can have image fills, in case of multiple image fills only// the last one is used as override valuedefault:lethasImageFill=layer.style?.fills.reduce((prev,curr)=>{if (curr.type!==Style.FillType.Pattern)returnprevreturntrue},false)if (!hasImageFill)breakreturn'/path/to/image.png'// actual image not exported, placeholder instead}returnundefined}constwalk=(layer,extract,initialValue)=>{if (!isLayerGroup(layer)){returnextract(layer)}varvalue=initialValuefor (constlofArray.from(layer.layers).reverse()){// layer groups can only create nested data objects, not valuesletv=isLayerGroup(l)?walk(l.layers,extract,undefined):extract(l)if (v===undefined)continuevalue={...value,[l.name]:v}}returnvalue}letdoc=getSelectedDocument()if (doc.selectedLayers.length!==1){message('☝️ Select exactly one layer group to create data set.')return}letselected=doc.selectedLayers.layers[0]letdata=walk(selected,toData,undefined)// `data` can be `undefined` if the symbol overrides// in the selected layer are disabledif (data===undefined){message('☝️ No symbol overrides found.')}else{// wrap data in array before encoding as JSON because Sketch expects a// set of values, not a single objectletjson=JSON.stringify([data],null,2)// use native macOS pasteboard APIs to copy the JSON so it can be easily// pasted outside Sketchletpasteboard=NSPasteboard.generalPasteboard()pasteboard.clearContents()pasteboard.setString_forType(json,NSPasteboardTypeString)message('📋 Data copied to clipboard.')}functionremoveEmptyNodes(obj){lethasEmptyNodes=falseObject.entries(obj).forEach(([key,value])=>{if (Object.keys(value).length===0){deleteobj[key]hasEmptyNodes=true}elseif (typeofvalue==='object'){obj[key]=removeEmptyNodes(value)}})returnhasEmptyNodes?removeEmptyNodes(obj):obj}