diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Extensions.md b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Extensions.md index c32e12e..7a509ad 100644 --- a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Extensions.md +++ b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Extensions.md @@ -72,7 +72,7 @@ struct ColorfulView: View { } ``` -TODO: add image of above view +![](ColorfulView) When adjusting color brightness, use .luminance instead of .brightness from the HSB color system. Luminance better represents how humans perceive light and dark, which is why HandySwiftUI includes support for the HLC color space. @@ -95,7 +95,7 @@ struct FormattedText: View { } ``` -TODO: add image of above view +![](FormattedText) In the above example, the built-in `.htmlLike` styling that ships with HandySwiftUI is combined with custom tags. Note that `.htmlLike` simply returns this: @@ -230,7 +230,7 @@ extension [String] { } ``` -TODO: add image of TranslateKit's menu bar +![](CommonTranslations) This highlighting feature was originally developed for [TranslateKit]'s menu bar "Common Translations" feature, where it helps users quickly spot matching phrases in their translation history. The function breaks down the search text into tokens and highlights each matching prefix, making it perfect for: diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/New Types.md b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/New Types.md index 3ec4525..11471be 100644 --- a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/New Types.md +++ b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/New Types.md @@ -13,7 +13,7 @@ HandySwiftUI provides a collection of views and types that fill common gaps in S ### Platform-Specific Values -HandySwiftUI provides an elegant way to handle platform-specific values of any type: +HandySwiftUI provides an elegant way to handle platform-specific values: ```swift struct AdaptiveView: View { @@ -27,25 +27,24 @@ struct AdaptiveView: View { Text("Welcome") .padding(Platform.value(default: 20.0, phone: 12.0)) - // Different fonts per platform - Text("Content") - .font(Platform.value(default: .headline, mac: .title3, phone: .subheadline)) - // Different colors per platform Circle() .fill(Platform.value(default: .blue, mac: .indigo, pad: .purple, vision: .cyan)) - - // Even custom enum values - ContentLayout(style: Platform.value(default: .regular, phone: .compact, mac: .expanded)) } } } ``` -TODO: add an image using "Last 30 Days" on Mac and iPhone with different font sizes +![](Last30Days) + +> Image: Getting a similar look across platforms for a title in [FreemiumKit] via: +> ```swift +> .font(Platform.value(default: .title2, phone: .headline)) +> ``` `Platform.value` works with any type - from simple numbers to colors, fonts, or your own custom types. Just provide a default and override specific platforms as needed. This can be enormously useful, especially given that it even has a specific case for iPad named `pad`, so you can even address phones and tablets separately. +This is by far my most-used HandySwiftUI helper saving me a ton of boilerplate `#if` checks. It's simple but so powerful! ### Readable Preview Detection @@ -136,7 +135,7 @@ struct SettingsView: View { } ``` -TODO: add video for above view +![](SettingsView) HandySwiftUI includes `Emoji` and `SFSymbol` enums that contain common emoji and symbols. You can also create custom enums by conforming to `SearchableOption` and providing `searchTerms` for each case to power the search functionality. @@ -231,7 +230,7 @@ struct SecureFileLoader { } ``` -TODO: add photo from FreemiumKit with access dialog +![](OpenPanel) The example taken right out of [FreemiumKit] demonstrates how `OpenPanel` simplifies handling security-scoped file access for dragged items on macOS while maintaining cross-platform compatibility. @@ -242,7 +241,7 @@ An alternative to SwiftUI's `TabView` that implements sidebar-style navigation c ```swift struct MainView: View { - enum Tab: String, Identifiable, CustomLabelConvertible { + enum Tab: String, CaseIterable, Identifiable, CustomLabelConvertible { case documents, recents, settings var id: Self { self } @@ -278,7 +277,7 @@ struct MainView: View { } ``` -TODO: add screenshot from Mac +![](SideTabView) `SideTabView` provides a vertical sidebar with icons and labels, optimized for larger screens with support for bottom-aligned tabs. The view automatically handles platform-specific styling and hover effects. diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Styles.md b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Styles.md index c1db60b..2829c51 100644 --- a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Styles.md +++ b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/Styles.md @@ -28,14 +28,17 @@ struct ButtonShowcase: View { .buttonStyle(.secondary()) // Attention-grabbing pulsating button - Button("Updates", systemName: "bell.fill") {} - .buttonStyle(.pulsating(color: .blue, cornerRadius: 20, glowRadius: 8, duration: 2)) + Button {} label: { + Label("Updates", systemImage: "bell.fill") + .padding(15) + } + .buttonStyle(.pulsating(color: .blue, cornerRadius: 20, glowRadius: 8, duration: 2)) } } } ``` -TODO: add video showcasing above view +![](ButtonStyles) ### Horizontal, Vertical, Fixed Icon-Width Labels @@ -97,11 +100,11 @@ struct APIConfigView: View { } ``` -TODO: add image from FreemiumKit +![](VerticalLabeledContent) The `.vertical` style allows customizing alignment (defaults to `leading`) and spacing (defaults to 4). Pass `muteLabel: false` if you're providing a custom label style, as by default labels are automatically styled smaller and grayed out. -For example: +For example, in [FreemiumKit]'s feature localization form, I want the vertical label to have a larger font: ```swift LabeledContent { @@ -114,7 +117,7 @@ LabeledContent { .labeledContentStyle(.vertical(muteLabel: false)) ``` -TODO: add image from FreemiumKit +![](MuteLabelFalse) ### Multi-Platform Toggle Style @@ -138,7 +141,7 @@ struct ProductRow: View { } ``` -TODO: add image from FreemiumKit iOS +![](CheckboxUniversal) The example is extracted from [FreemiumKit]'s products screen, which is optimized for macOS but also supports other platforms. diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/View Modifiers.md b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/View Modifiers.md index 983b5fe..ec57d95 100644 --- a/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/View Modifiers.md +++ b/Sources/HandySwiftUI/HandySwiftUI.docc/Essentials/View Modifiers.md @@ -33,7 +33,9 @@ struct AdaptiveText: View { } ``` -TODO: add example image from TranslateKit (API keys view when test unsuccessful) +![](YellowWithContrast) + +> Image: This warning indicator in [TranslateKit] uses `.yellow` but ensures a good contrast even in light mode to be legible. The `minContrast` parameter (ranging from 0 to 1) determines the minimum contrast ratio against either white (in dark mode) or black (in light mode) using the luminance value (perceived brightness). This ensures text stays readable regardless of the current color scheme. @@ -106,7 +108,10 @@ Text("With HandySwiftUI") .roundedRectangleBorder(.blue, cornerRadius: 12, lineWidth: 2) ``` -TODO: add example from TranslateKit badges +![](StateBadges) + +> Image: Badges in [TranslateKit] use this for rounded borders, for example. + ### Conditional Modifiers @@ -226,7 +231,9 @@ struct TodoView: View { } ``` -TODO: add example from CrossCraft when deleting a puzzle +![](ConfirmDelete) + +> Image: Puzzle deletion in [CrossCraft] with a confirmation dialog to avoid accidental deletes. The example shows how `.confirmDeleteDialog` handles the entire deletion flow – from confirmation to execution – with a single modifier. The dialog is automatically localized in ~40 languages and follows platform design guidelines. You can provide an optional `message` parameter in case you need to provide a different message. There's also an overload that takes a boolean for situations where no list is involved. diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/ColorfulView.png b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/ColorfulView.png new file mode 100644 index 0000000..55119c3 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/ColorfulView.png differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/CommonTranslations.jpeg b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/CommonTranslations.jpeg new file mode 100644 index 0000000..af36bdd Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/CommonTranslations.jpeg differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/FormattedText.png b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/FormattedText.png new file mode 100644 index 0000000..8252a9d Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/FormattedText.png differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/Last30Days.jpeg b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/Last30Days.jpeg new file mode 100644 index 0000000..3ea27df Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Extensions/Last30Days.jpeg differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/OpenPanel.jpeg b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/OpenPanel.jpeg new file mode 100644 index 0000000..3bad64a Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/OpenPanel.jpeg differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/SettingsView.gif b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/SettingsView.gif new file mode 100644 index 0000000..8c48890 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/SettingsView.gif differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/SideTabView.png b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/SideTabView.png new file mode 100644 index 0000000..781391d Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/NewTypes/SideTabView.png differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/ButtonStyles.gif b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/ButtonStyles.gif new file mode 100644 index 0000000..b5a3224 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/ButtonStyles.gif differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/CheckboxUniversal.png b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/CheckboxUniversal.png new file mode 100644 index 0000000..49aea51 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/CheckboxUniversal.png differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/MuteLabelFalse.jpeg b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/MuteLabelFalse.jpeg new file mode 100644 index 0000000..9bc5878 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/MuteLabelFalse.jpeg differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/VerticalLabeledContent.jpeg b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/VerticalLabeledContent.jpeg new file mode 100644 index 0000000..0f27816 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/Styles/VerticalLabeledContent.jpeg differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/ConfirmDelete.jpeg b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/ConfirmDelete.jpeg new file mode 100644 index 0000000..7cfdc42 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/ConfirmDelete.jpeg differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/StateBadges.png b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/StateBadges.png new file mode 100644 index 0000000..8d5f30b Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/StateBadges.png differ diff --git a/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/YellowWithContrast.png b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/YellowWithContrast.png new file mode 100644 index 0000000..2c07dc5 Binary files /dev/null and b/Sources/HandySwiftUI/HandySwiftUI.docc/Resources/ViewModifiers/YellowWithContrast.png differ diff --git a/Sources/HandySwiftUI/Types/Models/Emoji.swift b/Sources/HandySwiftUI/Types/Models/Emoji.swift index 3958d60..60cd769 100644 --- a/Sources/HandySwiftUI/Types/Models/Emoji.swift +++ b/Sources/HandySwiftUI/Types/Models/Emoji.swift @@ -1889,7 +1889,7 @@ extension Emoji: SearchableOption { /// """ public var view: some View { Text(self.rawValue) - .font(.largeTitle) + .font(.title3) } #warning("🧑‍💻 localize the search terms to support more languages") diff --git a/Sources/HandySwiftUI/Types/Views/HPicker.swift b/Sources/HandySwiftUI/Types/Views/HPicker.swift index f1acbfd..fcdeccb 100644 --- a/Sources/HandySwiftUI/Types/Views/HPicker.swift +++ b/Sources/HandySwiftUI/Types/Views/HPicker.swift @@ -63,7 +63,7 @@ public struct HPicker, selection: Binding, label: @escaping () -> L) { + public init(options: [T], locked: Set = [], selection: Binding, label: @escaping () -> L) { self.options = options self.locked = locked self.selection = selection diff --git a/Sources/HandySwiftUI/Types/Views/SearchableGridPicker.swift b/Sources/HandySwiftUI/Types/Views/SearchableGridPicker.swift index 98401f6..6cc8e4f 100644 --- a/Sources/HandySwiftUI/Types/Views/SearchableGridPicker.swift +++ b/Sources/HandySwiftUI/Types/Views/SearchableGridPicker.swift @@ -38,7 +38,7 @@ public struct SearchableGridPicker: View { @Binding var selection: Option? - @State var showPicker: Bool = Xcode.isRunningForPreviews + @State var showPicker: Bool = false @State var searchText: String = "" /// Filters the available options based on the entered search text. @@ -77,7 +77,7 @@ public struct SearchableGridPicker: View { ZStack { HStack { Text(self.title) - .foregroundStyle(.secondary) + .foregroundStyle(Platform.value(default: .primary, mac: .secondary)) Spacer() @@ -89,6 +89,8 @@ public struct SearchableGridPicker: View { } Image(systemName: "chevron.right") + .font(.system(size: 13.5).weight(.semibold)) + .opacity(0.55) } .foregroundStyle(.secondary) } @@ -112,9 +114,9 @@ public struct SearchableGridPicker: View { } label: { ZStack { option.view - .padding(Platform.value(default: 15, mac: 12)) + .padding(Platform.value(default: 12, mac: 8)) #if os(visionOS) - .contentShape(.hoverEffect, .rect(cornerRadius: 15)) + .contentShape(.hoverEffect, .rect(cornerRadius: 12)) .hoverEffect() #endif