Skip to content

Commit

Permalink
add back in scrolling source tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
greggman committed Mar 14, 2024
1 parent e01d6a3 commit 5123ecf
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 2 deletions.
4 changes: 3 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ <h1 id="title"></h1>
<div class="sampleContainer"></div>
</div>
<nav id="code" class="sourceFileNav">
<div class="sourceFileScrollContainer">
<div class="sourceLR" id="sourceL">&lt;</div>
<div id="sourceTabs" class="sourceFileScrollContainer">
<ul id="codeTabs"></ul>
</div>
<div class="sourceLR" id="sourceR">&gt;</div>
</nav>
<div id="sources"></div>
</main>
Expand Down
53 changes: 53 additions & 0 deletions public/css/SampleLayout.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,18 @@
transform: translateY(0.25em);
}

nav.sourceFileNav {
display: flex;
align-items: flex-start;
}

nav.sourceFileNav ul {
box-sizing: border-box;
list-style-type: none;
padding: 0;
margin: 0;
margin-top: 15px;
position: relative;
}

nav.sourceFileNav li {
Expand Down Expand Up @@ -97,12 +103,59 @@ nav.sourceFileNav[data-right=true]::after {
background: linear-gradient(270deg, rgba(0, 0, 0, 0.35), transparent);
}

.sourceLR {
display: none;
cursor: pointer;
width: 5em;
padding: 10px;
margin-top: 15px;
text-align: center;
color: var(--source-tab-color);
background-color: var(--source-tab-background);
border-left: 1px solid rgba(0, 0, 0, 0.5);
border-right: 1px solid rgba(0, 0, 0, 0.5);
}
.sourceLR:hover {
text-decoration: underline;
}
.sourceLRShow .sourceLR {
display: block;
}

nav.sourceFileNav div.sourceFileScrollContainer {
white-space: nowrap;
overflow-x: auto;
scrollbar-width: thin;
}

nav.sourceFileNav div.sourceFileScrollContainer::-webkit-scrollbar {
display: inline;
margin-top: 10px;
margin-bottom: 10px;
height: 11px;
width: 10px;
}

nav.sourceFileNav div.sourceFileScrollContainer::-webkit-scrollbar-thumb {
background: rgb(200, 200, 200);
height: 4px;
border-radius: 20px;
-webkit-box-shadow: inset 0px 0px 10px rgb(45, 33, 33);
border: 0.5px solid transparent;
background-clip: content-box;
}

nav.sourceFileNav div.sourceFileScrollContainer::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0);
}

nav.sourceFileNav li a {
display: block;
margin: 0;
padding: 10px;
color: var(--source-tab-color);
background-color: var(--source-tab-background);
border-right: 1px solid rgba(0, 0, 0, 0.5);
}

nav.sourceFileNav li:hover {
Expand Down
3 changes: 3 additions & 0 deletions public/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}

html, body {
margin: 0;
Expand Down
78 changes: 77 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ const sampleContainerElem = getElem('.sampleContainer', sampleElem);
const titleElem = getElem('#title', sampleElem);
const descriptionElem = getElem('#description', sampleElem);
const menuToggleElem = getElem('#menuToggle') as HTMLInputElement;
const codeElem = getElem('#code');
const sourceTabsElem = getElem('#sourceTabs');
const sourceLElem = getElem('#sourceL');
const sourceRElem = getElem('#sourceR');

const darkMatcher = window.matchMedia('(prefers-color-scheme: dark)');

Expand Down Expand Up @@ -78,7 +82,39 @@ function setURL(url: string) {
}

// Handle when the URL changes (browser back / forward)
window.addEventListener('popstate', parseURL);
window.addEventListener('popstate', (e) => {
e.preventDefault();
parseURL();
});

/**
* Scrolls the current tab into view.
*/
function moveIntoView(parent: HTMLElement, element: HTMLElement) {
const parentLeft = parent.scrollLeft;
const parentRight = parentLeft + parent.clientWidth;

const elemLeft = element.offsetLeft;
const elemRight = elemLeft + element.clientWidth;

if (elemLeft < parentLeft) {
parent.scrollLeft -= parentLeft - elemLeft;
} else if (elemRight > parentRight) {
parent.scrollLeft += elemRight - parentRight;
}
}

/**
* Switches to a tab relative to the current tab
*/
function switchToRelativeTab(offsetFromCurrentTab: number) {
const tabs = [...sourceTabsElem.querySelectorAll('a')];
const activeNdx = tabs.findIndex((tab) => tab.dataset.active === 'true');
const newNdx = (activeNdx + tabs.length + offsetFromCurrentTab) % tabs.length;
const tab = tabs[newNdx];
moveIntoView(sourceTabsElem, tab.parentElement!);
return tab;
}

/**
* Show/hide source tabs
Expand All @@ -89,6 +125,8 @@ function setSourceTab(sourceInfo: SourceInfo) {
const elem = e as HTMLElement;
elem.dataset.active = (elem.dataset.name === name).toString();
});
// Effectively makes the tab entirely visible if part of it is scrolled off.
switchToRelativeTab(0);
}

/**
Expand Down Expand Up @@ -151,6 +189,7 @@ function setSampleIFrame(
};

titleElem.textContent = name;
document.title = `WebGPU Samples - ${name}`;
descriptionElem.innerHTML = markdownConverter.makeHtml(description);

// Replace the iframe because changing src adds to the user's history.
Expand Down Expand Up @@ -271,6 +310,43 @@ for (const { title, description, samples } of pageCategories) {
);
}

sourceLElem.addEventListener('click', () => switchToRelativeTab(-1).click());
sourceRElem.addEventListener('click', () => switchToRelativeTab(1).click());

function checkIfSourceTabsFit() {
const parentWidth = sourceTabsElem.clientWidth;
const childWidth = [...sourceTabsElem.querySelectorAll('li')].reduce(
(sum, elem) => sum + elem.clientWidth,
0
);
const showLR = childWidth > parentWidth;
codeElem.classList.toggle('sourceLRShow', showLR);
}

const registerResizeCallback = (() => {
const elemToResizeCallback = new Map<
Element,
(entry: ResizeObserverEntry) => void
>();
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const cb = elemToResizeCallback.get(entry.target);
if (cb) {
cb(entry);
}
}
});
return function (
elem: Element,
callback: (entry: ResizeObserverEntry) => void
) {
elemToResizeCallback.set(elem, callback);
observer.observe(elem);
};
})();

registerResizeCallback(sourceTabsElem, checkIfSourceTabsFit);

/**
* Parse the page's current URL and then set the iframe appropriately.
*/
Expand Down

0 comments on commit 5123ecf

Please sign in to comment.