diff --git a/docs/source/_static/css/styles.css b/docs/source/_static/css/styles.css new file mode 100644 index 00000000..c79eb665 --- /dev/null +++ b/docs/source/_static/css/styles.css @@ -0,0 +1,194 @@ +/* ========================================================================== + BLOP CUSTOM THEME STYLES (PyData Theme Compatible) + ========================================================================== */ + +/* RESET & BASE */ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: var(--pst-font-family-sans-serif); + background-color: var(--pst-color-background); + color: var(--pst-color-text-base); + line-height: 1.6; +} + +/* NAVBAR (Adapting to Theme) */ +.navbar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.25rem 2rem; +} + +.logo { + font-size: 1.5rem; + font-weight: 600; + color: var(--pst-color-text-base); +} + +.navbar nav a { + margin-left: 1.5rem; + text-decoration: none; + color: var(--pst-color-text-base); + transition: color 0.2s; +} + +.navbar nav a:hover { + color: var(--pst-color-primary); +} + +/* HERO SECTION */ +.hero { + text-align: center; + padding: 4rem 2rem; +} + +.hero h1 { + font-size: clamp(2.5rem, 5vw, 4rem); + color: var(--pst-color-text-base); +} + +.subtitle { + margin-top: 0.5rem; + font-size: 1.1rem; + color: var(--pst-color-text-muted); +} + +/* CONTENT LAYOUT */ +.content { + padding: 4rem 2rem; + max-width: 1100px; + margin: auto; +} + +.content h2 { + font-size: 2rem; + margin-bottom: 1.5rem; + color: var(--pst-color-text-base); +} + +.two-column { + display: grid; + gap: 2rem; +} + +@media (min-width: 768px) { + .two-column { + grid-template-columns: 1fr 1fr; + align-items: center; + } +} + +/* IMAGE/VISUAL PLACEHOLDERS */ +.image-placeholder { + background: var(--pst-color-surface); + border: 1px solid var(--pst-color-border); + border-radius: 12px; + height: 300px; + display: flex; + align-items: center; + justify-content: center; +} + +/* INSTALLATION TABS */ +.tabs-container { + margin: 20px 0; +} + +.tabs { + display: flex; + list-style: none; + padding: 0; + margin: 0; + border-bottom: 2px solid var(--pst-color-border); +} + +.tab-item { + padding: 12px 24px; + cursor: pointer; + color: var(--pst-color-text-muted); + font-weight: 600; + transition: all 0.2s; + margin-bottom: -2px; +} + +.tab-item.active { + color: var(--pst-color-primary); + border-bottom: 3px solid var(--pst-color-primary); +} + +/* CODE BLOCKS (Unified Styling) */ +pre, .command-block pre { + background-color: var(--pst-color-inline-code-background) !important; + color: var(--pst-color-text-base) !important; + border: 1px solid var(--pst-color-border) !important; + padding: 16px !important; + border-radius: 8px !important; + font-family: var(--pst-font-family-monospace); + font-size: 0.9rem; + overflow-x: auto; + margin: 1rem 0; +} + +code { + font-family: var(--pst-font-family-monospace); + color: var(--pst-color-text-base); +} + +/* LEARN MORE GRID */ +.card-grid { + display: grid; + gap: 1.5rem; + margin-top: 2rem; +} + +@media (min-width: 600px) { .card-grid { grid-template-columns: repeat(2, 1fr); } } +@media (min-width: 900px) { .card-grid { grid-template-columns: repeat(4, 1fr); } } + +.card, .custom-card { + background-color: var(--pst-color-surface); + border: 1px solid var(--pst-color-border); + padding: 2rem; + border-radius: 16px; + font-weight: 600; + text-align: center; + text-decoration: none; + color: var(--pst-color-text-base); + transition: transform 0.2s, border-color 0.2s; + display: block; +} + +.card:hover, .custom-card:hover { + transform: translateY(-3px); + border-color: var(--pst-color-primary); + color: var(--pst-color-primary); +} + +/* REFERENCES / CITATION BOX */ +.citation-text { + background-color: var(--pst-color-surface); + border-left: 5px solid var(--pst-color-primary); + padding: 20px; + border-radius: 0 8px 8px 0; + color: var(--pst-color-text-base); + line-height: 1.6; + margin: 1.5rem 0; +} + +/* FOOTER */ +footer { + text-align: center; + padding: 2rem; + font-size: 0.9rem; + color: var(--pst-color-text-muted); +} + +/* SPHINX LAYOUT OVERRIDES (Keep these for full-width landing) */ +body.pagename-index .bd-sidebar { display: none !important; } +body.pagename-index .bd-toc { display: none !important; } +body.pagename-index .bd-main { grid-template-columns: 1fr !important; } +body.pagename-index .bd-content { max-width: 100% !important; } diff --git a/docs/source/_static/javascript/javascript.js b/docs/source/_static/javascript/javascript.js new file mode 100644 index 00000000..f48bb936 --- /dev/null +++ b/docs/source/_static/javascript/javascript.js @@ -0,0 +1,103 @@ +document.addEventListener("DOMContentLoaded", () => { + // Existing tab functionality + document.querySelectorAll('.tab-item').forEach(tab => { + tab.addEventListener('click', () => { + const container = tab.closest('.tabs-container'); + const targetTab = tab.getAttribute('data-tab'); + + // Remove active class from all tabs and panels + container.querySelectorAll('.tab-item') + .forEach(t => t.classList.remove('active')); + container.querySelectorAll('.tab-panel') + .forEach(p => p.classList.remove('active')); + + // Activate selected tab + tab.classList.add('active'); + document.getElementById(targetTab).classList.add('active'); + }); + }); + + // Header search functionality + const searchInput = document.getElementById('search-input'); + if (searchInput) { + searchInput.addEventListener('keypress', function(e) { + if (e.key === 'Enter') { + e.preventDefault(); + const query = this.value.trim(); + if (query) { + // Navigate to search page with query + const searchUrl = new URL('search.html', window.location.origin + window.location.pathname); + searchUrl.searchParams.set('q', query); + window.location.href = searchUrl.toString(); + } + } + }); + } + + // Header theme toggle functionality + const themeButton = document.querySelector('.theme-switch-button'); + const themeIcon = document.getElementById('theme-icon'); + + if (themeButton && themeIcon) { + + // Function to update icon based on current theme + function updateThemeIcon() { + const currentTheme = document.documentElement.dataset.theme || 'auto'; + const isDark = currentTheme === 'dark' || + (currentTheme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches); + + themeIcon.className = isDark ? 'fa fa-moon' : 'fa fa-sun'; + } + + // Initial icon update + updateThemeIcon(); + + // Theme toggle click handler + themeButton.addEventListener('click', function() { + const currentTheme = document.documentElement.dataset.theme || 'auto'; + let newTheme; + + if (currentTheme === 'auto' || currentTheme === 'light') { + newTheme = 'dark'; + } else { + newTheme = 'light'; + } + + // Update theme + document.documentElement.dataset.theme = newTheme; + localStorage.setItem('theme', newTheme); + + // Update icon + updateThemeIcon(); + }); + + // Listen for system theme changes when in auto mode + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', updateThemeIcon); + } +}); + +function copyCode(button) { + // Find the code text relative to the button + const container = button.parentElement; + const codeText = container.querySelector('code').innerText; + + // Use the Clipboard API + navigator.clipboard.writeText(codeText).then(() => { + // Visual feedback + const originalText = button.innerText; + button.innerText = 'Copied!'; + button.classList.add('copied'); + + // Reset button after 2 seconds + setTimeout(() => { + button.innerText = originalText; + button.classList.remove('copied'); + }, 2000); + }).catch(err => { + console.error('Failed to copy: ', err); + }); +} + +document.querySelectorAll('.copy-btn').forEach(button => { + button.addEventListener('click', () => copyCode(button)); +}); diff --git a/docs/source/_templates/index.html b/docs/source/_templates/index.html new file mode 100644 index 00000000..bd3047dd --- /dev/null +++ b/docs/source/_templates/index.html @@ -0,0 +1,277 @@ +{% extends "pydata_sphinx_theme/layout.html" %} + +{% block sidebar %}{% endblock %} + +{% block content %} +
+
+ + {# Left side: Logo and Navigation #} +
+ {# Logo placeholder - you can replace this with an actual logo #} +
+
+ B +
+ + Blop + +
+ + {# Navigation Links #} + +
+ + {# Right side: Search and Theme Toggle #} +
+ {# Search Bar #} + + + {# Theme Toggle Button #} + +
+
+
+ +
+ +
+

Blop

+

+ a BeamLine Optimization Package +

+
+ +
+
+

What is Blop?

+

+ Blop is a Python library for performing optimization for beamline + experiments. It is designed to integrate nicely with the Bluesky + ecosystem and primarily targets rapid beamline data acquisition + and control. +

+

+ Our goal is to provide a simple and practical data-driven + optimization interface for beamline experiments. +

+
+ +
+
+ [Visualization Placeholder] +
+
+
+ +
+ +
+

Learn More!

+
+ + {# We define the list so additional items can be easily added #} + {% set nav_items = [ + ("Tutorials", "tutorials.html", "Step-by-step guides to get started with Blop fundamentals and basic workflows"), + ("How-to", "howto.html", "Practical recipes and solutions for specific beamline optimization tasks"), + ("References", "references.html", "Complete API documentation, class references, and technical specifications"), + ("Release History", "release-history.html", "Version updates, new features, bug fixes, and changelog for v" + release) + ] %} + + {% for title, link, description in nav_items %} +
+ + {{ title }} + +
+ {{ description }} +
+
+ {% endfor %} +
+
+ +
+ +
+

References

+

If you use this package in your work, please cite the following paper:

+ +
+ Morris, T. W., Rakitin, M., Du, Y., Fedurin, M., Giles, A. C., Leshchev, D., Li, W. H., Romasky, B., Stavitski, E., Walter, A. L., Moeller, P., Nash, B., & Islegen-Wojdyla, A. (2024). A general Bayesian algorithm for the autonomous alignment of beamlines. Journal of Synchrotron Radiation, 31(6), 1446–1456. + + https://doi.org/10.1107/S1600577524008993 + +
+ +

BibTeX:

+
+      @Article{Morris2024,
+          author   = {Morris, Thomas W. and Rakitin, Max and Du, Yonghua and Fedurin, Mikhail and Giles, Abigail C. and Leshchev, Denis and Li, William H. and Romasky, Brianna and Stavitski, Eli and Walter, Andrew L. and Moeller, Paul and Nash, Boaz and Islegen-Wojdyla, Antoine},
+          journal  = {Journal of Synchrotron Radiation},
+          title    = {A general Bayesian algorithm for the autonomous alignment of beamlines},
+          year     = {2024},
+          month    = {Nov},
+          number   = {6},
+          pages    = {1446--1456},
+          volume   = {31},
+          doi      = {10.1107/S1600577524008993},
+          keywords = {Bayesian optimization, automated alignment, synchrotron radiation, digital twins, machine learning},
+          url      = {https://doi.org/10.1107/S1600577524008993},
+        }
+    
+
+
+{% endblock %} + +{% block scripts %} + {{ super() }} + +{% endblock %} diff --git a/docs/source/conf.py b/docs/source/conf.py index 1756eed1..7fd91048 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -144,7 +144,11 @@ # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = { + "navbar_start": ["navbar-logo"], + "navbar_center": ["navbar-nav"], + "navbar_end": [], +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -169,8 +173,13 @@ # Add custom CSS to fix .content height constraint for plotly plots html_css_files = [ "fix-content-height.css", + "css/styles.css", ] +html_additional_pages = { + "index": "index.html", +} + # -- Options for LaTeX output ---------------------------------------------