reqrote volatility with proper standard deviation and added tooltip
This commit is contained in:
@@ -41,7 +41,7 @@
|
|||||||
// @import 'bootstrap/scss/spinners';
|
// @import 'bootstrap/scss/spinners';
|
||||||
@import 'bootstrap/scss/tables';
|
@import 'bootstrap/scss/tables';
|
||||||
@import 'bootstrap/scss/toasts';
|
@import 'bootstrap/scss/toasts';
|
||||||
// @import 'bootstrap/scss/tooltip';
|
@import 'bootstrap/scss/tooltip';
|
||||||
@import 'bootstrap/scss/transitions';
|
@import 'bootstrap/scss/transitions';
|
||||||
|
|
||||||
// Optional helpers
|
// Optional helpers
|
||||||
|
|||||||
@@ -380,6 +380,20 @@ $tiers: (
|
|||||||
drop-shadow(0 4px 6px rgba(0, 0, 0, 0.2));
|
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
|
Pricing
|
||||||
-------------------------------------------------- */
|
-------------------------------------------------- */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as bootstrap from 'bootstrap';
|
import * as bootstrap from 'bootstrap';
|
||||||
window.bootstrap = bootstrap;
|
window.bootstrap = bootstrap;
|
||||||
|
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||||
|
|
||||||
// trap browser back and close the modal if open
|
// trap browser back and close the modal if open
|
||||||
const cardModal = document.getElementById('cardModal');
|
const cardModal = document.getElementById('cardModal');
|
||||||
@@ -25,3 +25,28 @@ cardModal.addEventListener('hide.bs.modal', () => {
|
|||||||
history.back();
|
history.back();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
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 });
|
||||||
@@ -8,6 +8,8 @@ import { priceHistory, skus } from '../../db/schema';
|
|||||||
import { eq, inArray } from 'drizzle-orm';
|
import { eq, inArray } from 'drizzle-orm';
|
||||||
import FirstEditionIcon from "../../components/FirstEditionIcon.astro";
|
import FirstEditionIcon from "../../components/FirstEditionIcon.astro";
|
||||||
|
|
||||||
|
import { Tooltip } from "bootstrap";
|
||||||
|
|
||||||
export const partial = true;
|
export const partial = true;
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
@@ -114,7 +116,6 @@ const priceHistoryForChart = historyRows.map(row => ({
|
|||||||
})).filter(r => r.calculatedAt !== null);
|
})).filter(r => r.calculatedAt !== null);
|
||||||
|
|
||||||
// ── Determine which range buttons to show ────────────────────────────────
|
// ── Determine which range buttons to show ────────────────────────────────
|
||||||
// Find the oldest data point to know what ranges are meaningful
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const oldestDate = historyRows.length
|
const oldestDate = historyRows.length
|
||||||
? Math.min(...historyRows
|
? Math.min(...historyRows
|
||||||
@@ -126,10 +127,10 @@ const dataSpanDays = (now - oldestDate) / 86_400_000;
|
|||||||
|
|
||||||
const showRanges = {
|
const showRanges = {
|
||||||
'1m': dataSpanDays >= 1,
|
'1m': dataSpanDays >= 1,
|
||||||
'3m': dataSpanDays >= 60, // meaningful if at least 2 months of data
|
'3m': dataSpanDays >= 60,
|
||||||
'6m': dataSpanDays >= 180, // meaningful if at least 6 months of data
|
'6m': dataSpanDays >= 180,
|
||||||
'1y': dataSpanDays >= 365, // meaningful if at least 9 months of data
|
'1y': dataSpanDays >= 365,
|
||||||
'all': dataSpanDays >= 400, // meaningful if more than ~13 months of data
|
'all': dataSpanDays >= 400,
|
||||||
};
|
};
|
||||||
|
|
||||||
const conditionOrder = ["Near Mint", "Lightly Played", "Moderately Played", "Heavily Played", "Damaged"];
|
const conditionOrder = ["Near Mint", "Lightly Played", "Moderately Played", "Heavily Played", "Damaged"];
|
||||||
@@ -264,7 +265,32 @@ const altSearchUrl = (card: any) => {
|
|||||||
<p class="mb-0 mt-1">${price.highestPrice}</p>
|
<p class="mb-0 mt-1">${price.highestPrice}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class={`alert rounded p-2 flex-fill d-flex flex-column mb-0 ${attributes?.volatilityClass}`}>
|
<div class={`alert rounded p-2 flex-fill d-flex flex-column mb-0 ${attributes?.volatilityClass}`}>
|
||||||
<h6 class="mb-auto">Volatility</h6>
|
<h6 class="mb-auto d-flex justify-content-between align-items-start">
|
||||||
|
<span>Volatility</span>
|
||||||
|
<span
|
||||||
|
class="volatility-info"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top"
|
||||||
|
data-bs-container="body"
|
||||||
|
data-bs-custom-class="volatility-popover"
|
||||||
|
data-bs-trigger="hover focus click"
|
||||||
|
data-bs-html="true"
|
||||||
|
data-bs-title={`
|
||||||
|
<div class='tooltip-heading fw-bold mb-1'>Monthly Volatility</div>
|
||||||
|
<div class='small'>
|
||||||
|
<p class="mb-1">
|
||||||
|
<strong>What this measures:</strong> how much the market price tends to move day-to-day,
|
||||||
|
scaled up to a monthly expectation.
|
||||||
|
</p>
|
||||||
|
<p class="mb-0">
|
||||||
|
A card with <strong>30% volatility</strong> typically swings ±30% over a month.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" fill="currentColor" viewBox="0 0 16 16"> <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/> <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/> </svg>
|
||||||
|
</span>
|
||||||
|
</h6>
|
||||||
<p class="mb-0 mt-1">{attributes?.volatility}</p>
|
<p class="mb-0 mt-1">{attributes?.volatility}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -320,9 +346,9 @@ const altSearchUrl = (card: any) => {
|
|||||||
<div class="btn-group btn-group-sm d-flex flex-row gap-1 justify-content-end mt-2" role="group" aria-label="Time range">
|
<div class="btn-group btn-group-sm d-flex flex-row gap-1 justify-content-end mt-2" role="group" aria-label="Time range">
|
||||||
{showRanges['1m'] && <button type="button" class="btn btn-dark price-range-btn active" data-range="1m">1M</button>}
|
{showRanges['1m'] && <button type="button" class="btn btn-dark price-range-btn active" data-range="1m">1M</button>}
|
||||||
{showRanges['3m'] && <button type="button" class="btn btn-dark price-range-btn" data-range="3m">3M</button>}
|
{showRanges['3m'] && <button type="button" class="btn btn-dark price-range-btn" data-range="3m">3M</button>}
|
||||||
{showRanges['6m'] && <button type="button" class="btn btn-dark price-range-btn d-none" data-range="6m">6M</button>}
|
{showRanges['6m'] && <button type="button" class="btn btn-dark price-range-btn" data-range="6m">6M</button>}
|
||||||
{showRanges['1y'] && <button type="button" class="btn btn-dark price-range-btn d-none" data-range="1y">1Y</button>}
|
{showRanges['1y'] && <button type="button" class="btn btn-dark price-range-btn" data-range="1y">1Y</button>}
|
||||||
{showRanges['all'] && <button type="button" class="btn btn-dark price-range-btn d-none" data-range="all">All</button>}
|
{showRanges['all'] && <button type="button" class="btn btn-dark price-range-btn" data-range="all">All</button>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user