athlefi-ui 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "Athlefi",
3
+ "short_name": "Athlefi",
4
+ "description": "Athlefi - Tu plataforma de fitness",
5
+ "icons": [
6
+ {
7
+ "src": "/android-chrome-192x192.png",
8
+ "sizes": "192x192",
9
+ "type": "image/png"
10
+ },
11
+ {
12
+ "src": "/android-chrome-512x512.png",
13
+ "sizes": "512x512",
14
+ "type": "image/png"
15
+ }
16
+ ],
17
+ "theme_color": "#1a1a1a",
18
+ "background_color": "#1a1a1a",
19
+ "display": "standalone",
20
+ "start_url": "/"
21
+ }
@@ -0,0 +1,50 @@
1
+ ---
2
+ export interface Props {
3
+ href: string;
4
+ class?: string;
5
+ external?: boolean;
6
+ ariaLabel?: string;
7
+ }
8
+
9
+ const {
10
+ href,
11
+ class: className = "",
12
+ external = false,
13
+ ariaLabel,
14
+ } = Astro.props;
15
+ ---
16
+
17
+ <a
18
+ href={href}
19
+ class={`footer-link ${className}`}
20
+ target={external ? "_blank" : undefined}
21
+ rel={external ? "noopener noreferrer" : undefined}
22
+ aria-label={ariaLabel}
23
+ >
24
+ <slot />
25
+ </a>
26
+
27
+ <style>
28
+ .footer-link {
29
+ display: inline-block;
30
+ color: var(--color-white);
31
+ font-family: var(--font-family-manrope);
32
+ font-size: var(--font-size-menu);
33
+ font-weight: var(--font-weight-menu);
34
+ line-height: var(--line-height-menu);
35
+ letter-spacing: var(--letter-spacing-menu);
36
+ text-decoration: none;
37
+ transition: color 0.2s ease-in-out;
38
+ border-radius: 2px;
39
+ }
40
+
41
+ .footer-link:hover {
42
+ color: var(--color-primary-60);
43
+ }
44
+
45
+ .footer-link:focus-visible {
46
+ outline: 2px solid var(--color-primary-60);
47
+ outline-offset: 2px;
48
+ }
49
+ </style>
50
+
@@ -0,0 +1,102 @@
1
+ ---
2
+ export interface Props {
3
+ type: "text" | "email" | "tel" | "textarea";
4
+ name: string;
5
+ label: string;
6
+ placeholder: string;
7
+ required?: boolean;
8
+ class?: string;
9
+ }
10
+
11
+ const {
12
+ type,
13
+ name,
14
+ label,
15
+ placeholder,
16
+ required = false,
17
+ class: className = ""
18
+ } = Astro.props;
19
+ ---
20
+
21
+ <div class={`form-input ${className}`}>
22
+ <!-- Label -->
23
+ <label for={name} class="form-input__label">
24
+ {label}
25
+ </label>
26
+
27
+ <!-- Input/Textarea -->
28
+ {type === "textarea" ? (
29
+ <textarea
30
+ id={name}
31
+ name={name}
32
+ placeholder={placeholder}
33
+ required={required}
34
+ rows={4}
35
+ class="form-input__field form-input__textarea"
36
+ ></textarea>
37
+ ) : (
38
+ <input
39
+ type={type}
40
+ id={name}
41
+ name={name}
42
+ placeholder={placeholder}
43
+ required={required}
44
+ class="form-input__field"
45
+ />
46
+ )}
47
+ </div>
48
+
49
+ <style>
50
+ .form-input {
51
+ display: flex;
52
+ flex-direction: column;
53
+ }
54
+
55
+ .form-input__label {
56
+ color: var(--color-white);
57
+ font-family: var(--font-family-manrope);
58
+ font-size: var(--font-size-body-m);
59
+ font-weight: var(--font-weight-medium);
60
+ line-height: var(--line-height-body-m);
61
+ margin-bottom: 8px;
62
+ }
63
+
64
+ .form-input__field {
65
+ width: 100%;
66
+ padding: 12px 16px;
67
+ background-color: rgba(255, 255, 255, 0.2);
68
+ border: 1px solid var(--color-white);
69
+ border-radius: 8px;
70
+ color: var(--color-white);
71
+ font-family: var(--font-family-manrope);
72
+ font-size: var(--font-size-body-m);
73
+ font-weight: var(--font-weight-body-m);
74
+ line-height: var(--line-height-body-m);
75
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
76
+ outline: none;
77
+ }
78
+
79
+ .form-input__field::placeholder {
80
+ color: var(--color-white);
81
+ opacity: 0.7;
82
+ }
83
+
84
+ .form-input__field:focus {
85
+ border-color: var(--color-primary-60);
86
+ box-shadow: 0 0 0 1px var(--color-primary-60);
87
+ }
88
+
89
+ .form-input__textarea {
90
+ resize: none;
91
+ }
92
+
93
+ /* Estados de validación HTML5 */
94
+ .form-input__field:invalid:not(:placeholder-shown) {
95
+ border-color: var(--color-error);
96
+ }
97
+
98
+ .form-input__field:valid:not(:placeholder-shown) {
99
+ border-color: var(--color-success);
100
+ }
101
+ </style>
102
+
@@ -0,0 +1,99 @@
1
+ ---
2
+ import trophyIcon from "../../icons/trophy-outline.svg?raw";
3
+ import personIcon from "../../icons/person-outline.svg?raw";
4
+ import footballIcon from "../../icons/american-football-outline.svg?raw";
5
+ import laptopIcon from "../../icons/laptop-outline.svg?raw";
6
+
7
+ export interface Props {
8
+ icon:
9
+ | "trophy-outline"
10
+ | "person-outline"
11
+ | "football-american-outline"
12
+ | "laptop-outline";
13
+ text: string;
14
+ title: string;
15
+ class?: string;
16
+ }
17
+
18
+ const { icon, title, text, class: className = "" } = Astro.props;
19
+
20
+ // Mapeo de íconos a contenido SVG
21
+ const iconMap = {
22
+ "trophy-outline": trophyIcon,
23
+ "person-outline": personIcon,
24
+ "football-american-outline": footballIcon,
25
+ "laptop-outline": laptopIcon,
26
+ };
27
+
28
+ const svgContent = iconMap[icon];
29
+ ---
30
+
31
+ <div class={`icon-card ${className}`}>
32
+ <!-- Ícono SVG -->
33
+ <div class="icon-card__icon-wrapper" aria-hidden="true">
34
+ <Fragment set:html={svgContent} />
35
+ </div>
36
+
37
+ <!-- Título -->
38
+ <h3 class="icon-card__title">
39
+ {title}
40
+ </h3>
41
+
42
+ <!-- Texto descriptivo -->
43
+ <p class="icon-card__text">
44
+ {text}
45
+ </p>
46
+ </div>
47
+
48
+ <style>
49
+ .icon-card {
50
+ display: flex;
51
+ flex-direction: column;
52
+ align-items: center;
53
+ text-align: center;
54
+ }
55
+
56
+ .icon-card__icon-wrapper {
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ width: 64px;
61
+ height: 64px;
62
+ margin-bottom: 16px;
63
+ }
64
+
65
+ .icon-card__icon-wrapper :global(svg) {
66
+ width: 48px;
67
+ height: 48px;
68
+ color: var(--color-primary-60);
69
+ fill: var(--color-primary-60);
70
+ }
71
+
72
+ .icon-card__title {
73
+ font-family: var(--font-family-manrope);
74
+ font-size: var(--font-size-h3);
75
+ font-weight: var(--font-weight-h3);
76
+ line-height: 1;
77
+ letter-spacing: var(--letter-spacing-h3);
78
+ color: var(--color-primary-60);
79
+ margin-bottom: 8px;
80
+ }
81
+
82
+ .icon-card__text {
83
+ font-family: var(--font-family-manrope);
84
+ font-size: var(--font-size-body-s);
85
+ font-weight: var(--font-weight-medium);
86
+ line-height: var(--line-height-body-s);
87
+ letter-spacing: var(--letter-spacing-body-s);
88
+ color: var(--color-white);
89
+ width: 160px;
90
+ }
91
+
92
+ /* Responsive: ancho mayor en pantallas grandes */
93
+ @media (min-width: 1024px) {
94
+ .icon-card__text {
95
+ width: 270px;
96
+ }
97
+ }
98
+ </style>
99
+
@@ -0,0 +1,59 @@
1
+ ---
2
+ import logoImage from "../../assets/Logo 3.png";
3
+
4
+ export interface Props {
5
+ class?: string;
6
+ size?: "sm" | "md" | "lg";
7
+ href?: string;
8
+ }
9
+
10
+ const {
11
+ class: className = "",
12
+ size = "lg",
13
+ href = "/"
14
+ } = Astro.props;
15
+ ---
16
+
17
+ <a
18
+ href={href}
19
+ class={`logo logo--${size} ${className}`}
20
+ aria-label="ATHLEFI - Ir a la página principal"
21
+ >
22
+ <img
23
+ src={logoImage.src}
24
+ alt="ATHLEFI"
25
+ class="logo__image"
26
+ width={logoImage.width}
27
+ height={logoImage.height}
28
+ />
29
+ </a>
30
+
31
+ <style>
32
+ .logo {
33
+ display: inline-flex;
34
+ align-items: center;
35
+ }
36
+
37
+ .logo__image {
38
+ width: 100%;
39
+ height: 100%;
40
+ object-fit: contain;
41
+ }
42
+
43
+ /* Tamaños */
44
+ .logo--sm {
45
+ width: 96px;
46
+ height: 24px;
47
+ }
48
+
49
+ .logo--md {
50
+ width: 128px;
51
+ height: 32px;
52
+ }
53
+
54
+ .logo--lg {
55
+ width: 208px;
56
+ height: 64px;
57
+ }
58
+ </style>
59
+
@@ -0,0 +1,70 @@
1
+ ---
2
+ export interface Props {
3
+ href: string;
4
+ class?: string;
5
+ isActive?: boolean;
6
+ ariaCurrent?:
7
+ | "page"
8
+ | "step"
9
+ | "location"
10
+ | "date"
11
+ | "time"
12
+ | "true"
13
+ | "false";
14
+ }
15
+
16
+ const {
17
+ href,
18
+ class: className = "",
19
+ isActive = false,
20
+ ariaCurrent = "page",
21
+ } = Astro.props;
22
+
23
+ // Detectar si el enlace está activo basado en la URL actual
24
+ const currentPath = Astro.url.pathname;
25
+ const isCurrentPage =
26
+ currentPath === href || (href !== "/" && currentPath.startsWith(href));
27
+
28
+ const activeState = isActive || isCurrentPage;
29
+ ---
30
+
31
+ <a
32
+ href={href}
33
+ class={`nav-link ${activeState ? "nav-link--active" : ""} ${className}`}
34
+ aria-current={activeState ? ariaCurrent : undefined}
35
+ >
36
+ <slot />
37
+ </a>
38
+
39
+ <style>
40
+ .nav-link {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ padding: 8px 12px;
44
+ font-family: var(--font-family-manrope);
45
+ font-size: var(--font-size-body-m);
46
+ font-weight: var(--font-weight-body-m);
47
+ line-height: var(--line-height-body-m);
48
+ letter-spacing: var(--letter-spacing-body-m);
49
+ color: var(--color-white);
50
+ text-decoration: none;
51
+ border-radius: 6px;
52
+ border-bottom: 2px solid transparent;
53
+ transition: color 0.2s ease-in-out, border-color 0.2s ease-in-out;
54
+ }
55
+
56
+ .nav-link:hover {
57
+ color: var(--color-primary-60);
58
+ }
59
+
60
+ .nav-link:focus-visible {
61
+ outline: 2px solid var(--color-primary-60);
62
+ outline-offset: 2px;
63
+ }
64
+
65
+ .nav-link--active {
66
+ color: var(--color-primary-60);
67
+ border-bottom-color: var(--color-primary-60);
68
+ }
69
+ </style>
70
+
@@ -0,0 +1,80 @@
1
+ ---
2
+ export interface Props {
3
+ platform: "youtube" | "facebook" | "twitter" | "instagram";
4
+ href: string;
5
+ class?: string;
6
+ }
7
+
8
+ const { platform, href, class: className = "" } = Astro.props;
9
+
10
+ const icons = {
11
+ youtube: {
12
+ viewBox: "0 0 24 24",
13
+ path: "M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z",
14
+ label: "YouTube",
15
+ },
16
+ facebook: {
17
+ viewBox: "0 0 24 24",
18
+ path: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z",
19
+ label: "Facebook",
20
+ },
21
+ twitter: {
22
+ viewBox: "0 0 24 24",
23
+ path: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z",
24
+ label: "X (Twitter)",
25
+ },
26
+ instagram: {
27
+ viewBox: "0 0 24 24",
28
+ path: "M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z",
29
+ label: "Instagram",
30
+ },
31
+ };
32
+
33
+ const icon = icons[platform];
34
+ ---
35
+
36
+ <a
37
+ href={href}
38
+ target="_blank"
39
+ rel="noopener noreferrer"
40
+ class={`social-icon ${className}`}
41
+ aria-label={`Síguenos en ${icon.label}`}
42
+ >
43
+ <svg
44
+ class="social-icon__svg"
45
+ fill="currentColor"
46
+ viewBox={icon.viewBox}
47
+ aria-hidden="true"
48
+ >
49
+ <path d={icon.path}></path>
50
+ </svg>
51
+ </a>
52
+
53
+ <style>
54
+ .social-icon {
55
+ display: inline-flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ width: 24px;
59
+ height: 24px;
60
+ color: var(--color-white);
61
+ text-decoration: none;
62
+ border-radius: 2px;
63
+ transition: color 0.2s ease-in-out;
64
+ }
65
+
66
+ .social-icon:hover {
67
+ color: var(--color-primary-60);
68
+ }
69
+
70
+ .social-icon:focus-visible {
71
+ outline: 2px solid var(--color-primary-60);
72
+ outline-offset: 2px;
73
+ }
74
+
75
+ .social-icon__svg {
76
+ width: 20px;
77
+ height: 20px;
78
+ }
79
+ </style>
80
+
@@ -0,0 +1,71 @@
1
+ ---
2
+ /**
3
+ * Copyright (c) 2025 Grupo DedSec S.A. de C.V.
4
+ * Este código fuente es propiedad exclusiva de Grupo DedSec S.A. de C.V.
5
+ * Se prohíbe su uso, reproducción, distribución o modificación, total o parcial, sin autorización expresa por escrito.
6
+ * No se permite el uso comercial ni la redistribución pública del mismo.
7
+ * Para licenciamiento, contactar a: admin@dedsec.com.mx
8
+ */
9
+
10
+ /**
11
+ * Átomo: TabButton
12
+ * @description Botón individual para tabs con estados activo/inactivo
13
+ */
14
+
15
+ export interface Props {
16
+ label: string;
17
+ tabId: string;
18
+ isActive?: boolean;
19
+ class?: string;
20
+ }
21
+
22
+ const {
23
+ label,
24
+ tabId,
25
+ isActive = false,
26
+ class: className = ""
27
+ } = Astro.props;
28
+ ---
29
+
30
+ <button
31
+ id={`tab-${tabId}`}
32
+ class={`tab-button ${isActive ? 'tab-button--active' : ''} ${className}`}
33
+ data-tab={tabId}
34
+ role="tab"
35
+ aria-selected={isActive}
36
+ aria-controls={`panel-${tabId}`}
37
+ >
38
+ {label}
39
+ </button>
40
+
41
+ <style>
42
+ .tab-button {
43
+ padding: 12px 24px;
44
+ background-color: transparent;
45
+ color: rgb(209, 213, 219);
46
+ border: none;
47
+ border-radius: 9999px;
48
+ cursor: pointer;
49
+ transition: all 0.3s ease;
50
+ font-family: var(--font-family-manrope);
51
+ font-size: var(--font-size-button-m);
52
+ font-weight: var(--font-weight-medium);
53
+ line-height: var(--line-height-button-m);
54
+ letter-spacing: var(--letter-spacing-button-m);
55
+ }
56
+
57
+ .tab-button--active {
58
+ background-color: var(--color-primary-60);
59
+ color: var(--color-primary-90);
60
+ }
61
+
62
+ .tab-button:hover:not(.tab-button--active) {
63
+ background-color: rgba(1, 234, 199, 0.1);
64
+ }
65
+
66
+ .tab-button:focus-visible {
67
+ outline: 2px solid var(--color-primary-60);
68
+ outline-offset: 2px;
69
+ }
70
+ </style>
71
+
@@ -0,0 +1,152 @@
1
+ ---
2
+ /**
3
+ * Componente átomo para texto con fuente monoespaciada
4
+ * @description Texto optimizado para mostrar datos técnicos, códigos o información estructurada
5
+ */
6
+
7
+ export interface Props {
8
+ /** Contenido de texto a mostrar */
9
+ text?: string;
10
+ /** Tamaño del texto */
11
+ size?: 'xs' | 'sm' | 'base' | 'lg' | 'xl';
12
+ /** Color del texto */
13
+ color?: 'primary' | 'secondary' | 'accent' | 'muted' | 'white' | 'inherit';
14
+ /** Peso de la fuente */
15
+ weight?: 'normal' | 'medium' | 'semibold' | 'bold';
16
+ /** Si el texto debe estar en mayúsculas */
17
+ uppercase?: boolean;
18
+ /** Si el texto debe tener espaciado entre letras */
19
+ tracking?: boolean;
20
+ /** Clases CSS adicionales */
21
+ class?: string;
22
+ /** ID único para el elemento */
23
+ id?: string;
24
+ /** Título para accesibilidad */
25
+ title?: string;
26
+ }
27
+
28
+ const {
29
+ text = '',
30
+ size = 'base',
31
+ color = 'inherit',
32
+ weight = 'normal',
33
+ uppercase = false,
34
+ tracking = false,
35
+ class: className = '',
36
+ id,
37
+ title,
38
+ ...rest
39
+ } = Astro.props;
40
+
41
+ // Procesamiento del contenido
42
+ const hasSlotContent = Astro.slots.has('default');
43
+ const content = hasSlotContent ? null : text;
44
+ ---
45
+
46
+ <span
47
+ class={`
48
+ text-mono
49
+ text-mono--${size}
50
+ text-mono--${color}
51
+ text-mono--${weight}
52
+ ${uppercase ? 'text-mono--uppercase' : ''}
53
+ ${tracking ? 'text-mono--tracking' : ''}
54
+ ${className}
55
+ `}
56
+ id={id}
57
+ title={title}
58
+ {...rest}
59
+ >
60
+ {hasSlotContent ? (
61
+ <slot />
62
+ ) : (
63
+ content
64
+ )}
65
+ </span>
66
+
67
+ <style>
68
+ /* Base monospace styling */
69
+ .text-mono {
70
+ font-family: 'Fira Code', 'JetBrains Mono', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
71
+ font-variant-numeric: tabular-nums;
72
+ letter-spacing: 0.025em;
73
+ transition: color 0.2s ease-in-out;
74
+ user-select: text;
75
+ -webkit-user-select: text;
76
+ -moz-user-select: text;
77
+ -ms-user-select: text;
78
+ }
79
+
80
+ /* Tamaños */
81
+ .text-mono--xs {
82
+ font-size: var(--font-size-body-xxs); /* 10px */
83
+ }
84
+
85
+ .text-mono--sm {
86
+ font-size: var(--font-size-body-xs); /* 12px */
87
+ }
88
+
89
+ .text-mono--base {
90
+ font-size: var(--font-size-body-s); /* 14px */
91
+ }
92
+
93
+ .text-mono--lg {
94
+ font-size: var(--font-size-body-m); /* 16px */
95
+ }
96
+
97
+ .text-mono--xl {
98
+ font-size: var(--font-size-body-l); /* 18px */
99
+ }
100
+
101
+ /* Colores */
102
+ .text-mono--primary {
103
+ color: var(--color-primary-60);
104
+ }
105
+
106
+ .text-mono--secondary {
107
+ color: rgb(209, 213, 219);
108
+ }
109
+
110
+ .text-mono--accent {
111
+ color: rgb(103, 232, 249);
112
+ }
113
+
114
+ .text-mono--muted {
115
+ color: rgb(156, 163, 175);
116
+ }
117
+
118
+ .text-mono--white {
119
+ color: var(--color-white);
120
+ }
121
+
122
+ .text-mono--inherit {
123
+ color: inherit;
124
+ }
125
+
126
+ /* Pesos */
127
+ .text-mono--normal {
128
+ font-weight: var(--font-weight-regular);
129
+ }
130
+
131
+ .text-mono--medium {
132
+ font-weight: var(--font-weight-medium);
133
+ }
134
+
135
+ .text-mono--semibold {
136
+ font-weight: 600;
137
+ }
138
+
139
+ .text-mono--bold {
140
+ font-weight: var(--font-weight-bold);
141
+ }
142
+
143
+ /* Modificadores */
144
+ .text-mono--uppercase {
145
+ text-transform: uppercase;
146
+ }
147
+
148
+ .text-mono--tracking {
149
+ letter-spacing: 0.05em;
150
+ }
151
+ </style>
152
+