chore: sync full current production website state to Gitea
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 3.2 KiB |
@@ -13,7 +13,7 @@
|
|||||||
* FUTURE:
|
* FUTURE:
|
||||||
* - When real online ordering launches, this page could show "Order from Askim"
|
* - When real online ordering launches, this page could show "Order from Askim"
|
||||||
* vs "Order from Backaplan" with different delivery radii.
|
* vs "Order from Backaplan" with different delivery radii.
|
||||||
* - Instagram handles for each location are mentioned where relevant.
|
* - Both branches now have the same opening hours.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Navbar from "@/components/Navbar";
|
import Navbar from "@/components/Navbar";
|
||||||
@@ -98,7 +98,7 @@ export default function LocationsPage() {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">OPENING HOURS</div>
|
<div className="text-[#B38B4D] text-xs tracking-widest mb-1">OPENING HOURS</div>
|
||||||
<div>Varies — please check our Instagram <span className="text-[#B38B4D]">@shahisweets_bp</span> for current hours.</div>
|
<div>Monday – Sunday • 11:00 – 21:00</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
+16
-50
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MENU PAGE — Premium Sidebar + Beautiful Loading Experience
|
* MENU PAGE — Premium Sidebar Navigation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useEffect, useState, useMemo } from "react";
|
import { useEffect, useState, useMemo } from "react";
|
||||||
@@ -11,26 +11,16 @@ import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|||||||
import Navbar from "@/components/Navbar";
|
import Navbar from "@/components/Navbar";
|
||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
import { useCart } from "@/components/CartContext";
|
import { useCart } from "@/components/CartContext";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
|
||||||
|
|
||||||
gsap.registerPlugin(ScrollTrigger);
|
gsap.registerPlugin(ScrollTrigger);
|
||||||
|
|
||||||
export default function MenuPage() {
|
export default function MenuPage() {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const [activeCategory, setActiveCategory] = useState("All");
|
const [activeCategory, setActiveCategory] = useState("All");
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [showVegetarianOnly, setShowVegetarianOnly] = useState(false);
|
const [showVegetarianOnly, setShowVegetarianOnly] = useState(false);
|
||||||
|
|
||||||
const { addToCart } = useCart();
|
const { addToCart } = useCart();
|
||||||
|
|
||||||
// Beautiful loading screen on initial load
|
|
||||||
useEffect(() => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setIsLoading(false);
|
|
||||||
}, 1350);
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Sidebar categories
|
// Sidebar categories
|
||||||
const sidebarCategories = [
|
const sidebarCategories = [
|
||||||
{ id: "All", name: "All Dishes" },
|
{ id: "All", name: "All Dishes" },
|
||||||
@@ -73,43 +63,6 @@ export default function MenuPage() {
|
|||||||
window.scrollTo({ top: 220, behavior: "smooth" });
|
window.scrollTo({ top: 220, behavior: "smooth" });
|
||||||
};
|
};
|
||||||
|
|
||||||
// === BEAUTIFUL LOADING SCREEN ===
|
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen bg-[#fbf7ef] flex items-center justify-center">
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="relative mx-auto mb-8 w-20 h-20">
|
|
||||||
<div className="absolute inset-0 rounded-full border-2 border-[#c99a2e]/30" />
|
|
||||||
<motion.div
|
|
||||||
className="absolute inset-0 rounded-full border-2 border-transparent border-t-[#c99a2e] border-r-[#d4a73d]"
|
|
||||||
animate={{ rotate: 360 }}
|
|
||||||
transition={{ duration: 1.3, repeat: Infinity, ease: "linear" }}
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-[6px] rounded-full border border-[#0f5a4a]/20" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-2">
|
|
||||||
<h2 className="font-serif text-3xl tracking-tight text-[#101724]">
|
|
||||||
Loading the Menu
|
|
||||||
</h2>
|
|
||||||
<p className="text-[#68717f] text-sm tracking-[1.5px]">Preparing the Royal Table...</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex justify-center gap-2 mt-6">
|
|
||||||
{[0, 1, 2].map((i) => (
|
|
||||||
<motion.div
|
|
||||||
key={i}
|
|
||||||
className="w-1.5 h-1.5 rounded-full bg-[#c99a2e]"
|
|
||||||
animate={{ opacity: [0.3, 1, 0.3] }}
|
|
||||||
transition={{ duration: 1.1, repeat: Infinity, delay: i * 0.18 }}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[#F8F5F0] text-[#2C2A26]">
|
<div className="min-h-screen bg-[#F8F5F0] text-[#2C2A26]">
|
||||||
<Navbar />
|
<Navbar />
|
||||||
@@ -270,7 +223,7 @@ export default function MenuPage() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Video on Hover */}
|
{/* Video on Hover - robust source selection with optimized fallbacks */}
|
||||||
<video
|
<video
|
||||||
muted
|
muted
|
||||||
loop
|
loop
|
||||||
@@ -278,7 +231,20 @@ export default function MenuPage() {
|
|||||||
preload="metadata"
|
preload="metadata"
|
||||||
className="absolute inset-0 w-full h-full object-cover opacity-0 group-hover:opacity-100 transition-opacity duration-150"
|
className="absolute inset-0 w-full h-full object-cover opacity-0 group-hover:opacity-100 transition-opacity duration-150"
|
||||||
>
|
>
|
||||||
<source src={`/videos/${item.video.replace(".mp4", ".webm")}`} type="video/webm" />
|
{/* Optimized variants first (smaller, better quality) */}
|
||||||
|
<source
|
||||||
|
src={`/videos/${item.video.replace(".mp4", "-optimized.webm")}`}
|
||||||
|
type="video/webm"
|
||||||
|
/>
|
||||||
|
<source
|
||||||
|
src={`/videos/${item.video.replace(".mp4", "-optimized.mp4")}`}
|
||||||
|
type="video/mp4"
|
||||||
|
/>
|
||||||
|
{/* Base variants as fallback */}
|
||||||
|
<source
|
||||||
|
src={`/videos/${item.video.replace(".mp4", ".webm")}`}
|
||||||
|
type="video/webm"
|
||||||
|
/>
|
||||||
<source src={`/videos/${item.video}`} type="video/mp4" />
|
<source src={`/videos/${item.video}`} type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -186,20 +186,21 @@ export default function ShahiKitchenHomepage() {
|
|||||||
|
|
||||||
{/* HERO - Full Banner Video with responsive framing */}
|
{/* HERO - Full Banner Video with responsive framing */}
|
||||||
<section className="relative min-h-[70dvh] sm:min-h-[78dvh] md:min-h-[85dvh] lg:min-h-[92dvh] xl:min-h-[100dvh]
|
<section className="relative min-h-[70dvh] sm:min-h-[78dvh] md:min-h-[85dvh] lg:min-h-[92dvh] xl:min-h-[100dvh]
|
||||||
flex items-center justify-center pt-20 lg:pt-[88px] overflow-hidden bg-[#fbf7ef]">
|
flex items-center justify-center pt-40 sm:pt-44 md:pt-52 lg:pt-[200px] xl:pt-[220px] overflow-hidden bg-[#fbf7ef]">
|
||||||
|
|
||||||
{/* Banner Video - Optimized positioning per device */}
|
{/* Banner Video - Optimized positioning per device */}
|
||||||
<video
|
<video
|
||||||
autoPlay
|
autoPlay
|
||||||
muted
|
muted
|
||||||
loop
|
|
||||||
playsInline
|
playsInline
|
||||||
|
preload="auto"
|
||||||
className="absolute inset-0 z-10 w-full h-full object-cover
|
className="absolute inset-0 z-10 w-full h-full object-cover
|
||||||
object-[50%_22%] sm:object-[50%_26%] md:object-[50%_30%]
|
object-[50%_10%] sm:object-[50%_12%] md:object-[50%_16%]
|
||||||
lg:object-[50%_35%] xl:object-[50%_38%]"
|
lg:object-[50%_20%] xl:object-[50%_24%]"
|
||||||
|
onError={(e) => console.error('Hero banner video failed to load', e)}
|
||||||
>
|
>
|
||||||
<source src="/videos/banner.webm" type="video/webm" />
|
{/* Using the compressed banner1.mp4 from images/logo as intended for the hero */}
|
||||||
<source src="/videos/banner.mp4" type="video/mp4" />
|
<source src="/images/logo/banner1.mp4" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
{/* Subtle gradient to improve visibility of baked-in text */}
|
{/* Subtle gradient to improve visibility of baked-in text */}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Contains:
|
* Contains:
|
||||||
* - Brand + short tagline
|
* - Brand + short tagline
|
||||||
* - Both physical locations with full addresses + phone/email
|
* - Both physical locations with full addresses + phone/email
|
||||||
* - Opening hours (different per branch — Backaplan is more variable)
|
* - Opening hours (same for both branches)
|
||||||
* - Quick links + social profiles
|
* - Quick links + social profiles
|
||||||
*
|
*
|
||||||
* Note: The phone numbers and addresses here are the canonical source.
|
* Note: The phone numbers and addresses here are the canonical source.
|
||||||
@@ -24,10 +24,10 @@ export default function Footer() {
|
|||||||
{/* Brand */}
|
{/* Brand */}
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<div className="flex items-center gap-3 mb-4">
|
||||||
<div className="w-10 h-10 rounded-xl overflow-hidden border border-[#c99a2e]/30 bg-white p-0.5 shadow-sm">
|
<div className="w-12 h-12 rounded-xl overflow-hidden border border-[#c99a2e]/30 bg-white p-1 shadow-sm">
|
||||||
<img
|
<img
|
||||||
src="/images/logo-shahi-chef-icon.jpg"
|
src="/images/logo/logo1.png"
|
||||||
alt="Shahi Kitchen Chef Logo"
|
alt="Shahi Kitchen Logo"
|
||||||
className="w-full h-full object-contain"
|
className="w-full h-full object-contain"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +66,7 @@ export default function Footer() {
|
|||||||
<div className="text-[#2C2A26] text-sm tracking-[1.5px] mb-4">OPENING HOURS</div>
|
<div className="text-[#2C2A26] text-sm tracking-[1.5px] mb-4">OPENING HOURS</div>
|
||||||
<div className="text-sm space-y-1">
|
<div className="text-sm space-y-1">
|
||||||
<div><span className="font-medium">Askim:</span> Mon–Sun 11:00–21:00</div>
|
<div><span className="font-medium">Askim:</span> Mon–Sun 11:00–21:00</div>
|
||||||
<div><span className="font-medium">Backaplan:</span> Check Instagram for current hours</div>
|
<div><span className="font-medium">Backaplan:</span> Mon–Sun 11:00–21:00</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ export default function Navbar({ variant = "default" }: NavbarProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<nav
|
<nav
|
||||||
className="fixed top-0 left-0 right-0 z-50 h-16 border-b border-[#c99a2e]/10 bg-[#fbf7ef]/80 backdrop-blur-3xl"
|
className="fixed top-0 left-0 right-0 z-[60] h-[64px] border-b border-[#c99a2e]/20 bg-[#fbf7ef] shadow-sm backdrop-blur-xl"
|
||||||
>
|
>
|
||||||
<div className="max-w-7xl mx-auto px-6 flex items-center justify-between h-full">
|
<div className="max-w-7xl mx-auto px-6 flex items-center justify-between h-full">
|
||||||
{/* Subtle gold accent line at the very bottom */}
|
{/* Top subtle gold line for extra frame separation */}
|
||||||
<div className="absolute bottom-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-[#c99a2e]/30 to-transparent" />
|
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-[#c99a2e]/20 to-transparent" />
|
||||||
{/* Premium Animated Logo */}
|
{/* Premium Animated Logo */}
|
||||||
<Link href="/" className="group flex items-center gap-3">
|
<Link href="/" className="group flex items-center gap-3">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
@@ -68,8 +68,8 @@ export default function Navbar({ variant = "default" }: NavbarProps) {
|
|||||||
className="grid h-12 w-12 place-items-center overflow-hidden rounded-2xl border border-[#c99a2e]/30 bg-white shadow-xl shadow-[#0f5a4a]/10 p-1 transition-all duration-300 group-hover:border-[#c99a2e]/70 group-hover:shadow-[#c99a2e]/25"
|
className="grid h-12 w-12 place-items-center overflow-hidden rounded-2xl border border-[#c99a2e]/30 bg-white shadow-xl shadow-[#0f5a4a]/10 p-1 transition-all duration-300 group-hover:border-[#c99a2e]/70 group-hover:shadow-[#c99a2e]/25"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="/images/logo-shahi-chef-icon.jpg"
|
src="/images/logo/logo1.png"
|
||||||
alt="Shahi Kitchen - Cute Chef with Large Mustaches"
|
alt="Shahi Kitchen Logo"
|
||||||
className="h-10 w-10 object-contain transition-all duration-500"
|
className="h-10 w-10 object-contain transition-all duration-500"
|
||||||
/>
|
/>
|
||||||
</motion.span>
|
</motion.span>
|
||||||
@@ -186,7 +186,7 @@ export default function Navbar({ variant = "default" }: NavbarProps) {
|
|||||||
<div className="flex items-center justify-between mb-10">
|
<div className="flex items-center justify-between mb-10">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<img
|
<img
|
||||||
src="/images/logo-shahi-chef-icon.jpg"
|
src="/images/logo/logo1.png"
|
||||||
alt="Shahi Kitchen"
|
alt="Shahi Kitchen"
|
||||||
className="h-12 w-12 rounded-xl object-contain"
|
className="h-12 w-12 rounded-xl object-contain"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export default function PlayfulHeroScene() {
|
|||||||
<div className="relative w-full h-full min-h-[520px] md:min-h-[620px] flex items-center justify-center overflow-hidden">
|
<div className="relative w-full h-full min-h-[520px] md:min-h-[620px] flex items-center justify-center overflow-hidden">
|
||||||
|
|
||||||
{/* Large cream background circle - matches website exactly so logo absorbs */}
|
{/* Large cream background circle - matches website exactly so logo absorbs */}
|
||||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2
|
<div className="absolute left-1/2 top-[58%] -translate-x-1/2 -translate-y-1/2
|
||||||
w-[440px] h-[440px] md:w-[540px] md:h-[540px] lg:w-[620px] lg:h-[620px]
|
w-[440px] h-[440px] md:w-[540px] md:h-[540px] lg:w-[620px] lg:h-[620px]
|
||||||
bg-[#fbf7ef] rounded-full blur-[130px] opacity-95" />
|
bg-[#fbf7ef] rounded-full blur-[130px] opacity-95" />
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ export default function PlayfulHeroScene() {
|
|||||||
opacity: { duration: 0.4 },
|
opacity: { duration: 0.4 },
|
||||||
scale: { duration: 0.4 }
|
scale: { duration: 0.4 }
|
||||||
}}
|
}}
|
||||||
className="w-[280px] h-[280px] md:w-[360px] md:h-[360px] lg:w-[420px] lg:h-[420px]"
|
className="w-[300px] h-[300px] md:w-[380px] md:h-[380px] lg:w-[440px] lg:h-[440px]"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={getLogoSrc()}
|
src={getLogoSrc()}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: 'shahikitchen',
|
||||||
|
cwd: '/var/www/shahikitchen.se',
|
||||||
|
script: 'npm',
|
||||||
|
args: 'run start',
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'production',
|
||||||
|
PORT: 3001
|
||||||
|
},
|
||||||
|
instances: 1,
|
||||||
|
exec_mode: 'fork',
|
||||||
|
max_memory_restart: '700M',
|
||||||
|
error_file: '/home/deploy/.pm2/logs/shahikitchen-error.log',
|
||||||
|
out_file: '/home/deploy/.pm2/logs/shahikitchen-out.log',
|
||||||
|
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
||||||
|
kill_timeout: 8000,
|
||||||
|
autorestart: true,
|
||||||
|
watch: false,
|
||||||
|
min_uptime: '10s'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
Binary file not shown.
Executable
+87
@@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Shahi Kitchen Production Deploy Script
|
||||||
|
# Run as: sudo -u deploy /var/www/shahikitchen.se/scripts/deploy.sh
|
||||||
|
#
|
||||||
|
# This script supports two modes:
|
||||||
|
# 1. Tarball mode (current primary method): Place new shahi.tar.gz in /tmp or /root and run
|
||||||
|
# 2. Git mode (if you initialize git in the future)
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_DIR="/var/www/shahikitchen.se"
|
||||||
|
PM2_APP_NAME="shahikitchen"
|
||||||
|
PORT=3001
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo " Shahi Kitchen - Production Deploy"
|
||||||
|
echo " $(date)"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
cd "$APP_DIR"
|
||||||
|
|
||||||
|
# --- Detect mode ---
|
||||||
|
if [ -f "/tmp/shahi.tar.gz" ] || [ -f "/root/shahi.tar.gz" ]; then
|
||||||
|
echo "[1/6] Tarball update detected"
|
||||||
|
TARBALL=""
|
||||||
|
if [ -f "/tmp/shahi.tar.gz" ]; then TARBALL="/tmp/shahi.tar.gz"; fi
|
||||||
|
if [ -f "/root/shahi.tar.gz" ]; then TARBALL="/root/shahi.tar.gz"; fi
|
||||||
|
|
||||||
|
echo "Using tarball: $TARBALL"
|
||||||
|
|
||||||
|
echo "Stopping PM2 app (graceful)..."
|
||||||
|
pm2 stop "$PM2_APP_NAME" || true
|
||||||
|
|
||||||
|
echo "Backing up current .next (quick safety)..."
|
||||||
|
rm -rf .next.bak 2>/dev/null || true
|
||||||
|
cp -a .next .next.bak 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "Extracting new tarball..."
|
||||||
|
tar --strip-components=1 -xzf "$TARBALL"
|
||||||
|
|
||||||
|
echo "Cleaning shipped node_modules + cache..."
|
||||||
|
rm -rf node_modules .next/cache 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "Running npm ci..."
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
echo "Building..."
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
elif git rev-parse --git-dir > /dev/null 2>&1; then
|
||||||
|
echo "[1/6] Git update mode"
|
||||||
|
pm2 stop "$PM2_APP_NAME" || true
|
||||||
|
git fetch --all
|
||||||
|
git reset --hard origin/main || git reset --hard origin/master
|
||||||
|
npm ci
|
||||||
|
npm run build
|
||||||
|
else
|
||||||
|
echo "ERROR: No tarball found in /tmp or /root, and no git repository."
|
||||||
|
echo "Please either:"
|
||||||
|
echo " - scp your new shahi.tar.gz to the server, or"
|
||||||
|
echo " - Run: cp /path/to/shahi.tar.gz /tmp/shahi.tar.gz"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[2/6] Dependencies and build complete"
|
||||||
|
|
||||||
|
echo "[3/6] Starting / restarting PM2..."
|
||||||
|
pm2 start ecosystem.config.cjs --only "$PM2_APP_NAME" || pm2 reload "$PM2_APP_NAME" --update-env || true
|
||||||
|
pm2 save
|
||||||
|
|
||||||
|
echo "[4/6] Reloading Nginx..."
|
||||||
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
|
||||||
|
echo "[5/6] Post-deploy health checks..."
|
||||||
|
echo "PM2 status:"
|
||||||
|
pm2 list | grep -E "shahikitchen|App name" || true
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Testing local Next.js process..."
|
||||||
|
curl -s --max-time 5 "http://127.0.0.1:${PORT}" | head -c 300 || echo "(first request may be slow)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "[6/6] Deploy finished successfully at $(date)"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Website should be live at: http://76.13.210.183"
|
||||||
|
echo "=========================================="
|
||||||
Reference in New Issue
Block a user