Add Tippy.js for tooltips in UptimeStatusIsland component and update styles
- Integrated Tippy.js for enhanced tooltip functionality in the UptimeStatusIsland component, providing detailed heartbeat information on hover. - Added custom styles for Tippy.js tooltips to support light and dark themes. - Updated package.json and package-lock.json to include @tippyjs/react and its dependencies.
This commit is contained in:
33
package-lock.json
generated
33
package-lock.json
generated
@@ -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",
|
||||
|
@@ -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",
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 (
|
||||
<div style={{ minWidth: 220 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', marginBottom: 4 }}>
|
||||
<FiCheckCircle color={hb.status === 1 ? 'green' : 'red'} style={{ marginRight: 6 }} />
|
||||
<b>{hb.status === 1 ? 'Up' : 'Down'}</b>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<FiClock style={{ marginRight: 6 }} />
|
||||
Local: {localTime}
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<FiGlobe style={{ marginRight: 6 }} />
|
||||
UTC: {utcTime}
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<FiActivity style={{ marginRight: 6 }} />
|
||||
Ping: {hb.ping ?? '--'} ms
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<FiPercent style={{ marginRight: 6 }} />
|
||||
Uptime 24h: {monitor.uptime24h?.toFixed(2) ?? '--'}%
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<FiLock style={{ marginRight: 6 }} />
|
||||
Cert valid for: {monitor.certExpiryDaysRemaining ?? '--'} days
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<span
|
||||
<Tippy
|
||||
key={i}
|
||||
title={
|
||||
hb
|
||||
? `Status: ${hb.status === 1 ? 'Up' : 'Down'}\nLocal: ${localTime}\nUTC: ${utcTime}`
|
||||
: ''
|
||||
}
|
||||
className={`w-full h-4 rounded-sm ${hb ? getHeartbeatColor(hb.status) : 'bg-gray-400 dark:bg-gray-600'} block`}
|
||||
></span>
|
||||
content={<HeartbeatPopup hb={hb} userZone={userZone} monitor={monitor} />}
|
||||
placement="top"
|
||||
animation="shift-away"
|
||||
theme="devnet"
|
||||
delay={[0, 0]}
|
||||
>
|
||||
<span
|
||||
className={`w-full h-4 rounded-sm ${hb ? getHeartbeatColor(hb.status) : 'bg-gray-400 dark:bg-gray-600'} block`}
|
||||
style={{ cursor: 'pointer' }}
|
||||
></span>
|
||||
</Tippy>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user