Prepare v0.5.3 release updates and UI polish

This commit is contained in:
h3p 2026-03-10 16:14:21 +01:00
parent 2ab0af9820
commit c655cc9917
8 changed files with 298 additions and 175 deletions

View file

@ -4,6 +4,25 @@ All notable changes to **Neon Vision Editor** are documented in this file.
The format follows *Keep a Changelog*. Versions use semantic versioning with prerelease tags.
## [v0.5.3] - 2026-03-10
### Added
- Added a new high-readability colorful light theme preset: `Prism Daylight` (also selectable while app appearance is set to dark).
- Added double-click-to-close behavior for tabs on macOS tab strips.
- Added split editor settings sections (`Basics` / `Behavior`) to reduce scrolling in the Editor tab.
### Improved
- Improved custom theme vibrancy by applying the vivid neon syntax profile to `Custom`, so syntax colors remain bright and saturated.
- Improved Cyber Lime readability in light mode by reducing overly bright green token intensity and switching to a blue cursor accent.
- Improved toolbar symbol color options on macOS with clearer separation between `Dark Gray` and `Black`, plus near-white rendering in dark mode for both options.
- Improved translucent macOS toolbar consistency by enforcing `0.8` opacity for toolbar surfaces in translucency mode.
### Fixed
- Fixed toolbar-symbol contrast edge cases in dark mode where gray/black variants could appear too similar.
### Release
- Notarized release published via `scripts/release_all.sh v0.5.3 notarized`.
## [v0.5.2] - 2026-03-09
### Added

View file

@ -361,7 +361,7 @@
CODE_SIGNING_ALLOWED = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 489;
CURRENT_PROJECT_VERSION = 490;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_APP_SANDBOX = YES;
@ -444,7 +444,7 @@
CODE_SIGNING_ALLOWED = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 489;
CURRENT_PROJECT_VERSION = 490;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_APP_SANDBOX = YES;

View file

@ -39,6 +39,24 @@ extension ContentView {
"AI Provider for Code Completion"
}
#if os(macOS)
private var macToolbarSymbolColor: Color {
let isDarkMode = colorScheme == .dark
switch toolbarSymbolsColorMacRaw {
case "black":
return isDarkMode
? Color(.sRGB, white: 0.94, opacity: 1.0)
: .black
case "darkGray":
return isDarkMode
? Color(.sRGB, white: 0.84, opacity: 1.0)
: Color(.sRGB, white: 0.40, opacity: 1.0)
default:
return NeonUIStyle.accentBlue
}
}
#endif
#if os(iOS)
private var iOSToolbarChromeStyle: GlassChromeStyle { .single }
private var iOSToolbarTintColor: Color {
@ -941,19 +959,19 @@ extension ContentView {
ToolbarItemGroup(placement: .primaryAction) {
Button(action: { openFileFromToolbar() }) {
Label("Open", systemImage: "folder")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Open File… (Cmd+O)")
Button(action: { viewModel.addNewTab() }) {
Label("New Tab", systemImage: "plus.square.on.square")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("New Tab (Cmd+T)")
Button(action: { requestCloseAllTabsFromToolbar() }) {
Label("Close All Tabs", systemImage: "xmark.square")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Close All Tabs")
@ -961,7 +979,7 @@ extension ContentView {
saveCurrentTabFromToolbar()
}) {
Label("Save", systemImage: "square.and.arrow.down")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.disabled(viewModel.selectedTab == nil)
.help("Save File (Cmd+S)")
@ -970,7 +988,7 @@ extension ContentView {
showFindReplace = true
}) {
Label("Find", systemImage: "magnifyingglass")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Find & Replace (Cmd+F)")
@ -978,7 +996,7 @@ extension ContentView {
openSettings()
}) {
Label("Settings", systemImage: "gearshape")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Settings")
}
@ -1036,7 +1054,7 @@ extension ContentView {
toggleMarkdownPreviewFromToolbar()
}) {
Label("Markdown Preview", systemImage: showMarkdownPreviewPane ? "doc.richtext.fill" : "doc.richtext")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.disabled(currentLanguage != "markdown")
.help("Toggle Markdown Preview")
@ -1049,7 +1067,7 @@ extension ContentView {
Button("Compact") { markdownPreviewTemplateRaw = "compact" }
} label: {
Label("Preview Style", systemImage: "textformat.size")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Markdown Preview Template")
}
@ -1058,7 +1076,7 @@ extension ContentView {
Button(action: { undoFromToolbar() }) {
Label("Undo", systemImage: "arrow.uturn.backward")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Undo (Cmd+Z)")
.keyboardShortcut("z", modifiers: .command)
@ -1068,7 +1086,7 @@ extension ContentView {
showUpdaterDialog(checkNow: true)
}) {
Label("Updates", systemImage: "arrow.triangle.2.circlepath.circle")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Check for Updates")
}
@ -1078,20 +1096,20 @@ extension ContentView {
openWindow(id: "blank-window")
}) {
Label("New Window", systemImage: "macwindow.badge.plus")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("New Window (Cmd+N)")
#endif
Button(action: { adjustEditorFontSize(-1) }) {
Label("Font -", systemImage: "textformat.size.smaller")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Decrease Font Size")
Button(action: { adjustEditorFontSize(1) }) {
Label("Font +", systemImage: "textformat.size.larger")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Increase Font Size")
@ -1099,7 +1117,7 @@ extension ContentView {
requestClearEditorContent()
}) {
Label("Clear", systemImage: "eraser")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Clear Editor")
@ -1107,7 +1125,7 @@ extension ContentView {
insertTemplateForCurrentLanguage()
}) {
Label("Template", systemImage: "doc.badge.plus")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Insert Template for Current Language")
@ -1115,7 +1133,7 @@ extension ContentView {
toggleSidebarFromToolbar()
}) {
Label("Sidebar", systemImage: "sidebar.left")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
.symbolVariant(viewModel.showSidebar ? .fill : .none)
}
.help("Toggle Sidebar (Cmd+Opt+S)")
@ -1124,7 +1142,7 @@ extension ContentView {
toggleProjectSidebarFromToolbar()
}) {
Label("Project", systemImage: "sidebar.right")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
.symbolVariant(showProjectStructureSidebar ? .fill : .none)
}
.help("Toggle Project Structure Sidebar")
@ -1133,7 +1151,7 @@ extension ContentView {
toggleAutoCompletion()
}) {
Label("AI", systemImage: "bolt.horizontal.circle")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
.symbolVariant(isAutoCompletionEnabled ? .fill : .none)
}
.help(isAutoCompletionEnabled ? "Disable Code Completion" : "Enable Code Completion")
@ -1143,7 +1161,7 @@ extension ContentView {
showBracketHelperBarMac.toggle()
}) {
Label("Brackets", systemImage: "chevron.left.chevron.right")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
.symbolVariant(showBracketHelperBarMac ? .fill : .none)
}
.help(showBracketHelperBarMac ? "Hide Bracket Helper Bar" : "Show Bracket Helper Bar")
@ -1154,7 +1172,7 @@ extension ContentView {
UserDefaults.standard.set(viewModel.isBrainDumpMode, forKey: "BrainDumpModeEnabled")
}) {
Label("Brain Dump", systemImage: "note.text")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
.symbolVariant(viewModel.isBrainDumpMode ? .fill : .none)
}
.help("Brain Dump Mode")
@ -1166,7 +1184,7 @@ extension ContentView {
NotificationCenter.default.post(name: .toggleTranslucencyRequested, object: enableTranslucentWindow)
}) {
Label("Translucency", systemImage: enableTranslucentWindow ? "rectangle.fill" : "rectangle")
.foregroundStyle(NeonUIStyle.accentBlue)
.foregroundStyle(macToolbarSymbolColor)
}
.help("Toggle Translucent Window Background")
.accessibilityLabel("Translucent Window Background")

View file

@ -331,6 +331,7 @@ struct ContentView: View {
#if os(macOS)
@State private var hostWindowNumber: Int? = nil
@AppStorage("ShowBracketHelperBarMac") var showBracketHelperBarMac: Bool = false
@AppStorage("SettingsToolbarSymbolsColorMac") var toolbarSymbolsColorMacRaw: String = "blue"
@State private var windowCloseConfirmationDelegate: WindowCloseConfirmationDelegate? = nil
#endif
@State var showMarkdownPreviewPane: Bool = false
@ -433,6 +434,13 @@ struct ContentView: View {
}
return AnyShapeStyle(Color(nsColor: .textBackgroundColor))
}
private var macToolbarBackgroundStyle: AnyShapeStyle {
if enableTranslucentWindow {
return AnyShapeStyle(macTranslucencyMode.material.opacity(0.8))
}
return AnyShapeStyle(Color(nsColor: .textBackgroundColor))
}
#elseif os(iOS)
var primaryGlassMaterial: Material { colorScheme == .dark ? .regularMaterial : .ultraThinMaterial }
var toolbarFallbackColor: Color {
@ -4066,7 +4074,7 @@ struct ContentView: View {
}
#if os(macOS)
.toolbarBackground(
macChromeBackgroundStyle,
macToolbarBackgroundStyle,
for: ToolbarPlacement.windowToolbar
)
.toolbarBackgroundVisibility(Visibility.visible, for: ToolbarPlacement.windowToolbar)
@ -4695,6 +4703,12 @@ struct ContentView: View {
.padding(.vertical, 6)
}
.buttonStyle(.plain)
#if os(macOS)
.simultaneousGesture(
TapGesture(count: 2)
.onEnded { requestCloseTab(tab) }
)
#endif
Button {
requestCloseTab(tab)
@ -4722,7 +4736,7 @@ struct ContentView: View {
}
.frame(minHeight: 42, maxHeight: 42, alignment: .center)
#if os(macOS)
.background(macChromeBackgroundStyle)
.background(macToolbarBackgroundStyle)
#else
.background(
enableTranslucentWindow

View file

@ -29,6 +29,7 @@ struct NeonSettingsView: View {
@AppStorage("SettingsEditorFontSize") private var editorFontSize: Double = 14
@AppStorage("SettingsLineHeight") private var lineHeight: Double = 1.0
@AppStorage("SettingsAppearance") private var appearance: String = "system"
@AppStorage("SettingsToolbarSymbolsColorMac") private var toolbarSymbolsColorMacRaw: String = "blue"
#if os(iOS)
@AppStorage("EnableTranslucentWindow") private var translucentWindow: Bool = true
#else
@ -73,6 +74,7 @@ struct NeonSettingsView: View {
@State private var showDataDisclosureDialog: Bool = false
@State private var availableEditorFonts: [String] = []
@State private var moreSectionTab: String = "support"
@State private var editorSectionTab: String = "basics"
@State private var diagnosticsCopyStatus: String = ""
@State private var supportRefreshTask: Task<Void, Never>?
@State private var isDiscoveringFonts: Bool = false
@ -271,7 +273,8 @@ struct NeonSettingsView: View {
minSize: macSettingsWindowSize.min,
idealSize: macSettingsWindowSize.ideal,
translucentEnabled: supportsTranslucency && translucentWindow,
translucencyModeRaw: macTranslucencyModeRaw
translucencyModeRaw: macTranslucencyModeRaw,
appearanceRaw: appearance
)
)
#endif
@ -512,6 +515,17 @@ struct NeonSettingsView: View {
.pickerStyle(.segmented)
}
HStack(alignment: .center, spacing: UI.space12) {
Text("Toolbar Symbols")
.frame(width: isCompactSettingsLayout ? nil : standardLabelWidth, alignment: .leading)
Picker("", selection: $toolbarSymbolsColorMacRaw) {
Text("Blue").tag("blue")
Text("Dark Gray").tag("darkGray")
Text("Black").tag("black")
}
.pickerStyle(.segmented)
}
if supportsTranslucency {
Toggle("Translucent Window", isOn: $translucentWindow)
.frame(maxWidth: .infinity, alignment: .leading)
@ -961,13 +975,88 @@ struct NeonSettingsView: View {
title: "Editor",
subtitle: "Display, indentation, editing behavior, and completion sources."
)
editorSectionPicker
if editorSectionTab == "basics" {
editorBasicsSettings
} else {
editorBehaviorSettings
}
}
}
private var editorSectionPicker: some View {
VStack(alignment: .leading, spacing: UI.space8) {
Text("Section")
.font(Typography.footnote)
.foregroundStyle(.secondary)
Picker("Section", selection: $editorSectionTab) {
Text("Basics").tag("basics")
Text("Behavior").tag("behavior")
}
.pickerStyle(.segmented)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
private var editorBasicsSettings: some View {
#if os(iOS)
VStack(spacing: UI.space16) {
settingsCardSection(
title: "Display",
icon: "eye",
tip: "Scope visuals are best used with line wrap disabled."
) {
VStack(spacing: UI.space16) {
settingsCardSection(
title: "Display",
icon: "eye",
tip: "Scope visuals are best used with line wrap disabled."
) {
Toggle("Show Line Numbers", isOn: $showLineNumbers)
Toggle("Highlight Current Line", isOn: $highlightCurrentLine)
Toggle("Highlight Matching Brackets", isOn: $highlightMatchingBrackets)
Toggle("Show Scope Guides (Non-Swift)", isOn: $showScopeGuides)
Toggle("Highlight Scoped Region", isOn: $highlightScopeBackground)
Toggle("Line Wrap", isOn: $lineWrapEnabled)
Text("When Line Wrap is enabled, scope guides/scoped region are turned off to avoid layout conflicts.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
Text("Scope guides are intended for non-Swift languages. Swift favors matching-token highlight.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
Text("Invisible character markers are disabled to avoid whitespace glyph artifacts.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
settingsCardSection(
title: "Indentation",
icon: "increase.indent",
emphasis: .secondary
) {
Picker("Indent Style", selection: $indentStyle) {
Text("Spaces").tag("spaces")
Text("Tabs").tag("tabs")
}
.pickerStyle(.segmented)
Stepper(value: $indentWidth, in: 2...8, step: 1) {
Text(localized("Indent Width: %lld", Int64(indentWidth)))
}
}
settingsCardSection(
title: "Layout",
icon: "sidebar.left",
emphasis: .secondary
) {
Picker("Project Navigator Position", selection: $projectNavigatorPlacementRaw) {
Text("Left").tag(ContentView.ProjectNavigatorPlacement.leading.rawValue)
Text("Right").tag(ContentView.ProjectNavigatorPlacement.trailing.rawValue)
}
.pickerStyle(.segmented)
}
}
#else
GroupBox("Editor Basics") {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .leading, spacing: UI.space10) {
Text("Display")
.font(Typography.sectionHeadline)
Toggle("Show Line Numbers", isOn: $showLineNumbers)
Toggle("Highlight Current Line", isOn: $highlightCurrentLine)
Toggle("Highlight Matching Brackets", isOn: $highlightMatchingBrackets)
@ -984,12 +1073,13 @@ struct NeonSettingsView: View {
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
settingsCardSection(
title: "Indentation",
icon: "increase.indent",
emphasis: .secondary
) {
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Indentation")
.font(Typography.sectionHeadline)
Picker("Indent Style", selection: $indentStyle) {
Text("Spaces").tag("spaces")
Text("Tabs").tag("tabs")
@ -1000,24 +1090,76 @@ struct NeonSettingsView: View {
Text(localized("Indent Width: %lld", Int64(indentWidth)))
}
}
.frame(maxWidth: .infinity, alignment: .leading)
settingsCardSection(
title: "Layout",
icon: "sidebar.left",
emphasis: .secondary
) {
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Layout")
.font(Typography.sectionHeadline)
Picker("Project Navigator Position", selection: $projectNavigatorPlacementRaw) {
Text("Left").tag(ContentView.ProjectNavigatorPlacement.leading.rawValue)
Text("Right").tag(ContentView.ProjectNavigatorPlacement.trailing.rawValue)
}
.pickerStyle(.segmented)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(UI.groupPadding)
}
#endif
}
settingsCardSection(
title: "Performance",
icon: "speedometer",
emphasis: .secondary
) {
private var editorBehaviorSettings: some View {
#if os(iOS)
VStack(spacing: UI.space16) {
settingsCardSection(
title: "Performance",
icon: "speedometer",
emphasis: .secondary
) {
Picker("Preset", selection: $performancePresetRaw) {
Text("Balanced").tag(ContentView.PerformancePreset.balanced.rawValue)
Text("Large Files").tag(ContentView.PerformancePreset.largeFiles.rawValue)
Text("Battery").tag(ContentView.PerformancePreset.battery.rawValue)
}
.pickerStyle(.segmented)
Text("Balanced keeps default behavior. Large Files and Battery enter performance mode earlier.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
settingsCardSection(
title: "Editing",
icon: "keyboard",
emphasis: .secondary
) {
Toggle("Auto Indent", isOn: $autoIndent)
Toggle("Auto Close Brackets", isOn: $autoCloseBrackets)
Toggle("Trim Trailing Whitespace", isOn: $trimTrailingWhitespace)
Toggle("Trim Edges for Syntax Detection", isOn: $trimWhitespaceForSyntaxDetection)
}
settingsCardSection(
title: "Completion",
icon: "sparkles",
emphasis: .secondary
) {
Toggle("Enable Completion", isOn: $completionEnabled)
Toggle("Include Words in Document", isOn: $completionFromDocument)
Toggle("Include Syntax Keywords", isOn: $completionFromSyntax)
Text("For lower latency on large files, keep only one completion source enabled.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
}
#else
GroupBox("Editor Behavior") {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .leading, spacing: UI.space10) {
Text("Performance")
.font(Typography.sectionHeadline)
Picker("Preset", selection: $performancePresetRaw) {
Text("Balanced").tag(ContentView.PerformancePreset.balanced.rawValue)
Text("Large Files").tag(ContentView.PerformancePreset.largeFiles.rawValue)
@ -1028,23 +1170,25 @@ struct NeonSettingsView: View {
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
settingsCardSection(
title: "Editing",
icon: "keyboard",
emphasis: .secondary
) {
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Editing")
.font(Typography.sectionHeadline)
Toggle("Auto Indent", isOn: $autoIndent)
Toggle("Auto Close Brackets", isOn: $autoCloseBrackets)
Toggle("Trim Trailing Whitespace", isOn: $trimTrailingWhitespace)
Toggle("Trim Edges for Syntax Detection", isOn: $trimWhitespaceForSyntaxDetection)
}
.frame(maxWidth: .infinity, alignment: .leading)
settingsCardSection(
title: "Completion",
icon: "sparkles",
emphasis: .secondary
) {
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Completion")
.font(Typography.sectionHeadline)
Toggle("Enable Completion", isOn: $completionEnabled)
Toggle("Include Words in Document", isOn: $completionFromDocument)
Toggle("Include Syntax Keywords", isOn: $completionFromSyntax)
@ -1052,109 +1196,12 @@ struct NeonSettingsView: View {
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
}
#else
GroupBox("Editor") {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .leading, spacing: UI.space10) {
Text("Display")
.font(Typography.sectionHeadline)
Toggle("Show Line Numbers", isOn: $showLineNumbers)
Toggle("Highlight Current Line", isOn: $highlightCurrentLine)
Toggle("Highlight Matching Brackets", isOn: $highlightMatchingBrackets)
Toggle("Show Scope Guides (Non-Swift)", isOn: $showScopeGuides)
Toggle("Highlight Scoped Region", isOn: $highlightScopeBackground)
Toggle("Line Wrap", isOn: $lineWrapEnabled)
Text("When Line Wrap is enabled, scope guides/scoped region are turned off to avoid layout conflicts.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
Text("Scope guides are intended for non-Swift languages. Swift favors matching-token highlight.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
Text("Invisible character markers are disabled to avoid whitespace glyph artifacts.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Indentation")
.font(Typography.sectionHeadline)
Picker("Indent Style", selection: $indentStyle) {
Text("Spaces").tag("spaces")
Text("Tabs").tag("tabs")
}
.pickerStyle(.segmented)
Stepper(value: $indentWidth, in: 2...8, step: 1) {
Text(localized("Indent Width: %lld", Int64(indentWidth)))
}
}
.frame(maxWidth: .infinity, alignment: .leading)
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Layout")
.font(Typography.sectionHeadline)
Picker("Project Navigator Position", selection: $projectNavigatorPlacementRaw) {
Text("Left").tag(ContentView.ProjectNavigatorPlacement.leading.rawValue)
Text("Right").tag(ContentView.ProjectNavigatorPlacement.trailing.rawValue)
}
.pickerStyle(.segmented)
}
.frame(maxWidth: .infinity, alignment: .leading)
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Performance")
.font(Typography.sectionHeadline)
Picker("Preset", selection: $performancePresetRaw) {
Text("Balanced").tag(ContentView.PerformancePreset.balanced.rawValue)
Text("Large Files").tag(ContentView.PerformancePreset.largeFiles.rawValue)
Text("Battery").tag(ContentView.PerformancePreset.battery.rawValue)
}
.pickerStyle(.segmented)
Text("Balanced keeps default behavior. Large Files and Battery enter performance mode earlier.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Editing")
.font(Typography.sectionHeadline)
Toggle("Auto Indent", isOn: $autoIndent)
Toggle("Auto Close Brackets", isOn: $autoCloseBrackets)
Toggle("Trim Trailing Whitespace", isOn: $trimTrailingWhitespace)
Toggle("Trim Edges for Syntax Detection", isOn: $trimWhitespaceForSyntaxDetection)
}
.frame(maxWidth: .infinity, alignment: .leading)
Divider()
VStack(alignment: .leading, spacing: UI.space10) {
Text("Completion")
.font(Typography.sectionHeadline)
Toggle("Enable Completion", isOn: $completionEnabled)
Toggle("Include Words in Document", isOn: $completionFromDocument)
Toggle("Include Syntax Keywords", isOn: $completionFromSyntax)
Text("For lower latency on large files, keep only one completion source enabled.")
.font(Typography.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(UI.groupPadding)
}
#endif
.frame(maxWidth: .infinity, alignment: .leading)
.padding(UI.groupPadding)
}
#endif
}
private var templateTab: some View {
@ -2311,6 +2358,7 @@ struct SettingsWindowConfigurator: NSViewRepresentable {
let idealSize: NSSize
let translucentEnabled: Bool
let translucencyModeRaw: String
let appearanceRaw: String
final class Coordinator {
var didInitialApply = false
@ -2409,7 +2457,15 @@ struct SettingsWindowConfigurator: NSViewRepresentable {
private func translucencyEnabledColor(enabled: Bool, window: NSWindow) -> NSColor {
guard enabled else { return NSColor.windowBackgroundColor }
let isDark = window.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
let isDark: Bool
switch appearanceRaw {
case "light":
isDark = false
case "dark":
isDark = true
default:
isDark = window.effectiveAppearance.bestMatch(from: [.darkAqua, .aqua]) == .darkAqua
}
let whiteLevel: CGFloat
switch translucencyModeRaw {
case "subtle":

View file

@ -341,12 +341,12 @@ struct WelcomeTourView: View {
private let pages: [TourPage] = [
TourPage(
title: "Whats New in This Release",
subtitle: "Major changes since v0.5.1:",
subtitle: "Major changes since v0.5.2:",
bullets: [
"Added editor performance presets in Settings (`Balanced`, `Large Files`, `Battery`) with shared runtime mapping.",
"Added configurable project navigator placement (`Left`/`Right`) for project-structure sidebar layout.",
"Added richer updater diagnostics details in Settings: staged update summary, last install-attempt summary, and recent sanitized log snippet.",
"Added CSV/TSV table mode with a `Table`/`Text` switch, lazy row rendering, and background parsing for larger datasets."
"Added a new high-readability colorful light theme preset: `Prism Daylight` (also selectable while app appearance is set to dark).",
"Added double-click-to-close behavior for tabs on macOS tab strips.",
"Added split editor settings sections (`Basics` / `Behavior`) to reduce scrolling in the Editor tab.",
"Improved custom theme vibrancy by applying the vivid neon syntax profile to `Custom`, so syntax colors remain bright and saturated."
],
iconName: "sparkles.rectangle.stack",
colors: [Color(red: 0.40, green: 0.28, blue: 0.90), Color(red: 0.96, green: 0.46, blue: 0.55)],

View file

@ -161,6 +161,7 @@ let editorThemeNames: [String] = [
"Plasma Storm",
"Inferno Neon",
"Ultraviolet Flux",
"Prism Daylight",
"Custom",
"Dracula",
"One Dark Pro",
@ -259,14 +260,14 @@ private func paletteForThemeName(_ name: String, defaults: UserDefaults) -> Them
return ThemePalette(
text: Color(red: 0.94, green: 0.98, blue: 0.92),
background: Color(red: 0.07, green: 0.09, blue: 0.06),
cursor: Color(red: 0.68, green: 1.00, blue: 0.20),
cursor: Color(red: 0.18, green: 0.48, blue: 0.96),
selection: Color(red: 0.18, green: 0.25, blue: 0.14),
keyword: Color(red: 0.68, green: 1.00, blue: 0.20),
string: Color(red: 0.20, green: 1.00, blue: 0.78),
keyword: Color(red: 0.45, green: 0.78, blue: 0.16),
string: Color(red: 0.13, green: 0.70, blue: 0.50),
number: Color(red: 1.00, green: 0.86, blue: 0.22),
comment: Color(red: 0.54, green: 0.62, blue: 0.50),
type: Color(red: 0.48, green: 0.86, blue: 1.00),
property: Color(red: 0.88, green: 1.00, blue: 0.36),
property: Color(red: 0.56, green: 0.78, blue: 0.28),
builtin: Color(red: 1.00, green: 0.48, blue: 0.40)
)
case "Plasma Storm":
@ -311,6 +312,20 @@ private func paletteForThemeName(_ name: String, defaults: UserDefaults) -> Them
property: Color(red: 0.68, green: 0.72, blue: 1.00),
builtin: Color(red: 1.00, green: 0.28, blue: 0.56)
)
case "Prism Daylight":
return ThemePalette(
text: Color(red: 0.08, green: 0.10, blue: 0.14),
background: Color(red: 0.96, green: 0.97, blue: 0.99),
cursor: Color(red: 0.14, green: 0.34, blue: 0.84),
selection: Color(red: 0.84, green: 0.89, blue: 0.99),
keyword: Color(red: 0.48, green: 0.13, blue: 0.71),
string: Color(red: 0.05, green: 0.48, blue: 0.33),
number: Color(red: 0.71, green: 0.28, blue: 0.03),
comment: Color(red: 0.37, green: 0.42, blue: 0.49),
type: Color(red: 0.00, green: 0.34, blue: 0.76),
property: Color(red: 0.64, green: 0.11, blue: 0.67),
builtin: Color(red: 0.76, green: 0.25, blue: 0.05)
)
case "Dracula":
return ThemePalette(
text: Color(red: 0.97, green: 0.97, blue: 0.95),
@ -606,7 +621,8 @@ func currentEditorTheme(colorScheme: ColorScheme) -> EditorTheme {
"Cyber Lime",
"Plasma Storm",
"Inferno Neon",
"Ultraviolet Flux"
"Ultraviolet Flux",
"Custom"
]
return vividNeonThemes.contains(name) ? .neonRaw : .standard
}()

View file

@ -64,7 +64,7 @@
> Status: **active release**
> Latest release: **v0.5.2**
> Latest release: **v0.5.3**
> Platform target: **macOS 26 (Tahoe)** compatible with **macOS Sequoia**
> Apple Silicon: tested / Intel: not tested
> Last updated (README): **2026-03-10** for release line **v0.5.2**
@ -161,7 +161,7 @@
- Security policy: [`SECURITY.md`](SECURITY.md)
- Release checklists: [`release/`](release/) — TestFlight & App Store preflight docs
## What's New Since v0.5.1
## What's New Since v0.5.2
- Added `Close All Tabs` actions across macOS, iOS, and iPadOS with a confirmation safeguard.
- Added project-sidebar quick actions (`Expand All` / `Collapse All`) and a default-on `Show Supported Files Only` filter.
@ -195,7 +195,7 @@ Prebuilt binaries are available on [GitHub Releases](https://github.com/h3pdesig
Best for direct notarized builds and fastest access to new stable versions.
- Download: [GitHub Releases](https://github.com/h3pdesign/Neon-Vision-Editor/releases)
- Latest release: **v0.5.2**
- Latest release: **v0.5.3**
- Channel: **Stable**
- Architecture: Apple Silicon (Intel not tested)
@ -598,15 +598,15 @@ All shortcuts use `Cmd` (`⌘`). iPad/iOS require a hardware keyboard.
## Changelog
Latest stable: **v0.5.2** (2026-03-09)
Latest stable: **v0.5.3** (2026-03-10)
### Recent Releases (At a glance)
| Version | Date | Highlights | Fixes | Breaking changes | Migration |
|---|---|---|---|---|---|
| [`v0.5.3`](https://github.com/h3pdesign/Neon-Vision-Editor/releases/tag/v0.5.3) | 2026-03-10 | a new high-readability colorful light theme preset: `Prism Daylight` (also selectable while app appearance is set to dark); double-click-to-close behavior for tabs on macOS tab strips; custom theme vibrancy by applying the vivid neon syntax profile to `Custom`, so syntax colors remain bright and saturated | toolbar-symbol contrast edge cases in dark mode where gray/black variants could appear too similar | None noted | None required |
| [`v0.5.2`](https://github.com/h3pdesign/Neon-Vision-Editor/releases/tag/v0.5.2) | 2026-03-09 | editor performance presets in Settings (`Balanced`, `Large Files`, `Battery`) with shared runtime mapping; configurable project navigator placement (`Left`/`Right`) for project-structure sidebar layout; iOS/iPadOS large-file responsiveness by lowering automatic large-file thresholds and applying preset-based tuning | missing diagnostics reset workflow by adding a dedicated `Clear Diagnostics` action that also clears file-open timing snapshots; macOS editor-window top-bar jumping when toggling the toolbar translucency control by keeping chrome flags stable; CSV/TSV mode header transparency so the mode bar now uses a solid standard window background | None noted | None required |
| [`v0.5.1`](https://github.com/h3pdesign/Neon-Vision-Editor/releases/tag/v0.5.1) | 2026-03-08 | bulk `Close All Tabs` actions to toolbar surfaces (macOS, iOS, iPadOS), including a confirmation step before closing; project-structure quick actions to expand all folders or collapse all folders in one step; Markdown preview stability by preserving relative scroll position during preview refreshes | diagnostics export safety by redacting token-like updater status fragments before copying; Markdown regression coverage with new tests for Claude-style mixed-content Markdown and code-fence matching behavior; accidental destructive tab-bulk-close behavior by requiring explicit user confirmation before closing all tabs | None noted | None required |
| [`v0.5.0`](https://github.com/h3pdesign/Neon-Vision-Editor/releases/tag/v0.5.0) | 2026-03-06 | updater staging hardening with retry/fallback behavior and staged-bundle integrity checks; explicit accessibility labels/hints for key toolbar actions and updater log/progress controls; CSV handling by enabling fast syntax profile earlier and for long-line CSV files to reduce freeze risk | updater staging resilience when `ditto` fails by retrying and falling back safely to copy-based staging; release preflight to fail on unresolved placeholder entries and stale README download metrics; inconsistent reappearance of the macOS settings tab title in the upper-left window title area | None noted | None required |
- Full release history: [`CHANGELOG.md`](CHANGELOG.md)
- Compare recent changes: [v0.5.0...v0.5.2](https://github.com/h3pdesign/Neon-Vision-Editor/compare/v0.5.0...v0.5.2)
@ -628,12 +628,12 @@ Latest stable: **v0.5.2** (2026-03-09)
## Release Integrity
- Tag: `v0.5.2`
- Tag: `v0.5.3`
- Tagged commit: `1c31306`
- Verify local tag target:
```bash
git rev-parse --verify v0.5.2
git rev-parse --verify v0.5.3
```
- Verify downloaded artifact checksum locally: