diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 0e35de3ce09..3305fad3cc7 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -228,7 +228,7 @@ jobs: # We copy everything to a local folder docker cp --follow-link BUILD:/sage/local/share/doc/sage/html livedoc docker cp --follow-link BUILD:/sage/local/share/doc/sage/pdf livedoc - docker cp BUILD:/sage/local/share/doc/sage/index.html livedoc + docker cp --follow-link BUILD:/sage/local/share/doc/sage/index.html livedoc zip -r livedoc.zip livedoc - name: Upload live doc diff --git a/.github/workflows/doc-publish.yml b/.github/workflows/doc-publish.yml index d5eafc953e1..5454519a6fb 100644 --- a/.github/workflows/doc-publish.yml +++ b/.github/workflows/doc-publish.yml @@ -129,6 +129,16 @@ jobs: run: unzip livedoc.zip -d livedoc if: steps.download-doc.outcome == 'success' + - name: Create _headers file for permissive CORS + run: | + cat < livedoc/livedoc/_headers + /* + Access-Control-Allow-Origin: * + Access-Control-Allow-Methods: GET + Access-Control-Allow-Headers: Content-Type + EOF + if: steps.download-doc.outcome == 'success' + - name: Deploy to netlify with doc-TAG alias id: deploy-netlify uses: netlify/actions/cli@master diff --git a/src/bin/sage-update-version b/src/bin/sage-update-version index c6680918a36..179461a8340 100755 --- a/src/bin/sage-update-version +++ b/src/bin/sage-update-version @@ -112,6 +112,25 @@ export SAGE_VERSION export SAGE_RELEASE_DATE envsubst <"$SAGE_ROOT/CITATION.cff.in" >"$SAGE_ROOT/CITATION.cff" +# Update src/doc/versions.txt file storing the URLs of the docs for the recent stable releases +if [[ $SAGE_VERSION =~ ^[0-9]+(\.[0-9]+)*$ ]]; then + file_path="$SAGE_ROOT/src/doc/en/website/versions.txt" + # Extract the most recent version line from versions.txt + line_number=$(grep -n '^[0-9]' "$file_path" | head -n 1 | cut -d: -f1) + version_line=$(sed -n "${line_number}p" "$file_path") + domain=${version_line#*--} + version=${SAGE_VERSION//./-} + # For the origin of this format, see .github/workflows/doc-publish.yml + url="doc-$version--$domain" + # Add new line to versions.txt + sed -i "${line_number}i $SAGE_VERSION $url" "$file_path" + # If the number of version lines is more than 10, remove the last line + line_count=$(grep -c '^[0-9]' "$file_path") + if [ "$line_count" -gt 10 ]; then + sed -i '$ d' "$file_path" + fi +fi + # Commit auto-generated changes git commit -m "Updated SageMath version to $SAGE_VERSION" -- \ "$SAGE_ROOT/VERSION.txt" \ @@ -124,6 +143,7 @@ git commit -m "Updated SageMath version to $SAGE_VERSION" -- \ "$SAGE_ROOT/build/pkgs/*/version_requirements.txt" \ "$SAGE_ROOT"/pkgs/*/VERSION.txt \ "$SAGE_ROOT/.upstream.d/20-github.com-sagemath-sage-releases" \ + "$SAGE_ROOT/src/doc/en/website/versions.txt" \ || die "Error committing to the repository." git tag -a "$SAGE_VERSION" -m "$SAGE_VERSION_BANNER" \ diff --git a/src/doc/common/static/custom-furo.css b/src/doc/common/static/custom-furo.css index ae75c2b6383..85d2a0776cf 100644 --- a/src/doc/common/static/custom-furo.css +++ b/src/doc/common/static/custom-furo.css @@ -24,14 +24,53 @@ a.pdf:hover { /* Style for announcement banner */ .announcement { - background: orange; + background: orange; } .announcement-content { - color: black; + color: black; } .announcement-content a { - color: white; - text-decoration: none; + color: white; + text-decoration: none; } + +/* Style for the floating versions menu */ + +.sidebar-drawer { + z-index: 100; +} + +.select-wrapper { + display: block; + text-align: center; +} + +#versions-menu { + display: inline-block; + font-size: small; + opacity: 1; + border: none; + background-color: transparent; + color: var(--color-sidebar-link-text--top-level);; +} + +#versions-menu:focus { + outline: none; +} + +body[data-theme="dark"] { + #versions-menu { + background-color: transparent; + } +} + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] { /* the same styles with body[data-theme="dark"] */ + #versions-menu { + background-color: transparent; + } + } +} + diff --git a/src/doc/common/static/custom-jupyter-sphinx.css b/src/doc/common/static/custom-jupyter-sphinx.css index 7e090b5e08d..482a2ddaed2 100644 --- a/src/doc/common/static/custom-jupyter-sphinx.css +++ b/src/doc/common/static/custom-jupyter-sphinx.css @@ -96,41 +96,41 @@ body[data-theme="dark"] { } @media (prefers-color-scheme: dark) { - body[data-theme="auto"] { /* the same styles with body[data-theme="dark"] */ - .jupyter_container { - color: white; - background-color: black; - } - - .jupyter_container .highlight { - background-color: black; - } - - .thebelab-button { - color: #d0d0d0; - background-color: #383838; - } - - .thebelab-button:active { - color: #368ce2; - } - - #thebelab-activate-button { - background-color: #383838; - } - - #thebelab-activate-button:active { - color: #368ce2; - } - - .thebelab-cell .jp-OutputArea-output { - color: white; - background-color: black; - } - - .thebelab-cell .jp-OutputArea-output pre { - color: white; - background-color: black; + body[data-theme="auto"] { /* the same styles with body[data-theme="dark"] */ + .jupyter_container { + color: white; + background-color: black; + } + + .jupyter_container .highlight { + background-color: black; + } + + .thebelab-button { + color: #d0d0d0; + background-color: #383838; + } + + .thebelab-button:active { + color: #368ce2; + } + + #thebelab-activate-button { + background-color: #383838; + } + + #thebelab-activate-button:active { + color: #368ce2; + } + + .thebelab-cell .jp-OutputArea-output { + color: white; + background-color: black; + } + + .thebelab-cell .jp-OutputArea-output pre { + color: white; + background-color: black; + } } - } } diff --git a/src/doc/common/static/jupyter-sphinx-furo.js b/src/doc/common/static/jupyter-sphinx-furo.js index a43a7c8b122..b63de354db8 100644 --- a/src/doc/common/static/jupyter-sphinx-furo.js +++ b/src/doc/common/static/jupyter-sphinx-furo.js @@ -58,6 +58,71 @@ const observer2 = new MutationObserver(callback); observer2.observe(document.getElementsByClassName("content")[0], { childList: true, subtree: true }); +// +// Version selector +// + +function fetchVersions() { + try { + let menu = document.getElementById('versions-menu'); + + // For the origin of the this site, see .github/workflows/doc-publish.yml + fetch('https://doc-release--sagemath.netlify.app/html/en/versions.txt') + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok ' + response.statusText); + } + return response.text(); + }) + .then(text => { + const lines = text.split('\n'); + lines.forEach(line => { + if (!line.startsWith('#')) { // Ignore the comment line + let [ver, url] = line.split(' '); + if (ver && url) { + if (!url.startsWith('https://')) { + url = 'https://' + url; + } + let option = document.createElement('option'); + option.value = url; + option.text = ver; + menu.add(option); + } + } + }); + }) + .catch(error => { + console.log('Failed to fetch versions.txt file.'); + }); + } catch (error) { + console.log('Failed to fetch versions.txt file.'); + } +} + +fetchVersions() + +// Function to change the version based on versions menu selection +function changeVersion() { + let select_element = document.getElementById("versions-menu"); + let selected_ver = select_element.options[select_element.selectedIndex].text; + let selected_url = select_element.value; + if (selected_url) { + if (window.location.protocol == 'file:') { + let pathname = window.location.pathname; + let cutoff_point = pathname.indexOf('doc/sage'); + if (cutoff_point !== -1) { + pathname = pathname.substring(cutoff_point + 8); + window.location.href = selected_url + pathname; + } else { + window.location.href = selected_url + 'html/en/index.html'; + } + } else { + window.location.href = selected_url + window.location.pathname; + } + } +} + + // Listen to the kernel status changes // https://thebe.readthedocs.io/en/stable/events.html thebelab.on("status", function (evt, data) { diff --git a/src/doc/common/templates-furo/sidebar/version-selector.html b/src/doc/common/templates-furo/sidebar/version-selector.html new file mode 100644 index 00000000000..6807b131dcf --- /dev/null +++ b/src/doc/common/templates-furo/sidebar/version-selector.html @@ -0,0 +1,6 @@ +
+ +
diff --git a/src/doc/en/website/versions.txt b/src/doc/en/website/versions.txt new file mode 100644 index 00000000000..12aed2b8cfe --- /dev/null +++ b/src/doc/en/website/versions.txt @@ -0,0 +1,17 @@ +# This file is used by the version selector of the Sage doc +# and updated by the script src/bin/sage-update-version +# +# The lines are for recent stable releases (at most 10 lines) +# A line consists of the version and the URL to the doc +# +# The sage-update-version script adds a new line for a new stable release +# when run by the Sage release manager to prepare a new release +# +10.4 doc-10-4--sagemath.netlify.app +10.3 doc-10-3--sagemath.netlify.app +10.2 doc-10-2--sagemath.netlify.app +10.1 doc-10-1--sagemath.netlify.app +10.0 doc-10-0--sagemath.netlify.app +9.8 doc-9-8--sagemath.netlify.app +9.7 doc-9-7--sagemath.netlify.app +9.6 doc-9-6--sagemath.netlify.app diff --git a/src/sage_docbuild/builders.py b/src/sage_docbuild/builders.py index 967616e2e28..871cc4705a2 100644 --- a/src/sage_docbuild/builders.py +++ b/src/sage_docbuild/builders.py @@ -442,6 +442,11 @@ def html(self): """ super().html() html_output_dir = self._output_dir('html') + + # This file is used by src/doc/common/static/jupyter-sphinx-furo.js + # for doc version selector + shutil.copy2(os.path.join(self.dir, 'versions.txt'), html_output_dir) + for f in os.listdir(html_output_dir): src = os.path.join(html_output_dir, f) dst = os.path.join(html_output_dir, '..', f) @@ -451,9 +456,8 @@ def html(self): else: shutil.copy2(src, dst) - root_index_file = os.path.join(html_output_dir, '../../../index.html') - shutil.copy2(os.path.join(SAGE_DOC_SRC, self.lang, 'website', 'root_index.html'), - root_index_file) + shutil.copy2(os.path.join(self.dir, 'root_index.html'), + os.path.join(html_output_dir, '../../../index.html')) def pdf(self): """ diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 9ff67bc9ca7..fbea163ead3 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -473,6 +473,7 @@ def linkcode_resolve(domain, info): "**": [ "sidebar/scroll-start.html", "sidebar/brand.html", + "sidebar/version-selector.html", "sidebar/search.html", "sidebar/home.html", "sidebar/navigation.html", @@ -679,7 +680,7 @@ def add_page_context(app, pagename, templatename, context, doctree): path2 = os.path.join(SAGE_DOC, 'html', 'en') relpath = os.path.relpath(path2, path1) context['release'] = release - context['documentation_title'] = 'Sage {}'.format(release) + ' Documentation' + context['documentation_title'] = f'Version {release} Documentation ' context['documentation_root'] = os.path.join(relpath, 'index.html') if 'website' in path1: context['title'] = 'Documentation' @@ -688,7 +689,7 @@ def add_page_context(app, pagename, templatename, context, doctree): if 'reference' in path1 and not path1.endswith('reference'): path2 = os.path.join(SAGE_DOC, 'html', 'en', 'reference') relpath = os.path.relpath(path2, path1) - context['reference_title'] = 'Sage {}'.format(release) + ' Reference Manual' + context['reference_title'] = f'Version {release} Reference Manual' context['reference_root'] = os.path.join(relpath, 'index.html') context['refsub'] = True if pagename.startswith('sage/'):