Skip to content

Commit

Permalink
Add authoring support for the @PageColor directive (swiftlang#525)
Browse files Browse the repository at this point in the history
Adds a new `@PageColor` metadata directive that allows for
customizing the color used to represent a given page.

`@PageColor` gives authors control over the color used
when rendering a page – initially this will affect the background
color Swift-DocC-Render uses in the page's introduction (hero) section.

Example:

    # What's New in SlothCreator

    @metadata {
        @PageColor(blue)
    }

    ![A sloth on a tree wearing a fedora.](sloth-fedora)

    Let's check out what's new in SlothCreator!

    ...

Details:

`@PageColor` accepts the following parameters:

  - `color`: An unnamed parameter that accepts one of the following:

     - `blue`: A context-dependent blue color.

     - `gray`: A context-dependent gray color.

     - `green`: A context-dependent orange color.

     - `orange`: A context-dependent orange color.

     - `purple`: A context-dependent purple color.

     - `red`: A context-dependent red color.

     - `yellow`: A context-dependent yellow color.

`@PageColor` is described on the Swift forums here:
https://forums.swift.org/t/support-for-customizing-a-page-s-accent-color-in-swift-docc/64093

Dependencies:

- swiftlang/swift-docc-render#582

rdar://106153042
  • Loading branch information
ethan-kusters committed Apr 7, 2023
1 parent fb643e3 commit 9cfbd39
Show file tree
Hide file tree
Showing 15 changed files with 392 additions and 15 deletions.
43 changes: 43 additions & 0 deletions Sources/SwiftDocC/Model/Rendering/References/TopicColor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2023 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 color that associated with a documentation topic.
public struct TopicColor: Codable, Hashable {
/// A string identifier for a built-in, standard color.
///
/// This value is expected to be one of the following:
/// - term `blue`: A context-dependent blue color.
///
/// - term `gray`: A context-dependent gray color.
///
/// - term `green`: A context-dependent orange color.
///
/// - term `orange`: A context-dependent orange color.
///
/// - term `purple`: A context-dependent purple color.
///
/// - term `red`: A context-dependent red color.
///
/// - term `yellow`: A context-dependent yellow color.
///
/// @Comment {
/// This value is optional to allow for a future where topic colors
/// can be defined by something besides the standard color identifiers.
///
/// For example, we may allow fully custom colors in the future and allow
/// for providing some kind of `ColorReference` here.
/// }
public let standardColorIdentifier: String?

/// Create a topic color with the given standard color identifier.
public init(standardColorIdentifier: String) {
self.standardColorIdentifier = standardColorIdentifier
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ public struct RenderMetadata: VariantContainer {
/// Authors can use the `@PageImage` metadata directive to provide custom icon and card images for a page.
public var images: [TopicImage] = []

/// Custom authored color that represents this page.
///
/// Authors can use the `@PageColor` metadata directive to provide a custom color for a page.
public var color: TopicColor?

/// Author provided custom metadata describing the page.
public var customMetadata: [String: String] = [:]

Expand Down Expand Up @@ -231,6 +236,7 @@ extension RenderMetadata: Codable {
public static let remoteSource = CodingKeys(stringValue: "remoteSource")
public static let tags = CodingKeys(stringValue: "tags")
public static let images = CodingKeys(stringValue: "images")
public static let color = CodingKeys(stringValue: "color")
public static let customMetadata = CodingKeys(stringValue: "customMetadata")
}

Expand All @@ -247,6 +253,7 @@ extension RenderMetadata: Codable {
requiredVariants = try container.decodeVariantCollectionIfPresent(ofValueType: Bool.self, forKey: .required) ?? .init(defaultValue: false)
roleHeadingVariants = try container.decodeVariantCollectionIfPresent(ofValueType: String?.self, forKey: .roleHeading)
images = try container.decodeIfPresent([TopicImage].self, forKey: .images) ?? []
color = try container.decodeIfPresent(TopicColor.self, forKey: .color)
customMetadata = try container.decodeIfPresent([String: String].self, forKey: .customMetadata) ?? [:]
let rawRole = try container.decodeIfPresent(String.self, forKey: .role)
role = rawRole == "tutorial" ? Role.tutorial.rawValue : rawRole
Expand Down Expand Up @@ -321,6 +328,7 @@ extension RenderMetadata: Codable {
}

try container.encodeIfNotEmpty(images, forKey: .images)
try container.encodeIfPresent(color, forKey: .color)
try container.encodeIfNotEmpty(customMetadata, forKey: .customMetadata)
}
}
4 changes: 4 additions & 0 deletions Sources/SwiftDocC/Model/Rendering/RenderNodeTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,10 @@ public struct RenderNodeTranslator: SemanticVisitor {
)
}
}

if let pageColor = documentationNode.metadata?.pageColor {
node.metadata.color = TopicColor(standardColorIdentifier: pageColor.rawValue)
}

var metadataCustomDictionary : [String: String] = [:]
if let customMetadatas = documentationNode.metadata?.customMetadata {
Expand Down
11 changes: 10 additions & 1 deletion Sources/SwiftDocC/Semantics/Metadata/Metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ public final class Metadata: Semantic, AutomaticDirectiveConvertible {
@ChildDirective(requirements: .zeroOrMore)
var supportedLanguages: [SupportedLanguage]

@ChildDirective
var _pageColor: PageColor? = nil

/// The optional, context-dependent color used to represent this page.
var pageColor: PageColor.Color? {
_pageColor?.color
}

static var keyPaths: [String : AnyKeyPath] = [
"documentationOptions" : \Metadata._documentationOptions,
"technologyRoot" : \Metadata._technologyRoot,
Expand All @@ -71,6 +79,7 @@ public final class Metadata: Semantic, AutomaticDirectiveConvertible {
"availability" : \Metadata._availability,
"pageKind" : \Metadata._pageKind,
"supportedLanguages" : \Metadata._supportedLanguages,
"_pageColor" : \Metadata.__pageColor,
]

/// Creates a metadata object with a given markup, documentation extension, and technology root.
Expand All @@ -93,7 +102,7 @@ public final class Metadata: Semantic, AutomaticDirectiveConvertible {

func validate(source: URL?, for bundle: DocumentationBundle, in context: DocumentationContext, problems: inout [Problem]) -> Bool {
// Check that something is configured in the metadata block
if documentationOptions == nil && technologyRoot == nil && displayName == nil && pageImages.isEmpty && customMetadata.isEmpty && callToAction == nil && availability.isEmpty && pageKind == nil {
if documentationOptions == nil && technologyRoot == nil && displayName == nil && pageImages.isEmpty && customMetadata.isEmpty && callToAction == nil && availability.isEmpty && pageKind == nil && pageColor == nil {
let diagnostic = Diagnostic(
source: source,
severity: .information,
Expand Down
69 changes: 69 additions & 0 deletions Sources/SwiftDocC/Semantics/Metadata/PageColor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2023 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
*/

import Foundation
import Markdown

/// A directive that specifies an accent color for a given documentation page.
///
/// Use the `PageColor` directive to provide a hint to the renderer as to how
/// the page should be accented with color. The renderer may use this color,
/// depending on the context, as a foundation for other colors used on the
/// page. For example, Swift-DocC-Render uses this color as the primary
/// background color of a page's introduction section and adjusts other
/// elements in the introduction section to account for the new background.
///
/// This directive is only valid within a ``Metadata`` directive:
///
/// ```markdown
/// @Metadata {
/// @PageColor(orange)
/// }
/// ```
public final class PageColor: Semantic, AutomaticDirectiveConvertible {
public let originalMarkup: BlockDirective

/// A context-dependent, standard color.
@DirectiveArgumentWrapped(name: .unnamed)
public var color: Color

/// A context-dependent, standard color.
public enum Color: String, CaseIterable, DirectiveArgumentValueConvertible {
/// A context-dependent blue color.
case blue

/// A context-dependent gray color.
case gray

/// A context-dependent green color.
case green

/// A context-dependent orange color.
case orange

/// A context-dependent purple color.
case purple

/// A context-dependent red color.
case red

/// A context-dependent yellow color.
case yellow
}

static var keyPaths: [String : AnyKeyPath] = [
"color": \PageColor._color,
]

@available(*, deprecated, message: "Do not call directly. Required for 'AutomaticDirectiveConvertible'.")
init(originalMarkup: BlockDirective) {
self.originalMarkup = originalMarkup
}
}
12 changes: 12 additions & 0 deletions Sources/SwiftDocC/SwiftDocC.docc/Resources/RenderNode.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -1791,6 +1791,15 @@
}
}
},
"TopicColor": {
"type": "object",
"properties": {
"standardColorIdentifier": {
"type": "string",
"enum": ["blue", "gray", "green", "orange", "purple", "red", "yellow"]
}
}
},
"SymbolTag": {
"type": "object",
"required": [
Expand Down Expand Up @@ -2250,6 +2259,9 @@
"$ref": "#/components/schemas/TopicImage"
}
},
"color": {
"$ref": "#/components/schemas/TopicColor"
},
"customMetadata": {
"type": "object",
"description" : "A dictionary containing arbitrary, user-provided metadata key/value pairs.\n\nThese values are authored using the `@CustomMetadata(key:value:)` directive.",
Expand Down
21 changes: 21 additions & 0 deletions Sources/SwiftDocC/SwiftDocC.docc/Resources/ThemeSettings.spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,27 @@
"secondary-label": {
"$ref": "#/components/schemas/Color"
},
"standard-blue-documentation-intro-fill": {
"$ref": "#/components/schemas/Color"
},
"standard-gray-documentation-intro-fill": {
"$ref": "#/components/schemas/Color"
},
"standard-green-documentation-intro-fill": {
"$ref": "#/components/schemas/Color"
},
"standard-orange-documentation-intro-fill": {
"$ref": "#/components/schemas/Color"
},
"standard-purple-documentation-intro-fill": {
"$ref": "#/components/schemas/Color"
},
"standard-red-documentation-intro-fill": {
"$ref": "#/components/schemas/Color"
},
"standard-yellow-documentation-intro-fill": {
"$ref": "#/components/schemas/Color"
},
"step-background": {
"$ref": "#/components/schemas/Color"
},
Expand Down
Loading

0 comments on commit 9cfbd39

Please sign in to comment.