spring-batch-rs 0.3.4

A toolkit for building enterprise-grade batch applications
Documentation
---
import {Icon} from '@astrojs/starlight/components';
import TableOfContentsList from './TableOfContents/TableOfContentsList.astro';

const { toc } = Astro.locals.starlightRoute;
---

{
	toc && (
		<mobile-starlight-toc data-min-h={toc.minHeadingLevel} data-max-h={toc.maxHeadingLevel}>
			<nav aria-labelledby="starlight__on-this-page--mobile">
				<details id="starlight__mobile-toc">
					<summary id="starlight__on-this-page--mobile" class="sl-flex">
						<span class="toggle sl-flex">
							{Astro.locals.t('tableOfContents.onThisPage')}
							<Icon name={'right-caret'} class="caret" size="1rem" />
						</span>
						<span class="display-current" />
					</summary>
					<div class="dropdown">
						<TableOfContentsList toc={toc.items} isMobile />
					</div>
				</details>
			</nav>
		</mobile-starlight-toc>
	)
}

<style>
	@layer starlight.core {
		nav {
			position: fixed;
			z-index: var(--sl-z-index-toc);
			top: calc(var(--sl-nav-height) + 1px);
			inset-inline: 0;
			border-top: 1px solid var(--sl-color-gray-5);
			background-color: var(--sl-color-bg-nav);
		}
		@media (min-width: 50rem) {
			nav {
				/* inset-inline-start: var(--sl-content-inline-start, 0); */
                z-index: 200;
			}
		}

		summary {
			gap: 0.5rem;
			align-items: center;
			height: var(--sl-mobile-toc-height);
			border-bottom: 1px solid var(--sl-color-hairline-shade);
			padding: 0.5rem 1rem;
			font-size: var(--sl-text-xs);
			outline-offset: var(--sl-outline-offset-inside);
		}
		summary::marker,
		summary::-webkit-details-marker {
			display: none;
		}

		.toggle {
			flex-shrink: 0;
			gap: 1rem;
			align-items: center;
			justify-content: space-between;
			border: 1px solid var(--sl-color-gray-5);
			border-radius: 0.5rem;
			padding-block: 0.5rem;
			padding-inline-start: 0.75rem;
			padding-inline-end: 0.5rem;
			line-height: 1;
			background-color: var(--sl-color-black);
			user-select: none;
			cursor: pointer;
		}
		details[open] .toggle {
			color: var(--sl-color-white);
			border-color: var(--sl-color-accent);
		}
		details .toggle:hover {
			color: var(--sl-color-white);
			border-color: var(--sl-color-gray-2);
		}

		:global([dir='rtl']) .caret {
			transform: rotateZ(180deg);
		}
		details[open] .caret {
			transform: rotateZ(90deg);
		}

		.display-current {
			white-space: nowrap;
			text-overflow: ellipsis;
			overflow: hidden;
			color: var(--sl-color-white);
		}

		.dropdown {
			--border-top: 1px;
			margin-top: calc(-1 * var(--border-top));
			border: var(--border-top) solid var(--sl-color-gray-6);
			border-top-color: var(--sl-color-hairline-shade);
			max-height: calc(85vh - var(--sl-nav-height) - var(--sl-mobile-toc-height));
			overflow-y: auto;
			background-color: var(--sl-color-black);
			box-shadow: var(--sl-shadow-md);
			overscroll-behavior: contain;
		}
	}
</style>

<script>
	import { StarlightTOC } from './TableOfContents/starlight-toc';

	class MobileStarlightTOC extends StarlightTOC {
		override set current(link: HTMLAnchorElement) {
			super.current = link;
			const display = this.querySelector('.display-current') as HTMLSpanElement;
			if (display) display.textContent = link.textContent;
		}

		constructor() {
			super();
			const details = this.querySelector('details');
			if (!details) return;
			const closeToC = () => {
				details.open = false;
			};
			// Close the table of contents whenever a link is clicked.
			details.querySelectorAll('a').forEach((a) => {
				a.addEventListener('click', closeToC);
			});
			// Close the table of contents when a user clicks outside of it.
			window.addEventListener('click', (e) => {
				if (!details.contains(e.target as Node)) closeToC();
			});
			// Or when they press the escape key.
			window.addEventListener('keydown', (e) => {
				if (e.key === 'Escape' && details.open) {
					const hasFocus = details.contains(document.activeElement);
					closeToC();
					if (hasFocus) {
						const summary = details.querySelector('summary');
						if (summary) summary.focus();
					}
				}
			});
		}
	}

	customElements.define('mobile-starlight-toc', MobileStarlightTOC);
</script>