analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
251 lines (249 loc) • 7.3 kB
JavaScript
// src/utils/utils.ts
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
function cn(...inputs) {
return twMerge(clsx(inputs));
}
// src/components/Text/Text.tsx
import { jsx } from "react/jsx-runtime";
var Text = ({
children,
size = "md",
weight = "normal",
color = "text-text-950",
as,
className = "",
...props
}) => {
let sizeClasses = "";
let weightClasses = "";
const sizeClassMap = {
"2xs": "text-2xs",
xs: "text-xs",
sm: "text-sm",
md: "text-md",
lg: "text-lg",
xl: "text-xl",
"2xl": "text-2xl",
"3xl": "text-3xl",
"4xl": "text-4xl",
"5xl": "text-5xl",
"6xl": "text-6xl"
};
sizeClasses = sizeClassMap[size] ?? sizeClassMap.md;
const weightClassMap = {
hairline: "font-hairline",
light: "font-light",
normal: "font-normal",
medium: "font-medium",
semibold: "font-semibold",
bold: "font-bold",
extrabold: "font-extrabold",
black: "font-black"
};
weightClasses = weightClassMap[weight] ?? weightClassMap.normal;
const baseClasses = "font-primary";
const Component = as ?? "p";
return /* @__PURE__ */ jsx(
Component,
{
className: cn(baseClasses, sizeClasses, weightClasses, color, className),
...props,
children
}
);
};
var Text_default = Text;
// src/components/ProgressCircle/ProgressCircle.tsx
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
var SIZE_CLASSES = {
small: {
container: "w-[90px] h-[90px]",
// 90px circle from design specs
strokeWidth: 4,
// 4px stroke width - matches ProgressBar small (h-1)
textSize: "2xl",
// 24px for percentage (font-size: 24px)
textWeight: "medium",
// font-weight: 500
labelSize: "2xs",
// Will be overridden with custom 8px in className
labelWeight: "bold",
// font-weight: 700
spacing: "gap-0",
// Reduced gap between percentage and label for better spacing
contentWidth: "max-w-[50px]"
// Reduced width to fit text inside circle
},
medium: {
container: "w-[152px] h-[152px]",
// 151.67px ≈ 152px circle from design specs
strokeWidth: 8,
// 8px stroke width - matches ProgressBar medium (h-2)
textSize: "2xl",
// 24px for percentage (font-size: 24px)
textWeight: "medium",
// font-weight: 500
labelSize: "xs",
// 12px for status label (font-size: 12px)
labelWeight: "medium",
// font-weight: 500 (changed from bold)
spacing: "gap-1",
// 4px gap between percentage and label
contentWidth: "max-w-[90px]"
// Reduced width to fit text inside circle
}
};
var VARIANT_CLASSES = {
blue: {
background: "stroke-primary-100",
// Light blue background (#BBDCF7)
fill: "stroke-primary-700",
// Blue for activity progress (#2271C4)
textColor: "text-primary-700",
// Blue text color (#2271C4)
labelColor: "text-text-700"
// Gray text for label (#525252)
},
green: {
background: "stroke-background-300",
// Gray background (#D5D4D4 - matches design)
fill: "stroke-success-200",
// Green for performance (#84D3A2 - matches design)
textColor: "text-text-800",
// Dark gray text (#404040 - matches design)
labelColor: "text-text-600"
// Medium gray text for label (#737373 - matches design)
}
};
var ProgressCircle = ({
value,
max = 100,
size = "small",
variant = "blue",
label,
showPercentage = true,
className = "",
labelClassName = "",
percentageClassName = ""
}) => {
const safeValue = isNaN(value) ? 0 : value;
const clampedValue = Math.max(0, Math.min(safeValue, max));
const percentage = max === 0 ? 0 : clampedValue / max * 100;
const sizeClasses = SIZE_CLASSES[size];
const variantClasses = VARIANT_CLASSES[variant];
const radius = size === "small" ? 37 : 64;
const circumference = 2 * Math.PI * radius;
const strokeDashoffset = circumference - percentage / 100 * circumference;
const center = size === "small" ? 45 : 76;
const svgSize = size === "small" ? 90 : 152;
return /* @__PURE__ */ jsxs(
"div",
{
className: cn(
"relative flex flex-col items-center justify-center",
sizeClasses.container,
"rounded-lg",
className
),
children: [
/* @__PURE__ */ jsxs(
"svg",
{
className: "absolute inset-0 transform -rotate-90",
width: svgSize,
height: svgSize,
viewBox: `0 0 ${svgSize} ${svgSize}`,
"aria-hidden": "true",
children: [
/* @__PURE__ */ jsx2(
"circle",
{
cx: center,
cy: center,
r: radius,
fill: "none",
strokeWidth: sizeClasses.strokeWidth,
className: cn(variantClasses.background, "rounded-lg")
}
),
/* @__PURE__ */ jsx2(
"circle",
{
cx: center,
cy: center,
r: radius,
fill: "none",
strokeWidth: sizeClasses.strokeWidth,
strokeLinecap: "round",
strokeDasharray: circumference,
strokeDashoffset,
className: cn(
variantClasses.fill,
"transition-all duration-500 ease-out shadow-soft-shadow-3 rounded-lg"
)
}
)
]
}
),
/* @__PURE__ */ jsx2(
"progress",
{
value: clampedValue,
max,
"aria-label": typeof label === "string" ? label : "Progress",
className: "absolute opacity-0 w-0 h-0"
}
),
/* @__PURE__ */ jsxs(
"div",
{
className: cn(
"relative z-10 flex flex-col items-center justify-center",
sizeClasses.spacing,
sizeClasses.contentWidth
),
children: [
showPercentage && /* @__PURE__ */ jsxs(
Text_default,
{
size: sizeClasses.textSize,
weight: sizeClasses.textWeight,
className: cn(
"text-center w-full",
variantClasses.textColor,
percentageClassName
),
children: [
Math.round(percentage),
"%"
]
}
),
label && /* @__PURE__ */ jsx2(
Text_default,
{
as: "span",
size: sizeClasses.labelSize,
weight: sizeClasses.labelWeight,
className: cn(
variantClasses.labelColor,
"text-center uppercase tracking-wide truncate w-full",
labelClassName
),
children: label
}
)
]
}
)
]
}
);
};
var ProgressCircle_default = ProgressCircle;
export {
ProgressCircle_default as default
};
//# sourceMappingURL=index.mjs.map