Skip to main content

Overview

Q-Sopa is designed to be highly customizable. This guide covers common customization scenarios with real code examples from the project.

API Configuration

The API base URL is configured in src/services/api.js.

Changing the API Endpoint

1

Locate the API configuration

Open src/services/api.js in your editor.
2

Update the BASE_URL

Modify the BASE_URL constant to point to your API:
// Before
const BASE_URL = "https://apiqsp-production.up.railway.app";

// After
const BASE_URL = "https://your-api-domain.com";
3

Test the connection

Run your development server and verify the API calls work:
npm run dev
The API must support the following endpoints:
  • GET /categories - Returns list of categories
  • GET /products - Returns all products
  • GET /products/category/:id - Returns products for a specific category
For better configuration management, use environment variables:
// src/services/api.js
const BASE_URL = import.meta.env.VITE_API_BASE_URL || "https://apiqsp-production.up.railway.app";

export const getCategorias = async () => {
  const res = await fetch(`${BASE_URL}/categories`);
  if (!res.ok) throw new Error("Error al cargar categorías");
  return res.json();
};
Create a .env file in your project root:
VITE_API_BASE_URL=https://your-api-domain.com
Never commit .env files containing sensitive data to version control. Add .env to your .gitignore file.

Branding and Colors

Primary Brand Color

The primary red color (#ec1313) is used throughout the application. To change it:
Update src/components/ProductCard/ProductCard.css:
/* Current: Red theme */
.product-btn {
  background-color: #ec1313;
}

.product-btn:hover {
  background-color: #c40b0b;
}

/* Example: Blue theme */
.product-btn {
  background-color: #1E90FF;
}

.product-btn:hover {
  background-color: #1873CC;
}
Update src/components/Categories/Categories.css:
/* Desktop active state */
.category-btn.active .category-icon {
  background-color: #ec1313; /* Change this */
  box-shadow: 0 0 12px rgba(236, 19, 19, 0.3);
}

.category-btn.active .category-underline {
  background-color: #ec1313; /* Change this */
}

/* Mobile drawer active state */
.drawer-item.active {
  background: rgba(236, 19, 19, 0.1); /* Change this */
  border-color: rgba(236, 19, 19, 0.3);
}

.drawer-item.active .drawer-item-icon {
  background: #ec1313; /* Change this */
  border-color: #ec1313;
  box-shadow: 0 4px 14px rgba(236, 19, 19, 0.35);
}
Update src/components/navbar/Navbar.css:
.navbar-logo {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid #ec1313; /* Change this */
  box-shadow: 0 0 15px rgba(236, 19, 19, 0.4);
}

Accent Color (Yellow)

The yellow accent color (#FFD60A) is used for prices and highlights:
/* src/components/ProductCard/ProductCard.css */
.product-info span {
  color: #FFD60A; /* Price color */
  font-weight: bold;
}

/* src/pages/Menu.css */
.menu-subtitle {
  color: #FFD60A; /* "Sabores Auténticos" text */
  font-weight: bold;
}

Background Colors

Q-Sopa uses a dark theme with these background layers:
/* Main background - src/App.css */
body {
  background-color: #121212;
  color: #f5f5f5;
}

/* Card background - src/components/ProductCard/ProductCard.css */
.product-card {
  background-color: #1E1E1E;
  border-radius: 15px;
}

/* Category icon background */
.category-icon {
  background-color: #1E1E1E;
  border: 1px solid #2a2a2a;
}
Maintain sufficient contrast ratios for accessibility. Use tools like WebAIM’s Contrast Checker to verify your color choices.

Component Customization

Product Card Layout

The ProductCard component is defined in src/components/ProductCard/ProductCard.jsx:
// src/components/ProductCard/ProductCard.jsx
export default function ProductCard({ title, price, image, badge, description }) {
  return (
    <div className="product-card">
      {badge && <div className="badge">{badge}</div>}
      <img src={image} alt={title} />
      
      <div className="product-info">
        <h4>{title}</h4>
        <span>${price}</span>
      </div>
      
      {/* Add description */}
      {description && <p className="product-description">{description}</p>}
      
      <button className="product-btn">Ingredientes</button>
    </div>
  );
}
Add corresponding CSS in ProductCard.css:
.product-description {
  color: #aaa;
  font-size: 13px;
  margin: 8px 0;
  line-height: 1.4;
}
Current dimensions in src/components/ProductCard/ProductCard.css:
.product-card img {
  width: 100%;
  height: 200px;        /* Fixed height */
  object-fit: cover;    /* Prevents distortion */
  border-radius: 10px;
  display: block;
}
For larger images:
.product-card img {
  height: 280px; /* Increase as needed */
}
For aspect ratio instead of fixed height:
.product-card img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 10px;
  display: block;
}
Change the “Ingredientes” button text or functionality:
// Add onClick handler
export default function ProductCard({ title, price, image, badge, onViewDetails }) {
  return (
    <div className="product-card">
      {/* ... */}
      <button 
        className="product-btn"
        onClick={() => onViewDetails({ title, price, image })}
      >
        View Details
      </button>
    </div>
  );
}

Grid Layout

The products grid is defined in src/pages/Menu.css:
.products-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 25px;
}
Customization options:
/* More columns (smaller cards) */
.products-grid {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

/* Fewer columns (larger cards) */
.products-grid {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

/* Fixed 3 columns on desktop */
.products-grid {
  grid-template-columns: repeat(3, 1fr);
}

/* Larger gap */
.products-grid {
  gap: 40px;
}

Category Icons

Q-Sopa uses Material Symbols for category icons. The icons are rendered in src/components/Categories/Categories.jsx:
<span className="material-symbols-outlined">{cat.icon}</span>

Adding New Icon Support

Icons are provided by your API’s categories endpoint. Each category should include an icon field:
{
  "id": 1,
  "name": "Burgers",
  "icon": "lunch_dining"
}
Browse available icons at Google Fonts Icons. Use the icon name exactly as shown (e.g., lunch_dining, local_pizza, restaurant).

Icon Styling

Customize icon appearance in Categories.css:
/* Desktop icons */
.category-icon {
  width: 48px;
  height: 48px;
  font-size: 22px; /* Icon size */
  border-radius: 14px;
}

/* Mobile drawer icons */
.drawer-item-icon {
  width: 38px;
  height: 38px;
  font-size: 18px; /* Icon size */
}
Customize the header text in src/pages/Menu.jsx:
<header className="menu-header">
  <span className="menu-subtitle">Sabores Auténticos</span>
  <h2>Nuestro Menú</h2>
  <p>Ingredientes premium, preparados al momento.</p>
</header>
Example customization:
<header className="menu-header">
  <span className="menu-subtitle">Fresh Daily</span>
  <h2>Our Menu</h2>
  <p>Farm-to-table ingredients, made with love.</p>
</header>

Logo Customization

Replace the logo in src/components/navbar/Navbar.jsx:
import logo from "../../assets/logo_Q-spoa.jpg";

// In the component:
<img src={logo} alt="Burger Bistro Logo" className="navbar-logo" />
1

Add your logo

Place your logo file in the src/assets/ directory (e.g., my-logo.png).
2

Update the import

import logo from "../../assets/my-logo.png";
3

Update the alt text

<img src={logo} alt="Your Restaurant Name" className="navbar-logo" />

Font Customization

The application uses ‘Plus Jakarta Sans’ font, defined in src/App.css:
body {
  margin: 0;
  font-family: 'Plus Jakarta Sans', sans-serif;
  background-color: #121212;
  color: #f5f5f5;
}
To use a different font:
  1. Google Fonts: Add to index.html:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
  1. Update CSS:
body {
  font-family: 'Inter', sans-serif;
}

Advanced: Adding New Features

Search Functionality

Add a search bar to filter products:
// In src/pages/Menu.jsx
const [searchTerm, setSearchTerm] = useState("");

const filteredProducts = products.filter(product =>
  product.name.toLowerCase().includes(searchTerm.toLowerCase())
);

// In the render:
<input
  type="text"
  placeholder="Search products..."
  value={searchTerm}
  onChange={(e) => setSearchTerm(e.target.value)}
  className="menu-search"
/>

<section className="products-grid">
  {filteredProducts.map((product) => (
    <ProductCard key={product.id} {...product} />
  ))}
</section>

Price Formatting

Add custom price formatting:
// Create src/utils/format.js
export const formatPrice = (price) => {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD'
  }).format(price);
};

// In ProductCard.jsx
import { formatPrice } from '../../utils/format';

<span>{formatPrice(price)}</span>

Next Steps

Deployment

Learn how to deploy your customized application

Troubleshooting

Fix common issues and errors

Build docs developers (and LLMs) love