Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
4a420242a8
commit
ce905431ed
@ -39,6 +39,8 @@ Use this checklist when setting up a new app with Bedrock:
|
|||||||
- [ ] Define custom `SurfaceColorProvider` with your brand colors
|
- [ ] Define custom `SurfaceColorProvider` with your brand colors
|
||||||
- [ ] Define custom `AccentColorProvider` for interactive elements
|
- [ ] Define custom `AccentColorProvider` for interactive elements
|
||||||
- [ ] Create typealiases for easy access (e.g., `AppSurface`, `AppAccent`)
|
- [ ] Create typealiases for easy access (e.g., `AppSurface`, `AppAccent`)
|
||||||
|
- [ ] **Import Bedrock**: Add `import Bedrock` to all files using theme/design constants (Required)
|
||||||
|
- [ ] **Asset Catalog Format**: Ensure `Contents.json` uses the `"color"` key and `"luminosity"` appearance (See `THEME_GUIDE.md` for template)
|
||||||
- [ ] **Legibility Alignment**: Apply `.preferredColorScheme(.dark)` to the root view if using a dark theme to ensure system text resolves to white (Required for legibility)
|
- [ ] **Legibility Alignment**: Apply `.preferredColorScheme(.dark)` to the root view if using a dark theme to ensure system text resolves to white (Required for legibility)
|
||||||
- [ ] Apply theme colors to all views (never use hardcoded colors)
|
- [ ] Apply theme colors to all views (never use hardcoded colors)
|
||||||
|
|
||||||
@ -98,6 +100,7 @@ Then add it to your target:
|
|||||||
Use the `Design` enum for consistent spacing, sizing, and styling:
|
Use the `Design` enum for consistent spacing, sizing, and styling:
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
|
import SwiftUI
|
||||||
import Bedrock
|
import Bedrock
|
||||||
|
|
||||||
struct MyView: View {
|
struct MyView: View {
|
||||||
|
|||||||
@ -59,20 +59,33 @@ public struct AppIconView: View {
|
|||||||
|
|
||||||
// Size calculations
|
// Size calculations
|
||||||
private var iconSize: CGFloat { size * 0.35 }
|
private var iconSize: CGFloat { size * 0.35 }
|
||||||
private var subtitleSize: CGFloat { size * 0.25 }
|
|
||||||
|
/// Dynamic subtitle size based on text length.
|
||||||
|
private var subtitleSize: CGFloat {
|
||||||
|
guard let length = config.subtitle?.count else { return 0 }
|
||||||
|
let baseSize = size * 0.14 // Reduced from 0.25 to prevent overwhelm
|
||||||
|
|
||||||
|
let scaleFactor: CGFloat = switch length {
|
||||||
|
case ...4: 1.0 // "PRO", "PLUS"
|
||||||
|
case 5...6: 0.85 // "SAMPLE", "CAMERA"
|
||||||
|
case 7...9: 0.70 // "MESSENGER"
|
||||||
|
default: 0.55
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseSize * scaleFactor
|
||||||
|
}
|
||||||
|
|
||||||
/// Dynamic title size based on text length.
|
/// Dynamic title size based on text length.
|
||||||
/// Shorter titles get larger fonts, longer titles shrink to fit within the border.
|
/// Shorter titles get larger fonts, longer titles shrink to fit within the border.
|
||||||
private var titleSize: CGFloat {
|
private var titleSize: CGFloat {
|
||||||
let baseSize = size * 0.12
|
let baseSize = size * 0.10 // Adjusted to 0.10 to better balance with subtitle
|
||||||
let length = config.title.count
|
let length = config.title.count
|
||||||
|
|
||||||
// Scale factor: full size for ≤6 chars, progressively smaller for longer
|
// Scale factor: full size for ≤6 chars, progressively smaller for longer
|
||||||
let scaleFactor: CGFloat = switch length {
|
let scaleFactor: CGFloat = switch length {
|
||||||
case ...6: 1.0 // "SELFIE", "CAMERA"
|
case ...6: 1.0 // "BEDROCK", "SELFIE"
|
||||||
case 7: 0.95 // "WEATHER"
|
case 7...8: 0.90 // "SETTINGS"
|
||||||
case 8: 0.85 // "SETTINGS"
|
case 9...10: 0.75 // "MESSENGER"
|
||||||
case 9: 0.75 // "MESSENGER"
|
|
||||||
default: 0.65 // Very long titles
|
default: 0.65 // Very long titles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -465,15 +465,12 @@ extension LaunchScreenConfig {
|
|||||||
cornerSymbol: "sparkle", // Sparkles in corners
|
cornerSymbol: "sparkle", // Sparkles in corners
|
||||||
decorativeSymbol: "circle.fill", // Circle in decorative line
|
decorativeSymbol: "circle.fill", // Circle in decorative line
|
||||||
patternStyle: .radial, // Radial glow effect
|
patternStyle: .radial, // Radial glow effect
|
||||||
layoutStyle: .iconAboveTitle,
|
iconSpacing: 12,
|
||||||
|
animationDuration: 0.6,
|
||||||
primaryColor: Color.Branding.primary,
|
primaryColor: Color.Branding.primary,
|
||||||
secondaryColor: Color.Branding.secondary,
|
secondaryColor: Color.Branding.secondary,
|
||||||
accentColor: Color.Branding.accent,
|
accentColor: Color.Branding.accent,
|
||||||
titleColor: .white,
|
titleColor: .white
|
||||||
iconSize: 52,
|
|
||||||
titleSize: 38,
|
|
||||||
iconSpacing: 12,
|
|
||||||
animationDuration: 0.6
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@ -389,6 +389,67 @@ For dark themes:
|
|||||||
- Text is white with varying opacity
|
- Text is white with varying opacity
|
||||||
- Ensure sufficient contrast (WCAG AA: 4.5:1 for text)
|
- Ensure sufficient contrast (WCAG AA: 4.5:1 for text)
|
||||||
|
|
||||||
|
## Asset Catalog Best Practices
|
||||||
|
|
||||||
|
While you can define colors directly in Swift, the **gold standard** for Bedrock themes is using an **Asset Catalog (`.xcassets`)**. This allows for visual editing, better system integration, and automatic Light/Dark mode switching.
|
||||||
|
|
||||||
|
### 1. Mandatory JSON Structure (Contents.json)
|
||||||
|
|
||||||
|
Xcode is extremely strict about the JSON schema in `.colorset/Contents.json`. To ensure your colors are correctly recognized (avoiding "unassigned children"), use this exact pattern:
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> Use the `"color"` key for data (not `"value"`) and `"appearance": "luminosity"` for theme variants.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "display-p3",
|
||||||
|
"components" : { "alpha": "1.000", "red": "0.06", "green": "0.06", "blue": "0.09" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [ { "appearance": "luminosity", "value": "light" } ],
|
||||||
|
"idiom" : "universal",
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "display-p3",
|
||||||
|
"components" : { "alpha": "1.000", "red": "0.96", "green": "0.96", "blue": "0.98" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [ { "appearance": "luminosity", "value": "dark" } ],
|
||||||
|
"idiom" : "universal",
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "display-p3",
|
||||||
|
"components" : { "alpha": "1.000", "red": "0.06", "green": "0.06", "blue": "0.09" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : { "author" : "xcode", "version" : 1 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. The 3-Variant Pattern
|
||||||
|
|
||||||
|
Always provide **Any (Universal)**, **Light**, and **Dark** variants.
|
||||||
|
- **Any**: Typically matches your dark branding for high-end apps.
|
||||||
|
- **Light/Dark**: Explicit luminosity overrides for standard OS behavior.
|
||||||
|
|
||||||
|
### 3. Folder Namespacing
|
||||||
|
|
||||||
|
Organize colors into folders (`Surface/`, `Text/`, `Accent/`).
|
||||||
|
- Enable **"Provides Namespace"** in the folder's `Contents.json`.
|
||||||
|
- This allows you to reference colors cleanly as `Color("Surface/Primary")` while keeping the catalog organized.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"info" : { "author" : "xcode", "version" : 1 },
|
||||||
|
"properties" : { "provides-namespace" : true }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Migrating Existing Views
|
## Migrating Existing Views
|
||||||
|
|
||||||
If you have views using hardcoded colors, migrate them:
|
If you have views using hardcoded colors, migrate them:
|
||||||
|
|||||||
@ -150,7 +150,7 @@ typealias AppBorder = MyAppBorderColors
|
|||||||
typealias AppInteractive = MyAppInteractiveColors
|
typealias AppInteractive = MyAppInteractiveColors
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Important**: Do NOT add typealiases inside `extension Color { }` as they will conflict with Bedrock's defaults and cause "ambiguous use" compiler errors. Use top-level `App`-prefixed typealiases instead.
|
> **Important**: Do NOT add typealiases inside `extension Color { }` as they will conflict with Bedrock's defaults and cause "ambiguous use" compiler errors. Use top-level `App`-prefixed typealiases instead. Ensure ALL typealiases mentioned in the theme are created, as components like `SettingsToggle` or `SettingsCard` rely on them for consistent branding.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -284,7 +284,7 @@ SettingsSectionHeader(
|
|||||||
|
|
||||||
### SettingsToggle
|
### SettingsToggle
|
||||||
|
|
||||||
A toggle row with title, subtitle, and optional title accessory (e.g., premium crown).
|
A toggle row with title, subtitle, and optional title accessory (e.g., premium crown). **Note: Subtitle is required.**
|
||||||
|
|
||||||
```swift
|
```swift
|
||||||
// Basic toggle
|
// Basic toggle
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user