diff --git a/CONFIG.md b/CONFIG.md index 0e842de4..b3c77e37 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -22,9 +22,13 @@ common: # RegExp pattern for color name validation before exporting nameValidateRegexp: '^[a-zA-Z_]+$' # RegExp pattern for: background, background_primary, widget_primary_background icons: + # Name of the Figma's frame where icons components are located + figmaFrameName: Colors # RegExp pattern for icon name validation before exporting nameValidateRegexp: '^(ic)_(\d\d)_([a-z0-9_]+)$' # RegExp pattern for: ic_24_icon_name, ic_24_icon images: + # Name of the Figma's frame where image components are located + figmaFrameName: Illustrations # RegExp pattern for image name validation before exporting nameValidateRegexp: '^(img)_([a-z0-9_]+)$' # RegExp pattern for: img_image_name diff --git a/Examples/AndroidExample/figma-export.yaml b/Examples/AndroidExample/figma-export.yaml index b59ac835..0f1df53c 100644 --- a/Examples/AndroidExample/figma-export.yaml +++ b/Examples/AndroidExample/figma-export.yaml @@ -3,6 +3,15 @@ figma: lightFileId: BEjfU0kCVnPqXdRLfoLvkf darkFileId: QwF30YrucxVwQyBNT0C09i +# [optional] Common export parameters +common: + icons: + # Name of the Figma's frame where icons components are located + figmaFrameName: Colors + images: + # Name of the Figma's frame where image components are located + figmaFrameName: Illustrations + android: mainRes: ./app/src/main/res images: diff --git a/README.md b/README.md index a72a56e9..c9edc057 100644 --- a/README.md +++ b/README.md @@ -311,11 +311,12 @@ File | Styles For `figma-export icons` -Your Figma file must contains a frame with `Icons` name which contains components for each icon. +By default your Figma file should contains a frame with `Icons` name which contains components for each icon. You may change a frame name in a [config](Config.md) file by setting `common.icons.figmaFrameName` property. For `figma-export images` -Your Figma file must contains a frame with `Illustrations` name which contains components for each illustration. +Your Figma file should contains a frame with `Illustrations` name which contains components for each illustration. You may change a frame name in a [config](Config.md) file by setting `common.images.figmaFrameName` property. + If you support dark mode you must have two Figma files. For `figma-export typography`. diff --git a/Release/figma-export.yaml b/Release/figma-export.yaml index e45fa61f..64c6ddad 100644 --- a/Release/figma-export.yaml +++ b/Release/figma-export.yaml @@ -1,8 +1,8 @@ --- figma: - # Identifier of Figma file + # Identifier of the file containing light color palette, icons and light images. To obtain a file id, open the file in the browser. The file id will be present in the URL after the word file and before the file name. lightFileId: shPilWnVdJfo10YF12345 - # [optional] Identifier of Figma file for dark mode + # [optional] Identifier of the file containing dark color palette and dark images. darkFileId: KfF6DnJTWHGZzC912345 # [optional] Common export parameters @@ -11,9 +11,13 @@ common: # RegExp pattern for color name validation before exporting nameValidateRegexp: '^[a-zA-Z_]+$' # RegExp pattern for: background, background_primary, widget_primary_background icons: + # Name of the Figma's frame where icons components are located + figmaFrameName: Colors # RegExp pattern for icon name validation before exporting nameValidateRegexp: '^(ic)_(\d\d)_([a-z0-9_]+)$' # RegExp pattern for: ic_24_icon_name, ic_24_icon images: + # Name of the Figma's frame where image components are located + figmaFrameName: Illustrations # RegExp pattern for image name validation before exporting nameValidateRegexp: '^(img)_([a-z0-9_]+)$' # RegExp pattern for: img_image_name @@ -21,6 +25,8 @@ common: ios: # Path to xcodeproj xcodeprojPath: "./Example.xcodeproj" + # Xcode Target containing resources and corresponding swift code + target: "UIComponents" # Absolute or relative path to the Assets.xcassets directory xcassetsPath: "./Resources/Assets.xcassets" # Is Assets.xcassets located in the main bundle? @@ -28,7 +34,7 @@ ios: # Parameters for exporting colors colors: - # Should be generate color assets instead of pure swift code + # How to export colors? Use .xcassets and UIColor extension (useColorAssets = true) or extension only (useColorAssets = false) useColorAssets: True # [required if useColorAssets: True] Name of the folder inside Assets.xcassets where to place colors (.colorset directories) assetsFolder: Colors @@ -47,13 +53,15 @@ ios: assetsFolder: Icons # Icon name style: camelCase or snake_case nameStyle: camelCase - # [optional] Enable Preserve Vector Data for specified icons + # [optional] An array of icon names that will supports Preseve Vecotor Data preservesVectorRepresentation: - ic24TabBarMain - ic24TabBarEvents - ic24TabBarProfile # [optional] Absolute or relative path to swift file where to export icons (SwiftUI’s Image) for accessing from the code (e.g. Image.illZeroNoInternet) swiftUIImageSwift: "./Source/Image+extension_icons.swift" + # [optional] Absolute or relative path to swift file where to generate extension for UIImage for accessing icons from the code (e.g. UIImage.ic24ArrowRight) + imageSwift: "./Example/Source/UIImage+extension_icons.swift" # Parameters for exporting images images: @@ -63,16 +71,31 @@ ios: nameStyle: camelCase # [optional] Absolute or relative path to swift file where to export images (SwiftUI’s Image) for accessing from the code (e.g. Image.illZeroNoInternet) swiftUIImageSwift: "./Source/Image+extension_illustrations.swift" + # [optional] Absolute or relative path to swift file where to generate extension for UIImage for accessing illustrations from the code (e.g. UIImage.illZeroNoInternet) + imageSwift: "./Example/Source/UIImage+extension_illustrations.swift" # Parameters for exporting typography typography: - # Path to directory where to place UIFont+extension.swift file - fontExtensionDirectory: "./Source/UIComponents/" - # Will FigmaExport generate UILabel for each text style (font) e.g. HeaderLabel, BodyLabel, CaptionLabel. + # [optional] Absolute or relative path to swift file where to export UIKit fonts (UIFont extension). + fontSwift: "./Source/UIComponents/UIFont+extension.swift" + # [optional] Absolute or relative path to swift file where to export SwiftUI fonts (Font extension). + swiftUIFontSwift: "./Source/View/Common/Font+extension.swift" + # Should FigmaExport generate UILabel for each text style (font)? E.g. HeaderLabel, BodyLabel, CaptionLabel generateLabels: true - # Path to directory where to place UILabel for each text style (font) (Requred if generateLabels = true) + # Relative or absolute path to directory where to place UILabel for each text style (font) (Requred if generateLabels = true) labelsDirectory: "./Source/UIComponents/" # [optional] Android export parameters android: + # Relative or absolute path to the `main/res` folder including it. The colors/icons/imags will be exported to this folder mainRes: "./main/res" + # Parameters for exporting images + images: + # Image file format: svg or png + format: webp + # Format options for webp format only + webpOptions: + # Encoding type: lossy or lossless + encoding: lossy + # Encoding quality in percents. Only for lossy encoding. + quality: 90 diff --git a/Sources/FigmaAPI/Endpoint/ComponentsEndpoint.swift b/Sources/FigmaAPI/Endpoint/ComponentsEndpoint.swift index 9f43eeed..35fdd41e 100644 --- a/Sources/FigmaAPI/Endpoint/ComponentsEndpoint.swift +++ b/Sources/FigmaAPI/Endpoint/ComponentsEndpoint.swift @@ -47,9 +47,3 @@ public struct ContainingFrame: Codable { public let name: String? public let pageName: String } - -public enum FrameName: String, Codable { - case components = "Components" - case icons = "Icons" - case illustrations = "Illustrations" -} diff --git a/Sources/FigmaExport/Input/Params.swift b/Sources/FigmaExport/Input/Params.swift index 9ee6fb4b..e80891f4 100644 --- a/Sources/FigmaExport/Input/Params.swift +++ b/Sources/FigmaExport/Input/Params.swift @@ -9,20 +9,22 @@ struct Params: Decodable { struct Common: Decodable { struct Colors: Decodable { - let nameValidateRegexp: String + let nameValidateRegexp: String? } struct Icons: Decodable { - let nameValidateRegexp: String + let nameValidateRegexp: String? + let figmaFrameName: String? } struct Images: Decodable { - let nameValidateRegexp: String + let nameValidateRegexp: String? + let figmaFrameName: String? } - let colors: Colors - let icons: Icons - let images: Images + let colors: Colors? + let icons: Icons? + let images: Images? } enum NameStyle: String, Decodable { diff --git a/Sources/FigmaExport/Loaders/ImagesLoader.swift b/Sources/FigmaExport/Loaders/ImagesLoader.swift index 4b2fa284..e6d974d8 100644 --- a/Sources/FigmaExport/Loaders/ImagesLoader.swift +++ b/Sources/FigmaExport/Loaders/ImagesLoader.swift @@ -8,6 +8,14 @@ final class ImagesLoader { let params: Params let platform: Platform + private var iconsFrameName: String { + params.common?.icons?.figmaFrameName ?? "Icons" + } + + private var imagesFrameName: String { + params.common?.images?.figmaFrameName ?? "Illustrations" + } + init(figmaClient: FigmaClient, params: Params, platform: Platform) { self.figmaClient = figmaClient self.params = params @@ -20,14 +28,14 @@ final class ImagesLoader { (.ios, .svg): return try _loadImages( fileId: params.figma.lightFileId, - frameName: .icons, + frameName: iconsFrameName, params: SVGParams(), filter: filter ).map { ImagePack.singleScale($0) } case (.ios, _): return try _loadImages( fileId: params.figma.lightFileId, - frameName: .icons, + frameName: iconsFrameName, params: PDFParams(), filter: filter ).map { ImagePack.singleScale($0) } @@ -39,13 +47,13 @@ final class ImagesLoader { case (.android, .png), (.android, .webp), (.ios, .none): let lightImages = try loadPNGImages( fileId: params.figma.lightFileId, - frameName: .illustrations, + frameName: imagesFrameName, filter: filter, platform: platform) let darkImages = try params.figma.darkFileId.map { try loadPNGImages( fileId: $0, - frameName: .illustrations, + frameName: imagesFrameName, filter: filter, platform: platform) } @@ -56,14 +64,14 @@ final class ImagesLoader { default: let light = try _loadImages( fileId: params.figma.lightFileId, - frameName: .illustrations, + frameName: imagesFrameName, params: SVGParams(), filter: filter) let dark = try params.figma.darkFileId.map { try _loadImages( fileId: $0, - frameName: .illustrations, + frameName: imagesFrameName, params: SVGParams(), filter: filter) } @@ -76,10 +84,10 @@ final class ImagesLoader { // MARK: - Helpers - private func fetchImageComponents(fileId: String, frameName: FrameName, filter: String? = nil) throws -> [NodeId: Component] { + private func fetchImageComponents(fileId: String, frameName: String, filter: String? = nil) throws -> [NodeId: Component] { var components = try loadComponents(fileId: fileId) .filter { - $0.containingFrame.name == frameName.rawValue && + $0.containingFrame.name == frameName && ($0.description == platform.rawValue || $0.description == nil || $0.description == "") && $0.description?.contains("none") == false } @@ -94,7 +102,7 @@ final class ImagesLoader { return Dictionary(uniqueKeysWithValues: components.map { ($0.nodeId, $0) }) } - private func _loadImages(fileId: String, frameName: FrameName, params: FormatParams, filter: String? = nil) throws -> [Image] { + private func _loadImages(fileId: String, frameName: String, params: FormatParams, filter: String? = nil) throws -> [Image] { let imagesDict = try fetchImageComponents(fileId: fileId, frameName: frameName, filter: filter) guard !imagesDict.isEmpty else { @@ -114,7 +122,7 @@ final class ImagesLoader { } } - private func loadPNGImages(fileId: String, frameName: FrameName, filter: String? = nil, platform: Platform) throws -> [ImagePack] { + private func loadPNGImages(fileId: String, frameName: String, filter: String? = nil, platform: Platform) throws -> [ImagePack] { let imagesDict = try fetchImageComponents(fileId: fileId, frameName: frameName, filter: filter) guard !imagesDict.isEmpty else { diff --git a/Sources/FigmaExport/Subcommands/ExportColors.swift b/Sources/FigmaExport/Subcommands/ExportColors.swift index 18bf4799..6a33e5cf 100644 --- a/Sources/FigmaExport/Subcommands/ExportColors.swift +++ b/Sources/FigmaExport/Subcommands/ExportColors.swift @@ -39,7 +39,7 @@ extension FigmaExportCommand { logger.info("Processing colors...") let processor = ColorsProcessor( platform: .ios, - nameValidateRegexp: params.common?.colors.nameValidateRegexp, + nameValidateRegexp: params.common?.colors?.nameValidateRegexp, nameStyle: params.ios?.colors.nameStyle ) let colorPairs = try processor.process(light: colors.light, dark: colors.dark).get() @@ -54,7 +54,7 @@ extension FigmaExportCommand { logger.info("Processing colors...") let processor = ColorsProcessor( platform: .android, - nameValidateRegexp: params.common?.colors.nameValidateRegexp, + nameValidateRegexp: params.common?.colors?.nameValidateRegexp, nameStyle: .snakeCase ) let colorPairs = try processor.process(light: colors.light, dark: colors.dark).get() diff --git a/Sources/FigmaExport/Subcommands/ExportIcons.swift b/Sources/FigmaExport/Subcommands/ExportIcons.swift index b6123086..a98d2353 100644 --- a/Sources/FigmaExport/Subcommands/ExportIcons.swift +++ b/Sources/FigmaExport/Subcommands/ExportIcons.swift @@ -53,7 +53,7 @@ extension FigmaExportCommand { logger.info("Processing icons...") let processor = ImagesProcessor( platform: .ios, - nameValidateRegexp: params.common?.icons.nameValidateRegexp, + nameValidateRegexp: params.common?.icons?.nameValidateRegexp, nameStyle: params.ios?.icons.nameStyle ) let icons = try processor.process(assets: images).get() @@ -105,7 +105,7 @@ extension FigmaExportCommand { logger.info("Processing icons...") let processor = ImagesProcessor( platform: .android, - nameValidateRegexp: params.common?.icons.nameValidateRegexp, + nameValidateRegexp: params.common?.icons?.nameValidateRegexp, nameStyle: .snakeCase ) let icons = try processor.process(light: images, dark: nil).get() diff --git a/Sources/FigmaExport/Subcommands/ExportImages.swift b/Sources/FigmaExport/Subcommands/ExportImages.swift index 70efa4e2..37962d8d 100644 --- a/Sources/FigmaExport/Subcommands/ExportImages.swift +++ b/Sources/FigmaExport/Subcommands/ExportImages.swift @@ -53,7 +53,7 @@ extension FigmaExportCommand { logger.info("Processing images...") let processor = ImagesProcessor( platform: .ios, - nameValidateRegexp: params.common?.images.nameValidateRegexp, + nameValidateRegexp: params.common?.images?.nameValidateRegexp, nameStyle: params.ios?.images.nameStyle ) let images = try processor.process(light: imagesTuple.light, dark: imagesTuple.dark).get() @@ -102,7 +102,7 @@ extension FigmaExportCommand { logger.info("Processing images...") let processor = ImagesProcessor( platform: .android, - nameValidateRegexp: params.common?.images.nameValidateRegexp, + nameValidateRegexp: params.common?.images?.nameValidateRegexp, nameStyle: .snakeCase ) let images = try processor.process(light: imagesTuple.light, dark: imagesTuple.dark).get()