1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
/*
This source file is part of the Swift.org open source project
Copyright (c) 2021 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception
See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/
/// A Tutorial Article section.
public struct TutorialArticleSection: RenderSection, Equatable {
public let kind: RenderSectionKind = .articleBody
/// The contents of the Tutorial Article.
public var content: [ContentLayout] = []
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
content = try container.decodeIfPresent([ContentLayout].self, forKey: .content) ?? []
}
/// Creates a tutorial article section from a given list
/// of content layout items.
///
/// - Parameter content: The content for this section.
public init(content: [ContentLayout]) {
self.content = content
}
}
/// The layout in which the content should be presented.
public enum ContentLayout: Equatable {
/// A full-width layout.
case fullWidth(content: [RenderBlockContent])
/// A layout for a piece of media that has an attached description.
case contentAndMedia(content: ContentAndMediaSection)
/// A multi-column layout.
case columns(content: [ContentAndMediaSection])
}
extension ContentLayout: Codable {
private enum CodingKeys: CodingKey {
case kind
case content
}
private enum LayoutKind: String, Codable {
case fullWidth, contentAndMedia, columns
}
private var kind: LayoutKind {
switch self {
case .fullWidth: return .fullWidth
case .contentAndMedia: return .contentAndMedia
case .columns: return .columns
}
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let kind = try container.decode(LayoutKind.self, forKey: .kind)
switch kind {
case .fullWidth:
self = try .fullWidth(content: container.decode([RenderBlockContent].self, forKey: .content))
case .contentAndMedia:
self = .contentAndMedia(content: try ContentAndMediaSection(from: decoder))
case .columns:
self = try .columns(content: container.decode([ContentAndMediaSection].self, forKey: .content))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(kind, forKey: .kind)
switch self {
case .fullWidth(let content):
try container.encode(content, forKey: .content)
case .contentAndMedia(let content):
try content.encode(to: encoder)
case .columns(let content):
try container.encode(content, forKey: .content)
}
}
}
// Diffable conformance
extension TutorialArticleSection: RenderJSONDiffable {
/// Returns the differences between this TutorialArticleSection and the given one.
func difference(from other: TutorialArticleSection, at path: CodablePath) -> JSONPatchDifferences {
var diffBuilder = DifferenceBuilder(current: self, other: other, basePath: path)
diffBuilder.addDifferences(atKeyPath: \.kind, forKey: CodingKeys.kind)
diffBuilder.addDifferences(atKeyPath: \.content, forKey: CodingKeys.content)
return diffBuilder.differences
}
/// Returns if this TutorialArticleSection is similar enough to the given one.
func isSimilar(to other: TutorialArticleSection) -> Bool {
return self.content == other.content
}
}
|