Add page settings, improve settings UI
This commit is contained in:
17
CHDataManagement/Model/Settings/PageSettings.swift
Normal file
17
CHDataManagement/Model/Settings/PageSettings.swift
Normal file
@ -0,0 +1,17 @@
|
||||
import Foundation
|
||||
|
||||
final class PageSettings: ObservableObject {
|
||||
|
||||
/// The prefix of the urls for all pages
|
||||
/// The full path will be `<pagePrefix>/<page-url-component>`
|
||||
@Published
|
||||
var pageUrlPrefix: String
|
||||
|
||||
@Published
|
||||
var contentWidth: Int
|
||||
|
||||
init(pageUrlPrefix: String, contentWidth: Int) {
|
||||
self.pageUrlPrefix = pageUrlPrefix
|
||||
self.contentWidth = contentWidth
|
||||
}
|
||||
}
|
@ -8,9 +8,9 @@ final class PostSettings: ObservableObject {
|
||||
|
||||
/// The maximum width of the main content
|
||||
@Published
|
||||
var contentWidth: CGFloat
|
||||
var contentWidth: Int
|
||||
|
||||
init(postsPerPage: Int, contentWidth: CGFloat) {
|
||||
init(postsPerPage: Int, contentWidth: Int) {
|
||||
self.postsPerPage = postsPerPage
|
||||
self.contentWidth = contentWidth
|
||||
}
|
||||
|
@ -11,16 +11,20 @@ final class Settings: ObservableObject {
|
||||
@Published
|
||||
var posts: PostSettings
|
||||
|
||||
@Published
|
||||
var pages: PageSettings
|
||||
|
||||
@Published
|
||||
var german: LocalizedSettings
|
||||
|
||||
@Published
|
||||
var english: LocalizedSettings
|
||||
|
||||
init(outputDirectoryPath: String, navigationBar: NavigationBarSettings, posts: PostSettings, german: LocalizedSettings, english: LocalizedSettings) {
|
||||
init(outputDirectoryPath: String, navigationBar: NavigationBarSettings, posts: PostSettings, pages: PageSettings, german: LocalizedSettings, english: LocalizedSettings) {
|
||||
self.outputDirectoryPath = outputDirectoryPath
|
||||
self.navigationBar = navigationBar
|
||||
self.posts = posts
|
||||
self.pages = pages
|
||||
self.german = german
|
||||
self.english = english
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ extension Settings {
|
||||
outputDirectoryPath: "/some/path",
|
||||
navigationBar: .init(iconPath: "/some/other/path", tags: []),
|
||||
posts: .mock,
|
||||
pages: .mock,
|
||||
german: .german,
|
||||
english: .english)
|
||||
}
|
||||
@ -17,6 +18,13 @@ extension PostSettings {
|
||||
}
|
||||
}
|
||||
|
||||
extension PageSettings {
|
||||
|
||||
static var mock: PageSettings {
|
||||
.init(pageUrlPrefix: "pages", contentWidth: 600)
|
||||
}
|
||||
}
|
||||
|
||||
extension LocalizedSettings {
|
||||
|
||||
static var german: LocalizedSettings {
|
||||
|
@ -0,0 +1,11 @@
|
||||
|
||||
struct PageSettingsFile {
|
||||
|
||||
let pageUrlPrefix: String
|
||||
|
||||
let contentWidth: Int
|
||||
}
|
||||
|
||||
extension PageSettingsFile: Codable {
|
||||
|
||||
}
|
@ -6,7 +6,7 @@ struct PostSettingsFile {
|
||||
let postsPerPage: Int
|
||||
|
||||
/// The maximum width of the main content
|
||||
let contentWidth: CGFloat
|
||||
let contentWidth: Int
|
||||
}
|
||||
|
||||
extension PostSettingsFile: Codable { }
|
||||
|
@ -9,6 +9,8 @@ struct SettingsFile {
|
||||
|
||||
let posts: PostSettingsFile
|
||||
|
||||
let pages: PageSettingsFile
|
||||
|
||||
let german: LocalizedSettingsFile
|
||||
|
||||
let english: LocalizedSettingsFile
|
||||
|
31
CHDataManagement/Views/Generic/IntegerField.swift
Normal file
31
CHDataManagement/Views/Generic/IntegerField.swift
Normal file
@ -0,0 +1,31 @@
|
||||
import SwiftUI
|
||||
|
||||
struct IntegerField: View {
|
||||
|
||||
private let titleKey: LocalizedStringKey
|
||||
|
||||
@Binding
|
||||
private var number: Int
|
||||
|
||||
@State
|
||||
private var text: String = ""
|
||||
|
||||
init(_ titleKey: LocalizedStringKey, number: Binding<Int>) {
|
||||
self.titleKey = titleKey
|
||||
self._number = number
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TextField(titleKey, text: $text)
|
||||
.onChange(of: text) { _, newValue in
|
||||
if let intValue = Int(newValue) {
|
||||
number = intValue
|
||||
} else {
|
||||
text = "\(number)"
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
text = "\(number)"
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,9 @@ struct FolderSettingsView: View {
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Select the folders for the app to work.")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom, 30)
|
||||
|
||||
Text("Content Folder")
|
||||
.font(.headline)
|
||||
.padding(.bottom, 1)
|
||||
@ -29,7 +31,10 @@ struct FolderSettingsView: View {
|
||||
Button(action: selectContentFolder) {
|
||||
Text("Select folder")
|
||||
}
|
||||
.padding(.bottom)
|
||||
Text("The folder where the raw content of the website is stored")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("Output Folder")
|
||||
.font(.headline)
|
||||
.padding(.bottom, 1)
|
||||
@ -37,8 +42,9 @@ struct FolderSettingsView: View {
|
||||
Button(action: selectOutputFolder) {
|
||||
Text("Select folder")
|
||||
}
|
||||
.padding(.bottom)
|
||||
|
||||
Text("The folder where the generated website is stored")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,9 @@ struct GenerationSettingsView: View {
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Regenerate the website and monitor the output")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom, 30)
|
||||
|
||||
|
||||
HStack {
|
||||
Button(action: generateFeed) {
|
||||
Text("Generate")
|
||||
|
@ -13,14 +13,18 @@ struct LocalizedPostFeedSettingsView: View {
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: 400)
|
||||
Text("The title of all post feed pages.")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("URL prefix")
|
||||
.font(.headline)
|
||||
TextField("", text: $settings.feedUrlPrefix)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: 400)
|
||||
Text("The prefix to generate the urls for all post feed pages.")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("Description")
|
||||
.font(.headline)
|
||||
TextEditor(text: $settings.description)
|
||||
@ -33,6 +37,7 @@ struct LocalizedPostFeedSettingsView: View {
|
||||
.background(Color.gray.opacity(0.1))
|
||||
.cornerRadius(8)
|
||||
Text("The description of all post feed pages.")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
|
@ -30,19 +30,25 @@ struct NavigationBarSettingsView: View {
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Customize the navigation bar for all pages at the top of the website")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom, 30)
|
||||
|
||||
Text("Icon Path")
|
||||
.font(.headline)
|
||||
TextField("", text: $content.settings.navigationBar.iconPath)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: 300)
|
||||
Text("Specify the path to the icon file with regard to the final website folder.")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom, 30)
|
||||
|
||||
Text("Icon Description")
|
||||
.font(.headline)
|
||||
IconDescriptionView(settings: content.settings.localized(in: language))
|
||||
Text("Provide a description of the icon for screen readers.")
|
||||
.padding(.bottom, 30)
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("Visible Tags")
|
||||
.font(.headline)
|
||||
FlowHStack {
|
||||
@ -66,6 +72,7 @@ struct NavigationBarSettingsView: View {
|
||||
.buttonStyle(.plain)
|
||||
}
|
||||
Text("Select the tags to show in the navigation bar. The number should be even.")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showTagPicker) {
|
||||
|
47
CHDataManagement/Views/Settings/PageSettingsView.swift
Normal file
47
CHDataManagement/Views/Settings/PageSettingsView.swift
Normal file
@ -0,0 +1,47 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PageSettingsView: View {
|
||||
|
||||
@Environment(\.language)
|
||||
private var language
|
||||
|
||||
@EnvironmentObject
|
||||
private var content: Content
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Page Settings")
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Change the way pages are displayed")
|
||||
.padding(.bottom, 30)
|
||||
|
||||
Text("Content Width")
|
||||
.font(.headline)
|
||||
IntegerField("", number: $content.settings.pages.contentWidth)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: 400)
|
||||
Text("The maximum width of the content in pages (in pixels)")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("Page URL Prefix")
|
||||
.font(.headline)
|
||||
TextField("", text: $content.settings.pages.pageUrlPrefix)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: 400)
|
||||
Text("The URL prefix used for the links to pages")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#Preview {
|
||||
PageSettingsView()
|
||||
.environmentObject(Content.mock)
|
||||
.padding()
|
||||
}
|
@ -15,7 +15,27 @@ struct PostFeedSettingsView: View {
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Change the way the posts are displayed")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom, 30)
|
||||
|
||||
Text("Content Width")
|
||||
.font(.headline)
|
||||
IntegerField("", number: $content.settings.posts.contentWidth)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: 400)
|
||||
Text("The maximum width of the content the post feed (in pixels)")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
|
||||
Text("Posts Per Page")
|
||||
.font(.headline)
|
||||
IntegerField("", number: $content.settings.posts.postsPerPage)
|
||||
.textFieldStyle(.roundedBorder)
|
||||
.frame(maxWidth: 400)
|
||||
Text("The maximum number of posts displayed on a single page")
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.bottom)
|
||||
|
||||
LocalizedPostFeedSettingsView(settings: content.settings.localized(in: language).posts)
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ struct DetailView: View {
|
||||
NavigationBarSettingsView()
|
||||
case .postFeed:
|
||||
PostFeedSettingsView()
|
||||
case .pages:
|
||||
PageSettingsView()
|
||||
case .none:
|
||||
Text("Select a setting from the sidebar")
|
||||
.foregroundStyle(.secondary)
|
||||
@ -42,40 +44,6 @@ struct DetailView: View {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct AppearanceView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Appearance Settings")
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Customize the look and feel of the app.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NotificationsView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Notifications Settings")
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Manage your notification preferences.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PrivacyView: View {
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Privacy Settings")
|
||||
.font(.largeTitle)
|
||||
.bold()
|
||||
Text("Configure your privacy and security settings.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
SectionedSettingsView()
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ enum SettingsSection: String {
|
||||
|
||||
case postFeed = "Post Feed"
|
||||
|
||||
case pages = "Pages"
|
||||
|
||||
}
|
||||
|
||||
extension SettingsSection {
|
||||
@ -20,6 +22,7 @@ extension SettingsSection {
|
||||
case .folders: return .folder
|
||||
case .navigationBar: return .menubarRectangle
|
||||
case .postFeed: return .rectangleGrid1x2
|
||||
case .pages: return .docRichtext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user