Skip to content
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

On Hover Footnote Preview #2522

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

shravanngoswamii
Copy link
Contributor

Added On-Hover Footnote Preview feature!
I used a small jQuery script for fetching the footnote definitions from the end of the page and its working very fine!

Screenshot 2024-06-05 075038

closes #2080

@fredrikekre
Copy link
Member

Nice. This would be awesome to have for docstring references too, but might be a bit more tricky since it doesn't have to be on the same page.

@shravanngoswamii
Copy link
Contributor Author

Nice. This would be awesome to have for docstring references too, but might be a bit more tricky since it doesn't have to be on the same page.

I can look into that if you can just tell me the part of codebase which deals with it!

Copy link
Member

@goerz goerz left a comment

Choose a reason for hiding this comment

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

Very nice feature, and the implementation looks very clean!

I've verified that this does not break anything when viewing the documentation with a non-js terminal browser like w3m.

One detail: I've had some interest in this kind of hover functionality, where I was hoping to re-use a future implementation for hover on footnotes (i.e., this implementation) for hover of bibliographic references as well, see JuliaDocs/DocumenterCitations.jl#67

It seems like that might work with this if I add the .footnote-reference class to the citation link in the rendered HTML. And then I would presumably need to add some extra hidden "preview text" to the page that contains some version of fully rendered reference.

I would like to understand a little better what requirements the JS in this PR imposes on any such preview text. See also @fredrikekre's comment about generalizing this to even more things like docstrings.

Thus, I might suggest naming everything not specifically in relation to "footnote" but in relation to "hover" to make it more general, and reusable by plugins.

This is somewhat optional. I don't want to hold up this PR by unreasonably complicating matters, but it might be worth taking into consideration.

// libraries: jquery
// arguments: $

$(document).ready(function() {
Copy link
Member

Choose a reason for hiding this comment

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

I think this is where it actually sets the preview text that will be shown on hover, right?

Can you elaborate a little on what assumptions this makes on the HTML of the footnote? I'm trying to figure out if these assumptions hold / could be made to hold for bibliographic references as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, this is used to get the footnote content in hidden span for preview! This jQuery code takes the footnote definitions from the end of the page and puts it into the hidden spans just under the footnotes based on their footnote IDs!

For bibliographic references, we will need another way because the references are in another file and not on same page!
We can add a hidden span in Julia part like this:

span[".footnote-preview", :id => "fn-$(f.id)"](footnote content comes here using that JQuery!)

We can add a small julia function which stores bibliographic reference on pages its being used on and then add them in span! This way we can use this method for all things that require hover preview feature whether it is footnotes, bibliographic references or docstring references!

We will just need those small julia functions for storing content and put them in span and similar css can be used for all, No Javascript or JQuery will be needed and this is most efficient way!

I used JQuery because I was not able to fetch content using Julia (lack of my expertise)

Copy link
Member

Choose a reason for hiding this comment

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

For bibliographic references, we will need another way because the references are in another file and not on same page!

That's probably not that much of an issue: I wouldn't mind adding (hidden) bibliography items on each page for anything that's being referenced on that page, just for the hover to be able to pick up the text for there. But there should be some existing JS to hook into (i.e., this PR) for showing the hover: I'd like to avoid having to instruct people using the plugin to manually set up JS.

@@ -0,0 +1,35 @@
.footnote-reference {
Copy link
Member

Choose a reason for hiding this comment

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

Maybe name these, e.g., .hover-reference and .hover-preview to make them more general for things beyond footnotes, like citations?

Copy link
Contributor Author

@shravanngoswamii shravanngoswamii Jun 6, 2024

Choose a reason for hiding this comment

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

for now until jQuery is being used we can only use this for footnotes but if can we use Julia for adding content then it will be better to change this to global use for preview features in all parts!

@mortenpi
Copy link
Member

Very cool! It looks like you can run into some "layout" issues when you have small windows or are close to edges I guess:

image

I don't know if there are any easy ways to work around this or not. We can always iterate on it later as well, if there aren't.

A few other thoughts:

  • We could use data-* attributes to label the footnote content, to make it reusable maybe?
  • I'm pretty happy to have JS copy the HTML/DOM around (as opposed to generating it with Julia). Although if we do want stuff from other pages, then we might indeed have to generate those as hidden elements.

Generally, I think I'd be happy to merge this pretty much as is, and iterate in follow-up PRs. Or if you want to fiddle with it a bit more, we can also wait.

@shravanngoswamii
Copy link
Contributor Author

I would be happy if you can wait a little! Sorry, actually I did not test it on small windows! I will make some changes in it as soon as I get some time!

@shravanngoswamii
Copy link
Contributor Author

I changed the CSS, but I am not able to have perfect positioning using only CSS, so I used some (lot, I guess) JavaScript! I do not know if we should have this much JS just for footnote preview on client side or not. Also when I integrate this in Documenter, it's not working properly, maybe I have to look at it properly!

This new template works fine, Just take a look at this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <style>
        .footnote-reference {
            position: relative;
            /* display: inline-block; */
        }

        .footnote-preview {
            display: none;
            position: fixed;
            z-index: 1000;
            max-width: min(300px, 90vw);
            width: max-content;
            background-color: var(--body-background-color, #ffffff);
            border: 1px solid var(--link-hover, #cccccc);
            padding: 10px;
            border-radius: 5px;
            box-sizing: border-box;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        .footnote-reference:hover .footnote-preview,
        .footnote-reference:focus-within .footnote-preview {
            display: block;
        }
    </style>

    <h2 id="Footnotes">
        <a class="docs-heading-anchor" href="#Footnotes">Footnotes</a>
        <a id="Footnotes-1"></a>
        <a class="docs-heading-anchor-permalink" href="#Footnotes" title="Permalink"></a>
    </h2>
    <p>Footnote references can be added with the <code>[^label]</code> syntax.
        <sup class="footnote-reference">
            <a id="citeref-1" href="#footnote-1" class="footnote-ref">[1]</a>
            <span class="footnote-preview" id="fn-1">A footnote definition uses the <code>[^label]: ...</code> syntax in a block scope.</span>
        </sup>
    </p>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const footnoteReferences = document.querySelectorAll('.footnote-reference');

            footnoteReferences.forEach(reference => {
                const preview = reference.querySelector('.footnote-preview');

                reference.addEventListener('mouseenter', () => positionPreview(reference, preview));
                reference.addEventListener('focus', () => positionPreview(reference, preview));
            });

            function positionPreview(reference, preview) {
                const refRect = reference.getBoundingClientRect();
                const viewportWidth = window.innerWidth;
                const viewportHeight = window.innerHeight;

                preview.style.left = '';
                preview.style.top = '';
                preview.style.bottom = '';
                preview.style.maxWidth = '';
                preview.style.maxWidth = `min(300px, ${viewportWidth * 0.9}px)`;

                const previewRect = preview.getBoundingClientRect();

                let left, top;
                const margin = 10;

                if (refRect.left + previewRect.width + margin > viewportWidth) {
                    left = viewportWidth - previewRect.width - margin;
                } else {
                    left = refRect.left + (refRect.width / 2) - (previewRect.width / 2);
                }
                left = Math.max(margin, left);

                if (refRect.bottom + previewRect.height + margin > viewportHeight) {
                    top = refRect.top - previewRect.height - margin;
                } else {
                    top = refRect.bottom + margin;
                }

                preview.style.left = `${left}px`;
                preview.style.top = `${top}px`;
            }

            window.addEventListener('resize', () => {
                footnoteReferences.forEach(reference => {
                    const preview = reference.querySelector('.footnote-preview');
                    if (getComputedStyle(preview).display === 'block') {
                        positionPreview(reference, preview);
                    }
                });
            });
        });
    </script>
</body>

</html>

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.

On-hover footnote preview
4 participants