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
| Path | Component file |
|---|
/aplicaciones | src/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
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 subtitle | Assigned category |
|---|
node, express, mongo | Node |
tailwind, css, scss | CSS |
react, next, ui, landing | Landing Page |
api, export | API |
| (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]);
Filtering and Search
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.
Featured Projects
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:
| Prop | Type | Default | Notes |
|---|
project | object | — | The project data object derived from secondImages |
featured | boolean | false | When true, renders the ★ Destacado badge |
isDark | boolean | — | Current dark/light mode from useDarkMode() |
colors | object | — | Theme palette from getThemeColors(isDark) |
Key rendering details:
| Element | Behaviour |
|---|
| Image | Scales to 1.1× on hover via a CSS transform transition |
| Title | Changes color to #4DB1FF on hover |
| Subtitle | Rendered as a two-line clamped description paragraph |
| Tags | Derived by splitting subtitle on -; only the first 3 tags are shown |
| Demo button | Opens demo URL in a new tab; disabled (opacity 0.4, no pointer) when demo is an empty string |
| Repo button | Opens repo URL in a new tab; disabled when repo is an empty string |
| Featured badge | Shows ★ 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
Open the gallery data file
Open src/utils/galerimages.js in your editor.
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";
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"
}
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
}