Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iwinser117/react-portafolio/llms.txt

Use this file to discover all available pages before exploring further.

The Projects page gives visitors a filterable, searchable overview of portfolio work. Projects are loaded from the secondImages static array in galerimages.js, automatically categorised by scanning each entry’s subtitle string, and rendered as interactive cards. A featured row surfaces highlighted projects when no filters are active, and the grid reacts to both category buttons and free-text search in real time.

Route

PathComponent file
/aplicacionessrc/pages/aplicaciones.jsx

Data Source

All project data comes from the secondImages array exported by src/utils/galerimages.js. The file also exports imagesTodowebp, which the component imports and maps into a fromTodo array internally — however, the final projects state is built with return [...fromSecond], so fromTodo is intentionally not included in the rendered project list. Only secondImages entries appear on the page. Each entry in secondImages has the following shape:
{
  src: <imported image>,   // resolved image asset
  alt: "Project title",    // used as the card title
  subtitle: "Tech - Stack",// hyphen-separated tech list; drives tags and category derivation
  demo: "https://...",     // live demo URL (empty string if unavailable)
  repo: "https://...",     // GitHub repository URL (empty string if unavailable)
  featured: true | false   // optional; defaults to false
}

Current projects in secondImages

TitleSubtitle / TagsDemoRepo
CRUD Lista tareasNodeJs - React - MongoDBcrudlistatareas.netlify.appnodeJs_react_crud
Autenticación JWTNodeJs - ExpressJs - oAuthautenticate.vercel.appautenticate
Generador ContraseñasTailwind - NextJsgeneratepassword-theta.vercel.appgeneratepassword
TableExportJSNodeJstable-export-js-4zq5.vercel.appTableExportJS
CRUD SAPNodeJs - Express - Odata - SAPmega-crud-table-ui5.vercel.appmega-crud-table-ui5
apk pdfVisor PDF - Androidpdf-generator-nodejs.vercel.apppdf_reader

Category Derivation

When the Proyectos component mounts, it calls deriveCategories(subtitle) for every entry in secondImages to compute the categories array for each project. A project can belong to multiple categories simultaneously.
const deriveCategories = (subtitle = "") => {
  const s = subtitle.toLowerCase();
  const categories = [];

  if (s.includes("node") || s.includes("express") || s.includes("mongo"))
    categories.push("Node");
  if (s.includes("tailwind") || s.includes("css") || s.includes("scss"))
    categories.push("CSS");
  if (s.includes("react") || s.includes("next") || s.includes("ui") || s.includes("landing"))
    categories.push("Landing Page");
  if (s.includes("api") || s.includes("export"))
    categories.push("API");

  return categories.length > 0 ? categories : ["Other"];
};
Keyword in subtitleAssigned category
node, express, mongoNode
tailwind, css, scssCSS
react, next, ui, landingLanding Page
api, exportAPI
(none of the above)Other
The full list of available category filter buttons is built dynamically at runtime with useMemo by iterating over every project’s categories array and collecting unique values into a Set, then prepending "All":
const categories = useMemo(() => {
  const cats = new Set();
  projects.forEach(p => p.categories.forEach(cat => cats.add(cat)));
  return ["All", ...Array.from(cats)];
}, [projects]);
Both the category filter and the text search are applied together inside a single useMemo that recomputes filteredProjects whenever projects, selectedCategory, or searchQuery changes:
const filteredProjects = useMemo(() => {
  return projects.filter(project => {
    const matchesCategory =
      selectedCategory === "All" ||
      project.categories.includes(selectedCategory);
    const matchesSearch =
      project.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
      project.subtitle.toLowerCase().includes(searchQuery.toLowerCase());
    return matchesCategory && matchesSearch;
  });
}, [projects, selectedCategory, searchQuery]);
  • Category filter — clicking a button sets selectedCategory via useState; clicking “All” resets to the full list.
  • Text search — the search input sets searchQuery via useState. The filter checks both project.title and project.subtitle case-insensitively.
When selectedCategory === 'All' and searchQuery === '', a Featured Projects row is shown above the main grid. It contains every project whose featured property is true:
const featuredProjects = projects.filter(p => p.featured);
Featured cards display a ★ Destacado badge in their top-right corner. The featured row is hidden as soon as any category filter or search query is active.

ProjectCard Component

Each project is rendered by the ProjectCard component, defined inline in aplicaciones.jsx. It accepts { project, featured, isDark, colors } props:
PropTypeDefaultNotes
projectobjectThe project data object derived from secondImages
featuredbooleanfalseWhen true, renders the ★ Destacado badge
isDarkbooleanCurrent dark/light mode from useDarkMode()
colorsobjectTheme palette from getThemeColors(isDark)
Key rendering details:
ElementBehaviour
ImageScales to 1.1× on hover via a CSS transform transition
TitleChanges color to #4DB1FF on hover
SubtitleRendered as a two-line clamped description paragraph
TagsDerived by splitting subtitle on -; only the first 3 tags are shown
Demo buttonOpens demo URL in a new tab; disabled (opacity 0.4, no pointer) when demo is an empty string
Repo buttonOpens repo URL in a new tab; disabled when repo is an empty string
Featured badgeShows ★ Destacado when featured={true} is passed
<div style={cardStyles.tags}>
  {project.tags.slice(0, 3).map((tag, idx) => (
    <span key={idx} style={cardStyles.tag}>{tag}</span>
  ))}
</div>

Theme

The page reads the global dark/light preference via the useDarkMode() hook from DarkModeProvider:
const isDark = useDarkMode();
const colors = getThemeColors(isDark);
getThemeColors(isDark) returns a palette object with keys like bgPrimary, textPrimary, gradientPrimary, shadowMedium, etc. All inline styles reference this object, so the entire page repaints automatically when the user toggles the theme.

Adding a New Project

1

Open the gallery data file

Open src/utils/galerimages.js in your editor.
2

Import the project image

Add an import for your image asset at the top of the file, alongside the existing imports:
import myNewProject from "@assets/myNewProject.webp";
3

Add an entry to secondImages

Append an object to the secondImages array:
{
  src: myNewProject,
  alt: "My New Project",           // becomes the card title
  subtitle: "React - Node - API",  // drives tag display and category derivation
  demo: "https://my-project.vercel.app/",
  repo: "https://github.com/iwinser117/my-new-project"
}
4

Mark as featured (optional)

Add featured: true to the entry to display it in the Featured Projects row at the top of the page when no filters are active:
{
  src: myNewProject,
  alt: "My New Project",
  subtitle: "React - Node - API",
  demo: "https://my-project.vercel.app/",
  repo: "https://github.com/iwinser117/my-new-project",
  featured: true
}

Build docs developers (and LLMs) love