fix: images resize with window, blend toolbar into content
Images sized themselves once at restyle time and never got re-measured on a pure window/pane resize (no text change, no image fingerprint change) - so they'd stay whatever width they were last styled at. The engine already had the fix for exactly this shape of problem for wide tables (a stamped .scrollableBlockFullRange attribute triggers a targeted restyle on width change), and the shared image-rendering helper already had a restyleOnWidthChange flag to opt into it - just never passed at the image call sites. Wired it on for both ![]() and ![[embed]] rendering. Also makes the titlebar/toolbar strip blend into the sidebar's background instead of reading as a separate bar, matching Mail/Notes/ Finder - titlebarAppearsTransparent + fullSizeContentView via a small NSViewRepresentable, same "reach into NSWindow directly" pattern applyMacAppearance() already uses since SwiftUI's WindowGroup has no direct API for either.
This commit is contained in:
@@ -34,6 +34,7 @@ struct OutpostApp: App {
|
|||||||
.onAppear { applyMacAppearance() }
|
.onAppear { applyMacAppearance() }
|
||||||
.onChange(of: appearance) { _, _ in applyMacAppearance() }
|
.onChange(of: appearance) { _, _ in applyMacAppearance() }
|
||||||
.logoutConfirmationDialog(isPresented: $isShowingLogoutConfirmation, session: session)
|
.logoutConfirmationDialog(isPresented: $isShowingLogoutConfirmation, session: session)
|
||||||
|
.background(TransparentTitlebarWindowAccessor())
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@@ -101,3 +102,27 @@ struct OutpostApp: App {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
/// Makes the titlebar/toolbar strip blend into the sidebar's own background
|
||||||
|
/// instead of reading as a separate bar — same look as Mail/Notes/Finder.
|
||||||
|
/// SwiftUI's `WindowGroup` exposes no direct hook for this, so this reaches
|
||||||
|
/// into the underlying `NSWindow` the way `applyMacAppearance()` above
|
||||||
|
/// reaches into `NSApp` for the same reason (no SwiftUI-level API exists).
|
||||||
|
/// A `View` (not the window itself) is what actually needs to extend under
|
||||||
|
/// the now-transparent titlebar — `.fullSizeContentView` just makes room;
|
||||||
|
/// the sidebar's `.background` already does the rest with no other change.
|
||||||
|
private struct TransparentTitlebarWindowAccessor: NSViewRepresentable {
|
||||||
|
func makeNSView(context: Context) -> NSView {
|
||||||
|
let view = NSView()
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
guard let window = view.window else { return }
|
||||||
|
window.titlebarAppearsTransparent = true
|
||||||
|
window.styleMask.insert(.fullSizeContentView)
|
||||||
|
}
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateNSView(_ nsView: NSView, context: Context) {}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
+4
@@ -75,6 +75,7 @@ extension MarkdownStyler {
|
|||||||
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
||||||
alignment: .left,
|
alignment: .left,
|
||||||
mode: .visibleSource(imageGap: imageEmbedConfig.imageGap),
|
mode: .visibleSource(imageGap: imageEmbedConfig.imageGap),
|
||||||
|
restyleOnWidthChange: true,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
attrs: &attrs
|
attrs: &attrs
|
||||||
)
|
)
|
||||||
@@ -88,6 +89,7 @@ extension MarkdownStyler {
|
|||||||
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
||||||
alignment: .left,
|
alignment: .left,
|
||||||
mode: .collapsedSource(markerTexts: ["![", "]", "(", ")"]),
|
mode: .collapsedSource(markerTexts: ["![", "]", "(", ")"]),
|
||||||
|
restyleOnWidthChange: true,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
attrs: &attrs
|
attrs: &attrs
|
||||||
)
|
)
|
||||||
@@ -166,6 +168,7 @@ extension MarkdownStyler {
|
|||||||
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
||||||
alignment: .left,
|
alignment: .left,
|
||||||
mode: .visibleSource(imageGap: imageEmbedConfig.imageGap),
|
mode: .visibleSource(imageGap: imageEmbedConfig.imageGap),
|
||||||
|
restyleOnWidthChange: true,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
attrs: &attrs
|
attrs: &attrs
|
||||||
)
|
)
|
||||||
@@ -179,6 +182,7 @@ extension MarkdownStyler {
|
|||||||
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
paragraphSpacing: imageEmbedConfig.paragraphSpacing,
|
||||||
alignment: .left,
|
alignment: .left,
|
||||||
mode: .collapsedSource(markerTexts: ["![[", "]]"]),
|
mode: .collapsedSource(markerTexts: ["![[", "]]"]),
|
||||||
|
restyleOnWidthChange: true,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
attrs: &attrs
|
attrs: &attrs
|
||||||
)
|
)
|
||||||
|
|||||||
+9
-5
@@ -269,21 +269,25 @@ extension NativeTextView {
|
|||||||
|
|
||||||
recalcOverscroll(for: scrollView, targetWidth: newSize.width, debugTag: "setFrameSize")
|
recalcOverscroll(for: scrollView, targetWidth: newSize.width, debugTag: "setFrameSize")
|
||||||
|
|
||||||
// Width change → only rendered table paragraphs need restyling. Their image
|
// Width change → only paragraphs tagged `.scrollableBlockFullRange`
|
||||||
// width can change, and an initially narrow table can become scrollable.
|
// (rendered tables and standalone images — see appendRenderedStandaloneBlock's
|
||||||
|
// `restyleOnWidthChange`) need restyling. Their display size is measured
|
||||||
|
// off the container width, and an initially narrow table can become
|
||||||
|
// scrollable.
|
||||||
if widthChanged {
|
if widthChanged {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if self.configuration.readingWidth == nil {
|
if self.configuration.readingWidth == nil {
|
||||||
self.restyleTableParagraphsForWidthChange()
|
self.restyleWidthDependentParagraphsForWidthChange()
|
||||||
}
|
}
|
||||||
self.updateWideTableOverlays()
|
self.updateWideTableOverlays()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restyle only table paragraphs via stamped anchor ranges; avoids re-tokenizing the doc.
|
/// Restyle only width-dependent paragraphs (tables, standalone images) via
|
||||||
private func restyleTableParagraphsForWidthChange() {
|
/// stamped anchor ranges; avoids re-tokenizing the doc.
|
||||||
|
private func restyleWidthDependentParagraphsForWidthChange() {
|
||||||
guard let storage = textStorage,
|
guard let storage = textStorage,
|
||||||
let coord = delegate as? NativeTextViewCoordinator else { return }
|
let coord = delegate as? NativeTextViewCoordinator else { return }
|
||||||
var ranges: [NSRange] = []
|
var ranges: [NSRange] = []
|
||||||
|
|||||||
Reference in New Issue
Block a user