Initial commit

This commit is contained in:
2025-10-04 18:22:24 +03:00
commit 2852c2c054
291 changed files with 38109 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
.loadingContainer {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 200px;
width: 100%;
padding: 20px;
background: transparent;
transition: all 0.3s ease;
position: relative;
}
/* Center the loading container when not fullscreen */
.loadingContainer:not(.fullScreen) {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-height: auto;
width: auto;
}
.fullScreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(4px);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.spinner {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
text-align: center;
}
.loadingText {
margin-top: 12px;
font-size: 14px;
font-weight: 500;
color: var(--ant-color-text-secondary);
text-align: center;
animation: pulse 2s ease-in-out infinite;
max-width: 200px;
line-height: 1.4;
}
/* Dark theme support */
@media (prefers-color-scheme: dark) {
.fullScreen {
background: rgba(0, 0, 0, 0.85);
}
.loadingText {
color: var(--ant-color-text-secondary);
}
}
/* Animation for text pulse effect */
@keyframes pulse {
0%, 100% {
opacity: 0.6;
}
50% {
opacity: 1;
}
}
/* Responsive design */
@media (max-width: 768px) {
.loadingContainer {
min-height: 150px;
padding: 16px;
}
.loadingContainer:not(.fullScreen) {
min-height: auto;
padding: 16px;
}
.loadingText {
font-size: 13px;
margin-top: 8px;
}
}
@media (max-width: 480px) {
.loadingContainer {
min-height: 120px;
padding: 12px;
}
.loadingContainer:not(.fullScreen) {
min-height: auto;
padding: 12px;
}
.loadingText {
font-size: 12px;
margin-top: 6px;
}
}
/* Custom spinner animation */
.spinner :global(.ant-spin-dot) {
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Enhanced focus states for accessibility */
.loadingContainer:focus-within {
outline: 2px solid var(--ant-color-primary);
outline-offset: 2px;
border-radius: 8px;
}
/* Smooth transitions for theme changes */
.loadingContainer,
.loadingText,
.spinner {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

View File

@@ -0,0 +1,77 @@
import { LoadingOutlined } from "@ant-design/icons";
import { Spin, SpinProps } from "antd";
import { ReactNode } from "react";
import styles from "./LoadingSpinner.module.css";
export interface LoadingSpinnerProps {
/** The text to display while loading */
text?: string;
/** The size of the spinner */
size?: "small" | "default" | "large";
/** Whether to show the spinner */
spinning?: boolean;
/** Custom CSS class name */
className?: string;
/** Whether to show the loading text */
showText?: boolean;
/** Custom icon */
icon?: ReactNode;
/** Whether to use full screen loading */
fullScreen?: boolean;
/** Custom background color */
backgroundColor?: string;
/** Custom text color */
textColor?: string;
}
export default function LoadingSpinner({
text = "",
size = "large",
spinning = true,
className = "",
showText = true,
icon,
fullScreen = false,
backgroundColor,
textColor,
}: LoadingSpinnerProps) {
const containerClass = `${styles.loadingContainer} ${
fullScreen ? styles.fullScreen : ""
} ${className}`;
const customIcon = icon || (
<LoadingOutlined
style={{
fontSize: size === "large" ? 32 : size === "default" ? 24 : 16,
color: textColor || "var(--ant-color-primary)",
}}
spin
/>
);
const containerStyle = {
backgroundColor: backgroundColor || undefined,
};
const textStyle = {
color: textColor || undefined,
};
return (
<div className={containerClass} style={containerStyle}>
<Spin
spinning={spinning}
size={size}
indicator={customIcon as SpinProps["indicator"]}
tip={showText ? text : undefined}
className={styles.spinner}
>
{showText && !fullScreen && (
<div className={styles.loadingText} style={textStyle}>
{text}
</div>
)}
</Spin>
</div>
);
}

View File

@@ -0,0 +1,2 @@
export { default } from "./LoadingSpinner";
export type { LoadingSpinnerProps } from "./LoadingSpinner";