Skip to content

Commit

Permalink
Add textColor modifier.
Browse files Browse the repository at this point in the history
Part of #51.
  • Loading branch information
jverkoey committed Aug 3, 2024
1 parent 1327a09 commit c047fdd
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 13 deletions.
34 changes: 34 additions & 0 deletions Sources/Slipstream/TailwindCSS/Color.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// A representation of a color.
@available(iOS 17.0, macOS 14.0, *)
public struct Color {
public static let black = Color(.black)
public static let white = Color(.white)

/// Creates a Color instance using a Tailwind CSS palette instance.
public init(_ colorPalette: ColorPalette, darkness: Int) {
self.storage = .palette(colorPalette, darkness: darkness)
}

init(_ value: Storage) {
self.storage = value
}

enum Storage {
case black
case white
case palette(ColorPalette, darkness: Int)
}
private let storage: Storage

/// Returns the Tailwind CSS color class for this color.
func toTailwindColorClass() -> String {
switch storage {
case .black:
return "black"
case .white:
return "white"
case .palette(let colorPalette, let darkness):
return colorPalette.closestTailwindColorStop(for: darkness)
}
}
}
52 changes: 52 additions & 0 deletions Sources/Slipstream/TailwindCSS/ColorPalette.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/// A representation of a Tailwind CSS color palette.
///
/// - SeeAlso: Tailwind CSS' [`color palettes`](https://tailwindcss.com/docs/customizing-colors) documentation.
@available(iOS 17.0, macOS 14.0, *)
public enum ColorPalette: String {

// MARK: - Grays

case slate
case gray
case zinc
case neutral
case stone

// MARK: - Tones, in order of the rainbow

case red
case orange
case amber
case yellow
case lime
case green
case emerald
case teal
case cyan
case sky
case blue
case indigo
case violet
case purple
case fuchsia
case pink
case rose

/// Chooses the closest tailwind color stop for the given darkness value.
func closestTailwindColorStop(for darkness: Int) -> String {
// Define the range of Tailwind CSS color palette numbers
let paletteNumbers = [0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950, 1000]

// Find the closest palette number
guard let closest = paletteNumbers.min(by: { abs($0 - darkness) < abs($1 - darkness) }) else {
return "500" // Default to middle value if no closest found
}

if closest == 0 {
return "white"
} else if closest == 1000 {
return "black"
}
return "\(rawValue)-\(closest)"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public enum FontSize: String {
}

extension View {
/// Set the font size.
/// Sets the font size.
///
/// - Parameter fontSize: The font size to apply to the modified view.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public enum FontSmoothing: String {
}

extension View {
/// Set the font smoothing for a view.
/// Sets the font smoothing for a view.
///
/// - Parameter fontSmoothing: The font smoothing to apply to the modified view.
///
Expand All @@ -18,7 +18,7 @@ extension View {
return modifier(ClassModifier(add: fontSmoothing.rawValue))
}

/// Set the font smoothing for a view to antialiased.
/// Sets the font smoothing for a view to antialiased.
///
/// - SeeAlso: Tailwind CSS' [`font-smoothing`](https://tailwindcss.com/docs/font-smoothing) documentation.
@available(iOS 17.0, macOS 14.0, *)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public enum FontWeight: String {
}

extension View {
/// Set the font weight.
/// Sets the font weight.
///
/// - Parameter fontWeight: The font weight to apply to the modified view.
///
Expand All @@ -25,7 +25,7 @@ extension View {
return modifier(ClassModifier(add: "font-" + fontWeight.rawValue))
}

/// Set the font weight to the closest equivalent Tailwind CSS font weight.
/// Sets the font weight to the closest equivalent Tailwind CSS font weight.
///
/// - Parameter weight: A font weight value. The closest Tailwind font
/// weight class that matches this weight will be used. If the weight is exactly between
Expand All @@ -37,7 +37,7 @@ extension View {
return fontWeight(closestTailwindFontWeight(weight: weight))
}

/// Set the font weight to bold.
/// Sets the font weight to bold.
///
/// - SeeAlso: Tailwind CSS' [`font-weight`](https://tailwindcss.com/docs/font-weight) documentation.
@available(iOS 17.0, macOS 14.0, *)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public enum TextAlignment: String {
}

extension View {
/// Control the alignment of text.
/// Controls the alignment of text.
///
/// - Parameter alignment: Text alignment to be applied to text within the modified view.
///
Expand Down
24 changes: 24 additions & 0 deletions Sources/Slipstream/TailwindCSS/Typography/View+textColor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
extension View {
/// Sets the text color to a specific Tailwind CSS palette.
///
/// - Parameters:
/// - colorPalette: The Tailwind CSS color palette to use.
/// - darkness: The darkness bracket within the color palette to use.
/// Higher values are darker. 0 corresponds to white, 1000 to black.
///
/// - SeeAlso: Tailwind CSS' [`text-color`](https://tailwindcss.com/docs/text-color) documentation.
/// - SeeAlso: Tailwind CSS' [customizing colors](https://tailwindcss.com/docs/customizing-colors) article.
@available(iOS 17.0, macOS 14.0, *)
public func textColor(_ colorPalette: ColorPalette, darkness: Int) -> some View {
return modifier(ClassModifier(add: "text-" + colorPalette.closestTailwindColorStop(for: darkness)))
}

/// Sets the text color.
///
/// - SeeAlso: Tailwind CSS' [`text-color`](https://tailwindcss.com/docs/text-color) documentation.
/// - SeeAlso: Tailwind CSS' [customizing colors](https://tailwindcss.com/docs/customizing-colors) article.
@available(iOS 17.0, macOS 14.0, *)
public func textColor(_ color: Color) -> some View {
return modifier(ClassModifier(add: "text-" + color.toTailwindColorClass()))
}
}
5 changes: 2 additions & 3 deletions Sources/Slipstream/W3C/Elements/GroupingContent/Div.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/// A view that has no special meaning at all.
///
/// A Div represents its children. It can be used with the ``View/class(_:)``,
/// ``View/language(_:)``, and ``View/title(_:)`` attributes to
/// mark up semantics common to a group of consecutive elements.
/// A Div represents its children. Modifiers applied to a Div will
/// propgate to its children.
///
/// ```swift
/// struct MySiteContent: View {
Expand Down
6 changes: 4 additions & 2 deletions Tests/SlipstreamTests/Sites/CatalogSiteTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ private struct CatalogSite: View {
.margin(.horizontal, .auto)
H6("Heading 6")
.margin(.vertical, 32)
.textColor(.white)
}
.textColor(.red, darkness: 800)
.padding(.horizontal, 48)
}
.id("root")
Expand All @@ -56,15 +58,15 @@ struct CatalogSiteTests {
<link rel="stylesheet" href="/css/bootstrap.css" />
</head>
<body id="root">
<div class="container px-12">
<div class="container text-red-800 px-12">
Hello
<br />world!
<h1 class="text-xl font-bold text-start">Heading 1</h1>
<h2 class="text-3xl text-center">Heading 2</h2>
<h3 class="text-end">Heading 3</h3>
<h4 class="antialiased">Heading 4</h4>
<h5 class="mx-auto">Heading 5</h5>
<h6 class="my-8">Heading 6</h6>
<h6 class="my-8 text-white">Heading 6</h6>
</div>
</body>
</html>
Expand Down
1 change: 0 additions & 1 deletion Tests/SlipstreamTests/TailwindCSS/MarginTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ private struct MarginView: View {
let margins: Int = 32
var body: some View {
Div {

}
.margin(.horizontal, margins)
}
Expand Down
20 changes: 20 additions & 0 deletions Tests/SlipstreamTests/TailwindCSS/TextColorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Testing
import Slipstream

struct TextColorTests {
@Test func darknessValues() throws {
try #expect(renderHTML(Div {}.textColor(.red, darkness: 0)) == #"<div class="text-white"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 50)) == #"<div class="text-red-50"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 100)) == #"<div class="text-red-100"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 200)) == #"<div class="text-red-200"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 300)) == #"<div class="text-red-300"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 400)) == #"<div class="text-red-400"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 500)) == #"<div class="text-red-500"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 600)) == #"<div class="text-red-600"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 700)) == #"<div class="text-red-700"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 800)) == #"<div class="text-red-800"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 900)) == #"<div class="text-red-900"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 950)) == #"<div class="text-red-950"></div>"#)
try #expect(renderHTML(Div {}.textColor(.red, darkness: 1000)) == #"<div class="text-black"></div>"#)
}
}

0 comments on commit c047fdd

Please sign in to comment.