diff --git a/Sources/MarkdownUI/Theme/Theme+DocC.swift b/Sources/MarkdownUI/Theme/Theme+DocC.swift index 43cf1939..82ce575f 100644 --- a/Sources/MarkdownUI/Theme/Theme+DocC.swift +++ b/Sources/MarkdownUI/Theme/Theme+DocC.swift @@ -16,10 +16,10 @@ extension Theme { /// Table | ![](DocCTable) public static let docC = Theme() .text { - ForegroundColor(.text) + ForegroundColor(.MD.DocCTheme.text) } .link { - ForegroundColor(.link) + ForegroundColor(.MD.DocCTheme.link) } .heading1 { configuration in configuration.label @@ -86,9 +86,9 @@ extension Theme { .background { ZStack { RoundedRectangle.container - .fill(Color.asideNoteBackground) + .fill(Color.MD.DocCTheme.asideNoteBackground) RoundedRectangle.container - .strokeBorder(Color.asideNoteBorder) + .strokeBorder(Color.MD.DocCTheme.asideNoteBorder) } } .markdownMargin(top: .em(1.6), bottom: .zero) @@ -105,7 +105,7 @@ extension Theme { .padding(.vertical, 8) .padding(.leading, 14) } - .background(Color.codeBackground) + .background(Color.MD.DocCTheme.codeBackground) .clipShape(.container) .markdownMargin(top: .em(0.8), bottom: .zero) } @@ -126,7 +126,7 @@ extension Theme { .table { configuration in configuration.label .fixedSize(horizontal: false, vertical: true) - .markdownTableBorderStyle(.init(.horizontalBorders, color: .grid)) + .markdownTableBorderStyle(.init(.horizontalBorders, color: .MD.DocCTheme.grid)) .markdownMargin(top: .em(1.6), bottom: .zero) } .tableCell { configuration in @@ -142,7 +142,7 @@ extension Theme { } .thematicBreak { Divider() - .overlay(Color.grid) + .overlay(Color.MD.DocCTheme.grid) .markdownMargin(top: .em(2.35), bottom: .em(2.35)) } } @@ -153,26 +153,28 @@ extension Shape where Self == RoundedRectangle { } } -extension Color { - fileprivate static let text = Color( - light: Color(rgba: 0x1d1d_1fff), dark: Color(rgba: 0xf5f5_f7ff) - ) - fileprivate static let secondaryLabel = Color( - light: Color(rgba: 0x6e6e_73ff), dark: Color(rgba: 0x8686_8bff) - ) - fileprivate static let link = Color( - light: Color(rgba: 0x0066_ccff), dark: Color(rgba: 0x2997_ffff) - ) - fileprivate static let asideNoteBackground = Color( - light: Color(rgba: 0xf5f5_f7ff), dark: Color(rgba: 0x3232_32ff) - ) - fileprivate static let asideNoteBorder = Color( - light: Color(rgba: 0x6969_69ff), dark: Color(rgba: 0x9a9a_9eff) - ) - fileprivate static let codeBackground = Color( - light: Color(rgba: 0xf5f5_f7ff), dark: Color(rgba: 0x3333_36ff) - ) - fileprivate static let grid = Color( - light: Color(rgba: 0xd2d2_d7ff), dark: Color(rgba: 0x4242_45ff) - ) +extension Color.MD { + struct DocCTheme { + fileprivate static let text = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x1d1d_1fff), dark: Color.MD.rgbaColor(rgba: 0xf5f5_f7ff) + ) + fileprivate static let secondaryLabel = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x6e6e_73ff), dark: Color.MD.rgbaColor(rgba: 0x8686_8bff) + ) + fileprivate static let link = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x0066_ccff), dark: Color.MD.rgbaColor(rgba: 0x2997_ffff) + ) + fileprivate static let asideNoteBackground = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0xf5f5_f7ff), dark: Color.MD.rgbaColor(rgba: 0x3232_32ff) + ) + fileprivate static let asideNoteBorder = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x6969_69ff), dark: Color.MD.rgbaColor(rgba: 0x9a9a_9eff) + ) + fileprivate static let codeBackground = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0xf5f5_f7ff), dark: Color.MD.rgbaColor(rgba: 0x3333_36ff) + ) + fileprivate static let grid = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0xd2d2_d7ff), dark: Color.MD.rgbaColor(rgba: 0x4242_45ff) + ) + } } diff --git a/Sources/MarkdownUI/Theme/Theme+GitHub.swift b/Sources/MarkdownUI/Theme/Theme+GitHub.swift index 90f32ff3..b9271788 100644 --- a/Sources/MarkdownUI/Theme/Theme+GitHub.swift +++ b/Sources/MarkdownUI/Theme/Theme+GitHub.swift @@ -16,20 +16,20 @@ extension Theme { /// Table | ![](GitHubTable) public static let gitHub = Theme() .text { - ForegroundColor(.text) - BackgroundColor(.background) + ForegroundColor(.MD.GithubTheme.text) + BackgroundColor(.MD.GithubTheme.background) FontSize(16) } .code { FontFamilyVariant(.monospaced) FontSize(.em(0.85)) - BackgroundColor(.secondaryBackground) + BackgroundColor(.MD.GithubTheme.secondaryBackground) } .strong { FontWeight(.semibold) } .link { - ForegroundColor(.link) + ForegroundColor(.MD.GithubTheme.link) } .heading1 { configuration in VStack(alignment: .leading, spacing: 0) { @@ -41,7 +41,7 @@ extension Theme { FontWeight(.semibold) FontSize(.em(2)) } - Divider().overlay(Color.divider) + Divider().overlay(Color.MD.GithubTheme.divider) } } .heading2 { configuration in @@ -54,7 +54,7 @@ extension Theme { FontWeight(.semibold) FontSize(.em(1.5)) } - Divider().overlay(Color.divider) + Divider().overlay(Color.MD.GithubTheme.divider) } } .heading3 { configuration in @@ -90,7 +90,7 @@ extension Theme { .markdownTextStyle { FontWeight(.semibold) FontSize(.em(0.85)) - ForegroundColor(.tertiaryText) + ForegroundColor(.MD.GithubTheme.tertiaryText) } } .paragraph { configuration in @@ -102,10 +102,10 @@ extension Theme { .blockquote { configuration in HStack(spacing: 0) { RoundedRectangle(cornerRadius: 6) - .fill(Color.border) + .fill(Color.MD.GithubTheme.border) .relativeFrame(width: .em(0.2)) configuration.label - .markdownTextStyle { ForegroundColor(.secondaryText) } + .markdownTextStyle { ForegroundColor(.MD.GithubTheme.secondaryText) } .relativePadding(.horizontal, length: .em(1)) } .fixedSize(horizontal: false, vertical: true) @@ -121,7 +121,7 @@ extension Theme { } .padding(16) } - .background(Color.secondaryBackground) + .background(Color.MD.GithubTheme.secondaryBackground) .clipShape(RoundedRectangle(cornerRadius: 6)) .markdownMargin(top: 0, bottom: 16) } @@ -132,16 +132,16 @@ extension Theme { .taskListMarker { configuration in Image(systemName: configuration.isCompleted ? "checkmark.square.fill" : "square") .symbolRenderingMode(.hierarchical) - .foregroundStyle(Color.checkbox, Color.checkboxBackground) + .foregroundStyle(Color.MD.GithubTheme.checkbox, Color.MD.GithubTheme.checkboxBackground) .imageScale(.small) .relativeFrame(minWidth: .em(1.5), alignment: .trailing) } .table { configuration in configuration.label .fixedSize(horizontal: false, vertical: true) - .markdownTableBorderStyle(.init(color: .border)) + .markdownTableBorderStyle(.init(color: .MD.GithubTheme.border)) .markdownTableBackgroundStyle( - .alternatingRows(Color.background, Color.secondaryBackground) + .alternatingRows(Color.MD.GithubTheme.background, Color.MD.GithubTheme.secondaryBackground) ) .markdownMargin(top: 0, bottom: 16) } @@ -161,36 +161,38 @@ extension Theme { .thematicBreak { Divider() .relativeFrame(height: .em(0.25)) - .overlay(Color.border) + .overlay(Color.MD.GithubTheme.border) .markdownMargin(top: 24, bottom: 24) } } -extension Color { - fileprivate static let text = Color( - light: Color(rgba: 0x0606_06ff), dark: Color(rgba: 0xfbfb_fcff) - ) - fileprivate static let secondaryText = Color( - light: Color(rgba: 0x6b6e_7bff), dark: Color(rgba: 0x9294_a0ff) - ) - fileprivate static let tertiaryText = Color( - light: Color(rgba: 0x6b6e_7bff), dark: Color(rgba: 0x6d70_7dff) - ) - fileprivate static let background = Color( - light: .white, dark: Color(rgba: 0x1819_1dff) - ) - fileprivate static let secondaryBackground = Color( - light: Color(rgba: 0xf7f7_f9ff), dark: Color(rgba: 0x2526_2aff) - ) - fileprivate static let link = Color( - light: Color(rgba: 0x2c65_cfff), dark: Color(rgba: 0x4c8e_f8ff) - ) - fileprivate static let border = Color( - light: Color(rgba: 0xe4e4_e8ff), dark: Color(rgba: 0x4244_4eff) - ) - fileprivate static let divider = Color( - light: Color(rgba: 0xd0d0_d3ff), dark: Color(rgba: 0x3334_38ff) - ) - fileprivate static let checkbox = Color(rgba: 0xb9b9_bbff) - fileprivate static let checkboxBackground = Color(rgba: 0xeeee_efff) +extension Color.MD { + struct GithubTheme { + fileprivate static let text = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x0606_06ff), dark: Color.MD.rgbaColor(rgba: 0xfbfb_fcff) + ) + fileprivate static let secondaryText = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x6b6e_7bff), dark: Color.MD.rgbaColor(rgba: 0x9294_a0ff) + ) + fileprivate static let tertiaryText = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x6b6e_7bff), dark: Color.MD.rgbaColor(rgba: 0x6d70_7dff) + ) + fileprivate static let background = Color.MD.displayMode( + light: .white, dark: Color.MD.rgbaColor(rgba: 0x1819_1dff) + ) + fileprivate static let secondaryBackground = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0xf7f7_f9ff), dark: Color.MD.rgbaColor(rgba: 0x2526_2aff) + ) + fileprivate static let link = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0x2c65_cfff), dark: Color.MD.rgbaColor(rgba: 0x4c8e_f8ff) + ) + fileprivate static let border = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0xe4e4_e8ff), dark: Color.MD.rgbaColor(rgba: 0x4244_4eff) + ) + fileprivate static let divider = Color.MD.displayMode( + light: Color.MD.rgbaColor(rgba: 0xd0d0_d3ff), dark: Color.MD.rgbaColor(rgba: 0x3334_38ff) + ) + fileprivate static let checkbox = Color.MD.rgbaColor(rgba: 0xb9b9_bbff) + fileprivate static let checkboxBackground = Color.MD.rgbaColor(rgba: 0xeeee_efff) + } } diff --git a/Sources/MarkdownUI/Utility/Color+RGBA.swift b/Sources/MarkdownUI/Utility/Color+RGBA.swift index 583e9a4c..4a491f84 100644 --- a/Sources/MarkdownUI/Utility/Color+RGBA.swift +++ b/Sources/MarkdownUI/Utility/Color+RGBA.swift @@ -1,47 +1,49 @@ import SwiftUI extension Color { - /// Creates a constant color from an RGBA value. - /// - Parameter rgba: A 32-bit value that represents the red, green, blue, and alpha components of the color. - public init(rgba: UInt32) { - self.init( - red: CGFloat((rgba & 0xff00_0000) >> 24) / 255.0, - green: CGFloat((rgba & 0x00ff_0000) >> 16) / 255.0, - blue: CGFloat((rgba & 0x0000_ff00) >> 8) / 255.0, - opacity: CGFloat(rgba & 0x0000_00ff) / 255.0 - ) - } - - /// Creates a context-dependent color with different values for light and dark appearances. - /// - Parameters: - /// - light: The light appearance color value. - /// - dark: The dark appearance color value. - public init(light: @escaping @autoclosure () -> Color, dark: @escaping @autoclosure () -> Color) { - #if os(watchOS) - self = dark() - #elseif canImport(UIKit) - self.init( - uiColor: .init { traitCollection in - switch traitCollection.userInterfaceStyle { - case .unspecified, .light: - return UIColor(light()) - case .dark: - return UIColor(dark()) - @unknown default: - return UIColor(light()) - } + struct MD { + /// Creates a constant color from an RGBA value. + /// - Parameter rgba: A 32-bit value that represents the red, green, blue, and alpha components of the color. + static func rgbaColor(rgba: UInt32) -> Color { + Color.init( + red: CGFloat((rgba & 0xff00_0000) >> 24) / 255.0, + green: CGFloat((rgba & 0x00ff_0000) >> 16) / 255.0, + blue: CGFloat((rgba & 0x0000_ff00) >> 8) / 255.0, + opacity: CGFloat(rgba & 0x0000_00ff) / 255.0 + ) } - ) - #elseif canImport(AppKit) - self.init( - nsColor: .init(name: nil) { appearance in - if appearance.bestMatch(from: [.aqua, .darkAqua]) == .aqua { - return NSColor(light()) - } else { - return NSColor(dark()) - } + + /// Creates a context-dependent color with different values for light and dark appearances. + /// - Parameters: + /// - light: The light appearance color value. + /// - dark: The dark appearance color value. + static func displayMode(light: @escaping @autoclosure () -> Color, dark: @escaping @autoclosure () -> Color) -> Color { +#if os(watchOS) + return dark() +#elseif canImport(UIKit) + return Color.init( + uiColor: .init { traitCollection in + switch traitCollection.userInterfaceStyle { + case .unspecified, .light: + return UIColor(light()) + case .dark: + return UIColor(dark()) + @unknown default: + return UIColor(light()) + } + } + ) +#elseif canImport(AppKit) + return Color.init( + nsColor: .init(name: nil) { appearance in + if appearance.bestMatch(from: [.aqua, .darkAqua]) == .aqua { + return NSColor(light()) + } else { + return NSColor(dark()) + } + } + ) +#endif } - ) - #endif - } + } }