Cevichería El Sabor Marino is a Django-powered single-page restaurant site that combines a rich ocean-themed visual identity with practical customer-facing functionality. The application is built on Python/Django with an SQLite database and uses jQuery, Owl Carousel, and custom vanilla JavaScript for all client-side interactions. This page documents every feature in detail so that developers and contributors understand exactly what is implemented and how each piece works.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/diazdavilajesus16-stack/Sevicheria-Mar-sabroso/llms.txt
Use this file to discover all available pages before exploring further.
Ocean-themed UI
CSS-animated fish, bubbles, seaweed, and plants create an immersive underwater atmosphere.
Hero carousel
3-slide full-width carousel with auto-play every 5 s, dot navigation, and prev/next controls.
Menu carousel
8 dishes in an Owl Carousel that adapts from 1 item on mobile to 3 on desktop.
Shopping cart
Client-side cart backed by a JavaScript array with toast notifications on every addition.
Promotions carousel
4 combo deals in an Owl Carousel that auto-advances every 4 s.
Contact form
Reservation form with client-side validation and an inline success confirmation message.
Scroll-reveal animations
Elements with
.scroll-reveal, .scroll-left, and .scroll-right animate in as they enter the viewport.Modal dialogs
Dish-detail modals opened with
abrirModal() and closed with cerrarModal().Ocean-themed animated UI
The page establishes its visual identity through a set of purely CSS-driven decorative elements layered behind the content.| Element type | CSS identifiers | Description |
|---|---|---|
| Fish | fish1 – fish9 | Nine independently animated fish that drift across the screen at varying speeds and directions. |
| Bubbles | bubble (multiple) | Rising bubble elements that float upward in a loop. |
| Seaweed | phaeo1 – phaeo4 | Four swaying seaweed elements anchored to the bottom of relevant sections. |
| Plants | plant1 – plant5 | Five decorative plant elements placed at section edges. |
All decorative elements are purely presentational and do not affect layout or interactivity. They are implemented entirely in
static/assets/css/estilo.css and require no JavaScript.Hero carousel
The main banner occupies the full viewport width and cycles through three slides that communicate the restaurant’s core offerings.| Slide | Headline |
|---|---|
| 1 | EL VERDADERO SABOR DEL MAR |
| 2 | CEVICHES PREMIUM |
| 3 | LECHE DE TIGRE |
static/assets/js/carrusel.js using the .carousel-track, .carousel-btn.next, .carousel-btn.prev, and .carousel-dots DOM elements.
How it works:
Initialization
On page load, the script reads all child elements of
.carousel-track as slides and programmatically creates one <span> dot per slide inside .carousel-dots. The first dot receives the active class.Navigation
Clicking
.carousel-btn.next increments slideIndex modulo the slide count. Clicking .carousel-btn.prev decrements it (wrapping via + slides.length). Clicking a dot sets slideIndex directly to that dot’s index.Visual update
updateCarousel() applies transform: translateX(-${slideIndex * 100}%) to the track and syncs the active class to the current dot.carrusel.js
Owl Carousel menu
The#menu section renders 8 dishes using the Owl Carousel 2.3.4 library, giving a touch-friendly draggable carousel that is fully responsive.
Available dishes
| Dish | Price |
|---|---|
| Ceviche Clásico | S/25 |
| Ceviche Mixto | S/30 |
| Pulpo a la Parrilla | S/40 |
| Langostinos al Ajillo | S/35 |
| Arroz con Mariscos | S/28 |
| Pescado a la Plancha | S/27 |
| Calamares Rellenos | S/32 |
| Chupe de Camarones | S/26 |
Responsive breakpoints
| Viewport width | Items visible |
|---|---|
| < 600 px (mobile) | 1 |
| ≥ 600 px (tablet) | 2 |
| ≥ 1000 px (desktop) | 3 |
Django data model
Each dish corresponds to aPlato instance in the database. The Plato model is defined in menu/models.py:
menu/models.py
disponible flag controls whether a dish appears on the menu without requiring a database deletion.
Shopping cart
The cart is a pure client-side feature backed by a JavaScript array. No server round-trip occurs when items are added.home.html
- The user clicks an “Add to cart” button on a dish card, which calls
agregarCarrito(nombre, precio). - The item object
{ nombre, precio }is pushed to thecarritoarray. mostrarNotificacion()creates a.toastelement, appends it to<body>, adds theshowclass after 100 ms, then removes it after 2,500 ms.actualizarCarrito()logs the current cart state to the console.
toggleCarrito(), which shows or hides the cart sidebar/panel.
The current implementation persists the cart only in memory. Refreshing the page clears all cart items. There is no checkout or payment flow — the cart is a UI prototype.
Toast notification implementation
home.html
Promotions carousel
The promotions section presents four combo deals in a second Owl Carousel instance, separate from the menu carousel.| Combo | Price |
|---|---|
| Combo Mar y Tierra | S/35 |
| Combo Tradicional | S/28 |
| Conchas Negras Premium | S/25 |
| Ceviche Supremo de Mariscos | S/15 |
About us and chef section
The about-us section and the chef history section are static content areas that use the scroll-reveal animation system for entrance effects.- About us — describes the restaurant’s history and philosophy.
- Chef section — presents the history of Chef Teresa Goicochea through a set of styled history cards.
These sections contain no dynamic data and are rendered directly from the
core/templates/home.html template without Django model queries.Contact and reservation form
The#contact section provides a form with three fields: name, email, and message.
| Field | Type | Purpose |
|---|---|---|
| Name | Text input | Guest’s full name |
| Email input | Contact address for confirmation | |
| Message | Textarea | Reservation details or questions |
- Client-side validation runs before submission to ensure all fields are filled and the email address is well-formed.
- On successful validation, the form displays an inline success confirmation message to the user.
- No page reload occurs; the feedback is shown dynamically within the form container.
Scroll-reveal animations
Entrance animations are triggered by a scroll event listener that checks whether an element has entered the viewport.home.html
| CSS class | Animation direction |
|---|---|
.scroll-reveal | Fade in (vertical) |
.scroll-left | Slide in from the left |
.scroll-right | Slide in from the right |
show class is added once an element’s top edge is within 150 px of the bottom of the viewport. The load event handler ensures elements already visible on page load animate in immediately without requiring a scroll.
Responsive design
The layout adapts across three primary breakpoints using CSS media queries defined instatic/assets/css/estilo.css.
| Breakpoint | Target devices | Menu items shown |
|---|---|---|
| < 600 px | Mobile phones | 1 |
| 600 px – 999 px | Tablets | 2 |
| ≥ 1000 px | Desktops | 3 |
Modal dialogs
Each dish card can trigger a detail modal that overlays the page with the dish name and description.home.html
| Element ID | Role |
|---|---|
modal | The overlay container shown/hidden by toggling display |
modalTitulo | <h> element populated with the dish name |
modalDesc | <p> element populated with the dish description |
abrirModal(nombre, desc) is called from the dish card’s action button, passing the dish’s name and description strings. cerrarModal() hides the overlay by setting display back to "none".
Tech stack summary
Tech stack summary
| Layer | Technology |
|---|---|
| Backend | Python 3, Django |
| Database | SQLite |
| Frontend markup | HTML5, CSS3 (estilo.css) |
| JavaScript | Vanilla JS + jQuery 3.6.0 |
| Carousel | Owl Carousel 2.3.4 |
| Typography | Poppins (Google Fonts) |
| Containerization | Docker + docker-compose |
Navbar links
Navbar links
Restaurant contact details
Restaurant contact details
The footer displays static contact information:
- Address: Av. Principal 123 – Lima, Perú
- Hours: Monday – Sunday, 11:00 am – 10:00 pm
- Phone and email are also listed in the footer.