From a267fcd8519d9104adb2bfe772adcca51255fb91 Mon Sep 17 00:00:00 2001 From: "Finch.io" Date: Thu, 29 Jun 2017 17:09:54 +0300 Subject: [PATCH] Release 0.1.4 (#16) * Sketch built-in update implementation * Text layer split compatibility update --- Slinky.sketchplugin/Contents/Sketch/Slinky.js | 57 ++++++++---------- .../Contents/Sketch/manifest.json | 3 +- appcast.xml | 21 +++++++ source/slinky/convert.ts | 59 ++++++++----------- source/typings/Sketch.d.ts | 17 +++++- 5 files changed, 89 insertions(+), 68 deletions(-) create mode 100644 appcast.xml diff --git a/Slinky.sketchplugin/Contents/Sketch/Slinky.js b/Slinky.sketchplugin/Contents/Sketch/Slinky.js index 1f55470..562d80a 100644 --- a/Slinky.sketchplugin/Contents/Sketch/Slinky.js +++ b/Slinky.sketchplugin/Contents/Sketch/Slinky.js @@ -1476,48 +1476,43 @@ function sketchToLayers(layerGroup, offset, command) { return { layers: layers, assets: assets }; } function splitText(layer) { - var textStorage = layer.createTextStorage(); - var attributeRuns = textStorage.attributeRuns(); - var attributeRunsCount = attributeRuns.count(); var fontWeights = ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black"]; var fontStyles = ["italic", "oblique"]; - var fillColor = (layer.style().fill()) ? layer.style().fill().color() : null; + var hasFill = (layer.style().fills().firstObject()) ? true : null; var textElements = []; - for (var i = 0; i < attributeRunsCount; i++) { - var obj = attributeRuns.objectAtIndex(i); - var textAttributes = { - text: "", - css: {} - }; - textAttributes.text = unescape(obj.string()); - var font = obj.font(); - var fontFamily = unescape(font.familyName()); - var fontName = unescape(font.displayName()); + var attributes = layer.attributedStringValue().treeAsDictionary().attributes; + attributes.forEach(function (attribute) { + var font = attribute.NSFont; + var fontFamily = unescape(font.family); + var fontName = unescape(font.name); var fontVariants = fontName.substr(fontFamily.length + 1).split(" "); var fontWeight = fontVariants.filter(function (variant) { return fontWeights.indexOf(variant.toLowerCase()) > -1; }); - if (fontWeight.length == 1) - textAttributes.css["font-weight"] = (fontWeights.indexOf(fontWeight[0].toLowerCase()) + 1) * 100; var fontStyle = fontVariants.filter(function (variant) { return fontStyles.indexOf(variant.toLowerCase()) > -1; }); - if (fontStyle.length == 1) - textAttributes.css["font-style"] = fontStyle[0].toLowerCase(); - if (obj.attribute_atIndex_effectiveRange_("NSUnderline", 0, null)) { - textAttributes.css["text-decoration"] = "underline"; - } - textAttributes.css["font-family"] = "'" + fontFamily + "'"; - textAttributes.css["font-size"] = font.pointSize() + 'px'; - if (!fillColor) { - var color = obj.foregroundColor().colorUsingColorSpaceName(NSCalibratedRGBColorSpace); - textAttributes.css["color"] = NSrgbaToHex(color); - textAttributes.css["opacity"] = color.alphaComponent(); + var fontColor = layer.attributedStringValue().attribute_atIndex_effectiveRange_("NSColor", attribute.location, null); + var css = { + "font-weight": (fontWeight.length == 1) ? (fontWeights.indexOf(fontWeight[0].toLowerCase()) + 1) * 100 + "" : null, + "font-style": (fontStyle.length == 1) ? fontStyle[0].toLowerCase() : null, + "text-decoration": (layer.attributedStringValue().attribute_atIndex_effectiveRange_("NSUnderline", attribute.location, null)) ? "underline" : null, + "font-family": "'" + fontFamily + "'", + "font-size": font.attributes.NSFontSizeAttribute + 'px', + "color": (!hasFill && fontColor) ? NSrgbaToHex(fontColor) : null, + }; + for (var propName in css) { + if (css[propName] === null || css[propName] === undefined) { + delete css[propName]; + } } - textElements.push(textAttributes); - } + textElements.push({ + text: unescape(attribute.text), + css: css + }); + }); return textElements; } function getCSS(layer) { var properties = parseCSSAttributes(layer.CSSAttributes().slice(1)); - if (layer.style().fill()) { - properties["color"] = rgbaToHex(layer.style().fill().color()); + if (layer.style().fills().firstObject()) { + properties["color"] = rgbaToHex(layer.style().fills().firstObject().color()); } if (layer.class() === MSTextLayer) { var textAlignment = [ diff --git a/Slinky.sketchplugin/Contents/Sketch/manifest.json b/Slinky.sketchplugin/Contents/Sketch/manifest.json index 3b4fce2..6f65523 100644 --- a/Slinky.sketchplugin/Contents/Sketch/manifest.json +++ b/Slinky.sketchplugin/Contents/Sketch/manifest.json @@ -1,13 +1,14 @@ { "name" : "Slinky", "identifier" : "com.sketchapp.slinky-plugin", - "version" : "0.1.3", + "version" : "0.1.4", "description" : "Export HTML email templates from Sketch", "authorEmail" : "human@finch.io", "author" : "finchalyzer", "homepage" : "https://github.com/finchalyzer/slinky", "disableCocoaScriptPreprocessor": true, "icon" : "icons/slinky.png", + "appcast": "https://raw.githubusercontent.com/finchalyzer/slinky/master/appcast.xml", "commands" : [ { "script" : "Slinky.js", diff --git a/appcast.xml b/appcast.xml new file mode 100644 index 0000000..9d092bf --- /dev/null +++ b/appcast.xml @@ -0,0 +1,21 @@ + + + + Slinky + https://raw.githubusercontent.com/finchalyzer/slinky/master/appcast.xml + Export HTML email templates from Sketch artboards + en + + Version 0.1.4 + + +
  • Sketch 45 support
  • + + ]]> +
    + Thu, 29 Jun 2017 12:00:00 +0000 + +
    +
    +
    diff --git a/source/slinky/convert.ts b/source/slinky/convert.ts index ca0fea3..874049a 100644 --- a/source/slinky/convert.ts +++ b/source/slinky/convert.ts @@ -508,59 +508,52 @@ function sketchToLayers(layerGroup: MSLayer[], offset?: {x: number, y: number}, function splitText(layer: MSLayer){ - const textStorage = layer.createTextStorage() - const attributeRuns = textStorage.attributeRuns() - const attributeRunsCount = attributeRuns.count() - const fontWeights = ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black"] const fontStyles = ["italic", "oblique"] - const fillColor = (layer.style().fill()) ? layer.style().fill().color() : null + const hasFill = (layer.style().fills().firstObject()) ? true : null var textElements: { text: string, css: any }[] = [] - for(var i = 0; i < attributeRunsCount; i++) { - - var obj = attributeRuns.objectAtIndex(i) - - var textAttributes = { - text: "", - css: {} - } + const attributes = layer.attributedStringValue().treeAsDictionary().attributes - textAttributes.text = unescape(obj.string()) + attributes.forEach((attribute)=>{ - var font = obj.font() + const font = attribute.NSFont - const fontFamily = unescape(font.familyName()) - const fontName = unescape(font.displayName()) + const fontFamily = unescape(font.family) + const fontName = unescape(font.name) const fontVariants = fontName.substr(fontFamily.length + 1).split(" ") const fontWeight = fontVariants.filter(variant => fontWeights.indexOf(variant.toLowerCase()) > -1) - if(fontWeight.length == 1) textAttributes.css["font-weight"] = (fontWeights.indexOf(fontWeight[0].toLowerCase()) + 1) * 100 - const fontStyle = fontVariants.filter(variant => fontStyles.indexOf(variant.toLowerCase()) > -1) - if(fontStyle.length == 1) textAttributes.css["font-style"] = fontStyle[0].toLowerCase() - if(obj.attribute_atIndex_effectiveRange_("NSUnderline", 0, null)){ - textAttributes.css["text-decoration"] = "underline" - } + const fontColor = layer.attributedStringValue().attribute_atIndex_effectiveRange_("NSColor", attribute.location, null) - textAttributes.css["font-family"] = `'${fontFamily}'` - textAttributes.css["font-size"] = font.pointSize() + 'px' + let css = { + "font-weight": (fontWeight.length == 1) ? (fontWeights.indexOf(fontWeight[0].toLowerCase()) + 1) * 100 + "" : null, + "font-style": (fontStyle.length == 1) ? fontStyle[0].toLowerCase() : null, + "text-decoration": (layer.attributedStringValue().attribute_atIndex_effectiveRange_("NSUnderline", attribute.location, null)) ? "underline" : null, + "font-family": `'${fontFamily}'`, + "font-size": font.attributes.NSFontSizeAttribute + 'px', + "color": (!hasFill && fontColor) ? NSrgbaToHex(fontColor) : null, + } - if(!fillColor){ - const color = obj.foregroundColor().colorUsingColorSpaceName(NSCalibratedRGBColorSpace) - textAttributes.css["color"] = NSrgbaToHex(color) - textAttributes.css["opacity"] = color.alphaComponent() + for (var propName in css) { + if (css[propName] === null || css[propName] === undefined) { + delete css[propName] + } } - textElements.push(textAttributes) + textElements.push({ + text: unescape(attribute.text), + css: css + }) - } + }) return textElements @@ -570,8 +563,8 @@ function getCSS(layer: MSLayer){ var properties = parseCSSAttributes(layer.CSSAttributes().slice(1)) - if(layer.style().fill()){ - properties["color"] = rgbaToHex(layer.style().fill().color()) + if(layer.style().fills().firstObject()){ + properties["color"] = rgbaToHex(layer.style().fills().firstObject().color()) } if(layer.class() === MSTextLayer){ diff --git a/source/typings/Sketch.d.ts b/source/typings/Sketch.d.ts index f28cf3c..011775a 100644 --- a/source/typings/Sketch.d.ts +++ b/source/typings/Sketch.d.ts @@ -43,12 +43,23 @@ interface MSLayer{ point(): {x: number, y: number} } style():{ - fill():{ - color(): any - } + fills(): MSStyleFill } + attributedStringValue(): any } +interface MSStyleFill{ + firstObject(): MSStyleFill + color(): { + red(): number, + green(): number, + blue(): number, + alpha(): number + } +} + + +declare var NSMakeRange: any declare var MSTextLayer: MSLayer declare var MSLayerGroup: MSLayer declare var MSShapeGroup: MSLayer