Files
gkachele-saas/demo/themes/restaurante-moderno/template.html

686 lines
24 KiB
HTML

<!DOCTYPE html>
<!--
GKACHELE™ SaaS PageBuilder - Tema Restaurante Moderno
© 2025 GKACHELE. Todos los derechos reservados.
Desarrollado desde noviembre 2024 por GKACHELE
Código propiedad de GKACHELE - Prohibida su reproducción sin autorización
-->
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ site_name or 'Restaurante' }}</title>
<!-- Design Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
:root {
--primary: {
{
colors.primary if colors else '#c94040'
}
}
;
--primary-rgb: 201,
64,
64;
--dark: #0f172a;
--white: #ffffff;
--bg-body: #f8fafc;
--bg-light: #f1f5f9;
--text-main: #1e293b;
--text-muted: #64748b;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 20px 25px -5px rgb(0 0 0 / 0.1);
--transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Outfit', sans-serif;
color: var(--text-main);
background: var(--bg-body);
line-height: 1.7;
-webkit-font-smoothing: antialiased;
padding-top: 80px;
}
h1,
h2,
h3,
.logo {
font-family: 'Playfair Display', serif;
font-weight: 800;
}
.section {
padding: 100px 20px;
position: relative;
}
.container {
max-width: 1100px;
margin: 0 auto;
}
/* header / Nav */
header {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
position: fixed;
top: 0;
width: 100%;
z-index: 1000;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
transition: var(--transition);
}
nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 40px;
max-width: 1200px;
margin: 0 auto;
position: relative;
}
.logo {
font-size: 26px;
color: var(--primary);
letter-spacing: -1px;
text-decoration: none;
}
.nav-links {
display: flex;
list-style: none;
gap: 30px;
}
.nav-links a {
text-decoration: none;
color: var(--text-main);
font-weight: 600;
font-size: 13px;
text-transform: uppercase;
letter-spacing: 1px;
transition: color 0.3s;
}
.nav-links a:hover {
color: var(--primary);
}
.menu-toggle {
display: none;
font-size: 24px;
color: var(--text-main);
cursor: pointer;
padding: 10px;
}
/* Hero */
.hero {
height: 85vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(rgba(15, 23, 42, 0.6), rgba(15, 23, 42, 0.6)),
url('https://images.unsplash.com/photo-1514362545857-3bc16c4c7d1b?auto=format&fit=crop&w=1920&q=80');
background-size: cover;
background-position: center;
color: var(--white);
text-align: center;
border-radius: 0 0 40px 40px;
margin: 0 10px;
}
.hero h1 {
font-size: 80px;
margin-bottom: 24px;
line-height: 1.1;
}
.hero p {
font-size: 22px;
font-weight: 300;
opacity: 0.9;
max-width: 700px;
margin: 0 auto 40px;
}
.btn {
display: inline-block;
padding: 18px 45px;
background: var(--primary);
color: var(--white);
text-decoration: none;
border-radius: 100px;
font-weight: 600;
font-size: 16px;
transition: var(--transition);
box-shadow: 0 10px 20px rgba(var(--primary-rgb), 0.3);
}
.btn:hover {
transform: translateY(-5px);
box-shadow: 0 15px 30px rgba(var(--primary-rgb), 0.5);
}
/* Menu Section */
.section-title {
text-align: center;
font-size: 48px;
margin-bottom: 80px;
position: relative;
}
.section-title::after {
content: '';
position: absolute;
bottom: -15px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 3px;
background: var(--primary);
}
.menu-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
}
.menu-item {
background: var(--white);
padding: 40px;
border-radius: 24px;
transition: var(--transition);
box-shadow: var(--shadow-md);
border: 1px solid rgba(0, 0, 0, 0.02);
display: flex;
flex-direction: column;
justify-content: space-between;
}
.menu-item:hover {
transform: translateY(-10px);
box-shadow: var(--shadow-lg);
}
.menu-price {
font-size: 24px;
font-weight: 800;
color: var(--primary);
margin-top: 20px;
}
.category-badge {
background: var(--bg-light);
color: var(--primary);
padding: 4px 12px;
border-radius: 20px;
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
border: 1px solid var(--primary);
}
/* Experience */
.horarios {
background: var(--white);
}
.horario-item {
background: var(--bg-body);
padding: 40px;
border-radius: 20px;
text-align: center;
border: 1px solid rgba(0, 0, 0, 0.03);
transition: var(--transition);
}
.contacto {
background: var(--dark);
color: var(--white);
}
.contacto .section-title {
color: var(--white);
}
.contacto-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 80px;
}
.contacto-info h3 {
border-left: 4px solid var(--primary);
padding-left: 20px;
margin-bottom: 25px;
}
/* Redes Sociales */
.redes-sociales {
display: flex;
gap: 15px;
margin-top: 20px;
}
.social-icon {
width: 44px;
height: 44px;
background: rgba(255, 255, 255, 0.1);
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
text-decoration: none;
transition: 0.3s;
}
.social-icon:hover {
background: var(--primary);
transform: translateY(-3px);
}
/* GK-Blocks UI */
.dynamic-blocks-wrapper {
margin: 40px 0;
}
.gk-block {
padding: 80px 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.gk-editable:hover {
outline: 2px solid var(--primary);
outline-offset: 4px;
border-radius: 4px;
background: rgba(201, 64, 64, 0.05);
cursor: pointer;
}
/* WhatsApp */
.whatsapp-float {
position: fixed;
bottom: 40px;
right: 40px;
background: #25d366;
color: white;
width: 64px;
height: 64px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
box-shadow: 0 10px 25px rgba(37, 211, 102, 0.4);
z-index: 9999;
text-decoration: none;
transition: 0.3s;
}
.whatsapp-float:hover {
transform: scale(1.1) rotate(5deg);
}
/* Responsive */
@media (max-width: 992px) {
.hero h1 {
font-size: 56px;
}
.section {
padding: 60px 20px;
}
}
@media (max-width: 768px) {
nav {
padding: 15px 20px;
}
.menu-toggle {
display: block;
}
.nav-links {
display: none;
flex-direction: column;
position: absolute;
top: 100%;
left: 0;
width: 100%;
background: white;
padding: 20px;
box-shadow: var(--shadow-lg);
gap: 20px;
z-index: 1000;
}
.nav-links.active {
display: flex !important;
}
.hero h1 {
font-size: 42px;
}
.contacto-content {
grid-template-columns: 1fr;
gap: 40px;
}
}
</style>
<script>
// Real-time Content Sync and Click-to-Edit Core
(function () {
if (window.parent !== window) {
window.addEventListener('message', function (e) {
if (!e.data) return;
if (e.data.type === 'update-content') {
updateDOMWithContent(e.data.content);
} else if (e.data.type === 'add-block') {
location.reload(); // Blocks are structural, hard to sync perfectly without a full re-render
} else if (e.data.type === 'remove-block') {
const el = document.querySelector(`[data-block-id="${e.data.block_id}"]`);
if (el) el.remove();
} else if (e.data.type === 'reorder-blocks') {
location.reload();
}
});
}
function updateDOMWithContent(content) {
if (!content) return;
// Base fields
const siteNameEls = document.querySelectorAll('[data-editable="site_name"], .site-name-sync');
siteNameEls.forEach(el => el.textContent = content.site_name);
const heroTitleEl = document.querySelector('[data-editable="hero_title"]');
if (heroTitleEl && content.hero_title) heroTitleEl.textContent = content.hero_title;
const heroDescEl = document.querySelector('[data-editable="hero_description"]');
if (heroDescEl && content.hero_description) heroDescEl.textContent = content.hero_description;
// Colors
if (content.colors && content.colors.primary) {
document.documentElement.style.setProperty('--primary', content.colors.primary);
}
// Contact
const direccionEl = document.querySelector('[data-editable="direccion"]');
if (direccionEl && content.direccion) direccionEl.textContent = content.direccion;
const telefonoEl = document.querySelector('[data-editable="telefono"]');
if (telefonoEl && content.telefono) telefonoEl.textContent = content.telefono;
const emailEl = document.querySelector('[data-editable="email"]');
if (emailEl && content.email) emailEl.textContent = content.email;
// MAP REGENERATION (Fixed variable scope)
const mapWrapper = document.getElementById('map-wrapper');
if (mapWrapper && content.direccion) {
const cleanAddress = content.direccion.trim().replace(/\s+/g, ' ');
const encoded = encodeURIComponent(cleanAddress);
const mapUrl = `https://www.google.com/maps?q=${encoded}&output=embed`;
mapWrapper.innerHTML = `<iframe src="${mapUrl}" width="100%" height="100%" style="border:0;" allowfullscreen="" loading="lazy"></iframe>`;
}
// SOCIAL MEDIA SYNC (Fixed variable scope)
const socialContainer = document.querySelector('.redes-sociales');
if (socialContainer && content.redes_sociales) {
socialContainer.innerHTML = '';
const redes = content.redes_sociales;
const icons = {
facebook: 'fa-facebook',
instagram: 'fa-instagram',
tiktok: 'fa-tiktok',
linkedin: 'fa-linkedin',
youtube: 'fa-youtube',
whatsapp: 'fa-whatsapp'
};
Object.keys(icons).forEach(key => {
if (redes[key]) {
const a = document.createElement('a');
a.href = redes[key];
a.className = 'social-icon';
a.target = '_blank';
a.innerHTML = `<i class="fab ${icons[key]}"></i>`;
socialContainer.appendChild(a);
}
});
}
}
document.addEventListener('DOMContentLoaded', function () {
// Inline Edit Listener
const editables = document.querySelectorAll('.gk-editable');
editables.forEach(el => {
el.addEventListener('click', function (e) {
e.preventDefault(); e.stopPropagation();
window.parent.postMessage({
type: 'gk-edit-field',
field: this.dataset.editable,
value: this.textContent.trim(),
type_field: this.dataset.type || 'text'
}, '*');
});
});
// Mobile Menu Toggle Logic Robust
const toggle = document.querySelector('.menu-toggle');
const nav = document.querySelector('.nav-links');
if (toggle && nav) {
toggle.addEventListener('click', (e) => {
e.stopPropagation();
nav.classList.toggle('active');
toggle.querySelector('i').classList.toggle('fa-bars');
toggle.querySelector('i').classList.toggle('fa-times');
});
document.addEventListener('click', () => nav.classList.remove('active'));
nav.addEventListener('click', (e) => e.stopPropagation());
}
});
})();
</script>
</head>
<body>
<!-- Header -->
<header>
<nav>
<a href="#inicio" class="logo gk-editable" data-editable="site_name" data-type="text">{{ site_name or
'Restaurante' }}</a>
<div class="menu-toggle">
<i class="fas fa-bars"></i>
</div>
<ul class="nav-links">
<li><a href="#inicio">Inicio</a></li>
<li><a href="#menu">Menú</a></li>
<li><a href="#horarios">Horarios</a></li>
<li><a href="#reservas">Reservas</a></li>
<li><a href="#contacto">Contacto</a></li>
</ul>
</nav>
</header>
<!-- Hero -->
<section id="inicio" class="section hero">
<div class="container">
<h1 data-editable="hero_title" data-type="text" class="gk-editable">{{ hero_title or 'Sabores que Enamoran'
}}</h1>
<p data-editable="hero_description" data-type="textarea" class="gk-editable">{{ hero_description or 'Una
experiencia gastronómica de alta cocina en el corazón de la ciudad.' }}</p>
<a href="#reservas" class="btn">Reservar Mesa</a>
</div>
</section>
<!-- Menu -->
<section id="menu" class="section">
<div class="container">
<h2 class="section-title">Nuestro Menú</h2>
<div class="menu-grid" id="menu-items-container">
{% if menu_items %}
{% for item_id, item in menu_items.items() %}
<div class="menu-item" data-item-id="{{ item_id }}">
<div>
<div
style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<h3 class="gk-editable" data-editable="menu_items.{{ item_id }}.nombre">{{ item.nombre or
'Plato' }}</h3>
<span class="category-badge">{{ item.categoria or 'Chef Choice' }}</span>
</div>
<p class="gk-editable" data-editable="menu_items.{{ item_id }}.descripcion"
style="font-size: 14px; color: var(--text-muted);">{{ item.descripcion or 'Preparado con
ingredientes premium.' }}</p>
</div>
<div class="menu-price gk-editable" data-editable="menu_items.{{ item_id }}.precio">${{ item.precio
or '0.00' }}</div>
</div>
{% endfor %}
{% else %}
<!-- Placeholder Items -->
<div class="menu-item">
<h3>Plato Demo 1</h3>
<p>Descripción deliciosa...</p>
<div class="menu-price">$25.00</div>
</div>
<div class="menu-item">
<h3>Plato Demo 2</h3>
<p>Descripción deliciosa...</p>
<div class="menu-price">$30.00</div>
</div>
{% endif %}
</div>
</div>
</section>
<!-- Horarios -->
<section id="horarios" class="section horarios">
<div class="container">
<h2 class="section-title">Horarios</h2>
<div class="menu-grid">
<div class="horario-item">
<h3>Lunes a Viernes</h3>
<p class="gk-editable" data-editable="horarios.lunes_viernes">{{ horarios.lunes_viernes or '12:00 -
22:00' }}</p>
</div>
<div class="horario-item">
<h3>Sábados</h3>
<p class="gk-editable" data-editable="horarios.sabados">{{ horarios.sabados or '12:00 - 23:00' }}
</p>
</div>
<div class="horario-item">
<h3>Domingos</h3>
<p class="gk-editable" data-editable="horarios.domingos">{{ horarios.domingos or '12:00 - 18:00' }}
</p>
</div>
</div>
</div>
</section>
<!-- Reservas -->
<section id="reservas" class="section">
<div class="container" style="max-width: 600px; text-align: center;">
<h2 class="section-title">Reservas</h2>
<p style="margin-bottom: 40px;">¿Deseas asegurar tu lugar? Llámanos o escríbenos directamente.</p>
<a href="tel:{{ telefono or '' }}" class="btn" style="background: var(--dark);">Llamar Ahora</a>
</div>
</section>
<!-- Blocks -->
<div class="dynamic-blocks-wrapper">
{% if blocks %}
{% for block in blocks|sort(attribute='order') %}
<section class="gk-block" data-block-id="{{ block.id }}">
<div class="container">
{% if block.type == 'texto' %}
<h2 class="gk-editable" data-editable="blocks.{{ block.id }}.content.titulo">{{ block.content.titulo or
'Título' }}</h2>
<p class="gk-editable" data-editable="blocks.{{ block.id }}.content.contenido">{{
block.content.contenido or 'Texto...' }}</p>
{% elif block.type == 'imagen' %}
<img src="{{ block.content.url }}" style="width: 100%; border-radius: 20px;">
{% endif %}
</div>
</section>
{% endfor %}
{% endif %}
</div>
<!-- Contacto -->
<section id="contacto" class="section contacto">
<div class="container">
<div class="contacto-content">
<div class="contacto-info">
<h3>Visítanos</h3>
<p><strong>Dirección:</strong> <span class="gk-editable" data-editable="direccion">{{ direccion or
'Calle Gourmet 123' }}</span></p>
<p><strong>Teléfono:</strong> <span class="gk-editable" data-editable="telefono">{{ telefono or '+00
000 000' }}</span></p>
<p><strong>Email:</strong> <span class="gk-editable" data-editable="email">{{ email or
'hola@restaurante.com' }}</span></p>
<div class="redes-sociales">
{% if redes_sociales.facebook %}<a href="{{ redes_sociales.facebook }}" class="social-icon"><i
class="fab fa-facebook"></i></a>{% endif %}
{% if redes_sociales.instagram %}<a href="{{ redes_sociales.instagram }}" class="social-icon"><i
class="fab fa-instagram"></i></a>{% endif %}
</div>
</div>
<div class="contacto-info">
<h3>Localización</h3>
<div id="map-wrapper"
style="border-radius: 20px; overflow: hidden; height: 300px; background: #334155;">
{% if mapa_url %}
<iframe src="{{ mapa_url }}" width="100%" height="100%" style="border:0;" allowfullscreen=""
loading="lazy"></iframe>
{% else %}
<div style="padding: 100px; text-align: center; color: #94a3b8;">Mapa Interactivo (Introduce
dirección)</div>
{% endif %}
</div>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer style="padding: 40px; text-align: center; font-size: 14px; opacity: 0.6;">
<p>&copy; 2025 {{ site_name or 'Restaurante' }}. Design Premium GK.</p>
</footer>
{% if redes_sociales.whatsapp %}
<a href="https://wa.me/{{ redes_sociales.whatsapp }}" class="whatsapp-float" target="_blank">
<i class="fab fa-whatsapp"></i>
</a>
{% endif %}
</body>
</html>