about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--content/bikes/fogcutter.md66
-rw-r--r--static/css/carousel.css48
-rw-r--r--static/images/fogcutter/IMG_0988.jpegbin0 -> 795564 bytes
-rw-r--r--static/images/fogcutter/IMG_0989.jpegbin0 -> 568182 bytes
-rw-r--r--static/images/fogcutter/IMG_0990.jpegbin0 -> 509543 bytes
-rw-r--r--static/images/fogcutter/IMG_0991.jpegbin0 -> 837291 bytes
-rw-r--r--static/images/fogcutter/IMG_0992.jpegbin0 -> 640921 bytes
-rw-r--r--static/images/fogcutter/IMG_0993.jpegbin0 -> 617697 bytes
-rw-r--r--static/images/fogcutter/IMG_0994.jpegbin0 -> 615454 bytes
-rw-r--r--static/images/fogcutter/IMG_0995.jpegbin0 -> 614971 bytes
-rw-r--r--static/images/fogcutter/IMG_0996.jpegbin0 -> 583817 bytes
-rw-r--r--static/images/fogcutter/IMG_0997.jpegbin0 -> 600864 bytes
-rw-r--r--static/images/fogcutter/IMG_0998.jpegbin0 -> 477406 bytes
-rw-r--r--static/images/fogcutter/IMG_0999.jpegbin0 -> 712966 bytes
-rw-r--r--static/images/fogcutter/IMG_1001.jpegbin0 -> 436923 bytes
-rw-r--r--static/images/fogcutter/IMG_1002.jpegbin0 -> 463719 bytes
-rw-r--r--static/js/carousel.js122
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;