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:
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:
< 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 typeface Weights: 400, 500, 700, 800
Material Symbols Icon font for UI elements Outlined style
Color System
The application uses a consistent dark theme color palette:
Purpose Color Hex Code Background Primary Black #121212Background Secondary Dark Gray #1E1E1EBackground Tertiary Darker Gray #1a1a1aBorder Gray #2a2a2aText Primary Off-white #f5f5f5Text Secondary Light Gray #aaaText Muted Gray #888Accent Red Red #ec1313Accent Red Hover Dark Red #c40b0bAccent Yellow Yellow #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 : 15 px ;
padding : 15 px ;
position : relative ;
transition : 0.3 s ;
}
.product-card:hover {
transform : translateY ( -5 px );
}
.product-card img {
width : 100 % ;
height : 200 px ;
object-fit : cover ;
border-radius : 10 px ;
display : block ;
}
.product-info {
display : flex ;
justify-content : space-between ;
margin-top : 10 px ;
}
.product-info h4 {
margin : 0 ;
}
.product-info span {
color : #FFD60A ;
font-weight : bold ;
}
.product-btn {
width : 100 % ;
margin-top : 15 px ;
padding : 10 px ;
background-color : #ec1313 ;
border : none ;
border-radius : 10 px ;
color : white ;
font-weight : bold ;
cursor : pointer ;
}
.product-btn:hover {
background-color : #c40b0b ;
}
.badge {
position : absolute ;
top : 10 px ;
right : 10 px ;
background-color : #FFD60A ;
color : black ;
padding : 4 px 8 px ;
border-radius : 20 px ;
font-size : 12 px ;
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 : 48 px ;
height : 48 px ;
border-radius : 14 px ;
background-color : #1E1E1E ;
border : 1 px solid #2a2a2a ;
display : flex ;
align-items : center ;
justify-content : center ;
font-size : 22 px ;
transition : 0.3 s ;
}
.category-btn.active .category-icon {
background-color : #ec1313 ;
color : white ;
border : none ;
box-shadow : 0 0 12 px 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:
Breakpoint Width Target Devices Mobile < 768pxPhones Tablet 768px - 1024pxTablets Desktop > 1024pxDesktops
Navbar Responsive Pattern
src/components/navbar/Navbar.css
@media ( max-width : 768 px ) {
.navbar {
grid-template-columns : 1 fr auto ;
padding : 10 px 20 px ;
}
.order-btn {
padding : 8 px 20 px ;
font-size : 14 px ;
}
}
Grid Layout Adjustments
.navbar {
max-width : 1600 px ;
margin : auto ;
display : grid ;
grid-template-columns : 1 fr auto 1 fr ; /* Desktop: 3 columns */
align-items : center ;
padding : 15 px 40 px ;
}
@media ( max-width : 768 px ) {
.navbar {
grid-template-columns : 1 fr auto ; /* Mobile: 2 columns */
padding : 10 px 20 px ;
}
}
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 : 18 px ;
}
Mobile View
Hamburger menu with slide-in drawer:
@media ( max-width : 768 px ) {
/* Hide desktop menu */
.categories-wrapper ,
.categories-container {
display : none ;
}
/* Hamburger button */
.drawer-toggle {
display : flex ;
flex-direction : column ;
justify-content : center ;
gap : 5 px ;
width : 40 px ;
height : 40 px ;
padding : 8 px ;
background : #1e1e1e ;
border : 1 px solid #2a2a2a ;
border-radius : 10 px ;
cursor : pointer ;
transition : border-color 0.2 s ;
}
/* Dark overlay */
.drawer-overlay {
display : block ;
position : fixed ;
inset : 0 ;
background : rgba ( 0 , 0 , 0 , 0.65 );
backdrop-filter : blur ( 3 px );
z-index : 100 ;
opacity : 0 ;
pointer-events : none ;
transition : opacity 0.3 s 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 : 260 px ;
background : #1a1a1a ;
border-right : 1 px solid #2a2a2a ;
z-index : 101 ;
flex-direction : column ;
padding : 72 px 12 px 32 px ;
gap : 4 px ;
transform : translateX ( -100 % );
transition : transform 0.3 s cubic-bezier ( 0.4 , 0 , 0.2 , 1 );
}
.drawer-panel.open {
transform : translateX ( 0 );
}
}
Hamburger Button
Three-line icon that opens the drawer
Dark Overlay
Backdrop with blur effect that closes drawer when clicked
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.3 s ;
}
.product-card:hover {
transform : translateY ( -5 px );
}
.category-icon {
transition : 0.3 s ;
}
.category-btn:hover .category-icon {
border-color : #ec1313 ;
color : #ec1313 ;
transform : scale ( 1.06 );
}
.product-btn {
background-color : #ec1313 ;
cursor : pointer ;
transition : background-color 0.3 s ;
}
.product-btn:hover {
background-color : #c40b0b ;
}
Drawer Animation
.drawer-panel {
transform : translateX ( -100 % );
transition : transform 0.3 s 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
Sticky Navigation
src/components/navbar/Navbar.css
.navbar-wrapper {
width : 100 % ;
background-color : #121212 ;
border-bottom : 1 px solid #2a2a2a ;
position : sticky ;
top : 0 ;
z-index : 1000 ;
}
Centered Content Container
.navbar {
max-width : 1600 px ;
margin : auto ;
padding : 15 px 40 px ;
}
Flexbox Patterns
/* Space-between layout */
.product-info {
display : flex ;
justify-content : space-between ;
margin-top : 10 px ;
}
/* Centered icon container */
.category-icon {
display : flex ;
align-items : center ;
justify-content : center ;
}
Grid System
.navbar {
display : grid ;
grid-template-columns : 1 fr auto 1 fr ;
align-items : center ;
}
Image Optimization
Consistent image sizing with object-fit:
.product-card img {
width : 100 % ;
height : 200 px ; /* Fixed height */
object-fit : cover ; /* Crop without distortion */
border-radius : 10 px ;
display : block ;
}
.navbar-logo {
width : 60 px ;
height : 60 px ;
border-radius : 50 % ;
object-fit : cover ;
border : 3 px solid #ec1313 ;
box-shadow : 0 0 15 px 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