Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to Compose Structure #15

Closed
wants to merge 19 commits into from
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@
//
// Created by Kai Azim on 2024-04-02.
//
// Thank you https://movingparts.io/variadic-views-in-swiftui
// Thanks to https://movingparts.io/variadic-views-in-swiftui

import SwiftUI

public struct DividedVStack<Content: View>: View {
public struct DividedVStack<Content>: View where Content: View {
let spacing: CGFloat?
let applyMaskToItems: Bool
let showDividers: Bool
var content: Content

@ViewBuilder let content: () -> Content

public init(spacing: CGFloat? = nil, applyMaskToItems: Bool = true, showDividers: Bool = true, @ViewBuilder content: () -> Content) {
public init(
spacing: CGFloat? = nil,
applyMaskToItems: Bool = true,
showDividers: Bool = true,
@ViewBuilder content: @escaping () -> Content
) {
self.spacing = spacing
self.applyMaskToItems = applyMaskToItems
self.showDividers = showDividers
self.content = content()
self.content = content
}

public var body: some View {
Expand All @@ -29,7 +35,7 @@ public struct DividedVStack<Content: View>: View {
showDividers: showDividers
)
) {
content
content()
}
}
}
Expand All @@ -38,7 +44,6 @@ struct DividedVStackLayout: _VariadicView_UnaryViewRoot {
let spacing: CGFloat
let applyMaskToItems: Bool
let showDividers: Bool

let innerPadding: CGFloat = 4

init(spacing: CGFloat?, applyMaskToItems: Bool, showDividers: Bool) {
Expand Down Expand Up @@ -88,8 +93,8 @@ public struct LuminareCroppedSectionItem: ViewModifier {
let innerPadding: CGFloat = 4
let innerCornerRadius: CGFloat = 2

let isFirstChild: Bool
let isLastChild: Bool
private let isFirstChild: Bool
private let isLastChild: Bool

public init(isFirstChild: Bool, isLastChild: Bool) {
self.isFirstChild = isFirstChild
Expand Down Expand Up @@ -134,3 +139,14 @@ public struct LuminareCroppedSectionItem: ViewModifier {
}
}
}

#Preview {
LuminareSection {
DividedVStack {
ForEach(37..<43) { num in
Text("\(num)")
}
}
}
.padding()
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import SwiftUI

public struct LuminareButtonStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled: Bool

let innerCornerRadius: CGFloat = 2
let elementMinHeight: CGFloat = 34
@State var isHovering: Bool = false

@State private var isHovering: Bool = false

public init() {}

Expand Down Expand Up @@ -45,8 +47,10 @@ public struct LuminareButtonStyle: ButtonStyle {

public struct LuminareDestructiveButtonStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled: Bool

let innerCornerRadius: CGFloat = 2
let elementMinHeight: CGFloat = 34

@State var isHovering: Bool = false

public init() {}
Expand Down Expand Up @@ -81,8 +85,10 @@ public struct LuminareDestructiveButtonStyle: ButtonStyle {

public struct LuminareCosmeticButtonStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled: Bool

let innerCornerRadius: CGFloat = 2
let elementMinHeight: CGFloat = 34

@State var isHovering: Bool = false
let icon: Image

Expand Down Expand Up @@ -126,25 +132,26 @@ public struct LuminareCosmeticButtonStyle: ButtonStyle {

public struct LuminareCompactButtonStyle: ButtonStyle {
@Environment(\.isEnabled) private var isEnabled: Bool

let elementMinHeight: CGFloat = 34
let elementExtraMinHeight: CGFloat = 25
let extraCompact: Bool
let borderlessWhileNotHovering: Bool

@State var isHovering: Bool = false
let cornerRadius: CGFloat = 8

public init(extraCompact: Bool = false) {
public init(extraCompact: Bool = false, borderlessWhileNotHovering: Bool = false) {
self.extraCompact = extraCompact
self.borderlessWhileNotHovering = borderlessWhileNotHovering
}

public func makeBody(configuration: Configuration) -> some View {
configuration.label
.padding(.horizontal, extraCompact ? 0 : 12)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(backgroundForState(isPressed: configuration.isPressed))
.background {
RoundedRectangle(cornerRadius: cornerRadius)
.strokeBorder(.quaternary, lineWidth: 1)
}
.background(border())
.fixedSize(horizontal: extraCompact, vertical: extraCompact)
.clipShape(.rect(cornerRadius: cornerRadius))
.onHover { hover in
Expand All @@ -156,15 +163,35 @@ public struct LuminareCompactButtonStyle: ButtonStyle {
.frame(minHeight: extraCompact ? elementExtraMinHeight : elementMinHeight)
.opacity(isEnabled ? 1 : 0.5)
}

@ViewBuilder private func border() -> some View {
Group {
if isHovering || !borderlessWhileNotHovering {
RoundedRectangle(cornerRadius: cornerRadius)
.strokeBorder(.quaternary, lineWidth: 1)
} else {
RoundedRectangle(cornerRadius: cornerRadius)
.strokeBorder(.clear, lineWidth: 1)
}
}
}

private func backgroundForState(isPressed: Bool) -> some View {
@ViewBuilder private func backgroundForState(isPressed: Bool) -> some View {
Group {
if isPressed {
Rectangle().foregroundStyle(.quaternary)
} else if isHovering {
Rectangle().foregroundStyle(.quaternary.opacity(0.7))
if borderlessWhileNotHovering {
Rectangle().foregroundStyle(.quinary)
} else {
Rectangle().foregroundStyle(.quaternary.opacity(0.7))
}
} else {
Rectangle().foregroundStyle(.quinary)
if borderlessWhileNotHovering {
Rectangle().foregroundStyle(.clear)
} else {
Rectangle().foregroundStyle(.quinary)
}
}
}
}
Expand Down
101 changes: 101 additions & 0 deletions Sources/Luminare/Components/Auxiliary/LuminareInfoView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//
// LuminareInfoView.swift
//
//
// Created by Kai Azim on 2024-06-02.
//

import SwiftUI

public struct LuminareInfoView<Content>: View where Content: View {
let color: Color
let arrowEdge: Edge

@ViewBuilder private let content: () -> Content

@State private var isShowingDescription: Bool = false
@State private var isHovering: Bool = false
@State private var hoverTimer: Timer?

public init(
color: Color = .accentColor,
arrowEdge: Edge = .bottom,
@ViewBuilder content: @escaping () -> Content
) {
self.color = color
self.arrowEdge = arrowEdge
self.content = content
}

public init(
_ key: LocalizedStringKey,
color: Color = .accentColor,
arrowEdge: Edge = .bottom
) where Content == Text {
self.init(color: color, arrowEdge: arrowEdge) {
Text(key)
}
}

public init() where Content == EmptyView {
self.init {
EmptyView()
}
}

public var body: some View {
VStack {
Circle()
.foregroundStyle(color)
.frame(width: 4, height: 4)
.padding(.leading, 4)
.padding(12)
.contentShape(.circle)
.padding(-12)
.onHover { hovering in
isHovering = hovering

if isHovering {
hoverTimer = Timer.scheduledTimer(withTimeInterval: 0.25, repeats: false) { _ in
isShowingDescription = true
}
} else {
hoverTimer?.invalidate()
isShowingDescription = false
}
}

.popover(isPresented: $isShowingDescription, arrowEdge: arrowEdge) {
content()
.multilineTextAlignment(.center)
}

Spacer()
}
}
}

#Preview {
LuminareSection {
LuminareCompose {
} label: {
Text("Pops to bottom")
} info: {
LuminareInfoView {
Text("An info description")
.padding()
}
}

LuminareCompose {
} label: {
Text("Pops to trailing")
} info: {
LuminareInfoView(color: .violet, arrowEdge: .trailing) {
Text("An info description")
.padding()
}
}
}
.padding()
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ struct ColorHueSliderView: View {
@State private var selectionCornerRadius: CGFloat = 0
@State private var selectionWidth: CGFloat = 0

// Gradient for the color spectrum slider
// gradient for the color spectrum slider
private let colorSpectrumGradient = Gradient(
colors: stride(from: 0.0, through: 1.0, by: 0.01)
.map {
Expand Down Expand Up @@ -109,3 +109,10 @@ struct ColorHueSliderView: View {
return 15 * edgeFactor
}
}

#Preview {
LuminareSection {
ColorHueSliderView(selectedColor: .constant(.accentColor))
}
.padding()
}
Loading
Loading