Skip to content

Add anchor for section titles for quick sharing of sections #408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Sep 15, 2022

Conversation

marinaaisa
Copy link
Member

Bug/issue #96943502, if applicable:

Summary

Add anchor for section titles for quick sharing of sections.
This anchor shows when user hovers the title section.

Issue: #273

Dependencies

NA

Testing

Steps:

  1. Open any docc archive
  2. Assert that all h2 and h3 titles in documentation pages show an anchor when hovering the title

Checklist

Make sure you check off the following items. If they cannot be completed, provide a reason.

  • Added tests
  • Ran npm test, and it succeeded
  • Updated documentation if necessary

@marinaaisa
Copy link
Member Author

@swift-ci test

2 similar comments
@marinaaisa
Copy link
Member Author

@swift-ci test

@marinaaisa
Copy link
Member Author

@swift-ci test

Copy link
Contributor

@dobromir-hristov dobromir-hristov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, very nice! 🚀

One thing I noticed is if I tab through, it does not show the anchors, deff something we should fix.

Need to check if we should disable this for IDE environments.

Also we may check with the DocC team if they plan to provide anchors for those Topic subsections, instead of us generating them - #190

Other than that, looks great :)

@marinaaisa
Copy link
Member Author

Thanks @dobromir-hristov !

One thing I noticed is if I tab through, it does not show the anchors, deff something we should fix.

Fixed! Good catch!

Need to check if we should disable this for IDE environments.

Why would we? it should scroll in the same way, right?

Also we may check with the DocC team if they plan to provide anchors for those Topic subsections, instead of us generating them - #190

Yeah, that would be much better than the generation I'm doing in the frontend!

Give it another review. I still need to add final tests for the handleFocusAndScroll function I added in the scrollToElement mixin.

@dobromir-hristov
Copy link
Contributor

I don't see a point in having a clickable link in the ide, since there is no URL bar

Copy link
Contributor

@dobromir-hristov dobromir-hristov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it looks good now. How does VO handle the hidden anchor item? Do we need anything special for it?

tag: {
type: String,
default: () => 'h2',
},
},
mounted() {
if (!this.anchor) return;
const element = document.getElementById(`${this.anchor}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty clever though I am not sure how I feel about it.

All headings would be rendered initially without an id and would then re-render to add the id, if there is no element with that anchor. This makes the component easier to user, but a bit more unpredictable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unpredictable? We use dynamic ids in many more components across the app... 🤔
But if you have any better approach, happy to look into it :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well you may be right. I would have probably just made this logic user controllable, via some boolean whether to apply an id to the element or not.

@marinaaisa
Copy link
Member Author

I think it looks good now. How does VO handle the hidden anchor item? Do we need anything special for it?

We are hiding it from VO because I think it's not providing any value to VO users. https://vuejs.org/guide/introduction.html#what-is-vue does it in the same way

@marinaaisa
Copy link
Member Author

I don't see a point in having a clickable link in the ide, since there is no URL bar

True, I don't render it anymore on IDEs f6bd656

@marinaaisa
Copy link
Member Author

@swift-ci test

Copy link
Contributor

@dobromir-hristov dobromir-hristov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. @mportiz08 can you look into the anchor logic if you are fine with it and we can merge this one I think

tag: {
type: String,
default: () => 'h2',
},
},
mounted() {
if (!this.anchor) return;
const element = document.getElementById(`${this.anchor}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well you may be right. I would have probably just made this logic user controllable, via some boolean whether to apply an id to the element or not.

Copy link
Contributor

@mportiz08 mportiz08 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool to see this in action, and I love that it just works as expected in places where no anchor data is provided.

I have a minor concern about the anchor generation, but I think the majority of my other comments are pretty small things that will be easy to fix.

},
mounted() {
if (!this.anchor) return;
const element = document.getElementById(`${this.anchor}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const element = document.getElementById(`${this.anchor}`);
const element = document.getElementById(this.anchor);

As a more general comment though, I don't totally understand the need for why this hook is needed. Why are there separate id and anchor values and how are they used differently?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are cases where the ID is applied on a section that wraps the heading (like in TopicsSection), but in other cases, the heading has to hold the ID.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not totally following how that requires the mounted hook here (probably just missing something).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think she wanted it to be more magical. Thats one of the points I raised that I wanted your input on :D

The component tries to find an already existing element with that id in the DOM, and if it doesnt, it adds that id to itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I just don't understand the magical part, to be more clear. Why would this logic have to happen after the initial render?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So all possible items that may have that ID are rendered? As I said I would probably control this through a prop instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mportiz08 I had this logic to check if the document has already an id on it where we want to link to. This happens in components that have the id in the beginning of the section itself instead of having it in the title.
Also in this way, we avoid duplication of ids in the HTML, since ID attributes must be unique in the document.

Controlling through a prop, as @dobromir-hristov suggested, would allow us more flexibility but would open the component for possible HTML's errors because we wouldn't prevent the document from duplication of HTML ids.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why we might choose to sometimes assign the ID attribute to a non-heading element instead of a heading, but I don't understand why we couldn't prevent the ID from being assigned in multiple places in the components themselves—it seems like that is controlled by our app and not outside forces. If that's the case, then we should be able to programmatically decide where the anchor uniquely goes before any mounted hook gets called after the initial render.

I think we both agree on the goal of only having unique IDs but maybe there's a little confusion about how to ensure it within the components themselves. Let me know if you want to talk about this offline—I may be missing a subtle thing here that might make this approach necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mportiz08 I set a meeting to continue discussing this. Interesting debate! Thanks :)

.header-anchor {
margin-left: -0.73em;
padding-right: 0.23em;
transition: opacity .25s;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to have someone from the design team review this new feature and test the experience in different browsers. The scrolling animation specifically (not this one) feels a little different in Safari but that may be a limitation of the JS scroll function itself.

@mportiz08
Copy link
Contributor

Just noting that we may want to close #190 when this gets merged.

@dobromir-hristov
Copy link
Contributor

Just noting that we may want to close #190 when this gets merged.

Even though this PR adds most of what #190 does, that one was assuming the anchors come from DocC. I think if Marina does that too, we can safely drop it :)

@marinaaisa
Copy link
Member Author

Even though this PR adds most of what #190 does, that one was assuming the anchors come from DocC. I think if Marina does that too, we can safely drop it :)

I moved most of the changes from #190 PR into this one, so we can merge it in here.

@marinaaisa
Copy link
Member Author

@swift-ci test

@marinaaisa marinaaisa force-pushed the r96943502/anchor-titles branch from 5c89246 to 4f2840c Compare August 31, 2022 16:03
@hqhhuang
Copy link
Contributor

hqhhuang commented Sep 1, 2022

Hey Marina!
This is brilliant! I still have questions about the id, but I will reach out offline for that.
I tested this and noticed 3 small things:

  1. The URL seems to be case sensitive. Is this intentional?
  2. This issue appears in Chrome only:
Screen.Recording.2022-09-01.at.4.24.57.PM.mov
  1. Do we want to dynamically update the URL with the anchors based on where the user is on the page as they scroll? I think the Vue Doc site does this.

@marinaaisa
Copy link
Member Author

Hey @hqhhuang ! thanks a lot for your comments!

  1. The URL seems to be case sensitive. Is this intentional?

URL are always case sensitive. You will see that some anchors are in lowercase and others aren't. This is because some come directly from docc (some have uppercase initials) and other we add them depending on the title (these ones are in lowercase). The anchor's names don't matter if they are in lowercase or not, as long as they point to an existing id with the same name.

  1. This issue appears in Chrome only:
    Screen.Recording.2022-09-01.at.4.24.57.PM.mov

This is because of the way we scroll to the section. We first scroll into the view where the title is, and then we scrollBy to overcome the navigation height. You can see it here: https://github.com/apple/swift-docc-render/blob/f5c1b7fd271518503e85f7a5d2dd5f993ded17be/src/mixins/scrollToElement.js#L26-L27
I'm not sure yet how to prevent that jumping at the beginning, in theory, it shouldn't be noticeable... we could look into improving it in the future.

  1. Do we want to dynamically update the URL with the anchors based on where the user is on the page as they scroll? I think the Vue Doc site does this.

Very good catch! Maybe this could a separate feature since it uses the ids but it doesn't depend on the new LinkableHeadinds, could you fill a radar or Github issue for it? Thanks!

@mportiz08
Copy link
Contributor

I know you're still iterating on the visual design of the link, but I wanted to say that we might want to consider some sort of absolute positioning of it to avoid situations like the following where the inline content needs to reflow sometimes:

Screen Recording 2022-09-02 at 1 33 46 PM

@hqhhuang
Copy link
Contributor

hqhhuang commented Sep 6, 2022

URL capitalization:

This is because some come directly from docc (some have uppercase initials) and other we add them depending on the title (these ones are in lowercase). The anchor's names don't matter if they are in lowercase or not, as long as they point to an existing id with the same name.

What are some existing examples of ones coming directly from docc? I think if we opted for all lowercase for Docc-render generated anchors, docc should also provide all lower case anchors. Is there a particular reason some of the docc ones have upper case initials?

Scroll jump:

This is because of the way we scroll to the section. We first scroll into the view where the title is, and then we scrollBy to overcome the navigation height. You can see it here:

https://github.com/apple/swift-docc-render/blob/f5c1b7fd271518503e85f7a5d2dd5f993ded17be/src/mixins/scrollToElement.js#L26-L27

Is there a difference between how Chrome and Safari handles the scroll? If this is the issue, I would sort of expect it to happen in both places.

Updating URL based on anchors:

Could you fill a radar or Github issue for it? Thanks!

rdar://99584817 I can try to work on this one in the coming weeks if we have a thumbs up from design.

Copy link
Contributor

@dobromir-hristov dobromir-hristov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested and it works OK. I think you havent missed any places where we use headings.

Just make sure you fix what Marcus pointed out, with the jumping text on hover.

@marinaaisa
Copy link
Member Author

I know you're still iterating on the visual design of the link, but I wanted to say that we might want to consider some sort of absolute positioning of it to avoid situations like the following where the inline content needs to reflow sometimes:

@mportiz08 oh true, fixed: 23fd3c7

but yes, the design specs aren't closed yet

@marinaaisa
Copy link
Member Author

Thanks for the feedback, @hqhhuang !

What are some existing examples of ones coming directly from docc? I think if we opted for all lowercase for Docc-render generated anchors, docc should also provide all lower case anchors.

For example in the slothcreator.json data file, the first object of the content key is:

{
  "anchor": "Overview",
  "level": 2,
  "type": "heading",
  "text": "Overview"
}

Is there a particular reason some of the docc ones have upper case initials?

I don't know. It shouldn't matter anyways

Is there a difference between how Chrome and Safari handles the scroll? If this is the issue, I would sort of expect it to happen in both places.

It may be a difference between browsers, yes! I will investigate those differences.

rdar://99584817 I can try to work on this one in the coming weeks if we have a thumbs up from design.

Thanks!

@marinaaisa
Copy link
Member Author

@swift-ci test

@marinaaisa
Copy link
Member Author

@swift-ci test

@marinaaisa
Copy link
Member Author

@swift-ci test

@marinaaisa
Copy link
Member Author

@swift-ci test

Copy link
Contributor

@mportiz08 mportiz08 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work @marinaaisa! This is working great, and I think it's almost ready to merge.

I just noticed one minor potential issue to look at with the color of the new linkable heading element.

Copy link
Contributor

@dobromir-hristov dobromir-hristov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, just check the things that Marcus pointed out.

@SamLanier
Copy link

New design approved.

@marinaaisa
Copy link
Member Author

@swift-ci test

@marinaaisa marinaaisa merged commit 0e106af into swiftlang:main Sep 15, 2022
@marinaaisa marinaaisa deleted the r96943502/anchor-titles branch September 15, 2022 13:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[SR-15915] Quickly select a section's URL on documentation pages
5 participants