@axzydev/axzy_ui_system 1.2.1 → 1.2.3

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.
Files changed (207) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +82 -1
  4. package/dist/index.css.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/App.tsx +354 -0
  9. package/src/assets/logo.png +0 -0
  10. package/src/assets/react.svg +1 -0
  11. package/src/components/alert/alert.props.ts +13 -0
  12. package/src/components/alert/alert.stories.tsx +41 -0
  13. package/src/components/alert/alert.tsx +53 -0
  14. package/src/components/avatar/avatar.props.ts +14 -0
  15. package/src/components/avatar/avatar.stories.tsx +46 -0
  16. package/src/components/avatar/avatar.tsx +53 -0
  17. package/src/components/badget/badget.props.ts +12 -0
  18. package/src/components/badget/badget.stories.tsx +76 -0
  19. package/src/components/badget/badget.tsx +61 -0
  20. package/src/components/breadcrumbs/breadcrumbs.props.ts +13 -0
  21. package/src/components/breadcrumbs/breadcrumbs.stories.tsx +21 -0
  22. package/src/components/breadcrumbs/breadcrumbs.tsx +34 -0
  23. package/src/components/button/button.props.ts +18 -0
  24. package/src/components/button/button.stories.tsx +174 -0
  25. package/src/components/button/button.tsx +117 -0
  26. package/src/components/calendar/calendar.props.ts +33 -0
  27. package/src/components/calendar/calendar.stories.tsx +91 -0
  28. package/src/components/calendar/calendar.tsx +608 -0
  29. package/src/components/calendar/index.ts +3 -0
  30. package/src/components/card/card.props.ts +13 -0
  31. package/src/components/card/card.stories.tsx +58 -0
  32. package/src/components/card/card.tsx +79 -0
  33. package/src/components/checkbox/checkbox.props.ts +11 -0
  34. package/src/components/checkbox/checkbox.stories.tsx +54 -0
  35. package/src/components/checkbox/checkbox.tsx +52 -0
  36. package/src/components/confirm-dialog/confirm-dialog.props.ts +14 -0
  37. package/src/components/confirm-dialog/confirm-dialog.stories.tsx +33 -0
  38. package/src/components/confirm-dialog/confirm-dialog.tsx +45 -0
  39. package/src/components/data-table/ITDataTable.stories.tsx +213 -0
  40. package/src/components/data-table/dataTable.props.ts +69 -0
  41. package/src/components/data-table/dataTable.tsx +313 -0
  42. package/src/components/date-picker/date-picker.props.ts +30 -0
  43. package/src/components/date-picker/date-picker.stories.tsx +90 -0
  44. package/src/components/date-picker/datePicker.tsx +307 -0
  45. package/src/components/dialog/dialog.props.ts +9 -0
  46. package/src/components/dialog/dialog.stories.tsx +80 -0
  47. package/src/components/dialog/dialog.tsx +88 -0
  48. package/src/components/divider/divider.props.ts +8 -0
  49. package/src/components/divider/divider.stories.tsx +34 -0
  50. package/src/components/divider/divider.tsx +21 -0
  51. package/src/components/drawer/drawer.props.ts +14 -0
  52. package/src/components/drawer/drawer.stories.tsx +41 -0
  53. package/src/components/drawer/drawer.tsx +53 -0
  54. package/src/components/dropfile/dropfile.stories.tsx +75 -0
  55. package/src/components/dropfile/dropfile.tsx +407 -0
  56. package/src/components/empty-state/empty-state.props.ts +9 -0
  57. package/src/components/empty-state/empty-state.stories.tsx +20 -0
  58. package/src/components/empty-state/empty-state.tsx +21 -0
  59. package/src/components/flex/flex.props.ts +22 -0
  60. package/src/components/flex/flex.stories.tsx +71 -0
  61. package/src/components/flex/flex.tsx +79 -0
  62. package/src/components/form-builder/fieldRenderer.tsx +218 -0
  63. package/src/components/form-builder/formBuilder.context.tsx +70 -0
  64. package/src/components/form-builder/formBuilder.props.ts +43 -0
  65. package/src/components/form-builder/formBuilder.stories.tsx +317 -0
  66. package/src/components/form-builder/formBuilder.tsx +186 -0
  67. package/src/components/form-builder/useFormBuilder.ts +80 -0
  68. package/src/components/form-header/form-header.props.ts +5 -0
  69. package/src/components/form-header/form-header.tsx +38 -0
  70. package/src/components/grid/grid.props.ts +17 -0
  71. package/src/components/grid/grid.stories.tsx +72 -0
  72. package/src/components/grid/grid.tsx +69 -0
  73. package/src/components/image/image.props.ts +7 -0
  74. package/src/components/image/image.tsx +38 -0
  75. package/src/components/input/input.props.ts +49 -0
  76. package/src/components/input/input.stories.tsx +115 -0
  77. package/src/components/input/input.tsx +615 -0
  78. package/src/components/layout/layout.props.ts +10 -0
  79. package/src/components/layout/layout.stories.tsx +114 -0
  80. package/src/components/layout/layout.tsx +80 -0
  81. package/src/components/loader/loader.props.ts +8 -0
  82. package/src/components/loader/loader.stories.tsx +105 -0
  83. package/src/components/loader/loader.tsx +108 -0
  84. package/src/components/navbar/navbar.props.ts +37 -0
  85. package/src/components/navbar/navbar.tsx +328 -0
  86. package/src/components/page/page.props.ts +19 -0
  87. package/src/components/page/page.stories.tsx +98 -0
  88. package/src/components/page/page.tsx +90 -0
  89. package/src/components/page-header/page-header.props.ts +11 -0
  90. package/src/components/page-header/page-header.stories.tsx +61 -0
  91. package/src/components/page-header/page-header.tsx +62 -0
  92. package/src/components/pagination/pagination.props.ts +53 -0
  93. package/src/components/pagination/pagination.stories.tsx +111 -0
  94. package/src/components/pagination/pagination.tsx +241 -0
  95. package/src/components/popover/popover.props.ts +12 -0
  96. package/src/components/popover/popover.stories.tsx +25 -0
  97. package/src/components/popover/popover.tsx +45 -0
  98. package/src/components/progress/progress.props.ts +12 -0
  99. package/src/components/progress/progress.stories.tsx +40 -0
  100. package/src/components/progress/progress.tsx +52 -0
  101. package/src/components/radio/radio.props.ts +16 -0
  102. package/src/components/radio/radio.stories.tsx +50 -0
  103. package/src/components/radio/radio.tsx +58 -0
  104. package/src/components/search-select/index.ts +2 -0
  105. package/src/components/search-select/search-select.props.ts +46 -0
  106. package/src/components/search-select/search-select.stories.tsx +129 -0
  107. package/src/components/search-select/search-select.tsx +229 -0
  108. package/src/components/searchTable/components/EditableCell.tsx +149 -0
  109. package/src/components/searchTable/components/PaginationControls.tsx +86 -0
  110. package/src/components/searchTable/components/PaginationInfo.tsx +20 -0
  111. package/src/components/searchTable/components/SearchAndSortBar.tsx +53 -0
  112. package/src/components/searchTable/components/SearchInput.tsx +33 -0
  113. package/src/components/searchTable/components/SortButton.tsx +50 -0
  114. package/src/components/searchTable/components/TableEmptyState.tsx +22 -0
  115. package/src/components/searchTable/components/TableHeader.tsx +35 -0
  116. package/src/components/searchTable/components/TableHeaderCell.tsx +43 -0
  117. package/src/components/searchTable/components/TableRow.tsx +144 -0
  118. package/src/components/searchTable/searchTable.props.ts +56 -0
  119. package/src/components/searchTable/searchTable.tsx +187 -0
  120. package/src/components/segmented-control/segmented-control.props.ts +18 -0
  121. package/src/components/segmented-control/segmented-control.stories.tsx +63 -0
  122. package/src/components/segmented-control/segmented-control.tsx +52 -0
  123. package/src/components/select/select.props.ts +25 -0
  124. package/src/components/select/select.stories.tsx +86 -0
  125. package/src/components/select/select.tsx +150 -0
  126. package/src/components/sidebar/sidebar.props.ts +28 -0
  127. package/src/components/sidebar/sidebar.stories.tsx +117 -0
  128. package/src/components/sidebar/sidebar.tsx +313 -0
  129. package/src/components/skeleton/skeleton.props.ts +12 -0
  130. package/src/components/skeleton/skeleton.stories.tsx +30 -0
  131. package/src/components/skeleton/skeleton.tsx +45 -0
  132. package/src/components/slide/slide.props.ts +45 -0
  133. package/src/components/slide/slide.stories.tsx +121 -0
  134. package/src/components/slide/slide.tsx +109 -0
  135. package/src/components/slider/slider.props.ts +10 -0
  136. package/src/components/slider/slider.stories.tsx +30 -0
  137. package/src/components/slider/slider.tsx +49 -0
  138. package/src/components/stack/stack.props.ts +19 -0
  139. package/src/components/stack/stack.stories.tsx +79 -0
  140. package/src/components/stack/stack.tsx +79 -0
  141. package/src/components/stat-card/stat-card.props.ts +13 -0
  142. package/src/components/stat-card/stat-card.stories.tsx +41 -0
  143. package/src/components/stat-card/stat-card.tsx +44 -0
  144. package/src/components/stepper/stepper.css +26 -0
  145. package/src/components/stepper/stepper.props.ts +29 -0
  146. package/src/components/stepper/stepper.stories.tsx +155 -0
  147. package/src/components/stepper/stepper.tsx +227 -0
  148. package/src/components/table/table.props.ts +43 -0
  149. package/src/components/table/table.stories.tsx +189 -0
  150. package/src/components/table/table.tsx +376 -0
  151. package/src/components/tabs/tabs.props.ts +18 -0
  152. package/src/components/tabs/tabs.stories.tsx +32 -0
  153. package/src/components/tabs/tabs.tsx +74 -0
  154. package/src/components/text/text.props.ts +9 -0
  155. package/src/components/text/text.tsx +20 -0
  156. package/src/components/textarea/textarea.props.ts +15 -0
  157. package/src/components/textarea/textarea.stories.tsx +27 -0
  158. package/src/components/textarea/textarea.tsx +55 -0
  159. package/src/components/theme-provider/themeProvider.props.ts +28 -0
  160. package/src/components/theme-provider/themeProvider.tsx +1854 -0
  161. package/src/components/time-picker/timePicker.props.ts +16 -0
  162. package/src/components/time-picker/timePicker.stories.tsx +131 -0
  163. package/src/components/time-picker/timePicker.tsx +317 -0
  164. package/src/components/toast/toast.css +32 -0
  165. package/src/components/toast/toast.props.ts +13 -0
  166. package/src/components/toast/toast.stories.tsx +138 -0
  167. package/src/components/toast/toast.tsx +87 -0
  168. package/src/components/tooltip/tooltip.props.ts +11 -0
  169. package/src/components/tooltip/tooltip.stories.tsx +20 -0
  170. package/src/components/tooltip/tooltip.tsx +55 -0
  171. package/src/components/topbar/topbar.props.ts +21 -0
  172. package/src/components/topbar/topbar.stories.tsx +80 -0
  173. package/src/components/topbar/topbar.tsx +205 -0
  174. package/src/components/triple-filter/tripleFilter.props.ts +15 -0
  175. package/src/components/triple-filter/tripleFilter.stories.tsx +32 -0
  176. package/src/components/triple-filter/tripleFilter.tsx +50 -0
  177. package/src/dev.css +2 -0
  178. package/src/hooks/useClickOutside.ts +21 -0
  179. package/src/hooks/useDebouncedSearch.ts +55 -0
  180. package/src/hooks/useEditableRow.ts +157 -0
  181. package/src/hooks/useTableState.ts +122 -0
  182. package/src/index.css +168 -0
  183. package/src/index.ts +165 -0
  184. package/src/main.tsx +9 -0
  185. package/src/showcases/DataShowcases.tsx +260 -0
  186. package/src/showcases/FeedbackShowcases.tsx +268 -0
  187. package/src/showcases/FormShowcases.tsx +1159 -0
  188. package/src/showcases/HomeShowcase.tsx +324 -0
  189. package/src/showcases/LayoutPrimitivesShowcases.tsx +569 -0
  190. package/src/showcases/NavigationShowcases.tsx +193 -0
  191. package/src/showcases/PageShowcases.tsx +207 -0
  192. package/src/showcases/ShowcaseLayout.tsx +139 -0
  193. package/src/showcases/StructureShowcases.tsx +152 -0
  194. package/src/types/badget.types.ts +37 -0
  195. package/src/types/button.types.ts +16 -0
  196. package/src/types/colors.types.ts +3 -0
  197. package/src/types/field.types.ts +103 -0
  198. package/src/types/formik.types.ts +15 -0
  199. package/src/types/input.types.ts +14 -0
  200. package/src/types/loader.types.ts +9 -0
  201. package/src/types/sizes.types.ts +1 -0
  202. package/src/types/table.types.ts +15 -0
  203. package/src/types/toast.types.ts +8 -0
  204. package/src/types/yup.types.ts +11 -0
  205. package/src/utils/color.utils.ts +99 -0
  206. package/src/utils/styles.ts +120 -0
  207. package/src/utils/table.utils.ts +10 -0
@@ -0,0 +1,324 @@
1
+ import React, { useState } from "react";
2
+ import { FaSearch } from "react-icons/fa";
3
+
4
+ export const HomeShowcase = () => {
5
+ const [techSearch, setTechSearch] = useState("");
6
+ const [selectedCategory, setSelectedCategory] = useState("all");
7
+
8
+ const LANGUAGES = [
9
+ {
10
+ name: "TypeScript",
11
+ icon: "https://raw.githubusercontent.com/devicons/devicon/master/icons/typescript/typescript-original.svg",
12
+ color: "#3178c6"
13
+ },
14
+ {
15
+ name: "JavaScript",
16
+ icon: "https://raw.githubusercontent.com/devicons/devicon/master/icons/javascript/javascript-original.svg",
17
+ color: "#f7df1e"
18
+ },
19
+ {
20
+ name: "C#",
21
+ icon: "https://raw.githubusercontent.com/devicons/devicon/master/icons/csharp/csharp-original.svg",
22
+ color: "#178600"
23
+ }
24
+ ];
25
+
26
+ const FRAMEWORKS = [
27
+ {
28
+ name: "Angular",
29
+ icon: "https://icongr.am/devicon/angularjs-original.svg?size=128&color=currentColor",
30
+ color: "#dd0031"
31
+ },
32
+ {
33
+ name: "React",
34
+ icon: "https://icongr.am/devicon/react-original.svg?size=128&color=currentColor",
35
+ color: "#61dafb"
36
+ },
37
+ {
38
+ name: "Ionic",
39
+ icon: "https://icongr.am/devicon/ionic-original.svg?size=128&color=currentColor",
40
+ color: "#3880ff"
41
+ },
42
+ {
43
+ name: ".NET / ASP.NET",
44
+ icon: "https://icongr.am/devicon/dot-net-original.svg?size=128&color=currentColor",
45
+ color: "#512bd4"
46
+ }
47
+ ];
48
+
49
+ const TECH_STACK = [
50
+ { name: "Docker", icon: "https://icongr.am/devicon/docker-original.svg?size=128&color=currentColor", category: "devops" },
51
+ { name: "Angular", icon: "https://icongr.am/devicon/angularjs-original.svg?size=128&color=currentColor", category: "frontend" },
52
+ { name: "C#", icon: "https://icongr.am/devicon/csharp-original.svg?size=128&color=currentColor", category: "backend" },
53
+ { name: "CSS3", icon: "https://icongr.am/devicon/css3-original.svg?size=128&color=currentColor", category: "frontend" },
54
+ { name: "Sass", icon: "https://icongr.am/devicon/sass-original.svg?size=128&color=currentColor", category: "frontend" },
55
+ { name: ".NET Core", icon: "https://icongr.am/devicon/dot-net-original.svg?size=128&color=currentColor", category: "backend" },
56
+ { name: "Electron", icon: "https://icongr.am/devicon/electron-original.svg?size=128&color=currentColor", category: "desktop" },
57
+ { name: "Express", icon: "https://icongr.am/devicon/express-original-wordmark.svg?size=128&color=currentColor", category: "backend" },
58
+ { name: "Git", icon: "https://icongr.am/devicon/git-original.svg?size=128&color=currentColor", category: "devops" },
59
+ { name: "GitHub", icon: "https://icongr.am/devicon/github-original.svg?size=128&color=currentColor", category: "devops", darkInvert: false },
60
+ { name: "GitLab", icon: "https://icongr.am/devicon/gitlab-original.svg?size=128&color=currentColor", category: "devops" },
61
+ { name: "HTML5", icon: "https://icongr.am/devicon/html5-original.svg?size=128&color=currentColor", category: "frontend" },
62
+ { name: "MongoDB", icon: "https://icongr.am/devicon/mongodb-original.svg?size=128&color=currentColor", category: "database" },
63
+ { name: "MySQL", icon: "https://icongr.am/devicon/mysql-original-wordmark.svg?size=128&color=currentColor", category: "database" },
64
+ { name: "Node.js", icon: "https://icongr.am/devicon/nodejs-original.svg?size=128&color=currentColor", category: "backend" },
65
+ { name: "React", icon: "https://icongr.am/devicon/react-original.svg?size=128&color=currentColor", category: "frontend" },
66
+ { name: "Android", icon: "https://icongr.am/devicon/android-original.svg?size=128&color=currentColor", category: "mobile" },
67
+ { name: "Python", icon: "https://icongr.am/devicon/python-original.svg?size=128&color=currentColor", category: "backend" },
68
+ { name: "TypeScript", icon: "https://icongr.am/devicon/typescript-original.svg?size=128&color=currentColor", category: "frontend" },
69
+ { name: "Kotlin", icon: "https://devicons.railway.app/i/kotlin.svg", category: "mobile" },
70
+ { name: "npm", icon: "https://devicons.railway.app/i/npm.svg", category: "devops" },
71
+ { name: "Redux", icon: "https://devicons.railway.app/i/redux.svg", category: "frontend" },
72
+ { name: "Yarn", icon: "https://cdn.iconscout.com/icon/free/png-512/free-yarn-34-1174974.png?f=webp&w=512", category: "devops" },
73
+ { name: "Visual Studio", icon: "https://icongr.am/devicon/visualstudio-plain.svg?size=128&color=currentColor", category: "tools" },
74
+ { name: "Flutter", icon: "https://cdn.iconscout.com/icon/free/png-512/free-flutter-2038877-1720090.png?f=webp&w=512", category: "mobile" },
75
+ { name: "Jest", icon: "https://cdn.iconscout.com/icon/free/png-512/free-jest-3521517-2945020.png?f=webp&w=512", category: "testing" }
76
+ ];
77
+
78
+ const categoriesList = [
79
+ { id: "all", name: "Todos" },
80
+ { id: "frontend", name: "Frontend" },
81
+ { id: "backend", name: "Backend" },
82
+ { id: "mobile", name: "Móvil" },
83
+ { id: "database", name: "Bases de Datos" },
84
+ { id: "devops", name: "DevOps" }
85
+ ];
86
+
87
+ const filteredTech = TECH_STACK.filter(tech => {
88
+ const matchesSearch = tech.name.toLowerCase().includes(techSearch.toLowerCase());
89
+ const matchesCategory = selectedCategory === "all" || tech.category === selectedCategory;
90
+ return matchesSearch && matchesCategory;
91
+ });
92
+
93
+ return (
94
+ <div className="space-y-10 animate-fade-in">
95
+ <style dangerouslySetInnerHTML={{
96
+ __html: `
97
+ @keyframes float {
98
+ 0%, 100% { transform: translateY(0px); }
99
+ 50% { transform: translateY(-10px); }
100
+ }
101
+ .animate-float {
102
+ animation: float 4s ease-in-out infinite;
103
+ }
104
+ @keyframes float-slow {
105
+ 0%, 100% { transform: translateY(0px) rotate(0deg); }
106
+ 50% { transform: translateY(-15px) rotate(2deg); }
107
+ }
108
+ .animate-float-slow {
109
+ animation: float-slow 6s ease-in-out infinite;
110
+ }
111
+ .animate-fade-in {
112
+ animation: fadeIn 0.5s ease-out forwards;
113
+ }
114
+ @keyframes fadeIn {
115
+ from { opacity: 0; transform: translateY(10px); }
116
+ to { opacity: 1; transform: translateY(0); }
117
+ }
118
+ ` }} />
119
+
120
+ {/* Hero Section */}
121
+ <div className="relative overflow-hidden rounded-3xl bg-gradient-to-br from-white/70 to-slate-50/50 dark:from-slate-900/60 dark:to-slate-950/40 border border-slate-100 dark:border-slate-800/80 backdrop-blur-md p-8 md:p-12 shadow-sm">
122
+ <div className="absolute top-0 right-0 w-80 h-80 bg-primary-500/10 rounded-full blur-3xl -z-10 pointer-events-none" />
123
+ <div className="absolute bottom-0 left-0 w-80 h-80 bg-purple-500/5 rounded-full blur-3xl -z-10 pointer-events-none" />
124
+
125
+ <div className="grid grid-cols-1 lg:grid-cols-12 gap-8 items-center">
126
+ {/* Text content */}
127
+ <div className="lg:col-span-7 space-y-6">
128
+ <div className="space-y-2">
129
+ <span className="px-3 py-1 text-xs font-semibold rounded-full bg-primary-100 dark:bg-primary-950/40 text-primary-600 dark:text-primary-400 border border-primary-200/30">
130
+ Portafolio Personal
131
+ </span>
132
+ <h1 className="text-3xl md:text-5xl font-black tracking-tight text-slate-800 dark:text-white leading-tight">
133
+ Hola 👋, soy <br />
134
+ <span className="bg-gradient-to-r from-primary-500 via-purple-500 to-indigo-500 bg-clip-text text-transparent">
135
+ Asael Amaro
136
+ </span>
137
+ </h1>
138
+ </div>
139
+
140
+ <div className="space-y-4">
141
+ <h2 className="text-xl font-bold text-slate-700 dark:text-slate-200">Sobre mí</h2>
142
+ <p className="text-slate-600 dark:text-slate-300 leading-relaxed text-base font-normal">
143
+ Desarrollador Fullstack con 4+ años de experiencia desarrollando aplicaciones web usando{" "}
144
+ <strong className="text-primary-500 font-semibold">TypeScript</strong>,{" "}
145
+ <strong className="text-purple-500 font-semibold">Angular 8+</strong>,{" "}
146
+ <strong className="text-indigo-500 font-semibold">JavaScript</strong>, y{" "}
147
+ <strong className="text-blue-500 font-semibold">ReactJS</strong>. Apasionado de los lenguajes de programación modernos
148
+ y las nuevas técnicas de desarrollo. Autodidacta y me encantan los nuevos retos.
149
+ </p>
150
+ </div>
151
+
152
+ <div className="flex flex-wrap gap-3 pt-2">
153
+ <span className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-xl bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 font-mono">
154
+ 💼 Fullstack Developer
155
+ </span>
156
+ <span className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-xl bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 font-mono">
157
+ 📅 4+ Años Exp
158
+ </span>
159
+ <span className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-xl bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300 font-mono">
160
+ 🚀 React & Angular
161
+ </span>
162
+ </div>
163
+ </div>
164
+
165
+ {/* Illustration/Image */}
166
+ <div className="lg:col-span-5 flex justify-center">
167
+ <div className="relative group">
168
+ {/* Decorative backglow */}
169
+ <div className="absolute inset-0 bg-gradient-to-tr from-primary-500 to-purple-500 rounded-full blur-2xl opacity-20 group-hover:opacity-35 transition-opacity duration-500" />
170
+
171
+ <div className="relative rounded-2xl overflow-hidden bg-slate-100/50 dark:bg-slate-950/20 p-4 border border-slate-200/30 dark:border-slate-800/40 backdrop-blur-sm">
172
+ <img
173
+ src="/animations/developer.gif"
174
+ alt="Developer Illustration"
175
+ className="w-full max-w-[280px] aspect-square object-cover rounded-xl shadow-inner animate-float"
176
+ onError={(e) => {
177
+ e.currentTarget.style.display = "none";
178
+ const container = e.currentTarget.parentElement;
179
+ if (container) {
180
+ const fallback = container.querySelector(".svg-fallback");
181
+ if (fallback) fallback.classList.remove("hidden");
182
+ }
183
+ }}
184
+ />
185
+
186
+ {/* Fallback SVG embedded */}
187
+ <div className="svg-fallback hidden w-full max-w-[280px] aspect-square flex items-center justify-center">
188
+ <svg className="w-full aspect-square" viewBox="0 0 200 200" fill="none">
189
+ <circle cx="100" cy="100" r="70" fill="url(#heroGlow)" opacity="0.2" />
190
+ <rect x="50" y="70" width="100" height="70" rx="8" fill="#1e293b" stroke="#475569" strokeWidth="4" />
191
+ <rect x="58" y="78" width="84" height="46" rx="4" fill="#0f172a" />
192
+ <line x1="66" y1="88" x2="100" y2="88" stroke="#3b82f6" strokeWidth="3" strokeLinecap="round" />
193
+ <line x1="66" y1="98" x2="120" y2="98" stroke="#10b981" strokeWidth="3" strokeLinecap="round" />
194
+ <line x1="66" y1="108" x2="90" y2="108" stroke="#8b5cf6" strokeWidth="3" strokeLinecap="round" />
195
+ <circle cx="130" cy="88" r="6" fill="#f59e0b" />
196
+ <path d="M 40 140 L 160 140 L 170 148 L 30 148 Z" fill="#334155" />
197
+ <rect x="154" y="120" width="12" height="18" rx="2" fill="#ef4444" />
198
+ <path d="M 166 124 C 170 124 170 130 166 130" stroke="#ef4444" strokeWidth="2" fill="none" />
199
+ <defs>
200
+ <radialGradient id="heroGlow" cx="50%" cy="50%" r="50%">
201
+ <stop offset="0%" stopColor="#3b82f6" />
202
+ <stop offset="100%" stopColor="#a855f7" stopOpacity="0" />
203
+ </radialGradient>
204
+ </defs>
205
+ </svg>
206
+ </div>
207
+ </div>
208
+ </div>
209
+ </div>
210
+ </div>
211
+ </div>
212
+
213
+ {/* Languages & Frameworks Sections */}
214
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
215
+ {/* Languages */}
216
+ <div className="p-6 rounded-2xl bg-white/70 dark:bg-slate-900/60 border border-slate-100 dark:border-slate-800 backdrop-blur-md shadow-sm space-y-4">
217
+ <h2 className="text-xl font-bold text-slate-800 dark:text-white flex items-center gap-2">
218
+ <span className="text-lg">🛠️</span> Lenguajes Principales
219
+ </h2>
220
+ <div className="grid grid-cols-3 gap-4">
221
+ {LANGUAGES.map((lang) => (
222
+ <div
223
+ key={lang.name}
224
+ className="group relative flex flex-col items-center gap-3 p-4 rounded-xl bg-slate-50/50 dark:bg-slate-950/20 border border-slate-200/50 dark:border-slate-800/40 hover:border-primary-500/40 transition-all duration-300 hover:scale-105 hover:shadow-sm"
225
+ >
226
+ <div className="w-12 h-12 flex items-center justify-center rounded-xl bg-white dark:bg-slate-900 shadow-sm border border-slate-100 dark:border-slate-800/80 group-hover:rotate-6 transition-transform duration-300">
227
+ <img src={lang.icon} alt={lang.name} className="w-8 h-8 object-contain" />
228
+ </div>
229
+ <span className="text-xs font-semibold text-slate-700 dark:text-slate-200">{lang.name}</span>
230
+ </div>
231
+ ))}
232
+ </div>
233
+ </div>
234
+
235
+ {/* Frameworks */}
236
+ <div className="p-6 rounded-2xl bg-white/70 dark:bg-slate-900/60 border border-slate-100 dark:border-slate-800 backdrop-blur-md shadow-sm space-y-4">
237
+ <h2 className="text-xl font-bold text-slate-800 dark:text-white flex items-center gap-2">
238
+ <span className="text-lg">🚀</span> Frameworks
239
+ </h2>
240
+ <div className="grid grid-cols-4 gap-3">
241
+ {FRAMEWORKS.map((fw) => (
242
+ <div
243
+ key={fw.name}
244
+ className="group relative flex flex-col items-center gap-2 p-3 rounded-xl bg-slate-50/50 dark:bg-slate-950/20 border border-slate-200/50 dark:border-slate-800/40 hover:border-primary-500/40 transition-all duration-300 hover:scale-105 hover:shadow-sm"
245
+ >
246
+ <div className="w-10 h-10 flex items-center justify-center rounded-xl bg-white dark:bg-slate-900 shadow-sm border border-slate-100 dark:border-slate-800/80 group-hover:-rotate-6 transition-transform duration-300">
247
+ <img src={fw.icon} alt={fw.name} className="w-6 h-6 object-contain" />
248
+ </div>
249
+ <span className="text-[10px] font-semibold text-slate-700 dark:text-slate-200 text-center truncate w-full">{fw.name}</span>
250
+ </div>
251
+ ))}
252
+ </div>
253
+ </div>
254
+ </div>
255
+
256
+ {/* Tech Stack Grid Section */}
257
+ <div className="p-6 md:p-8 rounded-3xl bg-white/70 dark:bg-slate-900/60 border border-slate-100 dark:border-slate-800 backdrop-blur-md shadow-sm space-y-6">
258
+ <div className="flex flex-col md:flex-row md:items-center justify-between gap-4">
259
+ <div>
260
+ <h2 className="text-2xl font-extrabold text-slate-800 dark:text-white">Tech Stack</h2>
261
+ <p className="text-xs text-slate-500">Mi conjunto completo de herramientas, frameworks y tecnologías.</p>
262
+ </div>
263
+
264
+ <div className="flex flex-col sm:flex-row gap-3">
265
+ {/* Search Input */}
266
+ <div className="relative">
267
+ <input
268
+ type="text"
269
+ placeholder="Filtrar tecnologías..."
270
+ value={techSearch}
271
+ onChange={(e) => setTechSearch(e.target.value)}
272
+ className="w-full sm:w-60 bg-slate-50 dark:bg-slate-950/40 text-slate-800 dark:text-white pl-8 pr-4 py-1.5 text-xs rounded-xl outline-none focus:ring-2 focus:ring-primary-500 border border-slate-200/60 dark:border-slate-800/80 transition-all"
273
+ />
274
+ <FaSearch className="absolute left-2.5 top-2.5 text-slate-400" size={11} />
275
+ </div>
276
+ </div>
277
+ </div>
278
+
279
+ {/* Category Pill Filters */}
280
+ <div className="flex flex-wrap gap-2 pb-2 border-b border-slate-100 dark:border-slate-800/60">
281
+ {categoriesList.map((cat) => (
282
+ <button
283
+ key={cat.id}
284
+ onClick={() => setSelectedCategory(cat.id)}
285
+ className={`px-3 py-1.5 rounded-lg text-xs font-semibold transition-all ${selectedCategory === cat.id
286
+ ? "bg-primary-500 text-white shadow-sm"
287
+ : "bg-slate-100/80 hover:bg-slate-200/80 dark:bg-slate-800/80 dark:hover:bg-slate-700/80 text-slate-600 dark:text-slate-300"
288
+ }`}
289
+ >
290
+ {cat.name}
291
+ </button>
292
+ ))}
293
+ </div>
294
+
295
+ {/* Tech Grid */}
296
+ {filteredTech.length > 0 ? (
297
+ <div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-4">
298
+ {filteredTech.map((tech, index) => (
299
+ <div
300
+ key={`${tech.name}-${index}`}
301
+ className="group relative flex flex-col items-center justify-center p-4 rounded-xl bg-slate-50/40 dark:bg-slate-950/10 border border-slate-200/30 dark:border-slate-800/20 hover:border-primary-500/40 transition-all duration-300 hover:scale-110 hover:-translate-y-1 hover:shadow-md cursor-pointer"
302
+ >
303
+ <div className="w-12 h-12 flex items-center justify-center rounded-xl bg-white dark:bg-slate-900 border border-slate-100 dark:border-slate-800/50 shadow-inner group-hover:rotate-3 transition-transform">
304
+ <img
305
+ src={tech.icon}
306
+ alt={tech.name}
307
+ className={`w-8 h-8 object-contain ${tech.darkInvert ? "dark:invert" : ""}`}
308
+ />
309
+ </div>
310
+ <span className="mt-2.5 text-[10px] font-semibold text-slate-600 dark:text-slate-300 text-center select-none truncate w-full">
311
+ {tech.name}
312
+ </span>
313
+ </div>
314
+ ))}
315
+ </div>
316
+ ) : (
317
+ <div className="text-center py-10 text-slate-400 dark:text-slate-500 text-sm">
318
+ No se encontraron tecnologías que coincidan con la búsqueda.
319
+ </div>
320
+ )}
321
+ </div>
322
+ </div>
323
+ );
324
+ };