Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .spi.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
version: 1
external_links:
documentation: "https://zodiackit.markbattistella.com/"
builder:
configs:
- documentation_targets: [ZodiacKit]
platform: ios
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lldb.library": "/Applications/Xcode-16.3.0.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB",
"lldb.launch.expressions": "native"
}
3 changes: 0 additions & 3 deletions Documentation/404.md

This file was deleted.

31 changes: 0 additions & 31 deletions Documentation/index.html

This file was deleted.

2 changes: 0 additions & 2 deletions Documentation/style.min.css

This file was deleted.

File renamed without changes.
4 changes: 3 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ let package = Package(
.iOS(.v13),
.macOS(.v10_15),
.macCatalyst(.v13),
.tvOS(.v13)
.tvOS(.v13),
.watchOS(.v4),
.visionOS(.v1)
],
products: [
.library(
Expand Down
441 changes: 264 additions & 177 deletions README.md

Large diffs are not rendered by default.

83 changes: 0 additions & 83 deletions Sources/ZodiacKit/Defaults/DefaultZodiacs.swift

This file was deleted.

85 changes: 0 additions & 85 deletions Sources/ZodiacKit/Error/ZodiacError.swift

This file was deleted.

94 changes: 94 additions & 0 deletions Sources/ZodiacKit/Extensions/AgnosticColor+Ext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// Project: ZodiacKit
// Author: Mark Battistella
// Website: https://markbattistella.com
//

#if canImport(UIKit)
import UIKit

/// A platform-agnostic typealias for color, using `UIColor` on iOS/tvOS/watchOS.
public typealias AgnosticColor = UIColor

#elseif canImport(AppKit)
import AppKit

/// A platform-agnostic typealias for color, using `NSColor` on macOS.
public typealias AgnosticColor = NSColor
#endif

extension AgnosticColor {

/// Initializes a color from a hexadecimal string.
///
/// Supported formats:
/// - `#RGB`
/// - `#RGBA`
/// - `#RRGGBB`
/// - `#RRGGBBAA`
///
/// The `#` prefix is optional. Alpha defaults to 1.0 if not provided.
///
/// - Parameter hex: A hexadecimal color string.
public convenience init?(hex: String) {
guard let parsedColor = HexColorParser(hex: hex) else { return nil }
self.init(
red: parsedColor.red,
green: parsedColor.green,
blue: parsedColor.blue,
alpha: parsedColor.alpha
)
}
}

/// A helper struct to parse hexadecimal color strings into RGBA components.
internal struct HexColorParser {

/// Alpha component of the color (0.0 - 1.0).
let alpha: CGFloat

/// Red component of the color (0.0 - 1.0).
let red: CGFloat

/// Green component of the color (0.0 - 1.0).
let green: CGFloat

/// Blue component of the color (0.0 - 1.0).
let blue: CGFloat

/// Parses a hexadecimal color string into its RGBA components.
///
/// Handles both short and full formats, with or without alpha:
/// - `RGB`, `RGBA`, `RRGGBB`, `RRGGBBAA`
///
/// - Parameter hex: A string containing the hexadecimal color.
/// - Returns: `nil` if the string is invalid or cannot be parsed.
init?(hex: String) {
var hexString = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()

if hexString.hasPrefix("#") {
hexString.removeFirst()
}

// Expand shorthand formats like RGB or RGBA to RRGGBB or RRGGBBAA
if hexString.count == 3 || hexString.count == 4 {
hexString = hexString.enumerated().map { "\($0.element)\($0.element)" }.joined()
}

guard hexString.count == 6 || hexString.count == 8 else { return nil }

let scanner = Scanner(string: hexString)
var rgbValue: UInt64 = 0
guard scanner.scanHexInt64(&rgbValue) else { return nil }

func normalizeColorComponent(_ component: UInt64) -> CGFloat {
CGFloat(component) / 255.0
}

let alpha = hexString.count == 8 ? (rgbValue >> 24) & 0xFF : 0xFF
self.alpha = normalizeColorComponent(alpha)
self.red = normalizeColorComponent((rgbValue >> 16) & 0xFF)
self.green = normalizeColorComponent((rgbValue >> 8) & 0xFF)
self.blue = normalizeColorComponent(rgbValue & 0xFF)
}
}
29 changes: 29 additions & 0 deletions Sources/ZodiacKit/Extensions/Calendar+Ext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// Project: ZodiacKit
// Author: Mark Battistella
// Website: https://markbattistella.com
//

import Foundation

/// Internal extension to provide commonly used calendar instances.
internal extension Calendar {

/// A Gregorian calendar instance configured to use GMT (UTC) timezone.
///
/// Useful for consistent date calculations that do not depend on the user's local time zone.
static let gregorian = Calendar(identifier: .gregorian).settingGMT()
}

private extension Calendar {

/// Returns a copy of the calendar with its time zone set to GMT (UTC).
///
/// This ensures date calculations remain consistent regardless of the user's local time zone.
/// - Returns: A `Calendar` instance with the time zone set to GMT.
func settingGMT() -> Calendar {
var calendar = self
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
return calendar
}
}
Loading
Loading