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
|
/*
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 section containing textual content and media laid out horizontally or vertically.
public struct ContentAndMediaSection: RenderSection, Equatable {
public var kind: RenderSectionKind = .contentAndMedia
/// The layout direction.
public var layout: Layout?
/// The title of the section.
public var title: String?
/// Text to display above the title.
public var eyebrow: String?
/// The body content of the section.
public var content: [RenderBlockContent] = []
/// An image or video to display opposite the text.
public var media: RenderReferenceIdentifier?
/// Whether the media comes before or after the text when read from top to bottom or leading to trailing.
public var mediaPosition: ContentAndMedia.MediaPosition
/// The kind of layout to use when rendering a section.
/// Content is always leading, and media is always trailing.
public enum Layout: String, Codable {
/// Content should be laid out horizontally, with the media on the trailing side.
case horizontal
/// Content should be laid out vertically, with the media trailing the content.
case vertical
}
/// Creates a new content and media section from the given parameters.
///
/// - Parameters:
/// - layout: The layout direction for the section.
/// - title: The title of the section.
/// - media: A reference to a media item for the section.
/// - mediaPosition: The position of the media in relation to the prose content.
public init(layout: Layout?, title: String?, media: RenderReferenceIdentifier?, mediaPosition: ContentAndMedia.MediaPosition) {
self.layout = layout
self.title = title
self.media = media
self.mediaPosition = mediaPosition
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
kind = try container.decodeIfPresent(RenderSectionKind.self, forKey: .kind) ?? .contentAndMedia
layout = try container.decodeIfPresent(Layout.self, forKey: .layout)
title = try container.decodeIfPresent(String.self, forKey: .title)
eyebrow = try container.decodeIfPresent(String.self, forKey: .eyebrow)
content = try container.decodeIfPresent([RenderBlockContent].self, forKey: .content) ?? []
media = try container.decodeIfPresent(RenderReferenceIdentifier.self, forKey: .media)
mediaPosition = try container.decodeIfPresent(ContentAndMedia.MediaPosition.self, forKey: .mediaPosition)
// Provide backwards-compatibility for ContentAndMediaSections that don't have a `mediaPosition` key.
?? .leading
}
}
// Diffable conformance
extension ContentAndMediaSection: RenderJSONDiffable {
/// Returns the differences between this ContentAndMediaSection and the given one.
func difference(from other: ContentAndMediaSection, at path: CodablePath) -> JSONPatchDifferences {
var diffBuilder = DifferenceBuilder(current: self, other: other, basePath: path)
diffBuilder.addDifferences(atKeyPath: \.kind, forKey: CodingKeys.kind)
diffBuilder.addDifferences(atKeyPath: \.layout, forKey: CodingKeys.layout)
diffBuilder.addDifferences(atKeyPath: \.title, forKey: CodingKeys.title)
diffBuilder.addDifferences(atKeyPath: \.eyebrow, forKey: CodingKeys.eyebrow)
diffBuilder.addDifferences(atKeyPath: \.content, forKey: CodingKeys.content)
diffBuilder.addDifferences(atKeyPath: \.media, forKey: CodingKeys.media)
diffBuilder.addDifferences(atKeyPath: \.mediaPosition, forKey: CodingKeys.mediaPosition)
return diffBuilder.differences
}
/// Returns if this ContentAndMediaSection is similar enough to the given one.
func isSimilar(to other: ContentAndMediaSection) -> Bool {
return self.title == other.title || self.content == other.content
}
}
|