diff options
| author | 2025-12-04 20:06:21 +0100 | |
|---|---|---|
| committer | 2025-12-04 20:06:21 +0100 | |
| commit | 5e9c3617cac1e3eac246e2ae7df6f4b71c33d37c (patch) | |
| tree | 435618816d2ccc5d29b21fa0c089f814972a2ce7 /docs/assets/js/docs.js | |
| parent | 78e40c6fe3afe7f815ef9d32646610e2d5436ba3 (diff) | |
Improve layout of documentation page and add search feature (#8247)
* Improve layout of documentation page and add search feature
Closes https://github.com/FreshRSS/FreshRSS/issues/7915, https://github.com/FreshRSS/FreshRSS/issues/5325
Also: anchor headings and fix building site locally
* Further improvements
* Set color of hyperlinks
* Consistent styling of close aside button across devices
* Mobile layout 600px -> 1200px
* Add suffix to docs `<title>`
* Note: titles of pages probably need to be improved, since currently they are just derived from the names of the first heading on every page
* Add favicon
* Improve font
* Try to fix favicon not loading correctly on GH pages
* Use local font
* Attempt to fix GH pages
* Final improvements
* Copy to clipboard button
* Support for nojs search
* Dark mode
* Load search.json (200KB json) only on search input focus
* Keep scroll state of sidebar across navigations
* Clickable images and CSP
CSP so we avoid hotlinking resources and clickable images are useful for zooming on mobile for example
* Fix typos
* Disable Dark Reader extension if dark mode CSS is loaded
* Support internationalisation (via language dropdown)
* Add Gemfile.lock
* Make CI build work with the custom plugin
* Make menus closable with Esc
* Fix typos CI
* Suggestions
* Use `ruby/setup-ruby` action in workflow for installing and caching gems.
* Run build only when there are changes to `docs/`
See: https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows?versionId=free-pro-team%40latest&productId=actions#running-your-workflow-only-when-a-push-to-specific-branches-occurs
* Change font to `Open Sans`
* Increase line height
* Fix Liquid syntax error
Diffstat (limited to 'docs/assets/js/docs.js')
| -rw-r--r-- | docs/assets/js/docs.js | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/docs/assets/js/docs.js b/docs/assets/js/docs.js new file mode 100644 index 000000000..c14fce920 --- /dev/null +++ b/docs/assets/js/docs.js @@ -0,0 +1,63 @@ +/* globals i18n */ + +if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + document.head.insertAdjacentHTML('beforeend', ` + <meta name="darkreader-lock"> + `); +} + +let asideNav; + +window.addEventListener('beforeunload', () => { + sessionStorage.setItem('sidebar_scrollTop', asideNav.scrollTop); +}); + +window.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + location.hash = 'close'; + } +}); + +document.addEventListener('DOMContentLoaded', () => { + asideNav = document.querySelector('aside > nav.docs'); + + const sidebar_scrollTop = sessionStorage.getItem('sidebar_scrollTop'); + if (sidebar_scrollTop) { + asideNav.scrollTo(0, sidebar_scrollTop); + sessionStorage.removeItem('sidebar_scrollTop'); + } + + for (const el of document.querySelectorAll('div.highlight')) { + /* eslint-disable @stylistic/max-len */ + el.insertAdjacentHTML('afterbegin', ` + <button class="copy" title="${i18n.copy_to_clipboard}"> + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> + <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z"/> + <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z"/> + </svg> + </button> + `); + /* eslint-enable @stylistic/max-len */ + const copyBtn = el.querySelector('button.copy'); + copyBtn.addEventListener('click', () => { + const snippet = el.querySelector('code').innerText; + if (navigator.clipboard) { + navigator.clipboard.writeText(snippet); + } else { + // Fallback if no HTTPS + const input = document.createElement('textarea'); + input.innerHTML = snippet; + document.body.append(input); + input.select(); + document.execCommand('copy'); + input.remove(); + } + }); + } + + for (const el of document.querySelectorAll('img')) { + if (el.parentNode.tagName !== 'A') { + el.outerHTML = `<a href="${el.getAttribute('src')}">${el.outerHTML}</a>`; + } + } +}); |
