Changes on sidebar styles, and content of pages

This commit is contained in:
cagsun 2025-06-26 15:16:44 +02:00
parent 7ae4644893
commit e3cd2c7f00
22 changed files with 1014 additions and 49 deletions

View file

@ -0,0 +1,44 @@
// src/components/ImageCarousel.js
import React from 'react';
import clsx from 'clsx';
import styles from './ImageCarousel.module.css';
export default function ImageCarousel({ images }) {
const [current, setCurrent] = React.useState(0);
if (!images || images.length === 0) return null;
return (
<div className={styles.carousel}>
<div className={styles.viewport}>
{images.map((img, idx) => (
<div
key={idx}
className={clsx(styles.slide, { [styles.active]: idx === current })}
>
<img src={img.src} alt={img.alt || `Slide ${idx + 1}`} />
{img.caption && <div className={styles.caption}>{img.caption}</div>}
</div>
))}
</div>
<div className={styles.thumbnails}>
{images.map((img, idx) => (
<button
key={idx}
onClick={() => setCurrent(idx)}
className={clsx(styles.thumbnailWrapper, {
[styles.activeThumbnail]: idx === current,
})}
>
<img
src={img.src}
alt={`Thumbnail ${idx + 1}`}
className={styles.thumbnail}
/>
</button>
))}
</div>
</div>
);
}

View file

@ -0,0 +1,66 @@
.carousel {
max-width: 600px;
margin: 2rem auto;
text-align: center;
}
.viewport {
position: relative;
min-height: 300px;
}
.slide {
display: none;
}
.slide.active {
display: block;
}
.slide img {
width: 100%;
height: auto;
border-radius: 0.5rem;
}
.caption {
margin-top: 0.5rem;
font-size: 0.9rem;
color: #666;
}
.thumbnails {
margin-top: 1rem;
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 0.5rem;
}
.thumbnailWrapper {
border: none;
background: none;
padding: 0;
cursor: pointer;
outline: none;
border-radius: 0.375rem;
transition: box-shadow 0.2s ease;
}
.thumbnail {
width: 60px;
height: 40px;
object-fit: cover;
border-radius: 0.375rem;
opacity: 0.8;
transition: opacity 0.2s ease;
}
.thumbnailWrapper:hover .thumbnail,
.thumbnailWrapper.activeThumbnail .thumbnail {
opacity: 1;
}
.activeThumbnail {
box-shadow: 0 0 0 2px #333;
}

View file

@ -0,0 +1,206 @@
import React, { useState } from 'react';
import { ChevronLeft, ChevronRight } from 'lucide-react';
const StepCarousel = ({
steps = [],
showStepNumbers = true,
showNavigation = true,
showDots = true,
className = ""
}) => {
const [currentStep, setCurrentStep] = useState(0);
// Default demo data if no steps provided
const defaultSteps = [
{
title: "Mill the Mould",
description: "Download the .stp-files and the blueprints for the mould for CNC milling. Metal examples for CNC Milling: Aluminium 7050, 7075-T6, Steel 1045. CNC mill the mould according to the blueprint and insert 8x10mm Dowel pins.",
image: "https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?w=600&h=400&fit=crop",
stepNumber: 1
},
{
title: "Inject",
description: "Fill the injection machine with Polypropylene, heat up for 10-12min, check the viscosity of the outcoming plastic. You need about 25g for the bottom part and 30g for the Top Part.",
image: "https://images.unsplash.com/photo-1581092160562-40aa08e78837?w=600&h=400&fit=crop",
stepNumber: 2
},
{
title: "Demoulding",
description: "Unscrew the moulds, use the demoulding pockets to open the moulds, knock out the sprues, cut them and do the afterwork.",
image: "https://images.unsplash.com/photo-1581092918056-0c4c3acd3789?w=600&h=400&fit=crop",
stepNumber: 3
},
{
title: "Drill the holes",
description: "You need to drill 2x D2mm for the button screws and 3x D2mm for the case screws. Keep attention just to drill 3mm deep. After that insert button screws.",
image: "https://images.unsplash.com/photo-1609592842914-b3e29c6b0b25?w=600&h=400&fit=crop",
stepNumber: 4
},
{
title: "Final Assembly",
description: "The final steps are inserting the lens, the circuit board and screwing the top and bottom together. Test the click and adjust button screws for the best feel.",
image: "https://images.unsplash.com/photo-1518709268805-4e9042af2ac1?w=600&h=400&fit=crop",
stepNumber: 5
}
];
const stepsData = steps.length > 0 ? steps : defaultSteps;
const nextStep = () => {
setCurrentStep((prev) => (prev + 1) % stepsData.length);
};
const prevStep = () => {
setCurrentStep((prev) => (prev - 1 + stepsData.length) % stepsData.length);
};
const goToStep = (index) => {
setCurrentStep(index);
};
return (
<div className={`max-w-4xl mx-auto bg-white rounded-lg shadow-lg overflow-hidden ${className}`}>
{/* Main Content Area */}
<div className="relative">
{/* Image Container */}
<div className="relative h-96 bg-gray-100 overflow-hidden">
<img
src={stepsData[currentStep].image}
alt={stepsData[currentStep].title}
className="w-full h-full object-cover transition-opacity duration-300"
/>
{/* Step Number Badge */}
{showStepNumbers && (
<div className="absolute top-4 left-4 bg-blue-600 text-white w-10 h-10 rounded-full flex items-center justify-center font-bold text-lg shadow-lg">
{stepsData[currentStep].stepNumber || currentStep + 1}
</div>
)}
{/* Navigation Arrows */}
{showNavigation && stepsData.length > 1 && (
<>
<button
onClick={prevStep}
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 hover:bg-opacity-70 text-white p-2 rounded-full transition-all duration-200"
aria-label="Previous step"
>
<ChevronLeft size={24} />
</button>
<button
onClick={nextStep}
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 hover:bg-opacity-70 text-white p-2 rounded-full transition-all duration-200"
aria-label="Next step"
>
<ChevronRight size={24} />
</button>
</>
)}
</div>
{/* Content Area */}
<div className="p-6">
<h3 className="text-2xl font-bold text-gray-900 mb-3">
{stepsData[currentStep].title}
</h3>
<p className="text-gray-700 leading-relaxed">
{stepsData[currentStep].description}
</p>
</div>
{/* Dot Navigation */}
{showDots && stepsData.length > 1 && (
<div className="flex justify-center space-x-2 pb-6">
{stepsData.map((_, index) => (
<button
key={index}
onClick={() => goToStep(index)}
className={`w-3 h-3 rounded-full transition-all duration-200 ${
index === currentStep
? 'bg-blue-600 transform scale-125'
: 'bg-gray-300 hover:bg-gray-400'
}`}
aria-label={`Go to step ${index + 1}`}
/>
))}
</div>
)}
</div>
{/* Step Counter */}
<div className="bg-gray-50 px-6 py-3 text-center text-sm text-gray-600 border-t">
Step {currentStep + 1} of {stepsData.length}
</div>
</div>
);
};
// Example usage component
const ExampleUsage = () => {
const customSteps = [
{
title: "Prepare Your Materials",
description: "Gather all necessary tools and materials before starting the project. Make sure you have adequate workspace and safety equipment.",
image: "https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?w=600&h=400&fit=crop",
stepNumber: 1
},
{
title: "Setup the Equipment",
description: "Configure your equipment according to the specifications. Double-check all connections and settings before proceeding.",
image: "https://images.unsplash.com/photo-1581092160562-40aa08e78837?w=600&h=400&fit=crop",
stepNumber: 2
}
];
return (
<div className="p-8 bg-gray-50 min-h-screen">
<div className="max-w-6xl mx-auto">
<h1 className="text-3xl font-bold text-center mb-8 text-gray-900">
Docusaurus Step Carousel Component
</h1>
<div className="mb-12">
<h2 className="text-xl font-semibold mb-4 text-gray-800">Default Example</h2>
<StepCarousel />
</div>
<div className="mb-12">
<h2 className="text-xl font-semibold mb-4 text-gray-800">Custom Steps Example</h2>
<StepCarousel steps={customSteps} />
</div>
<div className="mb-12">
<h2 className="text-xl font-semibold mb-4 text-gray-800">Minimal Version (No Navigation)</h2>
<StepCarousel
showNavigation={false}
showDots={false}
showStepNumbers={false}
/>
</div>
<div className="bg-white p-6 rounded-lg shadow mt-8">
<h3 className="text-lg font-semibold mb-3">Usage in Docusaurus:</h3>
<div className="bg-gray-100 p-4 rounded font-mono text-sm">
<div className="text-gray-600">// In your MDX file:</div>
<div className="mt-2">
{`import StepCarousel from '@site/src/components/StepCarousel';
<StepCarousel
steps={[
{
title: "Step 1",
description: "Description here...",
image: "/img/step1.jpg",
stepNumber: 1
}
]}
/>`}
</div>
</div>
</div>
</div>
</div>
);
};
export default ExampleUsage;

View file

@ -0,0 +1,255 @@
import React, { useState } from 'react';
const StepCarousel = ({
steps = [],
showStepNumbers = true,
showNavigation = true,
showDots = true,
className = ""
}) => {
const [currentStep, setCurrentStep] = useState(0);
// Default demo data if no steps provided
const defaultSteps = [
{
title: "Mill the Mould",
description: "Download the .stp-files and the blueprints for the mould for CNC milling. Metal examples for CNC Milling: Aluminium 7050, 7075-T6, Steel 1045. CNC mill the mould according to the blueprint and insert 8x10mm Dowel pins.",
image: "https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?w=600&h=400&fit=crop",
stepNumber: 1
},
{
title: "Inject",
description: "Fill the injection machine with Polypropylene, heat up for 10-12min, check the viscosity of the outcoming plastic. You need about 25g for the bottom part and 30g for the Top Part.",
image: "https://images.unsplash.com/photo-1581092160562-40aa08e78837?w=600&h=400&fit=crop",
stepNumber: 2
},
{
title: "Demoulding",
description: "Unscrew the moulds, use the demoulding pockets to open the moulds, knock out the sprues, cut them and do the afterwork.",
image: "https://images.unsplash.com/photo-1581092918056-0c4c3acd3789?w=600&h=400&fit=crop",
stepNumber: 3
},
{
title: "Drill the holes",
description: "You need to drill 2x D2mm for the button screws and 3x D2mm for the case screws. Keep attention just to drill 3mm deep. After that insert button screws.",
image: "https://images.unsplash.com/photo-1609592842914-b3e29c6b0b25?w=600&h=400&fit=crop",
stepNumber: 4
},
{
title: "Final Assembly",
description: "The final steps are inserting the lens, the circuit board and screwing the top and bottom together. Test the click and adjust button screws for the best feel.",
image: "https://images.unsplash.com/photo-1518709268805-4e9042af2ac1?w=600&h=400&fit=crop",
stepNumber: 5
}
];
const stepsData = steps.length > 0 ? steps : defaultSteps;
const nextStep = () => {
setCurrentStep((prev) => (prev + 1) % stepsData.length);
};
const prevStep = () => {
setCurrentStep((prev) => (prev - 1 + stepsData.length) % stepsData.length);
};
const goToStep = (index) => {
setCurrentStep(index);
};
const styles = {
container: {
maxWidth: '1024px',
margin: '0 auto',
backgroundColor: '#ffffff',
borderRadius: '8px',
boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)',
overflow: 'hidden'
},
imageContainer: {
position: 'relative',
height: '384px',
backgroundColor: '#f3f4f6',
overflow: 'hidden'
},
image: {
width: '100%',
height: '100%',
objectFit: 'cover',
transition: 'opacity 0.3s ease'
},
stepBadge: {
position: 'absolute',
top: '16px',
left: '16px',
backgroundColor: '#2563eb',
color: 'white',
width: '40px',
height: '40px',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontWeight: 'bold',
fontSize: '18px',
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)'
},
navButton: {
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
color: 'white',
width: '40px',
height: '40px',
borderRadius: '50%',
border: 'none',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '20px',
fontWeight: 'bold',
transition: 'background-color 0.2s ease'
},
prevButton: {
left: '16px'
},
nextButton: {
right: '16px'
},
content: {
padding: '24px'
},
title: {
fontSize: '24px',
fontWeight: 'bold',
color: '#111827',
marginBottom: '12px'
},
description: {
color: '#374151',
lineHeight: '1.6'
},
dotsContainer: {
display: 'flex',
justifyContent: 'center',
gap: '8px',
paddingBottom: '24px'
},
dot: {
width: '12px',
height: '12px',
borderRadius: '50%',
border: 'none',
cursor: 'pointer',
transition: 'all 0.2s ease'
},
activeDot: {
backgroundColor: '#2563eb',
transform: 'scale(1.25)'
},
inactiveDot: {
backgroundColor: '#d1d5db'
},
counter: {
backgroundColor: '#f9fafb',
padding: '12px 24px',
textAlign: 'center',
fontSize: '14px',
color: '#6b7280',
borderTop: '1px solid #e5e7eb'
}
};
return (
<div style={{...styles.container, className}}>
{/* Main Content Area */}
<div style={{position: 'relative'}}>
{/* Image Container */}
<div style={styles.imageContainer}>
<img
src={stepsData[currentStep].image}
alt={stepsData[currentStep].title}
style={styles.image}
/>
{/* Step Number Badge */}
{showStepNumbers && (
<div style={styles.stepBadge}>
{stepsData[currentStep].stepNumber || currentStep + 1}
</div>
)}
{/* Navigation Arrows */}
{showNavigation && stepsData.length > 1 && (
<>
<button
onClick={prevStep}
style={{...styles.navButton, ...styles.prevButton}}
onMouseEnter={(e) => e.target.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'}
onMouseLeave={(e) => e.target.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'}
aria-label="Previous step"
>
</button>
<button
onClick={nextStep}
style={{...styles.navButton, ...styles.nextButton}}
onMouseEnter={(e) => e.target.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'}
onMouseLeave={(e) => e.target.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'}
aria-label="Next step"
>
</button>
</>
)}
</div>
{/* Content Area */}
<div style={styles.content}>
<h3 style={styles.title}>
{stepsData[currentStep].title}
</h3>
<p style={styles.description}>
{stepsData[currentStep].description}
</p>
</div>
{/* Dot Navigation */}
{showDots && stepsData.length > 1 && (
<div style={styles.dotsContainer}>
{stepsData.map((_, index) => (
<button
key={index}
onClick={() => goToStep(index)}
style={{
...styles.dot,
...(index === currentStep ? styles.activeDot : styles.inactiveDot)
}}
onMouseEnter={(e) => {
if (index !== currentStep) {
e.target.style.backgroundColor = '#9ca3af';
}
}}
onMouseLeave={(e) => {
if (index !== currentStep) {
e.target.style.backgroundColor = '#d1d5db';
}
}}
aria-label={`Go to step ${index + 1}`}
/>
))}
</div>
)}
</div>
{/* Step Counter */}
<div style={styles.counter}>
Step {currentStep + 1} of {stepsData.length}
</div>
</div>
);
};
export default StepCarousel;

View file

@ -0,0 +1,17 @@
import React from 'react';
import ImageCarousel from './ImageCarousel';
import styles from './StepWithCarousel.module.css';
export default function StepWithCarousel({ title, children, images }) {
return (
<div className={styles.step}>
<div className={styles.text}>
<h2>{title}</h2>
{children}
</div>
<div className={styles.carousel}>
<ImageCarousel images={images} />
</div>
</div>
);
}

View file

@ -0,0 +1,18 @@
.step {
display: flex;
flex-wrap: wrap;
gap: 2rem;
margin-bottom: 3rem;
align-items: flex-start;
font-size:14px;
}
.text {
flex: 1;
min-width: 280px;
}
.carousel {
flex: 1;
min-width: 300px;
}