From 2f179129490209b68d5f834d5f0e7dbf85f8e2f7 Mon Sep 17 00:00:00 2001 From: zach Date: Mon, 16 Mar 2026 14:07:37 -0400 Subject: [PATCH] reqrote volatility with proper standard deviation and added tooltip --- src/assets/css/_bootstrap.scss | 2 +- src/assets/css/main.scss | 14 ++++++ src/assets/js/main.js | 29 ++++++++++- src/pages/partials/card-modal.astro | 76 +++++++++++++++++++---------- 4 files changed, 93 insertions(+), 28 deletions(-) diff --git a/src/assets/css/_bootstrap.scss b/src/assets/css/_bootstrap.scss index c34501a..b22f8d5 100644 --- a/src/assets/css/_bootstrap.scss +++ b/src/assets/css/_bootstrap.scss @@ -41,7 +41,7 @@ // @import 'bootstrap/scss/spinners'; @import 'bootstrap/scss/tables'; @import 'bootstrap/scss/toasts'; -// @import 'bootstrap/scss/tooltip'; +@import 'bootstrap/scss/tooltip'; @import 'bootstrap/scss/transitions'; // Optional helpers diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss index ddab7e6..ccc83b3 100644 --- a/src/assets/css/main.scss +++ b/src/assets/css/main.scss @@ -380,6 +380,20 @@ $tiers: ( drop-shadow(0 4px 6px rgba(0, 0, 0, 0.2)); } +.tooltip.volatility-popover .tooltip-inner { + background: #1d1f21; + color: #e9ecef; + padding: 0.9rem 1rem; + border-radius: 0.6rem; + text-align: left; + max-width: 260px; + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.tooltip.volatility-popover .tooltip-arrow::before { + border-top-color: #1d1f21 !important; +} + /* -------------------------------------------------- Pricing -------------------------------------------------- */ diff --git a/src/assets/js/main.js b/src/assets/js/main.js index 4aaa451..abc4f3a 100644 --- a/src/assets/js/main.js +++ b/src/assets/js/main.js @@ -1,6 +1,6 @@ import * as bootstrap from 'bootstrap'; window.bootstrap = bootstrap; - +import 'bootstrap/dist/js/bootstrap.bundle.min.js'; // trap browser back and close the modal if open const cardModal = document.getElementById('cardModal'); @@ -24,4 +24,29 @@ cardModal.addEventListener('hide.bs.modal', () => { if (history.state && history.state.modalOpen) { history.back(); } -}); \ No newline at end of file +}); + + + import { Tooltip } from "bootstrap"; + + // Initialize all tooltips globally + const initTooltips = () => { + document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => { + if (!el._tooltipInstance) { + el._tooltipInstance = new Tooltip(el, { + container: 'body', // ensures tooltip is appended to body, important for modals + }); + } + }); + }; + + // Run on page load + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initTooltips); + } else { + initTooltips(); + } + + // Optional: observe DOM changes for dynamically added tooltips (e.g., modals loaded later) + const observer = new MutationObserver(() => initTooltips()); + observer.observe(document.body, { childList: true, subtree: true }); \ No newline at end of file diff --git a/src/pages/partials/card-modal.astro b/src/pages/partials/card-modal.astro index d5f21d5..28d25ab 100644 --- a/src/pages/partials/card-modal.astro +++ b/src/pages/partials/card-modal.astro @@ -8,6 +8,8 @@ import { priceHistory, skus } from '../../db/schema'; import { eq, inArray } from 'drizzle-orm'; import FirstEditionIcon from "../../components/FirstEditionIcon.astro"; +import { Tooltip } from "bootstrap"; + export const partial = true; export const prerender = false; @@ -114,7 +116,6 @@ const priceHistoryForChart = historyRows.map(row => ({ })).filter(r => r.calculatedAt !== null); // ── Determine which range buttons to show ──────────────────────────────── -// Find the oldest data point to know what ranges are meaningful const now = Date.now(); const oldestDate = historyRows.length ? Math.min(...historyRows @@ -126,10 +127,10 @@ const dataSpanDays = (now - oldestDate) / 86_400_000; const showRanges = { '1m': dataSpanDays >= 1, - '3m': dataSpanDays >= 60, // meaningful if at least 2 months of data - '6m': dataSpanDays >= 180, // meaningful if at least 6 months of data - '1y': dataSpanDays >= 365, // meaningful if at least 9 months of data - 'all': dataSpanDays >= 400, // meaningful if more than ~13 months of data + '3m': dataSpanDays >= 60, + '6m': dataSpanDays >= 180, + '1y': dataSpanDays >= 365, + 'all': dataSpanDays >= 400, }; const conditionOrder = ["Near Mint", "Lightly Played", "Moderately Played", "Heavily Played", "Damaged"]; @@ -250,24 +251,49 @@ const altSearchUrl = (card: any) => {
-
-
-
Market Price
-

${price.marketPrice}

-
-
-
Lowest Price
-

${price.lowestPrice}

-
-
-
Highest Price
-

${price.highestPrice}

-
-
-
Volatility
-

{attributes?.volatility}

-
+
+
+
Market Price
+

${price.marketPrice}

+
+
Lowest Price
+

${price.lowestPrice}

+
+
+
Highest Price
+

${price.highestPrice}

+
+
+
+ Volatility + Monthly Volatility
+
+

+ What this measures: how much the market price tends to move day-to-day, + scaled up to a monthly expectation. +

+

+ A card with 30% volatility typically swings ±30% over a month. +

+
+ `} + > + + + +

{attributes?.volatility}

+
+
@@ -320,9 +346,9 @@ const altSearchUrl = (card: any) => {
{showRanges['1m'] && } {showRanges['3m'] && } - {showRanges['6m'] && } - {showRanges['1y'] && } - {showRanges['all'] && } + {showRanges['6m'] && } + {showRanges['1y'] && } + {showRanges['all'] && }