Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
4bec90cc31
commit
3807ba38dd
@ -20,7 +20,7 @@ extension Design {
|
|||||||
static let avatarLarge: CGFloat = 80
|
static let avatarLarge: CGFloat = 80
|
||||||
static let avatarOverlap: CGFloat = 40
|
static let avatarOverlap: CGFloat = 40
|
||||||
static let logoSize: CGFloat = 64
|
static let logoSize: CGFloat = 64
|
||||||
static let bannerHeight: CGFloat = 140
|
static let bannerHeight: CGFloat = 240
|
||||||
static let qrSize: CGFloat = 200
|
static let qrSize: CGFloat = 200
|
||||||
static let qrSizeLarge: CGFloat = 260
|
static let qrSizeLarge: CGFloat = 260
|
||||||
static let colorSwatchSize: CGFloat = 40
|
static let colorSwatchSize: CGFloat = 40
|
||||||
|
|||||||
@ -49,6 +49,7 @@ private struct CardBannerView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(height: Design.CardSize.bannerHeight)
|
.frame(height: Design.CardSize.bannerHeight)
|
||||||
|
.clipped()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,11 +59,13 @@ private struct ProfileBannerContent: View {
|
|||||||
let card: BusinessCard
|
let card: BusinessCard
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
ZStack {
|
ZStack {
|
||||||
if let photoData = card.photoData, let uiImage = UIImage(data: photoData) {
|
if let photoData = card.photoData, let uiImage = UIImage(data: photoData) {
|
||||||
Image(uiImage: uiImage)
|
Image(uiImage: uiImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
|
.frame(width: geometry.size.width, height: geometry.size.height)
|
||||||
.clipped()
|
.clipped()
|
||||||
} else {
|
} else {
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
@ -83,6 +86,7 @@ private struct ProfileBannerContent: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Logo Banner Content
|
// MARK: - Logo Banner Content
|
||||||
|
|
||||||
@ -90,6 +94,7 @@ private struct LogoBannerContent: View {
|
|||||||
let card: BusinessCard
|
let card: BusinessCard
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
ZStack {
|
ZStack {
|
||||||
LinearGradient(
|
LinearGradient(
|
||||||
colors: [card.theme.primaryColor, card.theme.secondaryColor],
|
colors: [card.theme.primaryColor, card.theme.secondaryColor],
|
||||||
@ -101,6 +106,7 @@ private struct LogoBannerContent: View {
|
|||||||
Image(uiImage: uiImage)
|
Image(uiImage: uiImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
|
.frame(width: geometry.size.width, height: geometry.size.height)
|
||||||
.clipped()
|
.clipped()
|
||||||
} else {
|
} else {
|
||||||
VStack(spacing: Design.Spacing.xSmall) {
|
VStack(spacing: Design.Spacing.xSmall) {
|
||||||
@ -115,6 +121,7 @@ private struct LogoBannerContent: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Cover Banner Content
|
// MARK: - Cover Banner Content
|
||||||
|
|
||||||
@ -122,10 +129,12 @@ private struct CoverBannerContent: View {
|
|||||||
let card: BusinessCard
|
let card: BusinessCard
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
if let coverPhotoData = card.coverPhotoData, let uiImage = UIImage(data: coverPhotoData) {
|
if let coverPhotoData = card.coverPhotoData, let uiImage = UIImage(data: coverPhotoData) {
|
||||||
Image(uiImage: uiImage)
|
Image(uiImage: uiImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
|
.frame(width: geometry.size.width, height: geometry.size.height)
|
||||||
.clipped()
|
.clipped()
|
||||||
} else {
|
} else {
|
||||||
ZStack {
|
ZStack {
|
||||||
@ -147,6 +156,7 @@ private struct CoverBannerContent: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Content View
|
// MARK: - Content View
|
||||||
|
|
||||||
@ -325,7 +335,7 @@ private struct ContactFieldsListView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: Design.Spacing.small) {
|
VStack(alignment: .leading, spacing: Design.Spacing.small) {
|
||||||
ForEach(card.orderedContactFields) { field in
|
ForEach(card.orderedContactFields) { field in
|
||||||
ContactFieldRowView(field: field) {
|
ContactFieldRowView(field: field, themeColor: card.theme.primaryColor) {
|
||||||
if let url = field.buildURL() {
|
if let url = field.buildURL() {
|
||||||
openURL(url)
|
openURL(url)
|
||||||
}
|
}
|
||||||
@ -337,6 +347,7 @@ private struct ContactFieldsListView: View {
|
|||||||
|
|
||||||
private struct ContactFieldRowView: View {
|
private struct ContactFieldRowView: View {
|
||||||
let field: ContactField
|
let field: ContactField
|
||||||
|
let themeColor: Color
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -346,7 +357,7 @@ private struct ContactFieldRowView: View {
|
|||||||
.font(.body)
|
.font(.body)
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.frame(width: Design.CardSize.socialIconSize, height: Design.CardSize.socialIconSize)
|
.frame(width: Design.CardSize.socialIconSize, height: Design.CardSize.socialIconSize)
|
||||||
.background(field.iconColor)
|
.background(themeColor)
|
||||||
.clipShape(.circle)
|
.clipShape(.circle)
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
|||||||
@ -212,7 +212,7 @@ struct CardEditorView: View {
|
|||||||
if !contactFields.isEmpty {
|
if !contactFields.isEmpty {
|
||||||
Section {
|
Section {
|
||||||
ForEach(contactFields) { field in
|
ForEach(contactFields) { field in
|
||||||
ContactFieldRowView(field: field) {
|
ContactFieldRowView(field: field, themeColor: selectedTheme.primaryColor) {
|
||||||
fieldToEdit = field
|
fieldToEdit = field
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,7 +231,7 @@ struct CardEditorView: View {
|
|||||||
|
|
||||||
// Add new contact fields
|
// Add new contact fields
|
||||||
Section {
|
Section {
|
||||||
ContactFieldPickerView { fieldType in
|
ContactFieldPickerView(themeColor: selectedTheme.primaryColor) { fieldType in
|
||||||
selectedFieldTypeForAdd = fieldType
|
selectedFieldTypeForAdd = fieldType
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
@ -284,6 +284,7 @@ struct CardEditorView: View {
|
|||||||
fieldType: fieldType,
|
fieldType: fieldType,
|
||||||
initialValue: "",
|
initialValue: "",
|
||||||
initialTitle: fieldType.titleSuggestions.first ?? "",
|
initialTitle: fieldType.titleSuggestions.first ?? "",
|
||||||
|
themeColor: selectedTheme.primaryColor,
|
||||||
onSave: { value, title in
|
onSave: { value, title in
|
||||||
addContactField(fieldType: fieldType, value: value, title: title)
|
addContactField(fieldType: fieldType, value: value, title: title)
|
||||||
}
|
}
|
||||||
@ -294,6 +295,7 @@ struct CardEditorView: View {
|
|||||||
fieldType: field.fieldType,
|
fieldType: field.fieldType,
|
||||||
initialValue: field.value,
|
initialValue: field.value,
|
||||||
initialTitle: field.title,
|
initialTitle: field.title,
|
||||||
|
themeColor: selectedTheme.primaryColor,
|
||||||
onSave: { value, title in
|
onSave: { value, title in
|
||||||
updateContactField(id: field.id, value: value, title: title)
|
updateContactField(id: field.id, value: value, title: title)
|
||||||
},
|
},
|
||||||
@ -555,6 +557,7 @@ private struct ImageLayoutRow: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
|
||||||
// Live card preview based on selected layout
|
// Live card preview based on selected layout
|
||||||
|
VStack(spacing: 0) {
|
||||||
ZStack(alignment: .bottomLeading) {
|
ZStack(alignment: .bottomLeading) {
|
||||||
// Banner preview based on layout
|
// Banner preview based on layout
|
||||||
EditorBannerPreviewView(
|
EditorBannerPreviewView(
|
||||||
@ -569,10 +572,18 @@ private struct ImageLayoutRow: View {
|
|||||||
// Overlay content based on layout
|
// Overlay content based on layout
|
||||||
if hasOverlappingContent {
|
if hasOverlappingContent {
|
||||||
overlayContent
|
overlayContent
|
||||||
.offset(x: Design.Spacing.large, y: Design.CardSize.avatarOverlap)
|
.padding(.leading, Design.Spacing.large)
|
||||||
|
.padding(.trailing, Design.Spacing.large)
|
||||||
|
.offset(y: Design.CardSize.avatarOverlap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spacer to make room for overlapping content
|
||||||
|
if hasOverlappingContent {
|
||||||
|
Spacer()
|
||||||
|
.frame(height: Design.CardSize.avatarOverlap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.bottom, hasOverlappingContent ? Design.CardSize.avatarOverlap : 0)
|
|
||||||
|
|
||||||
// Layout selector button
|
// Layout selector button
|
||||||
Button(action: onSelectLayout) {
|
Button(action: onSelectLayout) {
|
||||||
@ -628,14 +639,16 @@ private struct EditorBannerPreviewView: View {
|
|||||||
let selectedHeaderLayout: CardHeaderLayout
|
let selectedHeaderLayout: CardHeaderLayout
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
GeometryReader { geometry in
|
||||||
Group {
|
Group {
|
||||||
switch selectedHeaderLayout.bannerContent {
|
switch selectedHeaderLayout.bannerContent {
|
||||||
case .profile:
|
case .profile:
|
||||||
profileBannerPreview
|
profileBannerPreview(size: geometry.size)
|
||||||
case .logo:
|
case .logo:
|
||||||
logoBannerPreview
|
logoBannerPreview(size: geometry.size)
|
||||||
case .cover:
|
case .cover:
|
||||||
coverBannerPreview
|
coverBannerPreview(size: geometry.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(height: Design.CardSize.bannerHeight)
|
.frame(height: Design.CardSize.bannerHeight)
|
||||||
@ -645,12 +658,13 @@ private struct EditorBannerPreviewView: View {
|
|||||||
// MARK: - Layout Previews
|
// MARK: - Layout Previews
|
||||||
|
|
||||||
/// Profile photo fills the banner
|
/// Profile photo fills the banner
|
||||||
private var profileBannerPreview: some View {
|
private func profileBannerPreview(size: CGSize) -> some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
if let photoData, let uiImage = UIImage(data: photoData) {
|
if let photoData, let uiImage = UIImage(data: photoData) {
|
||||||
Image(uiImage: uiImage)
|
Image(uiImage: uiImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
|
.frame(width: size.width, height: size.height)
|
||||||
.clipped()
|
.clipped()
|
||||||
} else {
|
} else {
|
||||||
themeGradient
|
themeGradient
|
||||||
@ -668,7 +682,7 @@ private struct EditorBannerPreviewView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Logo (3:2) fills the banner
|
/// Logo (3:2) fills the banner
|
||||||
private var logoBannerPreview: some View {
|
private func logoBannerPreview(size: CGSize) -> some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
themeGradient
|
themeGradient
|
||||||
|
|
||||||
@ -676,6 +690,7 @@ private struct EditorBannerPreviewView: View {
|
|||||||
Image(uiImage: uiImage)
|
Image(uiImage: uiImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
|
.frame(width: size.width, height: size.height)
|
||||||
.clipped()
|
.clipped()
|
||||||
} else {
|
} else {
|
||||||
VStack(spacing: Design.Spacing.xSmall) {
|
VStack(spacing: Design.Spacing.xSmall) {
|
||||||
@ -691,12 +706,13 @@ private struct EditorBannerPreviewView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Cover photo fills the banner
|
/// Cover photo fills the banner
|
||||||
private var coverBannerPreview: some View {
|
private func coverBannerPreview(size: CGSize) -> some View {
|
||||||
Group {
|
Group {
|
||||||
if let coverPhotoData, let uiImage = UIImage(data: coverPhotoData) {
|
if let coverPhotoData, let uiImage = UIImage(data: coverPhotoData) {
|
||||||
Image(uiImage: uiImage)
|
Image(uiImage: uiImage)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
|
.frame(width: size.width, height: size.height)
|
||||||
.clipped()
|
.clipped()
|
||||||
} else {
|
} else {
|
||||||
ZStack {
|
ZStack {
|
||||||
@ -926,6 +942,7 @@ private struct ProfilePhotoView: View {
|
|||||||
|
|
||||||
private struct ContactFieldRowView: View {
|
private struct ContactFieldRowView: View {
|
||||||
let field: AddedContactField
|
let field: AddedContactField
|
||||||
|
let themeColor: Color
|
||||||
let onTap: () -> Void
|
let onTap: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -939,7 +956,7 @@ private struct ContactFieldRowView: View {
|
|||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
Circle()
|
Circle()
|
||||||
.fill(field.fieldType.iconColor)
|
.fill(themeColor)
|
||||||
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
||||||
.overlay(
|
.overlay(
|
||||||
field.fieldType.iconImage()
|
field.fieldType.iconImage()
|
||||||
|
|||||||
@ -39,6 +39,7 @@ struct AddedContactField: Identifiable, Equatable {
|
|||||||
/// Displays a vertical list of added contact fields with tap to edit and drag to reorder
|
/// Displays a vertical list of added contact fields with tap to edit and drag to reorder
|
||||||
struct AddedContactFieldsView: View {
|
struct AddedContactFieldsView: View {
|
||||||
@Binding var fields: [AddedContactField]
|
@Binding var fields: [AddedContactField]
|
||||||
|
var themeColor: Color = Color(red: 0.2, green: 0.2, blue: 0.2)
|
||||||
let onEdit: (AddedContactField) -> Void
|
let onEdit: (AddedContactField) -> Void
|
||||||
|
|
||||||
@State private var draggingField: AddedContactField?
|
@State private var draggingField: AddedContactField?
|
||||||
@ -51,12 +52,13 @@ struct AddedContactFieldsView: View {
|
|||||||
ForEach(fields) { field in
|
ForEach(fields) { field in
|
||||||
FieldRow(
|
FieldRow(
|
||||||
field: field,
|
field: field,
|
||||||
|
themeColor: themeColor,
|
||||||
onTap: { onEdit(field) },
|
onTap: { onEdit(field) },
|
||||||
onDelete: { deleteField(field) }
|
onDelete: { deleteField(field) }
|
||||||
)
|
)
|
||||||
.draggable(field.id.uuidString) {
|
.draggable(field.id.uuidString) {
|
||||||
// Drag preview
|
// Drag preview
|
||||||
FieldRowPreview(field: field)
|
FieldRowPreview(field: field, themeColor: themeColor)
|
||||||
}
|
}
|
||||||
.dropDestination(for: String.self) { items, _ in
|
.dropDestination(for: String.self) { items, _ in
|
||||||
guard let droppedId = items.first,
|
guard let droppedId = items.first,
|
||||||
@ -94,11 +96,12 @@ struct AddedContactFieldsView: View {
|
|||||||
/// Preview shown while dragging a field
|
/// Preview shown while dragging a field
|
||||||
private struct FieldRowPreview: View {
|
private struct FieldRowPreview: View {
|
||||||
let field: AddedContactField
|
let field: AddedContactField
|
||||||
|
let themeColor: Color
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: Design.Spacing.medium) {
|
HStack(spacing: Design.Spacing.medium) {
|
||||||
Circle()
|
Circle()
|
||||||
.fill(field.fieldType.iconColor)
|
.fill(themeColor)
|
||||||
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
||||||
.overlay(
|
.overlay(
|
||||||
field.fieldType.iconImage()
|
field.fieldType.iconImage()
|
||||||
@ -130,6 +133,7 @@ private struct FieldRowPreview: View {
|
|||||||
/// A display row for a contact field - tap to edit, hold to drag
|
/// A display row for a contact field - tap to edit, hold to drag
|
||||||
private struct FieldRow: View {
|
private struct FieldRow: View {
|
||||||
let field: AddedContactField
|
let field: AddedContactField
|
||||||
|
let themeColor: Color
|
||||||
let onTap: () -> Void
|
let onTap: () -> Void
|
||||||
let onDelete: () -> Void
|
let onDelete: () -> Void
|
||||||
|
|
||||||
@ -143,7 +147,7 @@ private struct FieldRow: View {
|
|||||||
|
|
||||||
// Icon
|
// Icon
|
||||||
Circle()
|
Circle()
|
||||||
.fill(field.fieldType.iconColor)
|
.fill(themeColor)
|
||||||
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
||||||
.overlay(
|
.overlay(
|
||||||
field.fieldType.iconImage()
|
field.fieldType.iconImage()
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import Bedrock
|
|||||||
|
|
||||||
/// Grid view for selecting contact field types to add
|
/// Grid view for selecting contact field types to add
|
||||||
struct ContactFieldPickerView: View {
|
struct ContactFieldPickerView: View {
|
||||||
|
var themeColor: Color = Color(red: 0.2, green: 0.2, blue: 0.2)
|
||||||
let onSelect: (ContactFieldType) -> Void
|
let onSelect: (ContactFieldType) -> Void
|
||||||
|
|
||||||
private let columns = Array(repeating: GridItem(.flexible(), spacing: Design.Spacing.medium), count: 3)
|
private let columns = Array(repeating: GridItem(.flexible(), spacing: Design.Spacing.medium), count: 3)
|
||||||
@ -27,7 +28,7 @@ struct ContactFieldPickerView: View {
|
|||||||
|
|
||||||
LazyVGrid(columns: columns, spacing: Design.Spacing.large) {
|
LazyVGrid(columns: columns, spacing: Design.Spacing.large) {
|
||||||
ForEach(ContactFieldType.allCases) { fieldType in
|
ForEach(ContactFieldType.allCases) { fieldType in
|
||||||
FieldTypeButton(fieldType: fieldType) {
|
FieldTypeButton(fieldType: fieldType, themeColor: themeColor) {
|
||||||
onSelect(fieldType)
|
onSelect(fieldType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,13 +41,14 @@ struct ContactFieldPickerView: View {
|
|||||||
|
|
||||||
private struct FieldTypeButton: View {
|
private struct FieldTypeButton: View {
|
||||||
let fieldType: ContactFieldType
|
let fieldType: ContactFieldType
|
||||||
|
let themeColor: Color
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button(action: action) {
|
Button(action: action) {
|
||||||
VStack(spacing: Design.Spacing.small) {
|
VStack(spacing: Design.Spacing.small) {
|
||||||
Circle()
|
Circle()
|
||||||
.fill(fieldType.iconColor)
|
.fill(themeColor)
|
||||||
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
||||||
.overlay(
|
.overlay(
|
||||||
fieldType.iconImage()
|
fieldType.iconImage()
|
||||||
|
|||||||
@ -8,6 +8,7 @@ struct ContactFieldEditorSheet: View {
|
|||||||
let fieldType: ContactFieldType
|
let fieldType: ContactFieldType
|
||||||
let initialValue: String
|
let initialValue: String
|
||||||
let initialTitle: String
|
let initialTitle: String
|
||||||
|
let themeColor: Color
|
||||||
let onSave: (String, String) -> Void
|
let onSave: (String, String) -> Void
|
||||||
let onDelete: (() -> Void)?
|
let onDelete: (() -> Void)?
|
||||||
|
|
||||||
@ -19,12 +20,14 @@ struct ContactFieldEditorSheet: View {
|
|||||||
fieldType: ContactFieldType,
|
fieldType: ContactFieldType,
|
||||||
initialValue: String = "",
|
initialValue: String = "",
|
||||||
initialTitle: String = "",
|
initialTitle: String = "",
|
||||||
|
themeColor: Color = Color(red: 0.2, green: 0.2, blue: 0.2),
|
||||||
onSave: @escaping (String, String) -> Void,
|
onSave: @escaping (String, String) -> Void,
|
||||||
onDelete: (() -> Void)? = nil
|
onDelete: (() -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
self.fieldType = fieldType
|
self.fieldType = fieldType
|
||||||
self.initialValue = initialValue
|
self.initialValue = initialValue
|
||||||
self.initialTitle = initialTitle
|
self.initialTitle = initialTitle
|
||||||
|
self.themeColor = themeColor
|
||||||
self.onSave = onSave
|
self.onSave = onSave
|
||||||
self.onDelete = onDelete
|
self.onDelete = onDelete
|
||||||
_value = State(initialValue: initialValue)
|
_value = State(initialValue: initialValue)
|
||||||
@ -61,7 +64,7 @@ struct ContactFieldEditorSheet: View {
|
|||||||
NavigationStack {
|
NavigationStack {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
// Header with icon
|
// Header with icon
|
||||||
FieldHeaderView(fieldType: fieldType)
|
FieldHeaderView(fieldType: fieldType, themeColor: themeColor)
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
@ -179,11 +182,12 @@ struct ContactFieldEditorSheet: View {
|
|||||||
|
|
||||||
private struct FieldHeaderView: View {
|
private struct FieldHeaderView: View {
|
||||||
let fieldType: ContactFieldType
|
let fieldType: ContactFieldType
|
||||||
|
let themeColor: Color
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: Design.Spacing.medium) {
|
HStack(spacing: Design.Spacing.medium) {
|
||||||
Circle()
|
Circle()
|
||||||
.fill(fieldType.iconColor)
|
.fill(themeColor)
|
||||||
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
.frame(width: Design.CardSize.avatarSize, height: Design.CardSize.avatarSize)
|
||||||
.overlay(
|
.overlay(
|
||||||
fieldType.iconImage()
|
fieldType.iconImage()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user