diff --git a/package-lock.json b/package-lock.json index dd45c49..9d2c786 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@astrolib/analytics": "^0.6.1", "@astrolib/seo": "^1.0.0-beta.8", "@fontsource-variable/inter": "^5.1.1", + "@tippyjs/react": "^4.2.6", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "astro": "^5.2.3", @@ -2329,6 +2330,16 @@ "fast-glob": "3.3.3" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@qwik.dev/partytown": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/@qwik.dev/partytown/-/partytown-0.11.1.tgz", @@ -2731,6 +2742,19 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, + "node_modules/@tippyjs/react": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz", + "integrity": "sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==", + "license": "MIT", + "dependencies": { + "tippy.js": "^6.3.1" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -11123,6 +11147,15 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, "node_modules/tlds": { "version": "1.259.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz", diff --git a/package.json b/package.json index dc8e987..37451cd 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@astrolib/analytics": "^0.6.1", "@astrolib/seo": "^1.0.0-beta.8", "@fontsource-variable/inter": "^5.1.1", + "@tippyjs/react": "^4.2.6", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", "astro": "^5.2.3", diff --git a/src/assets/styles/tailwind.css b/src/assets/styles/tailwind.css index 01c69d0..96aabe5 100644 --- a/src/assets/styles/tailwind.css +++ b/src/assets/styles/tailwind.css @@ -98,3 +98,21 @@ .dd *:first-child { margin-top: 0; } + +/* Custom Tippy.js theme for light/dark mode */ +.tippy-box[data-theme~='devnet'] { + background-color: #fff; + color: #222; + border-radius: 12px; + box-shadow: 0 4px 24px rgba(0,0,0,0.10); + font-size: 1rem; + padding: 0.75rem 1rem; +} +.dark .tippy-box[data-theme~='devnet'] { + background-color: #23272f; + color: #f3f4f6; + box-shadow: 0 4px 24px rgba(0,0,0,0.40); +} +.tippy-box[data-theme~='devnet'] .tippy-arrow { + color: inherit; +} diff --git a/src/components/UptimeStatusIsland.jsx b/src/components/UptimeStatusIsland.jsx index a1b13d8..ce44bca 100644 --- a/src/components/UptimeStatusIsland.jsx +++ b/src/components/UptimeStatusIsland.jsx @@ -1,6 +1,8 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; -import { FiAward, FiPercent, FiActivity } from 'react-icons/fi'; +import { FiAward, FiPercent, FiActivity, FiCheckCircle, FiClock, FiGlobe, FiLock } from 'react-icons/fi'; import { DateTime } from 'luxon'; +import Tippy from '@tippyjs/react'; +import 'tippy.js/dist/tippy.css'; function getStatusColor(validCert) { if (validCert === false) return 'bg-red-600'; @@ -55,6 +57,39 @@ function formatLocalTime(rawTime, zone = 'utc') { : 'Invalid DateTime'; } +function HeartbeatPopup({ hb, userZone, monitor }) { + const localTime = hb ? formatLocalTime(hb.time, userZone) : ''; + const utcTime = hb ? formatLocalTime(hb.time, 'utc') : ''; + return ( +
+
+ + {hb.status === 1 ? 'Up' : 'Down'} +
+
+ + Local: {localTime} +
+
+ + UTC: {utcTime} +
+
+ + Ping: {hb.ping ?? '--'} ms +
+
+ + Uptime 24h: {monitor.uptime24h?.toFixed(2) ?? '--'}% +
+
+ + Cert valid for: {monitor.certExpiryDaysRemaining ?? '--'} days +
+
+ ); +} + export default function UptimeStatusIsland() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); @@ -239,18 +274,20 @@ export default function UptimeStatusIsland() { {Array.from({ length: 40 }).map((_, i) => { const hbArr = monitor.heartbeatHistory ?? []; const hb = hbArr.slice(-40)[i]; - const localTime = hb ? formatLocalTime(hb.time, userZone) : ''; - const utcTime = hb ? formatLocalTime(hb.time, 'utc') : ''; return ( - + content={} + placement="top" + animation="shift-away" + theme="devnet" + delay={[0, 0]} + > + + ); })}