mirror of
https://github.com/timmypidashev/web.git
synced 2026-04-14 11:03:50 +00:00
Fixed
This commit is contained in:
@@ -1,373 +0,0 @@
|
||||
---
|
||||
// src/components/presentation/Presentation.astro
|
||||
export interface Props {
|
||||
autoStart?: boolean;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const { autoStart = false, title = "Start Presentation" } = Astro.props;
|
||||
---
|
||||
|
||||
<button id="presentation-button" class="presentation-hidden mb-6 px-4 py-2 bg-blue-bright text-background rounded-lg hover:bg-blue transition-colors font-medium" type="button">
|
||||
{title}
|
||||
</button>
|
||||
|
||||
<div class="presentation-progress"></div>
|
||||
|
||||
<script define:vars={{ autoStart }}>
|
||||
const button = document.getElementById("presentation-button");
|
||||
|
||||
let slides = [];
|
||||
let slide = 0;
|
||||
let presenting = false;
|
||||
|
||||
// Function to initialize slides
|
||||
const initSlides = () => {
|
||||
const slideElements = Array.from(document.querySelectorAll('.presentation-slide'));
|
||||
console.log('Found slides:', slideElements.length); // Debug log
|
||||
slides = slideElements.map((el) => el.outerHTML);
|
||||
|
||||
// Show button if we have slides and not auto-starting
|
||||
if (slides.length && !autoStart) {
|
||||
button.classList.remove("presentation-hidden");
|
||||
}
|
||||
|
||||
// Auto-start if enabled and we have slides
|
||||
if (autoStart && slides.length) {
|
||||
setTimeout(() => {
|
||||
startPresentation();
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
const nextSlide = () => {
|
||||
if (slide === slides.length - 1) {
|
||||
return slide;
|
||||
}
|
||||
return slide + 1;
|
||||
};
|
||||
|
||||
const prevSlide = () => {
|
||||
if (slide === 0) {
|
||||
return slide;
|
||||
}
|
||||
return slide - 1;
|
||||
};
|
||||
|
||||
const keyHandlers = {
|
||||
ArrowRight: nextSlide,
|
||||
ArrowLeft: prevSlide,
|
||||
};
|
||||
|
||||
const setProgress = () => {
|
||||
const progress = ((slide + 1) / slides.length) * 100;
|
||||
document.body.style.setProperty('--presentation-progress', `${progress}%`);
|
||||
};
|
||||
|
||||
const startPresentation = () => {
|
||||
if (!slides.length) return;
|
||||
|
||||
button.innerHTML = "Resume presentation";
|
||||
document.body.classList.add("presentation-overflow-hidden");
|
||||
presenting = true;
|
||||
|
||||
// Create presentation container and content area
|
||||
const container = document.createElement('div');
|
||||
container.id = 'presentation-container';
|
||||
container.className = 'presentation-container';
|
||||
|
||||
const content = document.createElement('main');
|
||||
content.id = 'presentation-content';
|
||||
|
||||
// Initialize with first slide
|
||||
const slideWrapper = document.createElement('div');
|
||||
slideWrapper.innerHTML = slides[slide];
|
||||
const slideElement = slideWrapper.querySelector('.presentation-slide');
|
||||
if (slideElement) {
|
||||
content.appendChild(slideElement);
|
||||
} else {
|
||||
content.innerHTML = slides[slide];
|
||||
}
|
||||
|
||||
// Add slide counter
|
||||
const counter = document.createElement('div');
|
||||
counter.id = 'slide-counter';
|
||||
counter.className = 'fixed bottom-8 right-8 bg-gray-800 bg-opacity-80 text-foreground px-4 py-2 rounded-lg font-mono z-20';
|
||||
counter.textContent = `${slide + 1} / ${slides.length}`;
|
||||
|
||||
container.appendChild(content);
|
||||
container.appendChild(counter);
|
||||
document.body.appendChild(container);
|
||||
|
||||
setProgress();
|
||||
initListeners();
|
||||
|
||||
console.log(`Presentation started with ${slides.length} slides`); // Debug log
|
||||
};
|
||||
|
||||
const endPresentation = () => {
|
||||
document.body.classList.remove("presentation-overflow-hidden");
|
||||
presenting = false;
|
||||
|
||||
const container = document.getElementById('presentation-container');
|
||||
if (container) {
|
||||
container.remove();
|
||||
}
|
||||
};
|
||||
|
||||
const transition = (nextSlideIndex) => {
|
||||
if (!presenting || nextSlideIndex === slide || !slides[nextSlideIndex]) {
|
||||
return;
|
||||
}
|
||||
|
||||
slide = nextSlideIndex;
|
||||
|
||||
const content = document.getElementById('presentation-content');
|
||||
const counter = document.getElementById('slide-counter');
|
||||
|
||||
if (content) {
|
||||
// Clear current content
|
||||
content.innerHTML = '';
|
||||
|
||||
// Create a wrapper div and set the slide content
|
||||
const slideWrapper = document.createElement('div');
|
||||
slideWrapper.innerHTML = slides[slide];
|
||||
|
||||
// Ensure the slide has proper presentation styling
|
||||
const slideElement = slideWrapper.querySelector('.presentation-slide');
|
||||
if (slideElement) {
|
||||
content.appendChild(slideElement);
|
||||
} else {
|
||||
// Fallback: just add the content directly
|
||||
content.innerHTML = slides[slide];
|
||||
}
|
||||
}
|
||||
|
||||
if (counter) {
|
||||
counter.textContent = `${slide + 1} / ${slides.length}`;
|
||||
}
|
||||
|
||||
setProgress();
|
||||
|
||||
console.log(`Transitioned to slide ${slide + 1}/${slides.length}`); // Debug log
|
||||
};
|
||||
|
||||
let listenersInitialized = false;
|
||||
const initListeners = () => {
|
||||
if (listenersInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
listenersInitialized = true;
|
||||
|
||||
window.addEventListener("keyup", (ev) => {
|
||||
console.log(`Key pressed: ${ev.key}`); // Debug log
|
||||
ev.preventDefault();
|
||||
const isEscape = ev.key === "Escape";
|
||||
if (isEscape) {
|
||||
endPresentation();
|
||||
return;
|
||||
}
|
||||
|
||||
const getSlide = keyHandlers[ev.key];
|
||||
if (!getSlide) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextSlideIndex = getSlide();
|
||||
console.log(`Current slide: ${slide}, Next slide: ${nextSlideIndex}`); // Debug log
|
||||
transition(nextSlideIndex);
|
||||
});
|
||||
|
||||
let touchstartX = 0;
|
||||
let touchendX = 0;
|
||||
|
||||
const handleGesture = () => {
|
||||
const magnitude = Math.abs(touchstartX - touchendX);
|
||||
|
||||
if (magnitude < 40) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (touchendX < touchstartX) {
|
||||
transition(nextSlide());
|
||||
}
|
||||
if (touchendX > touchstartX) {
|
||||
transition(prevSlide());
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("touchstart", (ev) => {
|
||||
touchstartX = ev.changedTouches[0].screenX;
|
||||
}, false);
|
||||
|
||||
document.addEventListener("touchend", (event) => {
|
||||
touchendX = event.changedTouches[0].screenX;
|
||||
handleGesture();
|
||||
}, false);
|
||||
};
|
||||
|
||||
// Initialize when DOM is ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSlides);
|
||||
} else {
|
||||
// DOM is already loaded
|
||||
initSlides();
|
||||
}
|
||||
|
||||
// Also try again after a short delay to catch any dynamically loaded content
|
||||
setTimeout(initSlides, 500);
|
||||
|
||||
// Initialize button click handler
|
||||
if (button) {
|
||||
button.addEventListener("click", startPresentation);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style is:global>
|
||||
.presentation-progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presentation-overflow-hidden {
|
||||
overflow: hidden;
|
||||
|
||||
.presentation-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presentation-progress {
|
||||
transition: width 1000ms;
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 21;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: var(--presentation-progress);
|
||||
height: 0.25rem;
|
||||
background: #fabd2f;
|
||||
}
|
||||
}
|
||||
|
||||
.presentation-container {
|
||||
z-index: 10;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
#presentation-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #000000;
|
||||
color: #ebdbb2;
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
padding: 4rem;
|
||||
}
|
||||
|
||||
.presentation-slide {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.presentation-slide.centered {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.presentation-slide.highlight {
|
||||
background-color: #fabd2f;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.presentation-slide.large {
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
.presentation-slide h1 {
|
||||
font-size: 3rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1.5rem;
|
||||
color: #fabd2f;
|
||||
}
|
||||
|
||||
.presentation-slide h2 {
|
||||
font-size: 2.5rem;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 1rem;
|
||||
color: #83a598;
|
||||
}
|
||||
|
||||
.presentation-slide h3 {
|
||||
font-size: 2rem;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 0.75rem;
|
||||
color: #b8bb26;
|
||||
}
|
||||
|
||||
.presentation-slide p {
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.presentation-slide ul, .presentation-slide ol {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.8;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.presentation-slide li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.presentation-slide code {
|
||||
background: #282828;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 0.25rem;
|
||||
font-family: 'Comic Code', monospace;
|
||||
color: #d3869b;
|
||||
}
|
||||
|
||||
.presentation-slide pre {
|
||||
background: #282828;
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
margin: 1rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.presentation-slide pre code {
|
||||
background: none;
|
||||
padding: 0;
|
||||
color: #ebdbb2;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#presentation-content {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.presentation-slide h1 { font-size: 2rem; }
|
||||
.presentation-slide h2 { font-size: 1.75rem; }
|
||||
.presentation-slide h3 { font-size: 1.5rem; }
|
||||
.presentation-slide p { font-size: 1.25rem; }
|
||||
.presentation-slide ul, .presentation-slide ol { font-size: 1.1rem; }
|
||||
}
|
||||
|
||||
.presentation-hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
326
src/src/components/resources/presentation.astro
Normal file
326
src/src/components/resources/presentation.astro
Normal file
@@ -0,0 +1,326 @@
|
||||
<button id="presentation-button" class="presentation-hidden" type="button"
|
||||
>Start Presentation</button
|
||||
>
|
||||
|
||||
<div class="presentation-progress"></div>
|
||||
|
||||
<script>
|
||||
const button = document.getElementById(
|
||||
"presentation-button"
|
||||
) as HTMLButtonElement;
|
||||
|
||||
let slides = Array.from(document.querySelectorAll(".presentation-slide"));
|
||||
|
||||
let slide = 0;
|
||||
let presenter = false;
|
||||
|
||||
const presentationId = window.location.href;
|
||||
|
||||
const nextSlide = () => {
|
||||
if (slide === slides.length - 1) {
|
||||
return slide;
|
||||
}
|
||||
|
||||
return slide + 1;
|
||||
};
|
||||
|
||||
const prevSlide = () => {
|
||||
if (slide === 0) {
|
||||
return slide;
|
||||
}
|
||||
|
||||
return slide - 1;
|
||||
};
|
||||
|
||||
const nextClass = "presentation-next";
|
||||
const currClass = "presentation-current";
|
||||
const prevClass = "presentation-prev";
|
||||
|
||||
const transitionClasses = [nextClass, currClass, prevClass];
|
||||
|
||||
const keyHandlers: Record<string, () => number> = {
|
||||
ArrowRight: nextSlide,
|
||||
ArrowLeft: prevSlide,
|
||||
};
|
||||
|
||||
const displaySlides = () => {
|
||||
for (let i = 0; i < slides.length; i++) {
|
||||
slides[i].classList.remove("active", "inactive", ...transitionClasses);
|
||||
|
||||
if (i === slide) {
|
||||
slides[i].classList.add("active", currClass);
|
||||
} else {
|
||||
slides[i].classList.add("inactive");
|
||||
|
||||
if (i > slide) {
|
||||
slides[i].classList.add(nextClass);
|
||||
} else {
|
||||
slides[i].classList.add(prevClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let presenting = false
|
||||
const startPresentation = () => {
|
||||
button.innerHTML = "Resume presentation";
|
||||
document.body.classList.add("presentation-overflow-hidden");
|
||||
|
||||
presenting = true
|
||||
displaySlides();
|
||||
setProgress();
|
||||
initListeners()
|
||||
};
|
||||
|
||||
const endPresentation = () => {
|
||||
document.body.classList.remove("presentation-overflow-hidden");
|
||||
|
||||
presenting = false
|
||||
slides.map((s) =>
|
||||
s.classList.remove("active", "inactive", ...transitionClasses)
|
||||
);
|
||||
};
|
||||
|
||||
const setPresenter = () => {
|
||||
presenter = true;
|
||||
document.body.classList.add("presentation-presenter")
|
||||
};
|
||||
|
||||
const setProgress = () => {
|
||||
const progress = ((slide+1)/slides.length)*100;
|
||||
document.body.style.setProperty('--presentation-progress', `${progress}%`)
|
||||
}
|
||||
|
||||
const transition = (nextSlide: number) => {
|
||||
if (!presenting) {
|
||||
return
|
||||
}
|
||||
|
||||
if (slide === nextSlide) {
|
||||
return;
|
||||
}
|
||||
|
||||
slides.forEach((s) => s.classList.remove(...transitionClasses));
|
||||
|
||||
|
||||
slide = nextSlide;
|
||||
|
||||
displaySlides();
|
||||
setProgress();
|
||||
};
|
||||
|
||||
|
||||
let listenersInitialized = false
|
||||
const initListeners = () => {
|
||||
if (listenersInitialized) {
|
||||
return
|
||||
}
|
||||
|
||||
listenersInitialized= true
|
||||
window.addEventListener("keyup", (ev) => {
|
||||
ev.preventDefault();
|
||||
const isEscape = ev.key === "Escape";
|
||||
if (isEscape) {
|
||||
endPresentation();
|
||||
return;
|
||||
}
|
||||
|
||||
const isSpace = ev.key === " ";
|
||||
if (isSpace) {
|
||||
setPresenter();
|
||||
return;
|
||||
}
|
||||
|
||||
const getSlide = keyHandlers[ev.key];
|
||||
|
||||
if (!getSlide) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextSlide = getSlide();
|
||||
transition(nextSlide);
|
||||
});
|
||||
|
||||
let touchstartX = 0;
|
||||
let touchendX = 0;
|
||||
const handleGesure = () => {
|
||||
const magnitude = Math.abs(touchstartX - touchendX);
|
||||
|
||||
if (magnitude < 40) {
|
||||
// Ignore since this could be a scroll up/down
|
||||
return;
|
||||
}
|
||||
|
||||
if (touchendX < touchstartX) {
|
||||
transition(nextSlide());
|
||||
}
|
||||
if (touchendX > touchstartX) {
|
||||
transition(prevSlide());
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
"touchstart",
|
||||
(ev) => {
|
||||
touchstartX = ev.changedTouches[0].screenX;
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"touchend",
|
||||
(event) => {
|
||||
touchendX = event.changedTouches[0].screenX;
|
||||
handleGesure();
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// If there is no presentation on the page then we don't initialize
|
||||
if (slides.length) {
|
||||
button.classList.remove("presentation-hidden");
|
||||
button.addEventListener("click", startPresentation);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style is:global>
|
||||
.presentation-progress {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presentation-overflow-hidden {
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
|
||||
.presentation-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-size: xx-large;
|
||||
}
|
||||
|
||||
.presentation-slide.large {
|
||||
font-size: x-large;
|
||||
}
|
||||
|
||||
.presentation-progress {
|
||||
transition: width 1000ms;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
top:0px;
|
||||
left: 0px;
|
||||
width: var(--presentation-progress);
|
||||
height: .25rem;
|
||||
background: var(--color-brand-muted);
|
||||
}
|
||||
|
||||
.presentation-slide {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
visibility: visible;
|
||||
|
||||
transition: transform 300ms ease-in-out;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
background-color: var(--color-base);
|
||||
color: var(--color-on-base);
|
||||
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
padding: 2rem 4rem;
|
||||
|
||||
z-index: 10;
|
||||
overflow: auto;
|
||||
|
||||
&.centered {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&.highlight{
|
||||
background-color: var(--color-brand);
|
||||
color: var(--color-on-brand)
|
||||
}
|
||||
|
||||
.presentation-slide-only {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.astro-code {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-height: 80vh;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.presentation-presenter {
|
||||
.presentation-slide {
|
||||
border: none;
|
||||
border-bottom: solid 8px var(--color-brand);
|
||||
}
|
||||
|
||||
.presentation-note {
|
||||
position: absolute;
|
||||
bottom: 24px;
|
||||
opacity: .8;
|
||||
right: 24px;
|
||||
left: 25%;
|
||||
z-index: 999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.presentation-slide-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presentation-next {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.presentation-current {
|
||||
transform: translateX(0%);
|
||||
}
|
||||
|
||||
.presentation-prev {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.presentation-note {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presentation-presenter {
|
||||
.presentation-slide {
|
||||
border: dotted 8px var(--color-brand);
|
||||
}
|
||||
|
||||
/* ensure that notes are visible if presentation mode is active, even if
|
||||
not presenting */
|
||||
.presentation-note {
|
||||
display: block;
|
||||
/* intentionally obnoxios color to draw attention */
|
||||
background-color: crimson;
|
||||
padding: 24px;
|
||||
color: white;
|
||||
font-size: xx-large;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -4,8 +4,7 @@ export interface Props {
|
||||
highlight?: boolean
|
||||
large?: boolean
|
||||
}
|
||||
|
||||
const { centered, highlight, large} = Astro.props
|
||||
const { centered = true, highlight, large } = Astro.props
|
||||
---
|
||||
|
||||
<section class="presentation-slide" class:list={{ centered, highlight, large }}>
|
||||
@@ -6,9 +6,12 @@ duration: "2 hours"
|
||||
tags: ["python", "programming", "beginner", "fundamentals"]
|
||||
---
|
||||
|
||||
import Slide from "@/components/presentation/Slide.astro";
|
||||
import Slide from "@/components/resources/slide.astro";
|
||||
import Presentation from "@/components/resources/presentation.astro";
|
||||
|
||||
<Slide centered>
|
||||
<Presentation />
|
||||
|
||||
<Slide large>
|
||||
# Welcome to Python! 🐍
|
||||
|
||||
**A beginner-friendly programming language**
|
||||
@@ -250,7 +253,7 @@ print(calculator())
|
||||
```
|
||||
</Slide>
|
||||
|
||||
<Slide centered>
|
||||
<Slide >
|
||||
## 🎉 Congratulations!
|
||||
|
||||
You've learned the basics of Python programming!
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
---
|
||||
// src/layouts/presentation.astro
|
||||
import "@/style/globals.css";
|
||||
import { ClientRouter } from "astro:transitions";
|
||||
|
||||
import Header from "@/components/header";
|
||||
import Footer from "@/components/footer";
|
||||
import Background from "@/components/background";
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
@@ -34,10 +37,34 @@ const ogImage = "https://timmypidashev.dev/og-image.jpg";
|
||||
defaultTransition={false}
|
||||
handleFocus={false}
|
||||
/>
|
||||
<style>
|
||||
::view-transition-new(:root) {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
::view-transition-old(:root) {
|
||||
animation: 90ms ease-out both fade-out;
|
||||
}
|
||||
@keyframes fade-out {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background text-foreground min-h-screen">
|
||||
<main class="w-full h-screen">
|
||||
<slot />
|
||||
<body class="bg-background text-foreground min-h-screen flex flex-col">
|
||||
<main class="flex-1 flex flex-col">
|
||||
<div class="max-w-5xl mx-auto pt-12 px-4 py-8 flex-1">
|
||||
<Background layout="content" position="right" client:only="react" transition:persist />
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
<Background layout="content" position="left" client:only="react" transition:persist />
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
document.addEventListener("astro:after-navigation", () => {
|
||||
window.scrollTo(0, 0);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,6 +2,7 @@
|
||||
export const prerender = true;
|
||||
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
import ContentLayout from "@/layouts/content.astro";
|
||||
import { Comments } from "@/components/blog/comments";
|
||||
|
||||
|
||||
@@ -1,41 +1,31 @@
|
||||
---
|
||||
export const prerender = true;
|
||||
|
||||
import { getCollection } from "astro:content";
|
||||
import ContentLayout from "@/layouts/content.astro";
|
||||
import PresentationLayout from "@/layouts/presentation.astro";
|
||||
import Presentation from "@/components/presentation/Presentation.astro";
|
||||
|
||||
const { slug } = Astro.params;
|
||||
import ResourceLayout from "@/layouts/resource.astro";
|
||||
|
||||
const resources = await getCollection("resources");
|
||||
const resource = resources.find(item => item.slug === slug);
|
||||
|
||||
if (!resource) {
|
||||
return new Response(null, {
|
||||
status: 404,
|
||||
statusText: 'Not found'
|
||||
});
|
||||
export async function getStaticPaths() {
|
||||
const resources = await getCollection("resources");
|
||||
return resources.map(resource => ({
|
||||
params: { slug: resource.slug },
|
||||
props: { resource },
|
||||
}));
|
||||
}
|
||||
|
||||
const { resource } = Astro.props;
|
||||
const { Content } = await resource.render();
|
||||
|
||||
const formattedDate = new Date(resource.data.date).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric"
|
||||
});
|
||||
|
||||
// Check if this is a curriculum resource to auto-start presentation
|
||||
const isCurriculum = resource.slug.includes('curriculum');
|
||||
const LayoutComponent = isCurriculum ? PresentationLayout : ContentLayout;
|
||||
---
|
||||
|
||||
<LayoutComponent
|
||||
title={`${resource.data.title} | Timothy Pidashev`}
|
||||
description={resource.data.description}
|
||||
>
|
||||
<Presentation autoStart={isCurriculum} title="Start Presentation" />
|
||||
|
||||
<div class="relative max-w-8xl mx-auto">
|
||||
<ResourceLayout title={`${resource.data.title} | Timothy Pidashev`}>
|
||||
<article class="w-full mx-auto px-4 pt-6 sm:pt-12">
|
||||
<header class="mb-8">
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-yellow-bright mb-4">
|
||||
{resource.data.title}
|
||||
</h1>
|
||||
</header>
|
||||
<div class="prose prose-invert prose-lg max-w-none">
|
||||
<Content />
|
||||
</div>
|
||||
</LayoutComponent>
|
||||
</article>
|
||||
</ResourceLayout>
|
||||
|
||||
Reference in New Issue
Block a user