Skip to main content

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.

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.

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 typeCSS identifiersDescription
Fishfish1fish9Nine independently animated fish that drift across the screen at varying speeds and directions.
Bubblesbubble (multiple)Rising bubble elements that float upward in a loop.
Seaweedphaeo1phaeo4Four swaying seaweed elements anchored to the bottom of relevant sections.
Plantsplant1plant5Five 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.

The main banner occupies the full viewport width and cycles through three slides that communicate the restaurant’s core offerings.
SlideHeadline
1EL VERDADERO SABOR DEL MAR
2CEVICHES PREMIUM
3LECHE DE TIGRE
The carousel is implemented in static/assets/js/carrusel.js using the .carousel-track, .carousel-btn.next, .carousel-btn.prev, and .carousel-dots DOM elements. How it works:
1

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.
2

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.
3

Visual update

updateCarousel() applies transform: translateX(-${slideIndex * 100}%) to the track and syncs the active class to the current dot.
4

Auto-play

setInterval advances slideIndex every 5,000 ms and calls updateCarousel() automatically.
carrusel.js
setInterval(() => {
  slideIndex = (slideIndex + 1) % slides.length;
  updateCarousel();
}, 5000);

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

DishPrice
Ceviche ClásicoS/25
Ceviche MixtoS/30
Pulpo a la ParrillaS/40
Langostinos al AjilloS/35
Arroz con MariscosS/28
Pescado a la PlanchaS/27
Calamares RellenosS/32
Chupe de CamaronesS/26

Responsive breakpoints

Viewport widthItems visible
< 600 px (mobile)1
≥ 600 px (tablet)2
≥ 1000 px (desktop)3
The menu auto-plays every 3,500 ms. Users can still drag or swipe between items without interrupting the timer.

Django data model

Each dish corresponds to a Plato instance in the database. The Plato model is defined in menu/models.py:
menu/models.py
class Categoria(models.Model):
    nombre = models.CharField(max_length=100)

class Plato(models.Model):
    categoria = models.ForeignKey(Categoria, on_delete=models.CASCADE)
    nombre    = models.CharField(max_length=200)
    descripcion = models.TextField()
    precio    = models.DecimalField(max_digits=8, decimal_places=2)
    imagen    = models.ImageField(upload_to='platos/')
    disponible = models.BooleanField(default=True)
    creado    = models.DateTimeField(auto_now_add=True)
The 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
let carrito = [];

function agregarCarrito(nombre, precio) {
    carrito.push({ nombre, precio });
    mostrarNotificacion(nombre + " agregado 🛒");
    actualizarCarrito();
}

function actualizarCarrito() {
    console.log(carrito);
}
User flow:
  1. The user clicks an “Add to cart” button on a dish card, which calls agregarCarrito(nombre, precio).
  2. The item object { nombre, precio } is pushed to the carrito array.
  3. mostrarNotificacion() creates a .toast element, appends it to <body>, adds the show class after 100 ms, then removes it after 2,500 ms.
  4. actualizarCarrito() logs the current cart state to the console.
The cart icon in the navbar is toggled via 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
function mostrarNotificacion(msg) {
    const notif = document.createElement("div");
    notif.className = "toast";
    notif.innerText = msg;
    document.body.appendChild(notif);
    setTimeout(() => notif.classList.add("show"), 100);
    setTimeout(() => {
        notif.classList.remove("show");
        setTimeout(() => notif.remove(), 300);
    }, 2500);
}

The promotions section presents four combo deals in a second Owl Carousel instance, separate from the menu carousel.
ComboPrice
Combo Mar y TierraS/35
Combo TradicionalS/28
Conchas Negras PremiumS/25
Ceviche Supremo de MariscosS/15
The promotions carousel auto-plays every 4,000 ms. It shares the Owl Carousel library configuration pattern used by the menu section but is configured independently with its own auto-play interval.

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.
FieldTypePurpose
NameText inputGuest’s full name
EmailEmail inputContact address for confirmation
MessageTextareaReservation details or questions
Behavior:
  • 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.
The form uses client-side validation only. Server-side validation and actual email delivery are not configured in the base project. Before deploying to production, add Django form validation and connect an email backend (e.g., SMTP or SendGrid).

Scroll-reveal animations

Entrance animations are triggered by a scroll event listener that checks whether an element has entered the viewport.
home.html
const scrollElements = document.querySelectorAll(
    '.scroll-reveal, .scroll-left, .scroll-right'
);

const elementInView = (el, offset = 100) => {
    const elementTop = el.getBoundingClientRect().top;
    return elementTop <= (window.innerHeight - offset);
};

const displayScrollElement = (element) => {
    element.classList.add('show');
};

const handleScrollAnimation = () => {
    scrollElements.forEach(el => {
        if (elementInView(el, 150)) {
            displayScrollElement(el);
        }
    });
};

window.addEventListener('scroll', () => { handleScrollAnimation(); });
window.addEventListener('load',   () => { handleScrollAnimation(); });
CSS classAnimation direction
.scroll-revealFade in (vertical)
.scroll-leftSlide in from the left
.scroll-rightSlide in from the right
The 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.
Add .scroll-reveal, .scroll-left, or .scroll-right to any new section element to automatically opt it into the entrance animation system.

Responsive design

The layout adapts across three primary breakpoints using CSS media queries defined in static/assets/css/estilo.css.
BreakpointTarget devicesMenu items shown
< 600 pxMobile phones1
600 px – 999 pxTablets2
≥ 1000 pxDesktops3
The navbar, hero carousel, section layouts, and footer all reflow at these breakpoints. The Poppins font (loaded from Google Fonts) is used consistently at all screen sizes.
Each dish card can trigger a detail modal that overlays the page with the dish name and description.
home.html
function abrirModal(nombre, desc) {
    document.getElementById("modal").style.display = "block";
    document.getElementById("modalTitulo").innerText = nombre;
    document.getElementById("modalDesc").innerText = desc;
}

function cerrarModal() {
    document.getElementById("modal").style.display = "none";
}
DOM elements involved:
Element IDRole
modalThe 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".
LayerTechnology
BackendPython 3, Django
DatabaseSQLite
Frontend markupHTML5, CSS3 (estilo.css)
JavaScriptVanilla JS + jQuery 3.6.0
CarouselOwl Carousel 2.3.4
TypographyPoppins (Google Fonts)
ContainerizationDocker + docker-compose
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.

Build docs developers (and LLMs) love