Drafts + Publish:
- New Home tab backed by documents.drafts (undocumented request shape
confirmed from a live network capture, not the OpenAPI spec).
- Reader toolbar menu now shows Publish... for an unpublished
document instead of an unconditional Unpublish (which could
previously be tapped on a draft at all). Publish opens a
MoveDocumentSheet-style collection/parent picker, pre-filled from
the draft's own collectionId/parentDocumentId when it already has
one. Publishing itself is documents.update(publish: true,
collectionId:) for the collection placement, plus a second
documents.move call only when a specific parent document was also
picked (documents.update has no parentDocumentId field).
- New Document defaults to Draft (collectionId/publish both now
optional on CreateDocumentRequest, previously collectionId was
required so a draft couldn't be created from this sheet at all).
Contextual entry points (right-click a collection/document) still
pre-fill that location, but now show a warning that doing so
auto-publishes.
- Fixed onDeleted only popping the reader's nav path without telling
the sidebar to refresh - Delete/Archive/Unpublish/Move all left the
sidebar showing stale state until an unrelated trigger (the 45s
poll, navigating away and back) happened to catch it up.
Comments:
- Replies (comments.create with parentCommentId, one level of nesting
same as Outline's own limit) and emoji reactions
(comments.add_reaction/remove_reaction, confirmed against Outline's
server source - not in the spec, and return {success: true} rather
than the updated comment, so a toggle refetches via comments.info
for the real post-toggle state) plus a document-level "new comment"
composer, since replying needs something to reply to.
- Inline anchor markers: a new engine-side mechanism
(CommentAnchorQuery/CommentAnchorRect/onCommentAnchorRectsChange)
resolves an anchored comment's anchorText to an on-screen rect via
the same viewRect utility the code-block copy button uses, kept in
sync on typing/resize/reflow the same way the code-block and image
positioning fixes earlier this session are. Renders as a thin blue
bar next to the commented text; tapping it opens the comments sheet
scrolled and highlighted to that thread. First-occurrence text
search only (Outline's API returns no position data, and no
prefix/suffix on read) - creating new anchored comments from this
app still isn't supported.
- Toolbar badge: tighter offset so the count doesn't clip past the
icon, caps at "10+".
45 lines
1.6 KiB
Swift
45 lines
1.6 KiB
Swift
//
|
|
// CommentAnchor.swift
|
|
// MarkdownEngine
|
|
//
|
|
// Lets an embedder ask "where on screen is this text?" for arbitrary
|
|
// plain-text needles (e.g. an anchored comment's `anchorText`) that the
|
|
// engine has no concept of on its own — it doesn't know what a comment is,
|
|
// it just resolves a search term to a rect the same way it already
|
|
// resolves code-block token ranges.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
/// A plain-text search term the embedder wants a screen rect for, tagged
|
|
/// with an opaque id so results can be matched back to whatever the
|
|
/// embedder cares about (e.g. a comment id). Engine does a first-occurrence
|
|
/// substring search against the current display text — no fuzzier
|
|
/// disambiguation than that, since the engine has no positional data to
|
|
/// work from beyond the text itself.
|
|
public struct CommentAnchorQuery: Sendable, Equatable {
|
|
public let id: String
|
|
public let anchorText: String
|
|
|
|
public init(id: String, anchorText: String) {
|
|
self.id = id
|
|
self.anchorText = anchorText
|
|
}
|
|
}
|
|
|
|
/// Resolved screen rect for one ``CommentAnchorQuery``. Delivered through
|
|
/// ``NativeTextViewWrapper/onCommentAnchorRectsChange`` — queries whose
|
|
/// `anchorText` isn't found in the current text (deleted, edited past
|
|
/// recognition) simply don't appear in the result.
|
|
public struct CommentAnchorRect: Identifiable, Sendable {
|
|
public let id: String
|
|
/// Frame of the matched text in the text view's coordinate space —
|
|
/// same coordinate system as ``CodeBlockSelection/rect``.
|
|
public let rect: CGRect
|
|
|
|
public init(id: String, rect: CGRect) {
|
|
self.id = id
|
|
self.rect = rect
|
|
}
|
|
}
|