mirror of
https://github.com/storytold/spark.git
synced 2026-10-18 00:22:59 +00:00
Fix Examples Page (#96)
* add hash navigation + scrollable examples list * add fullscreen example button
This commit is contained in:
committed by
GitHub
parent
825344ff59
commit
ba8083e8bf
+126
-64
@@ -34,7 +34,6 @@
|
|||||||
left: 0px;
|
left: 0px;
|
||||||
width: var(--panel-width);
|
width: var(--panel-width);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
|
||||||
border-right: var(--border-style);
|
border-right: var(--border-style);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -48,6 +47,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header .logo {
|
.header .logo {
|
||||||
@@ -74,6 +74,12 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.examples-container {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin-left: var(--panel-width);
|
margin-left: var(--panel-width);
|
||||||
width: calc(100% - var(--panel-width));
|
width: calc(100% - var(--panel-width));
|
||||||
@@ -88,17 +94,28 @@
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.code-button {
|
.action-buttons {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 12px;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-bottom: 0px;
|
|
||||||
background-color: #D43E4C;
|
background-color: #D43E4C;
|
||||||
opacity: .9;
|
opacity: .9;
|
||||||
z-index: 999;
|
|
||||||
box-shadow: 0 0 4px rgba(0, 0, 0, .15);
|
box-shadow: 0 0 4px rgba(0, 0, 0, .15);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-button:hover {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.example-link {
|
.example-link {
|
||||||
@@ -167,12 +184,13 @@
|
|||||||
right: -100%;
|
right: -100%;
|
||||||
left: auto;
|
left: auto;
|
||||||
width: 70%;
|
width: 70%;
|
||||||
height: 100%;
|
height: calc(100vh - 4rem);
|
||||||
transform: none;
|
transform: none;
|
||||||
transition: right 0.3s ease-in-out;
|
transition: right 0.3s ease-in-out;
|
||||||
z-index: 1001;
|
z-index: 1001;
|
||||||
background: #D43E4C;
|
background: #D43E4C;
|
||||||
border-left: var(--border-style);
|
border-left: var(--border-style);
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-panel.active {
|
.mobile-panel.active {
|
||||||
@@ -205,11 +223,79 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
const exampleMap = {
|
||||||
|
'hello-world': '/examples/hello-world/index.html',
|
||||||
|
'envmap': '/examples/envmap/index.html',
|
||||||
|
'interactivity': '/examples/interactivity/index.html',
|
||||||
|
'multiple-splats': '/examples/multiple-splats/index.html',
|
||||||
|
'multiple-viewpoints': '/examples/multiple-viewpoints/index.html',
|
||||||
|
'procedural-splats': '/examples/procedural-splats/index.html',
|
||||||
|
'raycasting': '/examples/raycasting/index.html',
|
||||||
|
'dynamic-lighting': '/examples/dynamic-lighting/index.html',
|
||||||
|
'particle-animation': '/examples/particle-animation/index.html',
|
||||||
|
'particle-simulation': '/examples/particle-simulation/index.html',
|
||||||
|
'webxr': '/examples/webxr/index.html',
|
||||||
|
'glsl': '/examples/glsl/index.html',
|
||||||
|
'debug-color': '/examples/debug-color/index.html',
|
||||||
|
'depth-of-field': '/examples/depth-of-field/index.html',
|
||||||
|
'splat-texture': '/examples/splat-texture/index.html',
|
||||||
|
'editor': '/examples/editor/index.html'
|
||||||
|
};
|
||||||
|
|
||||||
|
function getExampleFromHash() {
|
||||||
|
const hash = window.location.hash.substring(1);
|
||||||
|
return hash || 'hello-world';
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveExample(exampleKey) {
|
||||||
|
const path = exampleMap[exampleKey];
|
||||||
|
if (!path) return;
|
||||||
|
|
||||||
|
const iframe = document.querySelector('.example-frame');
|
||||||
|
const codeButton = document.querySelector('.code-button');
|
||||||
|
const fullPageButton = document.querySelector('.fullpage-button');
|
||||||
|
|
||||||
|
iframe.src = path;
|
||||||
|
|
||||||
|
if (codeButton) {
|
||||||
|
codeButton.href = `https://github.com/sparkjsdev/spark/blob/main${path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullPageButton) {
|
||||||
|
fullPageButton.href = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.example-link').forEach(link => {
|
||||||
|
link.classList.remove('active');
|
||||||
|
if (link.getAttribute('data-example') === exampleKey) {
|
||||||
|
link.classList.add('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.location.hash.substring(1) !== exampleKey) {
|
||||||
|
history.replaceState(null, null, `#${exampleKey}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadExamples() {
|
function loadExamples() {
|
||||||
const panel = document.querySelector('.panel');
|
const panel = document.querySelector('.panel');
|
||||||
const iframe = document.querySelector('.example-frame');
|
const iframe = document.querySelector('.example-frame');
|
||||||
|
|
||||||
|
const actionButtons = document.createElement('div');
|
||||||
|
actionButtons.classList.add('action-buttons');
|
||||||
|
|
||||||
|
const fullPageButton = document.createElement('a');
|
||||||
|
fullPageButton.classList.add('action-button', 'fullpage-button');
|
||||||
|
fullPageButton.target = '_blank';
|
||||||
|
fullPageButton.title = 'Open this example in full page';
|
||||||
|
fullPageButton.innerHTML = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" style="display:block;">
|
||||||
|
<path fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h6m10 0l-9 9m3-9h6v6"/>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
const codeButton = document.createElement('a');
|
const codeButton = document.createElement('a');
|
||||||
codeButton.classList.add('code-button');
|
codeButton.classList.add('action-button', 'code-button');
|
||||||
codeButton.target = '_blank';
|
codeButton.target = '_blank';
|
||||||
codeButton.title = 'View source code for this example on GitHub';
|
codeButton.title = 'View source code for this example on GitHub';
|
||||||
codeButton.innerHTML = `
|
codeButton.innerHTML = `
|
||||||
@@ -217,26 +303,26 @@
|
|||||||
<path fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m9 8l-4 4l4 4m6-8l4 4l-4 4"/>
|
<path fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m9 8l-4 4l4 4m6-8l4 4l-4 4"/>
|
||||||
</svg>
|
</svg>
|
||||||
`;
|
`;
|
||||||
document.body.appendChild(codeButton);
|
|
||||||
|
|
||||||
const initialLink = panel.querySelector('.example-link.active');
|
actionButtons.appendChild(fullPageButton);
|
||||||
if (initialLink) {
|
actionButtons.appendChild(codeButton);
|
||||||
const path = initialLink.getAttribute('href');
|
document.body.appendChild(actionButtons);
|
||||||
iframe.src = path;
|
|
||||||
codeButton.href = `https://github.com/sparkjsdev/spark/blob/main${path}`;
|
const initialExample = getExampleFromHash();
|
||||||
}
|
setActiveExample(initialExample);
|
||||||
|
|
||||||
panel.querySelectorAll('.example-link').forEach((link) => {
|
panel.querySelectorAll('.example-link').forEach((link) => {
|
||||||
link.addEventListener('click', (e) => {
|
link.addEventListener('click', (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const path = link.getAttribute('href');
|
const exampleKey = link.getAttribute('data-example');
|
||||||
iframe.src = path;
|
setActiveExample(exampleKey);
|
||||||
|
|
||||||
document.querySelectorAll('.example-link').forEach(l => l.classList.remove('active'));
|
|
||||||
link.classList.add('active');
|
|
||||||
codeButton.href = `https://github.com/sparkjsdev/spark/blob/main/${path.substring(1)}`;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener('hashchange', () => {
|
||||||
|
const exampleKey = getExampleFromHash();
|
||||||
|
setActiveExample(exampleKey);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupMobileMenu() {
|
function setupMobileMenu() {
|
||||||
@@ -264,7 +350,7 @@
|
|||||||
copyLinks();
|
copyLinks();
|
||||||
|
|
||||||
const observer = new MutationObserver(copyLinks);
|
const observer = new MutationObserver(copyLinks);
|
||||||
observer.observe(panel, { childList: true });
|
observer.observe(panel, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] });
|
||||||
|
|
||||||
document.body.appendChild(mobilePanel);
|
document.body.appendChild(mobilePanel);
|
||||||
|
|
||||||
@@ -289,38 +375,12 @@
|
|||||||
|
|
||||||
overlay.addEventListener('click', closeMenu);
|
overlay.addEventListener('click', closeMenu);
|
||||||
|
|
||||||
mobilePanel.querySelectorAll('.example-link').forEach(link => {
|
|
||||||
link.addEventListener('click', (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const path = link.getAttribute('href');
|
|
||||||
|
|
||||||
iframe.src = path;
|
|
||||||
|
|
||||||
document.querySelectorAll('.example-link').forEach(l => l.classList.remove('active'));
|
|
||||||
link.classList.add('active');
|
|
||||||
|
|
||||||
const example = link.getAttribute('data-source');
|
|
||||||
if (example) {
|
|
||||||
codeButton.href = example;
|
|
||||||
}
|
|
||||||
|
|
||||||
closeMenu();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
mobilePanel.addEventListener('click', (e) => {
|
mobilePanel.addEventListener('click', (e) => {
|
||||||
const link = e.target.closest('.example-link');
|
const link = e.target.closest('.example-link');
|
||||||
|
|
||||||
if (link) {
|
if (link) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const path = link.getAttribute('href');
|
const exampleKey = link.getAttribute('data-example');
|
||||||
iframe.src = path;
|
setActiveExample(exampleKey);
|
||||||
|
|
||||||
document.querySelectorAll('.example-link').forEach(l => l.classList.remove('active'));
|
|
||||||
link.classList.add('active');
|
|
||||||
panel.querySelector(`[href="${path}"]`)?.classList.add('active');
|
|
||||||
|
|
||||||
codeButton.href = `https://github.com/sparkjsdev/spark/blob/main${path}`;
|
|
||||||
closeMenu();
|
closeMenu();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -360,22 +420,24 @@
|
|||||||
</a>
|
</a>
|
||||||
<span class="title">EXAMPLES</span>
|
<span class="title">EXAMPLES</span>
|
||||||
</div>
|
</div>
|
||||||
<a href="/examples/hello-world/index.html" class="example-link active">Hello World</a>
|
<div class="examples-container">
|
||||||
<a href="/examples/envmap/index.html" class="example-link">Environment Map</a>
|
<a href="#hello-world" data-example="hello-world" class="example-link">Hello World</a>
|
||||||
<a href="/examples/interactivity/index.html" class="example-link">Interactivity</a>
|
<a href="#envmap" data-example="envmap" class="example-link">Environment Map</a>
|
||||||
<a href="/examples/multiple-splats/index.html" class="example-link">Multiple Splats</a>
|
<a href="#interactivity" data-example="interactivity" class="example-link">Interactivity</a>
|
||||||
<a href="/examples/multiple-viewpoints/index.html" class="example-link">Multiple Viewpoints</a>
|
<a href="#multiple-splats" data-example="multiple-splats" class="example-link">Multiple Splats</a>
|
||||||
<a href="/examples/procedural-splats/index.html" class="example-link">Procedural Splats</a>
|
<a href="#multiple-viewpoints" data-example="multiple-viewpoints" class="example-link">Multiple Viewpoints</a>
|
||||||
<a href="/examples/raycasting/index.html" class="example-link">Raycasting</a>
|
<a href="#procedural-splats" data-example="procedural-splats" class="example-link">Procedural Splats</a>
|
||||||
<a href="/examples/dynamic-lighting/index.html" class="example-link">Dynamic Lighting</a>
|
<a href="#raycasting" data-example="raycasting" class="example-link">Raycasting</a>
|
||||||
<a href="/examples/particle-animation/index.html" class="example-link">Particle Animation</a>
|
<a href="#dynamic-lighting" data-example="dynamic-lighting" class="example-link">Dynamic Lighting</a>
|
||||||
<a href="/examples/particle-simulation/index.html" class="example-link">Particle Simulation</a>
|
<a href="#particle-animation" data-example="particle-animation" class="example-link">Particle Animation</a>
|
||||||
<a href="/examples/webxr/index.html" class="example-link">WebXR</a>
|
<a href="#particle-simulation" data-example="particle-simulation" class="example-link">Particle Simulation</a>
|
||||||
<a href="/examples/glsl/index.html" class="example-link">GLSL Shaders</a>
|
<a href="#webxr" data-example="webxr" class="example-link">WebXR</a>
|
||||||
<a href="/examples/debug-color/index.html" class="example-link">Debug Coloring</a>
|
<a href="#glsl" data-example="glsl" class="example-link">GLSL Shaders</a>
|
||||||
<a href="/examples/depth-of-field/index.html" class="example-link">Depth of Field</a>
|
<a href="#debug-color" data-example="debug-color" class="example-link">Debug Coloring</a>
|
||||||
<a href="/examples/splat-texture/index.html" class="example-link">Splat Texture</a>
|
<a href="#depth-of-field" data-example="depth-of-field" class="example-link">Depth of Field</a>
|
||||||
<a href="/examples/editor/index.html" class="example-link">Editor</a>
|
<a href="#splat-texture" data-example="splat-texture" class="example-link">Splat Texture</a>
|
||||||
|
<a href="#editor" data-example="editor" class="example-link">Editor</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<iframe class="example-frame" src=""></iframe>
|
<iframe class="example-frame" src=""></iframe>
|
||||||
|
|||||||
Reference in New Issue
Block a user