Skip to main content
Glama
hiltonbrown

Next.js MCP Server Template

by hiltonbrown
Loading.tsx3.17 kB
// Loading components with skeleton states import React from 'react'; import { SkeletonProps } from '@/types/components'; export const Skeleton: React.FC<SkeletonProps> = ({ width = '100%', height = '1rem', className = '', animate = true }) => { return ( <div className={`bg-gray-200 rounded ${animate ? 'animate-pulse' : ''} ${className}`} style={{ width, height }} /> ); }; export const SkeletonText: React.FC<{ lines?: number; className?: string }> = ({ lines = 3, className = '' }) => { return ( <div className={`space-y-2 ${className}`}> {Array.from({ length: lines }).map((_, index) => ( <Skeleton key={index} height="1rem" width={index === lines - 1 ? '60%' : '100%'} /> ))} </div> ); }; export const SkeletonCard: React.FC<{ className?: string }> = ({ className = '' }) => { return ( <div className={`p-6 bg-white rounded-lg shadow border ${className}`}> <div className="flex items-center space-x-4"> <Skeleton width="3rem" height="3rem" className="rounded-full" /> <div className="flex-1"> <Skeleton width="60%" height="1.25rem" className="mb-2" /> <Skeleton width="40%" height="1rem" /> </div> </div> </div> ); }; export const LoadingSpinner: React.FC<{ size?: 'sm' | 'md' | 'lg'; className?: string }> = ({ size = 'md', className = '' }) => { const sizeClasses = { sm: 'w-4 h-4', md: 'w-8 h-8', lg: 'w-12 h-12' }; return ( <div className={`animate-spin rounded-full border-2 border-gray-300 border-t-blue-600 ${sizeClasses[size]} ${className}`}></div> ); }; export const LoadingOverlay: React.FC<{ isLoading: boolean; message?: string; children: React.ReactNode; className?: string; }> = ({ isLoading, message = 'Loading...', children, className = '' }) => { return ( <div className={`relative ${className}`}> {children} {isLoading && ( <div className="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center rounded-lg"> <div className="text-center"> <LoadingSpinner className="mx-auto mb-2" /> <p className="text-sm text-gray-600">{message}</p> </div> </div> )} </div> ); }; export const LoadingButton: React.FC<{ isLoading: boolean; loadingText?: string; children: React.ReactNode; className?: string; onClick?: () => void; disabled?: boolean; }> = ({ isLoading, loadingText = 'Loading...', children, className = '', onClick, disabled }) => { return ( <button onClick={onClick} disabled={disabled || isLoading} className={`relative ${className}`} > {isLoading && ( <div className="absolute inset-0 flex items-center justify-center"> <LoadingSpinner size="sm" /> </div> )} <span className={isLoading ? 'invisible' : ''}> {children} </span> {isLoading && ( <span className="absolute inset-0 flex items-center justify-center text-sm"> {loadingText} </span> )} </button> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hiltonbrown/xero-mcp-with-next-js'

If you have feedback or need assistance with the MCP directory API, please join our Discord server