diff --git a/README.md b/README.md index 18cb721..e6cec46 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ This templating is used in the `filter` and `fileNames` configurations. - `full_name`: The full name of the component. If part of a component set, comprised of the name of the component set and the component name. The component name otherwise. - `name`: The name of the component +- `normalized_name`: A name object for the `full_name` - `key`: The key of the component - `id`: The id of the component - `set_name`: The name of the set of which this component is a part of, empty if not part of a set @@ -181,6 +182,7 @@ This templating is used in the file at the `templatePath` configuration. - `colors`: A list of `Color` objects - `floats`: A list of `Float` objects - `strings`: A list of `String` objects +- `icons`: A list of `Icon` objects as for the icon export. Useful to generate code accessors to the icons. - `booleans`: A list of `Boolean` objects - `text_styles`: A list of `TextStyle` objects - `figma`: A `Figma` object @@ -243,6 +245,7 @@ Hint: You can also use Jinja filters to modify the name, e.g. `{{ color.name|low - `snake`: The name in snake case - `kebab`: The name in kebab case - `pascal`: The name in pascal case +- `camel`: The name in camel case #### Figma - `file`: The Figma file name diff --git a/figex-core/src/main/kotlin/com/iodigital/figex/ExportHelpers.kt b/figex-core/src/main/kotlin/com/iodigital/figex/ExportHelpers.kt index da55db5..c02e0e8 100644 --- a/figex-core/src/main/kotlin/com/iodigital/figex/ExportHelpers.kt +++ b/figex-core/src/main/kotlin/com/iodigital/figex/ExportHelpers.kt @@ -2,6 +2,10 @@ package com.iodigital.figex import com.hubspot.jinjava.Jinjava import com.hubspot.jinjava.JinjavaConfig +import com.iodigital.figex.ext.camel +import com.iodigital.figex.ext.kebab +import com.iodigital.figex.ext.pascal +import com.iodigital.figex.ext.snake import com.iodigital.figex.jinjava.LowercaseFilter import com.iodigital.figex.jinjava.ReplaceSpecialChars import com.iodigital.figex.jinjava.StartsWithFilter @@ -42,14 +46,24 @@ internal fun createTemplateContext( defaultMode: String, filter: String, values: List>, + components: List, ) = mapOf( "colors" to values.subContextFor(defaultMode, filter, FigExArgbColor::class), "floats" to values.subContextFor(defaultMode, filter, Float::class), "strings" to values.subContextFor(defaultMode, filter, String::class), "booleans" to values.subContextFor(defaultMode, filter, Boolean::class), "text_styles" to values.subContextFor(defaultMode, filter, FigExTextStyle::class), + "icons" to components.map { it.toContext() } ) + createTemplateContext(file) +internal fun String.toNameObject() = mapOf( + "original" to this, + "snake" to this.snake(), + "camel" to this.camel(), + "kebab" to this.kebab(), + "pascal" to this.pascal(), +) + internal fun createTemplateContext( file: FigmaFile, scale: FigExConfig.Export.Icons.Scale, diff --git a/figex-core/src/main/kotlin/com/iodigital/figex/FigEx.kt b/figex-core/src/main/kotlin/com/iodigital/figex/FigEx.kt index b33f352..bb409f1 100644 --- a/figex-core/src/main/kotlin/com/iodigital/figex/FigEx.kt +++ b/figex-core/src/main/kotlin/com/iodigital/figex/FigEx.kt @@ -11,8 +11,10 @@ import com.iodigital.figex.utils.cacheDir import com.iodigital.figex.utils.info import com.iodigital.figex.utils.startStatusAnimation import com.iodigital.figex.utils.status +import com.iodigital.figex.utils.warning import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import kotlinx.coroutines.cancel import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch @@ -86,23 +88,29 @@ object FigEx { ignoreUnsupportedLinks = ignoreUnsupportedLinks, ) val file = loadFigmaFile(config = config, api = api) + val components = async { + loadComponents(api = api, file = file) + } + val values = async { + loadValues(config = config, api = api, file = file) + } + listOf( launch { - val values = loadValues(config = config, api = api, file = file) performValueExports( root = configFile.absoluteFile.parentFile, file = file, config = config, - values = values, + values = values.await(), + components = components.await(), ) }, launch { - val components = loadComponents(api = api, file = file) performIconExports( root = configFile.absoluteFile.parentFile, file = file, config = config, - components = components, + components = components.await(), exporter = api ) } @@ -134,6 +142,7 @@ object FigEx { file: FigmaFile, config: FigExConfig, values: List>, + components: List, ) = config.exports.mapNotNull { it as? FigExConfig.Export.Values }.forEach { @@ -141,6 +150,7 @@ object FigEx { export = it, file = file, values = values, + components = components, root = root, ) } @@ -152,12 +162,23 @@ object FigEx { components: List, exporter: FigmaImageExporter, ) = withContext(Dispatchers.IO) { - config.exports.mapNotNull { + val iconExports = config.exports.mapNotNull { it as? FigExConfig.Export.Icons - }.map { + } + + // Clear all destinations first, multiple might have same destination + iconExports.forEach { export -> + if (export.clearDestination) { + val destination = root.makeChild(export.destinationPath) + warning(tag = tag, " Clearing destination: ${destination.absolutePath}") + destination.deleteRecursively() + } + } + + iconExports.map { export -> launch { performIconExport( - export = it, + export = export, file = file, components = components, root = root, diff --git a/figex-core/src/main/kotlin/com/iodigital/figex/IconExports.kt b/figex-core/src/main/kotlin/com/iodigital/figex/IconExports.kt index 9279b0e..1f764a6 100644 --- a/figex-core/src/main/kotlin/com/iodigital/figex/IconExports.kt +++ b/figex-core/src/main/kotlin/com/iodigital/figex/IconExports.kt @@ -37,10 +37,6 @@ internal suspend fun performIconExport( ) = withContext(Dispatchers.IO) { //region Make destination val destinationRoot = root.makeChild(export.destinationPath) - if (export.clearDestination) { - warning(tag = tag, " Clearing destination: ${destinationRoot.absolutePath}") - destinationRoot.deleteRecursively() - } info(tag = tag, " Creating destination: ${destinationRoot.absolutePath}") destinationRoot.mkdirs() //endregion diff --git a/figex-core/src/main/kotlin/com/iodigital/figex/ValueExports.kt b/figex-core/src/main/kotlin/com/iodigital/figex/ValueExports.kt index 48e7bdf..63adaae 100644 --- a/figex-core/src/main/kotlin/com/iodigital/figex/ValueExports.kt +++ b/figex-core/src/main/kotlin/com/iodigital/figex/ValueExports.kt @@ -3,6 +3,7 @@ package com.iodigital.figex import com.iodigital.figex.api.FigmaApi import com.iodigital.figex.ext.walk import com.iodigital.figex.models.figex.FigExArgbColor +import com.iodigital.figex.models.figex.FigExComponent import com.iodigital.figex.models.figex.FigExConfig import com.iodigital.figex.models.figex.FigExTextStyle import com.iodigital.figex.models.figex.FigExValue @@ -122,11 +123,13 @@ internal fun performValuesExport( export: FigExConfig.Export.Values, file: FigmaFile, values: List>, + components: List, ) { val context = createTemplateContext( file = file, defaultMode = export.defaultMode ?: "", values = values, + components =components, filter = export.filter, ) + export.templateVariables val template = root.makeChild(export.templatePath) diff --git a/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExComponent.kt b/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExComponent.kt index b9cd3bd..7634341 100644 --- a/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExComponent.kt +++ b/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExComponent.kt @@ -1,6 +1,7 @@ package com.iodigital.figex.models.figex import com.iodigital.figex.models.Contextable +import com.iodigital.figex.toNameObject data class FigExComponent( val setKey: String?, @@ -21,5 +22,8 @@ data class FigExComponent( "key" to key, "id" to id, "set_id" to (setId ?: ""), + "normalized_name" to fullName.map { if (it.isLetterOrDigit()) it else "_" } + .joinToString("") + .toNameObject(), ) } \ No newline at end of file diff --git a/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExValue.kt b/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExValue.kt index 9ba49eb..6d7f8a1 100644 --- a/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExValue.kt +++ b/figex-core/src/main/kotlin/com/iodigital/figex/models/figex/FigExValue.kt @@ -5,6 +5,7 @@ import com.iodigital.figex.ext.kebab import com.iodigital.figex.ext.pascal import com.iodigital.figex.ext.snake import com.iodigital.figex.models.Contextable +import com.iodigital.figex.toNameObject import kotlin.reflect.KClass data class FigExValue( @@ -40,14 +41,6 @@ data class FigExValue( } } - private fun String.toNameObject() = mapOf( - "original" to this, - "snake" to this.snake(), - "camel" to this.camel(), - "kebab" to this.kebab(), - "pascal" to this.pascal(), - ) - private fun Any.toContext(): Map = if (this is Contextable) { toContext() } else { diff --git a/gradle-plugin/src/functionalTest/expected_full_dump.json.txt b/gradle-plugin/src/functionalTest/expected_full_dump.json.txt index c079de0..442c973 100644 --- a/gradle-plugin/src/functionalTest/expected_full_dump.json.txt +++ b/gradle-plugin/src/functionalTest/expected_full_dump.json.txt @@ -179,6 +179,71 @@ "unused": 64.0 } }, + "icons": [ + "sidebarSidebarInfo", + "contentStep", + "sidebarSidebarInteractive", + "contentArrowDirectionRight", + "contentArrowDirectionLeft", + "favoriteToggleIsfavoriteFalse", + "favoriteToggleIsfavoriteTrue", + "section", + "contentButton", + "pill", + "sidebarInfo", + "contentStep", + "sidebarInteractive", + "contentNext", + "directionRight", + "directionLeft", + "isfavoriteFalse", + "isfavoriteTrue", + "resourcesTile", + "menu", + "Key", + "cmd_", + "Key", + "alt_", + "shift_", + "capsLock_", + "return_", + "return_", + "returnText_", + "cmdText_", + "pageUpText_", + "pageDownText_", + "pgupText_", + "pgdnText_", + "tabText_", + "escText_", + "altText_", + "shiftText_", + "optionText_", + "capsLockText_", + "enterText_", + "deleteText_", + "ejectText_", + "ctrl_", + "ctrlText_", + "delText_", + "deleteBack_", + "deleteForward_", + "esc_", + "tab_", + "pageUp_", + "pageDown_", + "power_", + "eject_", + "upArrow_", + "downArrow_", + "rightArrow_", + "leftArrow_", + "osDivider", + "_", + "button", + "card", + "search" + ], "text_styles": { "section_eyebrow": { "base": { diff --git a/samples/config.json b/samples/config.json index fb2fa73..eb311c3 100644 --- a/samples/config.json +++ b/samples/config.json @@ -35,7 +35,7 @@ "filter": "{% if full_name|startsWith('content', true) %} true {% else %} false {% endif %}", "fileNames" : "{{ full_name|replaceSpecialChars('_')|lowercase }}", "destinationPath": "../sample_output/icons/drawable", - "clearDestination": false + "clearDestination": true }, { "type": "icons", @@ -43,8 +43,8 @@ "filter": "{% if full_name|startsWith('content', true) %} true {% else %} false {% endif %}", "fileNames": "{{ full_name|replaceSpecialChars('_')|lowercase }}", "destinationPath": "../sample_output/icons", - "clearDestination": false, - "useAndroidRasterScales": false + "clearDestination": true, + "useAndroidRasterScales": true } ] } \ No newline at end of file diff --git a/samples/full_dump.json.figex b/samples/full_dump.json.figex index 77bd11c..92b336b 100644 --- a/samples/full_dump.json.figex +++ b/samples/full_dump.json.figex @@ -35,6 +35,11 @@ }{{ ", " if not loop.last else "" }} {%- endfor %} }, + "icons": [ + {%- for icon in icons %} + "{{ icon.normalized_name.camel }}"{{ ", " if not loop.last else "" }} + {%- endfor %} + ], "text_styles": { {%- for style in text_styles %} "{{ style.name.snake }}": {