Skip to main content

Styling Approach

Q-Sopa uses a component-scoped CSS approach where each component has its own CSS file co-located in the same directory:
components/
├── ProductCard/
│   ├── ProductCard.jsx
│   └── ProductCard.css  ← Scoped to ProductCard component
├── Navbar/
│   ├── Navbar.jsx
│   └── Navbar.css       ← Scoped to Navbar component
While Tailwind CSS 4.2.1 is installed as a dependency, the current implementation uses traditional CSS files for styling.

Global Styles

Base Styles

Global styles are defined in src/App.css (root level) and applied to the entire application:
src/App.css
body {
  margin: 0;
  font-family: 'Plus Jakarta Sans', sans-serif;
  background-color: #121212;
  color: #f5f5f5;
}
Global Design Tokens:
  • Primary Font: Plus Jakarta Sans (loaded from Google Fonts)
  • Background: #121212 (dark theme)
  • Text Color: #f5f5f5 (light gray)
  • Accent Color: #ec1313 (red)
  • Secondary Accent: #FFD60A (yellow)

Font Integration

Fonts are loaded in index.html:
index.html
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;700;800&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet">

Plus Jakarta Sans

Primary typefaceWeights: 400, 500, 700, 800

Material Symbols

Icon font for UI elementsOutlined style

Color System

The application uses a consistent dark theme color palette:
PurposeColorHex Code
Background PrimaryBlack#121212
Background SecondaryDark Gray#1E1E1E
Background TertiaryDarker Gray#1a1a1a
BorderGray#2a2a2a
Text PrimaryOff-white#f5f5f5
Text SecondaryLight Gray#aaa
Text MutedGray#888
Accent RedRed#ec1313
Accent Red HoverDark Red#c40b0b
Accent YellowYellow#FFD60A
The red accent color (#ec1313) is used consistently for primary actions, active states, and brand identity.

CSS Class Naming Conventions

The project follows a BEM-inspired naming pattern:
/* Block */
.navbar
.product-card
.category-btn

/* Block with modifier */
.navbar-wrapper
.navbar-left
.navbar-center

/* Element */
.navbar-logo
.product-info
.category-icon

/* State modifier (uses additional class) */
.category-btn.active
.drawer-item.active

Example from ProductCard Component

src/components/ProductCard/ProductCard.css
.product-card {
  background-color: #1E1E1E;
  border-radius: 15px;
  padding: 15px;
  position: relative;
  transition: 0.3s;
}

.product-card:hover {
  transform: translateY(-5px);
}

.product-card img {
  width: 100%;
  height: 200px;
  object-fit: cover;
  border-radius: 10px;
  display: block;
}

.product-info {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
}

.product-info h4 {
  margin: 0;
}

.product-info span {
  color: #FFD60A;
  font-weight: bold;
}

.product-btn {
  width: 100%;
  margin-top: 15px;
  padding: 10px;
  background-color: #ec1313;
  border: none;
  border-radius: 10px;
  color: white;
  font-weight: bold;
  cursor: pointer;
}

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

.badge {
  position: absolute;
  top: 10px;
  right: 10px;
  background-color: #FFD60A;
  color: black;
  padding: 4px 8px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: bold;
}

Material Symbols Icons

Q-Sopa uses Google’s Material Symbols for iconography:
<span className="material-symbols-outlined">{cat.icon}</span>
Icon Usage in Categories Component:
src/components/Categories/Categories.jsx
<div className="category-icon">
  <span className="material-symbols-outlined">{cat.icon}</span>
</div>
Corresponding styles:
src/components/Categories/Categories.css
.category-icon {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  background-color: #1E1E1E;
  border: 1px solid #2a2a2a;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  transition: 0.3s;
}

.category-btn.active .category-icon {
  background-color: #ec1313;
  color: white;
  border: none;
  box-shadow: 0 0 12px rgba(236, 19, 19, 0.3);
}
Icon names are fetched from the API and rendered dynamically. Ensure icon names match Material Symbols naming conventions.

Responsive Design Patterns

Q-Sopa implements a mobile-first responsive design with breakpoints:
BreakpointWidthTarget Devices
Mobile< 768pxPhones
Tablet768px - 1024pxTablets
Desktop> 1024pxDesktops
src/components/navbar/Navbar.css
@media (max-width: 768px) {
  .navbar {
    grid-template-columns: 1fr auto;
    padding: 10px 20px;
  }

  .order-btn {
    padding: 8px 20px;
    font-size: 14px;
  }
}

Grid Layout Adjustments

.navbar {
  max-width: 1600px;
  margin: auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;  /* Desktop: 3 columns */
  align-items: center;
  padding: 15px 40px;
}

@media (max-width: 768px) {
  .navbar {
    grid-template-columns: 1fr auto;     /* Mobile: 2 columns */
    padding: 10px 20px;
  }
}

Mobile Drawer Implementation

The Categories component features a sophisticated mobile drawer pattern:

Desktop View

Horizontal scrollable category list:
src/components/Categories/Categories.css
.categories-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.categories-wrapper::-webkit-scrollbar {
  display: none;
}

.categories-container {
  display: flex;
  gap: 18px;
}

Mobile View

Hamburger menu with slide-in drawer:
@media (max-width: 768px) {
  /* Hide desktop menu */
  .categories-wrapper,
  .categories-container {
    display: none;
  }

  /* Hamburger button */
  .drawer-toggle {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 40px;
    height: 40px;
    padding: 8px;
    background: #1e1e1e;
    border: 1px solid #2a2a2a;
    border-radius: 10px;
    cursor: pointer;
    transition: border-color 0.2s;
  }

  /* Dark overlay */
  .drawer-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.65);
    backdrop-filter: blur(3px);
    z-index: 100;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
  }

  .drawer-overlay.open {
    opacity: 1;
    pointer-events: all;
  }

  /* Slide-in panel */
  .drawer-panel {
    display: flex;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: 260px;
    background: #1a1a1a;
    border-right: 1px solid #2a2a2a;
    z-index: 101;
    flex-direction: column;
    padding: 72px 12px 32px;
    gap: 4px;
    transform: translateX(-100%);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  }

  .drawer-panel.open {
    transform: translateX(0);
  }
}
1

Hamburger Button

Three-line icon that opens the drawer
2

Dark Overlay

Backdrop with blur effect that closes drawer when clicked
3

Slide-in Panel

Left-side panel with smooth transform animation

Drawer JSX Structure

src/components/Categories/Categories.jsx
<>
  {/* Desktop: horizontal menu */}
  <div className="categories-wrapper">
    <div className="categories-container">
      {categories.map((cat) => (
        <button className="category-btn">{/* ... */}</button>
      ))}
    </div>
  </div>

  {/* Mobile: hamburger button */}
  <button
    className="drawer-toggle"
    onClick={() => setDrawerOpen(true)}
  >
    <span />
    <span />
    <span />
  </button>

  {/* Mobile: overlay */}
  <div
    className={`drawer-overlay ${drawerOpen ? "open" : ""}`}
    onClick={() => setDrawerOpen(false)}
  />

  {/* Mobile: drawer panel */}
  <nav className={`drawer-panel ${drawerOpen ? "open" : ""}`}>
    <span className="drawer-title">Categorías</span>
    {categories.map((cat) => (
      <button className="drawer-item">{/* ... */}</button>
    ))}
  </nav>
</>
The drawer implementation requires both CSS media queries and JavaScript state management to work correctly. Don’t forget to implement the keyboard escape handler for accessibility.

Animation and Transitions

Smooth transitions enhance the user experience:

Hover Effects

.product-card {
  transition: 0.3s;
}

.product-card:hover {
  transform: translateY(-5px);
}

.category-icon {
  transition: 0.3s;
}

.category-btn:hover .category-icon {
  border-color: #ec1313;
  color: #ec1313;
  transform: scale(1.06);
}

Button Transitions

.product-btn {
  background-color: #ec1313;
  cursor: pointer;
  transition: background-color 0.3s;
}

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

Drawer Animation

.drawer-panel {
  transform: translateX(-100%);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.drawer-panel.open {
  transform: translateX(0);
}
Use cubic-bezier easing functions for more natural, polished animations. The drawer uses cubic-bezier(0.4, 0, 0.2, 1) for a smooth deceleration effect.

Layout Patterns

src/components/navbar/Navbar.css
.navbar-wrapper {
  width: 100%;
  background-color: #121212;
  border-bottom: 1px solid #2a2a2a;
  position: sticky;
  top: 0;
  z-index: 1000;
}

Centered Content Container

.navbar {
  max-width: 1600px;
  margin: auto;
  padding: 15px 40px;
}

Flexbox Patterns

/* Space-between layout */
.product-info {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
}

/* Centered icon container */
.category-icon {
  display: flex;
  align-items: center;
  justify-content: center;
}

Grid System

.navbar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}

Image Optimization

Consistent image sizing with object-fit:
.product-card img {
  width: 100%;
  height: 200px;        /* Fixed height */
  object-fit: cover;    /* Crop without distortion */
  border-radius: 10px;
  display: block;
}

.navbar-logo {
  width: 60px;
  height: 60px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid #ec1313;
  box-shadow: 0 0 15px rgba(236, 19, 19, 0.4);
}
Using object-fit: cover ensures images maintain their aspect ratio while filling their containers, preventing distortion.

Best Practices

Scoped Styles

Keep CSS files co-located with their components

BEM Naming

Use consistent, descriptive class names

Transitions

Add smooth transitions for interactive elements

Responsive

Test all breakpoints and implement mobile patterns

Next Steps

Development Setup

Set up your development environment

Project Structure

Understand the codebase organization

Build docs developers (and LLMs) love