Skip to content

Instantly share code, notes, and snippets.

@jayesh15111988
Created September 2, 2022 09:39
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jayesh15111988/ec13ecf2f87035239e6a5d4c6a046958 to your computer and use it in GitHub Desktop.
A source code to demo applying attributed strings attribute from markdown styles
//
// CustomAttributedStringTextView.swift
// SwiftUIBlogPosts
//
// Created by Jayesh Kawli on 8/31/22.
//
import SwiftUI
struct CustomAttributedStringTextViewModel {
let customAttributedInputString: AttributedString
init() {
let inputString = "^[Amsterdam](cityStyle: 'amsterdamStyle', cityColor: 'amsterdamColor') is a great city and ^[regular rainbow style](rainbowStyle: 'regular') awesome city to live in ^[first half rainbow style](rainbowStyle: 'firstHalf') or ^[second half rainbow style](rainbowStyle: 'secondHalf')"
self.customAttributedInputString = (try? AttributedString(
markdown: inputString,
including: AttributeScopes.CustomCityAttributes.self,
options: AttributedString.MarkdownParsingOptions(allowsExtendedAttributes: true))) ?? AttributedString(inputString)
}
}
struct CustomAttributedStringTextView: View {
let customAttributedStringTextViewModel: CustomAttributedStringTextViewModel
init() {
self.customAttributedStringTextViewModel = CustomAttributedStringTextViewModel()
}
var body: some View {
Text(customStyledAttributedString(input: customAttributedStringTextViewModel.customAttributedInputString))
.padding()
}
private func customStyledAttributedString(input: AttributedString) -> AttributedString {
var output = input
for run in output.runs {
let customCityAttributes = run.customCityAttributes
guard customCityAttributes.customCityStyle != nil || customCityAttributes.customColorStyle != nil || customCityAttributes.customRainbowStyle != nil else {
continue
}
let range = run.range
if let customCityStyle = customCityAttributes.customCityStyle {
if customCityStyle == .amsterdamStyle {
output[range].font = .largeTitle
}
}
if let customColorStyle = customCityAttributes.customColorStyle {
if customColorStyle == .amsterdamColor {
output[range].foregroundColor = .orange
}
}
if let customRainbowStyle = customCityAttributes.customRainbowStyle {
let rainbowColorsCollection: [Color]
switch customRainbowStyle {
case .regular:
rainbowColorsCollection = rainbowColorsCollectionFull
case .firstHalf:
rainbowColorsCollection = rainbowColorsCollectionFirstHalf
case .secondHalf:
rainbowColorsCollection = rainbowColorsCollectionSecondHalf
}
var integerIndex = 0
for i in output[range].characters.indices {
output[i..<output[range].characters.index(after: i)].foregroundColor = rainbowColorsCollection[integerIndex % rainbowColorsCollection.count]
integerIndex += 1
}
}
}
return output
}
private var rainbowColorsCollectionFull: [Color] {
[.red, .orange, .yellow, .green, .blue, .indigo, .purple]
}
private var rainbowColorsCollectionFirstHalf: [Color] {
[.red, .orange, .yellow]
}
private var rainbowColorsCollectionSecondHalf: [Color] {
[.green, .blue, .indigo, .purple]
}
}
public enum CustomCityStyleAttributes: CodableAttributedStringKey, MarkdownDecodableAttributedStringKey {
public enum Value: String, Codable {
case amsterdamStyle
}
public static var name = "cityStyle"
}
public enum CustomCityColorAttributes: CodableAttributedStringKey, MarkdownDecodableAttributedStringKey {
public enum Value: String, Codable {
case amsterdamColor
}
public static var name = "cityColor"
}
public enum CustomRainbowStyleAttributes: CodableAttributedStringKey, MarkdownDecodableAttributedStringKey {
public enum Value: String, Codable {
case regular
case firstHalf
case secondHalf
}
public static var name = "rainbowStyle"
}
public extension AttributeScopes {
struct CustomCityAttributes: AttributeScope {
let customCityStyle: CustomCityStyleAttributes
let customColorStyle: CustomCityColorAttributes
let customRainbowStyle: CustomRainbowStyleAttributes
let swiftUI: SwiftUIAttributes
}
var customCityAttributes: CustomCityAttributes.Type { CustomCityAttributes.self }
}
@between40and2
Copy link

customStyledAttributedString can be refactored to support any new attribute-style definition ,on-demand , in plug-in fashion (vs currently modify the method’s content)

Good job!

@between40and2
Copy link

This (in gist) is far more easy to write than @-ing you in TT. 😃

^[string_to_decorate](attribute_key_1: attribute_value_1, attribute_key_2: attribute_value_2), this piece can be reinterpreted as ^[concept](semantic_this : … , style_that : … , annotation_for_classification: …) - think in CSS’s element’s class and style attributes. That will make the purpose of annotation not only for styling but also anything else (and potentially later re-styling)

This Apple’s markdown extension, supporting dictionary and more, is far more expressive than CSS’s class attribute’s merely flat string list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment