dvorakmortonxd.dev/src/app/components/ServiceButton.tsx

47 lines
2.3 KiB
TypeScript

"use client";
import React, { useEffect, useState, ReactNode } from 'react';
export default function ServiceButton({ url, checkUrl, className, icon, name, desc, access }: { url: string, checkUrl?: string, className: string, icon: ReactNode, name: string, desc: string, access?: 'public' | 'private' | 'on_request' }) {
const [status, setStatus] = useState<'pending' | 'up' | 'down'>('pending');
useEffect(() => {
const checkStatus = async () => {
try {
const targetUrl = checkUrl || url;
const res = await fetch(`/api/ping?url=${encodeURIComponent(targetUrl)}`);
const data = await res.json();
setStatus(data.status);
} catch {
setStatus('down');
}
};
checkStatus();
}, [url, checkUrl]);
return (
<a href={url} target="_blank" rel="noopener noreferrer" className={`service-button ${className}`} style={{ position: 'relative' }}>
<div style={{
position: 'absolute',
top: '8px',
right: '8px',
width: '10px',
height: '10px',
borderRadius: '50%',
backgroundColor: status === 'up' ? '#4ade80' : status === 'down' ? '#ef4444' : '#9ca3af',
boxShadow: status === 'up' ? '0 0 5px #4ade80' : status === 'down' ? '0 0 5px #ef4444' : 'none',
transition: 'all 0.3s ease'
}} title={status === 'up' ? 'Active' : status === 'down' ? 'Dead' : 'Checking...'} />
<span className="service-icon">{icon}</span>
<span className="service-text">
<span className="service-name">
{name}
{access === 'public' && <span style={{ color: 'var(--accent)', fontSize: '0.7em', marginLeft: '6px' }}>(public)</span>}
{access === 'private' && <span style={{ color: 'var(--red)', fontSize: '0.7em', marginLeft: '6px' }}>(private)</span>}
{access === 'on_request' && <span style={{ color: 'var(--accent2)', fontSize: '0.7em', marginLeft: '6px' }}>(on request)</span>}
</span>
<span className="service-desc">{desc}</span>
</span>
</a>
);
}