Swift-DocC sidebar

I’ve built a version of the Swift-Argument-Parser docs on my fork with the version of Swift-DocC-Render from the open PR if anyone is interested in trying out the proposed sidebar and page-design updates: https://ethan-kusters.github.io/swift-argument-parser/documentation/argumentparser.

5 Likes

Yeah, I'm not sure I'm really feeling it as proposed.

Here's a super-quick example of how it would look if we dropped the margins and the removed the hero background. Personally, I think it looks a lot better with fewer visual flourishes. Just MHO.

The body content still feels a bit "off" to me; it feels very narrow. The topics shortcuts give it a weird alignment, and I feel that perhaps the big sidebar is just serving to emphasise how much horizontal space is being wasted.


Also, on an iPad in portrait mode, the sidebar is very annoying. There really needs to be a button to hide it. The narrower width also makes code snippets basically illegible

6 Likes

I believe this was the exact rationale for the page design changes being discussed in the other thread: New Swift-DocC content styling. That pitch discusses moving the metadata information that currently occupies the righthand sidebar up into the top of the page to make room for the new navigation sidebar on the left.

When there’s an implementation available for that change, I’ll update the Argument-Parser demo site so we can get a feel for it.

1 Like

It would be useful to have an alphabetical list of all types and protocols:

  • Could the sidebar have an additional "index" tab?
  • Or could the filter bar support this use case?
  • Or could a "site map" page be generated?

Could the sidebar icons also be used as the default favicon?

By default this is essentially what DocC will produce. A documentation author can choose to organize the symbols in their project more specifically by putting them into topic groups: Swift.org: Arrange Top-Level Symbols Using Topic Groups.

The folks working on ArgumentParser have chosen to do this which is why you're seeing symbols grouped into more logical sections in the navigator for the demo I published.

Personally- I think the filter bar supports this use case well. The only time I would want an alphabetical list instead of an author-organized list is when I already know what I'm looking for or know at least part of the name of the symbol I'm looking for. In this case, using the filter bar seems like a faster solution than scrolling an alphabetical list.

From my perspective- the navigator should essentially be a site map. How would you see a more dedicated site map page behaving differently than the navigator?

I love this idea! Maybe the top-level technology star icon could be used? It might be odd for the favicon to change between pages but offering the top-level icon as a default seems like a great improvement.

2 Likes

for me at least, 90% of the time i already do know part of the name of the symbol im looking for, i just need to fill in some blanks in my memory. aside from search, the most useful organization for me would be grouping by:

  • initializers
  • static methods (since these are often initializer-like)
  • instance properties
  • subscripts
  • instance methods
  • static properties
  • operators

in a well-designed API, the kind of a symbol (e.g., subscript) should already provide some hint as to its role.

if there too many instance methods to sort through, i am usually more interested in what protocol interface they are associated with than what “topic” they fall under. however, this type of organization is hard to implement with the information provided by the symbol graphs.

a site map is a search engine concept, like a robots.txt. unless you are referring to something different?

browsers cache favicons by default, even if no etag is provided. so you can serve a different favicon for each page if you want, but there’s no guarantee the user will see it.

Hi Beatriz,

The design and overall concept of the sidebar looks lovely. I explored it with @ethankusters temporary overlay of ArgumentParser.

Seeing the filtering, I immediately reached for it - and was a little surprised when content was highlighted by the filtering action. Then it was even more awkward as some of the titles that matched the filter value I used weren't easily visible in the sidebar, sort of highlighting the difficulty of the "too much horizontal space used by the sidebar" while also "not enough to be visible". (The article titles were frequently cut off)

I also think that using a tag (for example, to just show an article or tutorial) is completely opaque and if you hadn't called it out in your introduction, I wouldn't have had a clue that was an option. In fact, I'm not even sure today how to trigger the filter to just show articles within the module.

I think the filtering mechanism is important, and even better (and a much more involved implementation) would be a full fuzzy search that returned based on some amount of potential relevance. For either of these cases, I'd like to advocate for the possibility of having a separate result area displayed that shows the results, and leaving the side-bar and it's navigational structure untouched.

Since DocC is leaning into the SPA/javascript driven documentation rather than static rendering, this seems like it could be doable - and it preserves the navigational capability that the sidebar provides, which IMO is its single biggest benefit.

While I love the additional detail being available for the functions in the sidebar, as others have pointed out, it's pretty heavy space-wise, and might suggest that the most valuable thing to display is the symbol's name, followed by arguments. I do like the box to the left indicating the kind of symbol (protocol, struct, enumeration, class, etc), but it's the thing that allows me to disambiguate between two otherwise similar symbols. The cases where I've wanted or needed to that seemed to boil down to the arguments that a function or method took - and often the type associated with the argument - which is probably more than can easily fit in the sidebar.

I don't know who enabled the option-click-disclosure to fully expand a tree downward, but THANK YOU!!!! That's hugely beneficial, and far easier for me to navigate than the scroll-down-click-scroll-down-click sequences.

1 Like

yes, fuzzy search is a must. also, i noticed the search bar is at the bottom of the sidebar in the desktop layout, but it is at the top of the sidebar in the mobile layout. wouldn’t it be better the other way around?

1 Like

Would it be possible to not have the footer extend under the sidebar? I find it a bit jarring to scroll to the bottom of the content view and have the entire page jump up due to the footer view.

4 Likes

Both kinds of navigation are useful: topic groups for new users, and default groups for quick reference.

For example, if we wanted to audit the missing conformances of Never (SE-0319), we'd need a list of all the protocols. We could search either the source code, or the generated documentation.

I'm not sure how it would differ from the navigator. Perhaps the nested hierarchy would be flattened?

(A long time ago, there was a site map page for the Foundation framework.)

1 Like

Just a quick update here: The initial support for the Navigator was merged to main this afternoon but will remain behind a feature flag as we continue iterating on it and discussing in this thread.

Here are some instructions if you're interested in trying it out locally with your own content:

  1. Follow the instructions here to build and run the version of docc on main.

  2. Clone the pre-built version of Swift-DocC-Render from the swift-docc-render-artifact repo with:

    git clone https://github.com/apple/swift-docc-render-artifact.git
    
  3. Modify the theme-settings.json at dist/theme-settings.json so that the features.docs.navigator.enable property is set to true.

  4. Set the DOCC_HTML_DIR environment variable to the dist directory at the root of your swift-docc-render-artifact repository.

    export DOCC_HTML_DIR=/path/to/swift-docc-render-artifact/dist
    
  5. Generate a compatible DocC archive by passing the --enable-experimental-json-index flag to docc convert.

    docc convert <path-to-docc-catalog> --enable-experimental-json-index
    

Alternatively, the Swift Argument Parser demo is still up on my fork if you're looking for an easier way to try things out here.

1 Like

I totally agree! Fuzzy search here would be great. We don't expect the initial release of the sidebar to have it, but I've filed [SR-15900] Add support for fuzzy search in the DocC-Render navigator · Issue #278 · apple/swift-docc-render · GitHub to track this as an enhancement.

3 Likes

@rauhul Agreed! This really is great feedback we should explore. I've filed [SR-15902] DocC-Render footer causes navigator sidebar to scroll · Issue #277 · apple/swift-docc-render · GitHub to track this. Thank you for bringing it up here.


Thanks @Joseph_Heck! This is really great feedback from you and others.

We're using the navigator fragments emitted by the Swift compiler's symbol graph tool directly here, but per the symbol graph spec, the intention of the navigator fragments is to be optimized for scenarios with limited horizontal space so I think this is essentially a bug.

We actually have some inconsistencies here, for example, we don't include identifiers like struct and class but we do include func . I agree that the kind icons already convey this information so optimizing the experience to just include the symbol's name and (if applicable) arguments is likely what makes sense here.

I've filed [SR-15901] Swift symbol graph navigator fragments should be better optimized for limited horizontal space · Issue #180 · apple/swift-docc · GitHub to track this. CC: @QuietMisdreavus :smiley:

1 Like

We actually have some inconsistencies here, for example, we don't include identifiers like struct and class but we do include func . I agree that the kind icons already convey this information so optimizing the experience to just include the symbol's name and (if applicable) arguments is likely what makes sense here.

On this specific point: The rational for this choice was that some symbol kinds like structures and classes have specific icons, but many other symbol kinds share the same icon. Some examples (not sure this is exhaustive):

  • Functions (mutating or otherwise) and static functions use the icon [M]
  • Mutable and immutable properties both use [P]
  • static let members and and global variables (whether they're let or var) use [V]
  • Enumerations and enumeration cases both use [E]. Interestingly, enumerations don't get an enum prefix but cases do get a case prefix (presumably because it's obvious in context; cases are always children)

I don't have an opinion on what we should do—if anything—to address those cases.

1 Like

I agree that hiding the sidebar should be optional, we should probably consider that improvement in the future across all viewports and not only for small/medium viewport sizes.

1 Like

The field only allows for filtering the content—placing it at the bottom provides more clarity for the functionality it provides.

1 Like

I'm excited to announce that the Swift-DocC sidebar has been enabled by default in Swift-DocC-Render with:

The sidebar will only be available for DocC archives produced by the latest version of DocC that includes the necessary index file.

I've updated the ArgumentParser demo with the latest changes: https://ethan-kusters.github.io/swift-argument-parser/documentation/argumentparser/.

If you'd like to try out the sidebar with your own Swift Package, you can do the following:

Testing instructions:

Note that I'm going to use the Swift-DocC Plugin to simplify the instructions here but it's not actually required for this functionality. It just makes testing prerelease versions of the docc CLI a little more user-friendly.

  1. Build the latest version of Swift-DocC:

    git clone https://github.com/apple/swift-docc.git
    cd swift-docc
    swift build
    

  1. Set the DOCC_EXEC environment variable to your locally built copy of docc:
    export DOCC_EXEC=`pwd`/.build/debug/docc
    

  1. Clone the latest pre-built version of Swift-DocC-Render:

    git clone https://github.com/apple/swift-docc-render-artifact.git
    cd swift-docc-render-artifact
    

  1. Set the DOCC_HTML_DIR environment variable to your local copy of Swift-DocC-Render:

    export DOCC_HTML_DIR=`pwd`/dist
    

  1. Adopt the Swift-DocC-Plugin in your package by following the instructions here.

    .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),
    

  1. Change directory to your package and run the preview-documentation command for your target:
    cd <path-to-your-package>
    swift package --disable-sandbox preview-documentation --target <name-of-package-target>
    

  1. That's it!

If you encounter any issues while trying things out, a bug report on bugs.swift.org (and soon GitHub Issues) would be really appreciated.

- Ethan

5 Likes

I've been generating docs with the commands

env DOCC_JSON_PRETTYPRINT="YES" \
swift package \
--allow-writing-to-directory "\(outputPath)" \
generate-documentation \
--disable-indexing \
--transform-for-static-hosting \
--output-path "\(outputPath)" \
--hosting-base-path "\(hostingBasePath)" \
--target "\(target)"

for macOS and

xcodebuild \
-derivedDataPath "$PWD/.derivedData" \
docbuild \
-scheme "\(target)" \
-destination 'generic/platform=\(platform.rawValue)'

xcrun docc process-archive transform-for-static-hosting \
$(find "$PWD/.derivedData" -type d -name "*.doccarchive") \
--output-path "\(outputPath)" \
--hosting-base-path "\(hostingBasePath)"

for iOS using the DocC plugin in a package manifest, with Swift 5.6. (This is in the context of generating package documentation in the Swift Package Index.)

Following this discussion here I was wondering if there's a way to get the new sidebar with this setup or if we need to wait for some SPM/DocC release to get it automatically?

I've tried removing the parameter --disable-indexing but that doesn't change anything. The documentation of that parameter

By default, the Swift-DocC plugin will generate an index of content that is useful for IDE’s, like Xcode, to render a navigator of all included documentation in the archive. Since this index isn’t relevant when hosting online, you can pass the --disable-indexing flag when generating documentation thats intended for an online host.

led me to believe this is something we'll want to set. But reading the discussion above about --index becoming the default I'm now wondering if this setting would prevent the sidebar from appearing even if we were using the proper DocC version that supported it.

Is this a parameter we should be setting for generated and hosted documentation?

2 Likes

Hi @finestructure!

The sidebar is included in Swift 5.7 Development toolchains on Swift.org here. In general both of the command-line invocations you provided look correct to me (it is correct to continue passing --disable-indexing even when you want the sidebar to be available on the web) and I'd expect them to "just work" once you update to a 5.7 toolchain.

If you'd like to continue using Swift 5.6 for building the actual source code, but use the Swift 5.7 version of Swift-DocC, you should be able to by passing a custom DocC executable path to your SwiftPM or xcodebuild invocation.

Assuming you have a recent 5.7 development toolchain installed but a version of Xcode with a 5.6 toolchain selected:

env DOCC_EXEC="/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/docc" \
env DOCC_JSON_PRETTYPRINT="YES" \
swift package \
    --allow-writing-to-directory "\(outputPath)" \
    generate-documentation \
    --disable-indexing \
    --transform-for-static-hosting \ # <-- Note: This is optional with Swift 5.7 since the transformation is enabled by default.
    --output-path "\(outputPath)" \
    --hosting-base-path "\(hostingBasePath)" \
    --target "\(target)"

And for iOS, you should be able to combine your two commands into one via the EXTRA_DOCC_FLAGS build setting.

xcodebuild \
    -derivedDataPath "$PWD/.derivedData" \
    docbuild \
    -scheme "\(target)" \
    -destination 'generic/platform=\(platform.rawValue)' \
    EXTRA_DOCC_FLAGS="--hosting-base-path '\(hostingBasePath)' --transform-for-static-hosting"
    DOCC_EXEC="/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/docc" \

cp -r $(find "$PWD/.derivedData" -type d -name "*.doccarchive") "\(outputPath)"
4 Likes

That's great to hear, thanks for confirming, Ethan!

1 Like