Remove images, select tags
This commit is contained in:
parent
7e91b4b08c
commit
64b6d88a41
@ -18,6 +18,7 @@
|
|||||||
E218501B2CEE59EC0090B18B /* Tag+Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218501A2CEE59E80090B18B /* Tag+Storage.swift */; };
|
E218501B2CEE59EC0090B18B /* Tag+Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218501A2CEE59E80090B18B /* Tag+Storage.swift */; };
|
||||||
E218501D2CEE6CB60090B18B /* VerticalCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218501C2CEE6CB30090B18B /* VerticalCenter.swift */; };
|
E218501D2CEE6CB60090B18B /* VerticalCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218501C2CEE6CB30090B18B /* VerticalCenter.swift */; };
|
||||||
E218501F2CEE6DAC0090B18B /* ImagePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218501E2CEE6DAC0090B18B /* ImagePickerView.swift */; };
|
E218501F2CEE6DAC0090B18B /* ImagePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218501E2CEE6DAC0090B18B /* ImagePickerView.swift */; };
|
||||||
|
E21850232CF10C850090B18B /* TagSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21850222CF10C840090B18B /* TagSelectionView.swift */; };
|
||||||
E24252012C50E0A40029FF16 /* HighlightedTextEditor in Frameworks */ = {isa = PBXBuildFile; productRef = E24252002C50E0A40029FF16 /* HighlightedTextEditor */; };
|
E24252012C50E0A40029FF16 /* HighlightedTextEditor in Frameworks */ = {isa = PBXBuildFile; productRef = E24252002C50E0A40029FF16 /* HighlightedTextEditor */; };
|
||||||
E24252032C5163CF0029FF16 /* Importer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252022C5163CF0029FF16 /* Importer.swift */; };
|
E24252032C5163CF0029FF16 /* Importer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252022C5163CF0029FF16 /* Importer.swift */; };
|
||||||
E24252062C51684E0029FF16 /* GenericMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252052C51684E0029FF16 /* GenericMetadata.swift */; };
|
E24252062C51684E0029FF16 /* GenericMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252052C51684E0029FF16 /* GenericMetadata.swift */; };
|
||||||
@ -89,6 +90,7 @@
|
|||||||
E218501A2CEE59E80090B18B /* Tag+Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tag+Storage.swift"; sourceTree = "<group>"; };
|
E218501A2CEE59E80090B18B /* Tag+Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Tag+Storage.swift"; sourceTree = "<group>"; };
|
||||||
E218501C2CEE6CB30090B18B /* VerticalCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalCenter.swift; sourceTree = "<group>"; };
|
E218501C2CEE6CB30090B18B /* VerticalCenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalCenter.swift; sourceTree = "<group>"; };
|
||||||
E218501E2CEE6DAC0090B18B /* ImagePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerView.swift; sourceTree = "<group>"; };
|
E218501E2CEE6DAC0090B18B /* ImagePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerView.swift; sourceTree = "<group>"; };
|
||||||
|
E21850222CF10C840090B18B /* TagSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSelectionView.swift; sourceTree = "<group>"; };
|
||||||
E24252022C5163CF0029FF16 /* Importer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Importer.swift; sourceTree = "<group>"; };
|
E24252022C5163CF0029FF16 /* Importer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Importer.swift; sourceTree = "<group>"; };
|
||||||
E24252052C51684E0029FF16 /* GenericMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericMetadata.swift; sourceTree = "<group>"; };
|
E24252052C51684E0029FF16 /* GenericMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericMetadata.swift; sourceTree = "<group>"; };
|
||||||
E24252072C5168750029FF16 /* GenericMetadata+Localized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GenericMetadata+Localized.swift"; sourceTree = "<group>"; };
|
E24252072C5168750029FF16 /* GenericMetadata+Localized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GenericMetadata+Localized.swift"; sourceTree = "<group>"; };
|
||||||
@ -300,6 +302,7 @@
|
|||||||
E2B85F4B2C4B8B7F0047CD0C /* Posts */ = {
|
E2B85F4B2C4B8B7F0047CD0C /* Posts */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E21850222CF10C840090B18B /* TagSelectionView.swift */,
|
||||||
E218501E2CEE6DAC0090B18B /* ImagePickerView.swift */,
|
E218501E2CEE6DAC0090B18B /* ImagePickerView.swift */,
|
||||||
E21850082CEE01BF0090B18B /* PagePickerView.swift */,
|
E21850082CEE01BF0090B18B /* PagePickerView.swift */,
|
||||||
E2A21C112CB18D520060935B /* DatePickerView.swift */,
|
E2A21C112CB18D520060935B /* DatePickerView.swift */,
|
||||||
@ -481,6 +484,7 @@
|
|||||||
E2A37D292CED2C6A0000979F /* TagsListView.swift in Sources */,
|
E2A37D292CED2C6A0000979F /* TagsListView.swift in Sources */,
|
||||||
E24252032C5163CF0029FF16 /* Importer.swift in Sources */,
|
E24252032C5163CF0029FF16 /* Importer.swift in Sources */,
|
||||||
E2A37D252CEBD7A10000979F /* PageListView.swift in Sources */,
|
E2A37D252CEBD7A10000979F /* PageListView.swift in Sources */,
|
||||||
|
E21850232CF10C850090B18B /* TagSelectionView.swift in Sources */,
|
||||||
E21850152CEE55D40090B18B /* FileOnDisk.swift in Sources */,
|
E21850152CEE55D40090B18B /* FileOnDisk.swift in Sources */,
|
||||||
E2A21C332CB5BCAC0060935B /* PageDetailView.swift in Sources */,
|
E2A21C332CB5BCAC0060935B /* PageDetailView.swift in Sources */,
|
||||||
E2A21C122CB18D560060935B /* DatePickerView.swift in Sources */,
|
E2A21C122CB18D560060935B /* DatePickerView.swift in Sources */,
|
||||||
|
@ -30,14 +30,25 @@ struct PostImageGalleryView: View {
|
|||||||
@State
|
@State
|
||||||
private var showImagePicker = false
|
private var showImagePicker = false
|
||||||
|
|
||||||
|
private var imageAtCurrentIndex: Image? {
|
||||||
|
guard !post.images.isEmpty else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
guard currentIndex < post.images.count else {
|
||||||
|
return post.images.last?.imageToDisplay
|
||||||
|
}
|
||||||
|
return post.images[currentIndex].imageToDisplay
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .center) {
|
ZStack(alignment: .center) {
|
||||||
ZStack(alignment: .bottomTrailing) {
|
ZStack(alignment: .bottomTrailing) {
|
||||||
ZStack(alignment: .bottom) {
|
ZStack(alignment: .bottom) {
|
||||||
post.images[currentIndex]
|
if let imageAtCurrentIndex {
|
||||||
.imageToDisplay
|
imageAtCurrentIndex
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
|
}
|
||||||
if post.images.count > 1 {
|
if post.images.count > 1 {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
ForEach(0..<post.images.count, id: \.self) { index in
|
ForEach(0..<post.images.count, id: \.self) { index in
|
||||||
@ -60,6 +71,9 @@ struct PostImageGalleryView: View {
|
|||||||
Button(action: { showImagePicker = true }) {
|
Button(action: { showImagePicker = true }) {
|
||||||
NavigationIcon(symbol: .plus, edge: .all)
|
NavigationIcon(symbol: .plus, edge: .all)
|
||||||
}
|
}
|
||||||
|
Button(action: removeImage) {
|
||||||
|
NavigationIcon(symbol: .trash, edge: .all)
|
||||||
|
}
|
||||||
}.padding()
|
}.padding()
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
@ -120,6 +134,13 @@ struct PostImageGalleryView: View {
|
|||||||
post.images.swapAt(currentIndex, currentIndex+1)
|
post.images.swapAt(currentIndex, currentIndex+1)
|
||||||
currentIndex += 1
|
currentIndex += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func removeImage() {
|
||||||
|
post.images.remove(at: currentIndex)
|
||||||
|
if currentIndex >= post.images.count {
|
||||||
|
currentIndex = post.images.count - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview(traits: .fixedLayout(width: 300, height: 250)) {
|
#Preview(traits: .fixedLayout(width: 300, height: 250)) {
|
||||||
|
@ -1,22 +1,5 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
private struct CenteredPost<Content>: View where Content: View {
|
|
||||||
|
|
||||||
let content: Content
|
|
||||||
|
|
||||||
init(@ViewBuilder content: () -> Content) {
|
|
||||||
self.content = content()
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HorizontalCenter {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
.listRowBackground(ColorPalette.listBackground)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PostList: View {
|
struct PostList: View {
|
||||||
|
|
||||||
@EnvironmentObject
|
@EnvironmentObject
|
||||||
@ -25,13 +8,13 @@ struct PostList: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
if content.posts.isEmpty {
|
if content.posts.isEmpty {
|
||||||
CenteredPost {
|
HorizontalCenter {
|
||||||
Text("No posts yet.")
|
Text("No posts yet.")
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
}
|
}
|
||||||
CenteredPost {
|
HorizontalCenter {
|
||||||
Button(action: addNewPost) {
|
Button(action: addNewPost) {
|
||||||
Text("Add post")
|
Text("Add post")
|
||||||
}
|
}
|
||||||
@ -39,7 +22,7 @@ struct PostList: View {
|
|||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
}
|
}
|
||||||
ForEach(content.posts) { post in
|
ForEach(content.posts) { post in
|
||||||
CenteredPost {
|
HorizontalCenter {
|
||||||
PostView(post: post)
|
PostView(post: post)
|
||||||
.frame(maxWidth: 600)
|
.frame(maxWidth: 600)
|
||||||
}
|
}
|
||||||
@ -48,8 +31,7 @@ struct PostList: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listStyle(.plain)
|
.listStyle(.plain)
|
||||||
.background(ColorPalette.listBackground)
|
//.scrollContentBackground(.hidden)
|
||||||
.scrollContentBackground(.hidden)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addNewPost() {
|
private func addNewPost() {
|
||||||
|
@ -1,13 +1,28 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import SFSafeSymbols
|
||||||
|
|
||||||
struct PostView: View {
|
struct PostView: View {
|
||||||
|
|
||||||
|
@ObservedObject
|
||||||
|
var post: Post
|
||||||
|
|
||||||
@Environment(\.language)
|
@Environment(\.language)
|
||||||
var language
|
private var language
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
LocalizedPostView(post: post, localized: post.localized(in: language))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct LocalizedPostView: View {
|
||||||
|
|
||||||
@ObservedObject
|
@ObservedObject
|
||||||
var post: Post
|
var post: Post
|
||||||
|
|
||||||
|
@ObservedObject
|
||||||
|
var localized: LocalizedPost
|
||||||
|
|
||||||
@State
|
@State
|
||||||
private var showDatePicker = false
|
private var showDatePicker = false
|
||||||
|
|
||||||
@ -20,6 +35,12 @@ struct PostView: View {
|
|||||||
@State
|
@State
|
||||||
private var showTagPicker = false
|
private var showTagPicker = false
|
||||||
|
|
||||||
|
@Environment(\.language)
|
||||||
|
private var language
|
||||||
|
|
||||||
|
@EnvironmentObject
|
||||||
|
private var content: Content
|
||||||
|
|
||||||
private var linkedPageText: String {
|
private var linkedPageText: String {
|
||||||
if let page = post.linkedPage {
|
if let page = post.linkedPage {
|
||||||
return page.localized(in: language).title
|
return page.localized(in: language).title
|
||||||
@ -29,7 +50,7 @@ struct PostView: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
if post.localized(in: language).images.isEmpty {
|
if localized.images.isEmpty {
|
||||||
Button(action: { showImagePicker = true }) {
|
Button(action: { showImagePicker = true }) {
|
||||||
Text("Add image")
|
Text("Add image")
|
||||||
}
|
}
|
||||||
@ -37,7 +58,7 @@ struct PostView: View {
|
|||||||
.foregroundStyle(.blue)
|
.foregroundStyle(.blue)
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
} else {
|
} else {
|
||||||
PostImageGalleryView(post: post.localized(in: language))
|
PostImageGalleryView(post: localized)
|
||||||
.aspectRatio(1.33, contentMode: .fill)
|
.aspectRatio(1.33, contentMode: .fill)
|
||||||
}
|
}
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
@ -49,7 +70,7 @@ struct PostView: View {
|
|||||||
Toggle("Draft", isOn: $post.isDraft)
|
Toggle("Draft", isOn: $post.isDraft)
|
||||||
}
|
}
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
TextField("", text: post.localized(in: language).editableTitle())
|
TextField("", text: $localized.title)
|
||||||
.font(.system(size: 24, weight: .bold))
|
.font(.system(size: 24, weight: .bold))
|
||||||
.foregroundStyle(Color.primary)
|
.foregroundStyle(Color.primary)
|
||||||
.textFieldStyle(.plain)
|
.textFieldStyle(.plain)
|
||||||
@ -60,22 +81,21 @@ struct PostView: View {
|
|||||||
en: tag.english.name,
|
en: tag.english.name,
|
||||||
de: tag.german.name)
|
de: tag.german.name)
|
||||||
)
|
)
|
||||||
.onTapGesture {
|
.foregroundStyle(.white)
|
||||||
remove(tag: tag)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Button(action: { showTagPicker = true }) {
|
Button(action: { showTagPicker = true }) {
|
||||||
SwiftUI.Image(systemSymbol: .plusCircleFill)
|
Image(systemSymbol: .squareAndPencilCircleFill)
|
||||||
.resizable()
|
.resizable()
|
||||||
.aspectRatio(1, contentMode: .fit)
|
.aspectRatio(1, contentMode: .fit)
|
||||||
.frame(height: 18)
|
.frame(height: 22)
|
||||||
.foregroundColor(Color.blue)
|
.foregroundColor(Color.blue)
|
||||||
//.opacity(0.7)
|
.background(Circle()
|
||||||
.padding(.top, 3)
|
.fill(Color.white)
|
||||||
|
.padding(1))
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
}
|
}
|
||||||
TextEditor(text: post.localized(in: language).editableContent())
|
TextEditor(text: $localized.content)
|
||||||
.font(.body)
|
.font(.body)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.textEditorStyle(.plain)
|
.textEditorStyle(.plain)
|
||||||
@ -91,7 +111,7 @@ struct PostView: View {
|
|||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
}
|
}
|
||||||
.background(Color.secondary.colorInvert())
|
.background(Color(NSColor.windowBackgroundColor))
|
||||||
.cornerRadius(8)
|
.cornerRadius(8)
|
||||||
.sheet(isPresented: $showDatePicker) {
|
.sheet(isPresented: $showDatePicker) {
|
||||||
DatePickerView(
|
DatePickerView(
|
||||||
@ -106,8 +126,13 @@ struct PostView: View {
|
|||||||
.sheet(isPresented: $showImagePicker) {
|
.sheet(isPresented: $showImagePicker) {
|
||||||
ImagePickerView(
|
ImagePickerView(
|
||||||
showImagePicker: $showImagePicker,
|
showImagePicker: $showImagePicker,
|
||||||
post: post.localized(in: language)
|
post: localized)
|
||||||
)
|
}
|
||||||
|
.sheet(isPresented: $showTagPicker) {
|
||||||
|
TagSelectionView(
|
||||||
|
presented: $showTagPicker,
|
||||||
|
selected: $post.tags,
|
||||||
|
tags: $content.tags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,11 +145,10 @@ struct PostView: View {
|
|||||||
List {
|
List {
|
||||||
PostView(post: .fullMock)
|
PostView(post: .fullMock)
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
//.listRowBackground(ColorPalette.listBackground)
|
|
||||||
.environment(\.language, ContentLanguage.german)
|
.environment(\.language, ContentLanguage.german)
|
||||||
PostView(post: .mock)
|
PostView(post: .mock)
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
//.listRowBackground(ColorPalette.listBackground)
|
|
||||||
}
|
}
|
||||||
|
.environmentObject(Content.mock)
|
||||||
//.listStyle(.plain)
|
//.listStyle(.plain)
|
||||||
}
|
}
|
||||||
|
95
CHDataManagement/Views/Posts/TagSelectionView.swift
Normal file
95
CHDataManagement/Views/Posts/TagSelectionView.swift
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import SwiftUI
|
||||||
|
import SFSafeSymbols
|
||||||
|
|
||||||
|
struct TagSelectionView: View {
|
||||||
|
|
||||||
|
@Binding
|
||||||
|
var presented: Bool
|
||||||
|
|
||||||
|
@Binding
|
||||||
|
private var selected: [Tag]
|
||||||
|
|
||||||
|
@Binding
|
||||||
|
private var tags: [Tag]
|
||||||
|
|
||||||
|
@Environment(\.language)
|
||||||
|
private var language
|
||||||
|
|
||||||
|
init(presented: Binding<Bool>, selected: Binding<[Tag]>, tags: Binding<[Tag]>) {
|
||||||
|
self._presented = presented
|
||||||
|
self._selected = selected
|
||||||
|
self._tags = tags
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
List {
|
||||||
|
Section("Selected tags") {
|
||||||
|
ForEach(selected) { tag in
|
||||||
|
HStack {
|
||||||
|
Image(systemSymbol: .minusCircleFill)
|
||||||
|
.foregroundStyle(.red)
|
||||||
|
.onTapGesture {
|
||||||
|
deselect(tag: tag)
|
||||||
|
}
|
||||||
|
Text(tag.localized(in: language).name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onMove(perform: moveTag)
|
||||||
|
}
|
||||||
|
Section("Available tags") {
|
||||||
|
ForEach(tags.filter({ !selected.contains($0) })) { tag in
|
||||||
|
HStack {
|
||||||
|
Image(systemSymbol: .plusCircleFill)
|
||||||
|
.foregroundStyle(.green)
|
||||||
|
Text(tag.localized(in: language).name)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.contentShape(Rectangle())
|
||||||
|
.onTapGesture {
|
||||||
|
select(tag: tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(minHeight: 300)
|
||||||
|
.padding()
|
||||||
|
Button(action: dismiss) {
|
||||||
|
Text("Save")
|
||||||
|
}.padding()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func moveTag(from source: IndexSet, to destination: Int) {
|
||||||
|
selected.move(fromOffsets: source, toOffset: destination)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func deselect(tag: Tag) {
|
||||||
|
guard let index = selected.firstIndex(of: tag) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
selected.remove(at: index)
|
||||||
|
|
||||||
|
let insertIndex = tags.firstIndex(where: { $0 > tag }) ?? tags.endIndex
|
||||||
|
tags.insert(tag, at: insertIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func select(tag: Tag) {
|
||||||
|
guard let index = tags.firstIndex(of: tag) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tags.remove(at: index)
|
||||||
|
selected.append(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func dismiss() {
|
||||||
|
presented = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
TagSelectionView(
|
||||||
|
presented: .constant(true),
|
||||||
|
selected: .constant([.hiking, .nature]),
|
||||||
|
tags: .constant([.sports, .mock]))
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user