Skip to content

Instantly share code, notes, and snippets.

@egabor
Last active February 19, 2022 20:07
Show Gist options
  • Save egabor/3a9ef11b0efa376407da49ecc6eb9991 to your computer and use it in GitHub Desktop.
Save egabor/3a9ef11b0efa376407da49ecc6eb9991 to your computer and use it in GitHub Desktop.
[FONT] Snippets for Xcode for generating strongly typed font resources. [SwiftGen 6.0]
pod 'SwiftGen', '~> 6.0'
if [[ -f "${PODS_ROOT}/SwiftGen/bin/swiftgen" ]]; then
"${PODS_ROOT}/SwiftGen/bin/swiftgen" config run --config <#$SRCROOT/path-to-config-file#>/swiftgen-fonts.yml
else
echo "warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it."
fi
input_dir: <#ProjectName#>/<#Resources#>
output_dir: <#ProjectName#>/<#Resources#>/Generated/
fonts:
inputs:
- Fonts/OpenSans
outputs:
params:
enumName: Fonts
publicAccess: true
templatePath: "swiftui-fonts.stencil"
output: Fonts.swift
// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
{% if families %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set fontType %}{{param.fontTypeName|default:"FontConvertible"}}{% endset %}
#if os(OSX)
import AppKit.NSFont
#elseif os(iOS) || os(tvOS) || os(watchOS)
import UIKit.UIFont
#endif
import SwiftUI
// Deprecated typealiases
@available(*, deprecated, renamed: "{{fontType}}.Font", message: "This typealias will be removed in SwiftGen 7.0")
{{accessModifier}} typealias {{param.fontAliasName|default:"Font"}} = {{fontType}}.Font
// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length
// MARK: - Fonts
// swiftlint:disable identifier_name line_length type_body_length
{% macro transformPath path %}{% filter removeNewlines %}
{% if param.preservePath %}
{{path}}
{% else %}
{{path|basename}}
{% endif %}
{% endfilter %}{% endmacro %}
{{accessModifier}} enum {{param.enumName|default:"FontFamily"}} {
{% for family in families %}
{{accessModifier}} enum {{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} {
{% for font in family.fonts %}
{{accessModifier}} static let {{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{fontType}}(name: "{{font.name}}", family: "{{family.name}}", path: "{% call transformPath font.path %}")
{% endfor %}
{{accessModifier}} static let all: [{{fontType}}] = [{% for font in family.fonts %}{{font.style|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}{{ ", " if not forloop.last }}{% endfor %}]
}
{% endfor %}
{{accessModifier}} static let allCustomFonts: [{{fontType}}] = [{% for family in families %}{{family.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.all{{ ", " if not forloop.last }}{% endfor %}].flatMap { $0 }
{{accessModifier}} static func registerAllCustomFonts() {
allCustomFonts.forEach { $0.register() }
}
}
// swiftlint:enable identifier_name line_length type_body_length
// MARK: - Implementation Details
{{accessModifier}} struct {{fontType}} {
{{accessModifier}} let name: String
{{accessModifier}} let family: String
{{accessModifier}} let path: String
#if os(OSX)
{{accessModifier}} typealias Font = NSFont
#elseif os(iOS) || os(tvOS) || os(watchOS)
{{accessModifier}} typealias Font = UIFont
#endif
{{accessModifier}} func font(size: CGFloat) -> Font {
guard let font = Font(font: self, size: size) else {
fatalError("Unable to initialize font '\(name)' (\(family))")
}
return font
}
{{accessModifier}} func swiftUIFont(fixedSize: CGFloat) -> SwiftUI.Font {
if #available(iOS 14.0, *) {
return SwiftUI.Font.custom(name, fixedSize: fixedSize)
} else {
return SwiftUI.Font(UIFont(name: name, size: fixedSize)!)
}
}
{{accessModifier}} func swiftUIFont(size: CGFloat, relativeTo textStyle: SwiftUI.Font.TextStyle = .body) -> SwiftUI.Font {
if #available(iOS 14.0, *) {
return SwiftUI.Font.custom(name, size: size, relativeTo: textStyle)
} else {
return SwiftUI.Font(UIFont(name: name, size: size)!)
}
}
{{accessModifier}} func register() {
// swiftlint:disable:next conditional_returns_on_newline
guard let url = url else { return }
CTFontManagerRegisterFontsForURL(url as CFURL, .process, nil)
}
fileprivate var url: URL? {
// swiftlint:disable:next implicit_return
{% if param.lookupFunction %}
return {{param.lookupFunction}}(name, family, path)
{% else %}
return {{param.bundle|default:"BundleToken.bundle"}}.url(forResource: path, withExtension: nil)
{% endif %}
}
}
{{accessModifier}} extension {{fontType}}.Font {
convenience init?(font: {{fontType}}, size: CGFloat) {
#if os(iOS) || os(tvOS) || os(watchOS)
if !UIFont.fontNames(forFamilyName: font.family).contains(font.name) {
font.register()
}
#elseif os(OSX)
if let url = font.url, CTFontManagerGetScopeForURL(url as CFURL) == .none {
font.register()
}
#endif
self.init(name: font.name, size: size)
}
}
{% if not param.bundle and not param.lookupFunction %}
// swiftlint:disable convenience_type
private final class BundleToken {
static let bundle: Bundle = {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle(for: BundleToken.self)
#endif
}()
}
// swiftlint:enable convenience_type
{% endif %}
{% else %}
// No fonts found
{% endif %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment