added a themepreview to themeditor

added background to themeeditor
extracted the raw themepreview to thempreview and made the previous view themebutton
fixed padding above your themes header
This commit is contained in:
neon443
2025-07-09 12:12:34 +01:00
parent e2cb313ddc
commit a3003a6e90
5 changed files with 173 additions and 142 deletions

View File

@@ -72,11 +72,12 @@
A98554632E0587DF009051BD /* HostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554622E0587DF009051BD /* HostsView.swift */; }; A98554632E0587DF009051BD /* HostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98554622E0587DF009051BD /* HostsView.swift */; };
A9A587202E0BF220006B31E6 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = A9A5871F2E0BF220006B31E6 /* SwiftTerm */; }; A9A587202E0BF220006B31E6 /* SwiftTerm in Frameworks */ = {isa = PBXBuildFile; productRef = A9A5871F2E0BF220006B31E6 /* SwiftTerm */; };
A9BA1D192E1D9AE1005BDCEF /* SwiftTerm.Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BA1D182E1D9AE1005BDCEF /* SwiftTerm.Color.swift */; }; A9BA1D192E1D9AE1005BDCEF /* SwiftTerm.Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BA1D182E1D9AE1005BDCEF /* SwiftTerm.Color.swift */; };
A9BA1D1B2E1E81CA005BDCEF /* ThemePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BA1D1A2E1E81CA005BDCEF /* ThemePreview.swift */; };
A9C4140C2E096DB7005E3047 /* SSHError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C4140B2E096DB7005E3047 /* SSHError.swift */; }; A9C4140C2E096DB7005E3047 /* SSHError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C4140B2E096DB7005E3047 /* SSHError.swift */; };
A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; }; A9C897EF2DF1A9A400EF9A5F /* SSHHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */; };
A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.swift */; }; A9D819292E0E904200442D38 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819282E0E904200442D38 /* Theme.swift */; };
A9D8192D2E0E9EB500442D38 /* ThemeManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */; }; A9D8192D2E0E9EB500442D38 /* ThemeManagerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */; };
A9D8192F2E0F1BEE00442D38 /* ThemePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */; }; A9D8192F2E0F1BEE00442D38 /* ThemeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D8192E2E0F1BEE00442D38 /* ThemeButton.swift */; };
A9D819312E102D8700442D38 /* HostkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819302E102D8700442D38 /* HostkeysView.swift */; }; A9D819312E102D8700442D38 /* HostkeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D819302E102D8700442D38 /* HostkeysView.swift */; };
A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; }; A9DA97712E0D30ED00142DDC /* HostSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97702E0D30ED00142DDC /* HostSymbol.swift */; };
A9DA97732E0D40C100142DDC /* HostSymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* HostSymbolPreview.swift */; }; A9DA97732E0D40C100142DDC /* HostSymbolPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9DA97722E0D40C100142DDC /* HostSymbolPreview.swift */; };
@@ -194,11 +195,12 @@
A98554602E058433009051BD /* HostsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsManager.swift; sourceTree = "<group>"; }; A98554602E058433009051BD /* HostsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsManager.swift; sourceTree = "<group>"; };
A98554622E0587DF009051BD /* HostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsView.swift; sourceTree = "<group>"; }; A98554622E0587DF009051BD /* HostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostsView.swift; sourceTree = "<group>"; };
A9BA1D182E1D9AE1005BDCEF /* SwiftTerm.Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTerm.Color.swift; sourceTree = "<group>"; }; A9BA1D182E1D9AE1005BDCEF /* SwiftTerm.Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTerm.Color.swift; sourceTree = "<group>"; };
A9BA1D1A2E1E81CA005BDCEF /* ThemePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreview.swift; sourceTree = "<group>"; };
A9C4140B2E096DB7005E3047 /* SSHError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHError.swift; sourceTree = "<group>"; }; A9C4140B2E096DB7005E3047 /* SSHError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHError.swift; sourceTree = "<group>"; };
A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; }; A9C897EE2DF1A9A400EF9A5F /* SSHHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHHandler.swift; sourceTree = "<group>"; };
A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; }; A9D819282E0E904200442D38 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManagerView.swift; sourceTree = "<group>"; }; A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManagerView.swift; sourceTree = "<group>"; };
A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreview.swift; sourceTree = "<group>"; }; A9D8192E2E0F1BEE00442D38 /* ThemeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeButton.swift; sourceTree = "<group>"; };
A9D819302E102D8700442D38 /* HostkeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostkeysView.swift; sourceTree = "<group>"; }; A9D819302E102D8700442D38 /* HostkeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostkeysView.swift; sourceTree = "<group>"; };
A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; }; A9DA97702E0D30ED00142DDC /* HostSymbol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbol.swift; sourceTree = "<group>"; };
A9DA97722E0D40C100142DDC /* HostSymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbolPreview.swift; sourceTree = "<group>"; }; A9DA97722E0D40C100142DDC /* HostSymbolPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostSymbolPreview.swift; sourceTree = "<group>"; };
@@ -533,9 +535,10 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */, A9D8192C2E0E9EB500442D38 /* ThemeManagerView.swift */,
A9D8192E2E0F1BEE00442D38 /* ThemePreview.swift */, A9D8192E2E0F1BEE00442D38 /* ThemeButton.swift */,
A9FD376A2E16DABF005319A8 /* AnsiPickerView.swift */, A9FD376A2E16DABF005319A8 /* AnsiPickerView.swift */,
A9485C772E1BFA5000209824 /* ThemeEditorView.swift */, A9485C772E1BFA5000209824 /* ThemeEditorView.swift */,
A9BA1D1A2E1E81CA005BDCEF /* ThemePreview.swift */,
); );
path = Themes; path = Themes;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -718,11 +721,12 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
A9D8192F2E0F1BEE00442D38 /* ThemePreview.swift in Sources */, A9D8192F2E0F1BEE00442D38 /* ThemeButton.swift in Sources */,
A96C6B022E0C49E800F377FE /* CenteredLabel.swift in Sources */, A96C6B022E0C49E800F377FE /* CenteredLabel.swift in Sources */,
A923172F2E08851200ECE1E6 /* ShellView.swift in Sources */, A923172F2E08851200ECE1E6 /* ShellView.swift in Sources */,
A9D819292E0E904200442D38 /* Theme.swift in Sources */, A9D819292E0E904200442D38 /* Theme.swift in Sources */,
A9D8192D2E0E9EB500442D38 /* ThemeManagerView.swift in Sources */, A9D8192D2E0E9EB500442D38 /* ThemeManagerView.swift in Sources */,
A9BA1D1B2E1E81CA005BDCEF /* ThemePreview.swift in Sources */,
A9FD375D2E143D7E005319A8 /* KeyStoreError.swift in Sources */, A9FD375D2E143D7E005319A8 /* KeyStoreError.swift in Sources */,
A9835C3C2E17CCA500969508 /* TrafficLights.swift in Sources */, A9835C3C2E17CCA500969508 /* TrafficLights.swift in Sources */,
A9485C782E1BFA5000209824 /* ThemeEditorView.swift in Sources */, A9485C782E1BFA5000209824 /* ThemeEditorView.swift in Sources */,

View File

@@ -0,0 +1,90 @@
//
// ThemeButton.swift
// ShhShell
//
// Created by neon443 on 27/06/2025.
//
import SwiftUI
struct ThemeButton: View {
@ObservedObject var hostsManager: HostsManager
@Binding var theme: Theme
@State var canModify: Bool
@State private var showRenameAlert: Bool = false
@State private var rename: String = ""
var isSelected: Bool {
return hostsManager.isThemeSelected(theme)
}
var body: some View {
let padding: CGFloat = 10
let innerPadding: CGFloat = 5
let outerR: CGFloat = 15
var paletteR: CGFloat {
outerR-padding
}
var selectionR: CGFloat {
outerR-innerPadding
}
ZStack(alignment: .center) {
Rectangle()
.fill(Color.accentColor)
.opacity(isSelected ? 1 : 0)
Rectangle()
.fill(theme.background.suiColor)
.clipShape(
RoundedRectangle(
cornerRadius: isSelected ? selectionR : 0
)
)
.padding(isSelected ? innerPadding : 0)
ThemePreview(theme: theme, padding: padding, paletteR: paletteR)
}
.onTapGesture {
hostsManager.selectTheme(theme)
}
.animation(.spring, value: isSelected)
.clipShape(RoundedRectangle(cornerRadius: outerR))
.contextMenu {
if canModify {
NavigationLink {
ThemeEditorView(hostsManager: hostsManager, theme: $theme)
} label: {
Label("Edit", systemImage: "pencil")
}
Button() {
rename = theme.name
showRenameAlert.toggle()
} label: {
Label("Rename", systemImage: "text.cursor")
}
Button(role: .destructive) {
hostsManager.deleteTheme(theme)
} label: {
Label("Delete", systemImage: "trash")
}
}
}
.alert("Rename \(theme.name)", isPresented: $showRenameAlert) {
TextField("", text: $rename)
Button("OK") {
hostsManager.renameTheme(theme, to: rename)
rename = ""
}
}
}
}
#Preview {
ThemeButton(
hostsManager: HostsManager(),
theme: .constant(Theme.defaultTheme),
canModify: true
)
.border(Color.red)
}

View File

@@ -16,14 +16,16 @@ struct ThemeEditorView: View {
@Environment(\.dismiss) var dismiss @Environment(\.dismiss) var dismiss
var body: some View { var body: some View {
ZStack {
hostsManager.selectedTheme.background.suiColor.opacity(0.7)
.ignoresSafeArea(.all)
NavigationStack { NavigationStack {
ThemePreview(theme: theme, padding: 10, paletteR: 20)
.id(theme)
.padding(.bottom)
.fixedSize(horizontal: false, vertical: true)
List { List {
Section("Preview") {
// ThemePreview(hostsManager: HostsManager(), theme: .constant(theme), canModify: false)
// .id(theme)
}
Section("Name") { Section("Name") {
TextField("Name", text: $theme.name) TextField("Name", text: $theme.name)
.textFieldStyle(.roundedBorder) .textFieldStyle(.roundedBorder)
@@ -67,6 +69,7 @@ struct ThemeEditorView: View {
} }
} }
} }
}
#Preview { #Preview {
ThemeEditorView(hostsManager: HostsManager(), theme: .constant(Theme.defaultTheme)) ThemeEditorView(hostsManager: HostsManager(), theme: .constant(Theme.defaultTheme))

View File

@@ -50,6 +50,7 @@ struct ThemeManagerView: View {
HStack { HStack {
Text("Your Themes") Text("Your Themes")
.padding(.horizontal) .padding(.horizontal)
.padding(.vertical)
.font(.headline) .font(.headline)
Spacer() Spacer()
} }
@@ -69,7 +70,7 @@ struct ThemeManagerView: View {
} else { } else {
LazyVGrid(columns: layout, alignment: .center, spacing: 8) { LazyVGrid(columns: layout, alignment: .center, spacing: 8) {
ForEach($hostsManager.themes) { $theme in ForEach($hostsManager.themes) { $theme in
ThemePreview(hostsManager: hostsManager, theme: $theme, canModify: true) ThemeButton(hostsManager: hostsManager, theme: $theme, canModify: true)
} }
} }
.padding(.horizontal) .padding(.horizontal)
@@ -85,7 +86,7 @@ struct ThemeManagerView: View {
} }
LazyVGrid(columns: layout, alignment: .center, spacing: 8) { LazyVGrid(columns: layout, alignment: .center, spacing: 8) {
ForEach(Theme.builtinThemes) { theme in ForEach(Theme.builtinThemes) { theme in
ThemePreview(hostsManager: hostsManager, theme: .constant(theme), canModify: false) ThemeButton(hostsManager: hostsManager, theme: .constant(theme), canModify: false)
} }
} }
.padding(.horizontal) .padding(.horizontal)

View File

@@ -2,46 +2,17 @@
// ThemePreview.swift // ThemePreview.swift
// ShhShell // ShhShell
// //
// Created by neon443 on 27/06/2025. // Created by neon443 on 09/07/2025.
// //
import SwiftUI import SwiftUI
struct ThemePreview: View { struct ThemePreview: View {
@ObservedObject var hostsManager: HostsManager @State var theme: Theme
@Binding var theme: Theme @State var padding: CGFloat
@State var canModify: Bool @State var paletteR: CGFloat
@State private var showRenameAlert: Bool = false
@State private var rename: String = ""
var isSelected: Bool {
return hostsManager.isThemeSelected(theme)
}
var body: some View { var body: some View {
let padding: CGFloat = 10
let innerPadding: CGFloat = 5
let outerR: CGFloat = 15
var paletteR: CGFloat {
outerR-padding
}
var selectionR: CGFloat {
outerR-innerPadding
}
ZStack(alignment: .center) {
Rectangle()
.fill(Color.accentColor)
.opacity(isSelected ? 1 : 0)
Rectangle()
.fill(theme.background.suiColor)
.clipShape(
RoundedRectangle(
cornerRadius: isSelected ? selectionR : 0
)
)
.padding(isSelected ? innerPadding : 0)
VStack { VStack {
Text(theme.name) Text(theme.name)
.foregroundStyle(theme.foreground.suiColor) .foregroundStyle(theme.foreground.suiColor)
@@ -71,46 +42,8 @@ struct ThemePreview: View {
} }
.padding(padding) .padding(padding)
} }
.onTapGesture {
hostsManager.selectTheme(theme)
}
.animation(.spring, value: isSelected)
.clipShape(RoundedRectangle(cornerRadius: outerR))
.contextMenu {
if canModify {
NavigationLink {
ThemeEditorView(hostsManager: hostsManager, theme: $theme)
} label: {
Label("Edit", systemImage: "pencil")
}
Button() {
rename = theme.name
showRenameAlert.toggle()
} label: {
Label("Rename", systemImage: "text.cursor")
}
Button(role: .destructive) {
hostsManager.deleteTheme(theme)
} label: {
Label("Delete", systemImage: "trash")
}
}
}
.alert("Rename \(theme.name)", isPresented: $showRenameAlert) {
TextField("", text: $rename)
Button("OK") {
hostsManager.renameTheme(theme, to: rename)
rename = ""
}
}
}
} }
#Preview { #Preview {
ThemePreview( ThemePreview(theme: Theme.defaultTheme, padding: 5, paletteR: 10)
hostsManager: HostsManager(),
theme: .constant(Theme.defaultTheme),
canModify: true
)
.border(Color.red)
} }