diff options
author | Franck Cuny <franck@fcuny.net> | 2024-09-22 13:24:30 -0700 |
---|---|---|
committer | Franck Cuny <franck@fcuny.net> | 2024-09-22 13:24:30 -0700 |
commit | 53db590eed6e90138583e01d2c391b05d2ba3b6f (patch) | |
tree | f1ce3408d360352a51a9f719a84bee20400635f4 | |
parent | render the TOC correctly for mobile and desktop (diff) | |
download | fcuny.net-53db590eed6e90138583e01d2c391b05d2ba3b6f.tar.gz |
add information about the fog cutter
17 files changed, 236 insertions, 0 deletions
diff --git a/content/bikes/fogcutter.md b/content/bikes/fogcutter.md new file mode 100644 index 0000000..7ca46a0 --- /dev/null +++ b/content/bikes/fogcutter.md @@ -0,0 +1,66 @@ +--- +title: SOMA Fog Cutter +date: 2024-09-22 +template: orphan.html +--- + +A [SOMA](https://www.somafab.com/archives/product/fog-cutter-frame-set) [Fog Cutter](https://www.somafab.com/archives/product/fog-cutter-frame-set) road bike, build by [Blue Heron Bike](https://www.blueheronbikesberkeley.com/bike-accessories) in Berkeley. The size of the frame is 58cm and the color is blue. It comes with a carbon fork. + +**Asking price is $2800.** + +You can contact me <a href="mailto:franck@fcuny.net?subject=SOMA%20fog%20cutter">by email</a>. + +<div id="carousel-container"></div> + +<script> + // Specify the images for this carousel + const pageImages = [ + '/images/fogcutter/IMG_0988.jpeg', + '/images/fogcutter/IMG_0989.jpeg', + '/images/fogcutter/IMG_0990.jpeg', + '/images/fogcutter/IMG_0991.jpeg', + '/images/fogcutter/IMG_0992.jpeg', + '/images/fogcutter/IMG_0993.jpeg', + '/images/fogcutter/IMG_0994.jpeg', + '/images/fogcutter/IMG_0995.jpeg', + '/images/fogcutter/IMG_0996.jpeg', + '/images/fogcutter/IMG_0997.jpeg', + '/images/fogcutter/IMG_0998.jpeg', + '/images/fogcutter/IMG_0999.jpeg', + '/images/fogcutter/IMG_1001.jpeg', + '/images/fogcutter/IMG_1002.jpeg', + ]; + + // Check if the initializeCarousel function is available + if (typeof initializeCarousel === 'function') { + // Initialize the carousel + initializeCarousel('carousel-container', pageImages); + } else { + console.error('Carousel initialization function not found. Make sure carousel.js is properly loaded.'); + } +</script> + +## Part list + +| part | model | +|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Frame | [SOMA Fog Cutter](https://www.somafab.com/archives/product/fog-cutter-frame-set) 58cm in blue | +| Fork | [Soma Fork Fog Cutter Carbon Cerulean Blue (Thru-Axle)](https://www.somafabshop.com/shop/231007-soma-fork-fog-cutter-carbon-cerulean-blue-thru-axle-5617?search=cerulean&product=product.template%285617%2C%29#attr=) | +| Headset | | +| Front and rear wheel | [DT Swiss XR 331 29 20 mm DB VI](https://www.dtswiss.com/en/support/product-support?matnr=RTXR3329N28S011223) | +| Tire | | +| Front hub | [SP dynamo PL7](https://www.sp-dynamo.com/series7-pl7) | +| Rear hub | [Shimano Tiagra rs740](https://bike.shimano.com/en-US/product/component/tiagra-4700/FH-RS470.html) | +| Rear derailleur | [Shimano Ultegra RX 11 speed](https://bike.shimano.com/en-US/product/component/ultegra-rx/RD-RX800-GS.html) | +| Front derailleur | [Shimano Metrea 2x11 speed](https://bike.shimano.com/en-US/product/component/metrea-u5000/FD-U5000-F.html) | +| Handlebar | [Zipp Service Course 70 Ergo Drop Handlebar 42cm](https://www.sram.com/en/zipp/models/hb-dbsc-7e-b2) | +| Brifter | [Shimano Dura Ace 9120](https://bike.shimano.com/en-US/product/component/duraace-r9100/ST-R9120-R.html) | +| Saddle | [Brooks C15 black](https://www.brooksengland.com/en_us/c15.html) | +| Seat post | [SIM Works Beatnik post (black)](https://www.sim.works/products/beatnik-post-1) | +| Front light | [Busch & Müller Lumotec IQ-X Headlamp](https://www.bumm.de/en/products/dynamo-scheinwerfer/produkt/164rtsndi-01-schwarz-164rtsndi-silber%20.html) | +| Brake | | +| Crank | [White Industries Square Taper road cranks](https://www.whiteind.com/product/square-taper-road-cranks/) | +| Chain ring | [White Industries 52/32](https://www.whiteind.com/product/vbc-chainring-sets/) | +| Pedal | | +| Bar tape | [Lizzard Skin (brown)](https://www.lizardskins.com/cycling) | +| Bottle cage | | diff --git a/static/css/carousel.css b/static/css/carousel.css new file mode 100644 index 0000000..d1505e1 --- /dev/null +++ b/static/css/carousel.css @@ -0,0 +1,48 @@ +/* File: carousel.css */ + +.carousel { + width: 100%; + max-width: 46rem; /* As per your specification */ + margin: 0 auto; +} + +.carousel-main-image { + width: 100%; + height: auto; + margin-bottom: 20px; +} + +.carousel-main-image img { + width: 100%; + height: auto; + display: block; +} + +.carousel-vignettes { + display: flex; + justify-content: center; + gap: 10px; + overflow-x: auto; + padding: 10px 0; +} + +.vignette { + cursor: pointer; + transition: opacity 0.3s ease; + flex: 0 0 auto; +} + +.vignette:hover { + opacity: 0.8; +} + +.vignette.active { + border: 2px solid #007bff; +} + +.vignette img { + display: block; + width: 120px; + height: 80px; + object-fit: cover; +} diff --git a/static/images/fogcutter/IMG_0988.jpeg b/static/images/fogcutter/IMG_0988.jpeg new file mode 100644 index 0000000..3efafd6 --- /dev/null +++ b/static/images/fogcutter/IMG_0988.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0989.jpeg b/static/images/fogcutter/IMG_0989.jpeg new file mode 100644 index 0000000..528c8a1 --- /dev/null +++ b/static/images/fogcutter/IMG_0989.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0990.jpeg b/static/images/fogcutter/IMG_0990.jpeg new file mode 100644 index 0000000..166b63f --- /dev/null +++ b/static/images/fogcutter/IMG_0990.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0991.jpeg b/static/images/fogcutter/IMG_0991.jpeg new file mode 100644 index 0000000..06b1294 --- /dev/null +++ b/static/images/fogcutter/IMG_0991.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0992.jpeg b/static/images/fogcutter/IMG_0992.jpeg new file mode 100644 index 0000000..e37329b --- /dev/null +++ b/static/images/fogcutter/IMG_0992.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0993.jpeg b/static/images/fogcutter/IMG_0993.jpeg new file mode 100644 index 0000000..76606a3 --- /dev/null +++ b/static/images/fogcutter/IMG_0993.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0994.jpeg b/static/images/fogcutter/IMG_0994.jpeg new file mode 100644 index 0000000..2cb0ebc --- /dev/null +++ b/static/images/fogcutter/IMG_0994.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0995.jpeg b/static/images/fogcutter/IMG_0995.jpeg new file mode 100644 index 0000000..0642afd --- /dev/null +++ b/static/images/fogcutter/IMG_0995.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0996.jpeg b/static/images/fogcutter/IMG_0996.jpeg new file mode 100644 index 0000000..dadc25e --- /dev/null +++ b/static/images/fogcutter/IMG_0996.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0997.jpeg b/static/images/fogcutter/IMG_0997.jpeg new file mode 100644 index 0000000..d601460 --- /dev/null +++ b/static/images/fogcutter/IMG_0997.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0998.jpeg b/static/images/fogcutter/IMG_0998.jpeg new file mode 100644 index 0000000..dc99cd9 --- /dev/null +++ b/static/images/fogcutter/IMG_0998.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_0999.jpeg b/static/images/fogcutter/IMG_0999.jpeg new file mode 100644 index 0000000..95bd086 --- /dev/null +++ b/static/images/fogcutter/IMG_0999.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_1001.jpeg b/static/images/fogcutter/IMG_1001.jpeg new file mode 100644 index 0000000..887e029 --- /dev/null +++ b/static/images/fogcutter/IMG_1001.jpeg Binary files differdiff --git a/static/images/fogcutter/IMG_1002.jpeg b/static/images/fogcutter/IMG_1002.jpeg new file mode 100644 index 0000000..72efefa --- /dev/null +++ b/static/images/fogcutter/IMG_1002.jpeg Binary files differdiff --git a/static/js/carousel.js b/static/js/carousel.js new file mode 100644 index 0000000..f30f934 --- /dev/null +++ b/static/js/carousel.js @@ -0,0 +1,122 @@ +function createCarousel(images) { + const carousel = document.createElement('div'); + carousel.className = 'carousel'; + let currentIndex = 0; + + // Create main image container + const mainImageContainer = document.createElement('div'); + mainImageContainer.className = 'carousel-main-image'; + carousel.appendChild(mainImageContainer); + + // Create vignette container + const vignetteContainer = document.createElement('div'); + vignetteContainer.className = 'carousel-vignettes'; + carousel.appendChild(vignetteContainer); + + // Function to update the main displayed image + function updateMainImage() { + mainImageContainer.innerHTML = ''; + const img = document.createElement('img'); + img.src = images[currentIndex]; + img.style.width = '100%'; + img.style.height = 'auto'; + mainImageContainer.appendChild(img); + } + + // Function to create vignettes + function createVignettes() { + vignetteContainer.innerHTML = ''; + const containerWidth = carousel.offsetWidth; + const vignetteWidth = 120; + const vignetteHeight = 80; + const vignetteMargin = 10; + const maxVignettes = Math.floor(containerWidth / (vignetteWidth + vignetteMargin)); + + const startIndex = Math.max(0, currentIndex - Math.floor(maxVignettes / 2)); + const endIndex = Math.min(images.length, startIndex + maxVignettes); + + for (let i = startIndex; i < endIndex; i++) { + const vignette = document.createElement('div'); + vignette.className = 'vignette'; + if (i === currentIndex) vignette.classList.add('active'); + + const img = document.createElement('img'); + img.src = images[i]; + img.style.width = vignetteWidth + 'px'; + img.style.height = vignetteHeight + 'px'; + img.style.objectFit = 'cover'; + + vignette.appendChild(img); + vignette.addEventListener('click', () => goToImage(i)); + vignetteContainer.appendChild(vignette); + } + } + + // Function to go to a specific image + function goToImage(index) { + currentIndex = index; + updateMainImage(); + createVignettes(); + } + + // Function to go to the next image + function nextImage() { + currentIndex = (currentIndex + 1) % images.length; + updateMainImage(); + createVignettes(); + } + + // Function to go to the previous image + function prevImage() { + currentIndex = (currentIndex - 1 + images.length) % images.length; + updateMainImage(); + createVignettes(); + } + + // Event listener for keyboard navigation + document.addEventListener('keydown', (e) => { + if (e.key === 'ArrowRight') nextImage(); + if (e.key === 'ArrowLeft') prevImage(); + }); + + // Initialize the carousel + updateMainImage(); + + // Use setTimeout to delay the initial creation of vignettes + setTimeout(() => { + createVignettes(); + }, 0); + + // Recalculate vignettes on window resize + window.addEventListener('resize', createVignettes); + + return carousel; +} + +// Function to initialize the carousel with specific images +function initializeCarousel(containerId, images) { + document.addEventListener('DOMContentLoaded', () => { + const container = document.getElementById(containerId); + if (container) { + const carouselElement = createCarousel(images); + container.appendChild(carouselElement); + + // Use ResizeObserver to detect when the carousel is fully rendered + const resizeObserver = new ResizeObserver(entries => { + for (let entry of entries) { + if (entry.target === carouselElement) { + createVignettes(); + resizeObserver.disconnect(); // Stop observing once vignettes are created + } + } + }); + + resizeObserver.observe(carouselElement); + } else { + console.error(`Container with id "${containerId}" not found.`); + } + }); +} + +// Make the initializeCarousel function globally available +window.initializeCarousel = initializeCarousel; |