chore: sync full current production website state to Gitea

This commit is contained in:
Anonymous
2026-06-02 10:27:50 +00:00
parent 56fe68eb48
commit fe78fd9fa1
14 changed files with 149 additions and 71 deletions
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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 */}
+5 -5
View File
@@ -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> MonSun 11:0021:00</div> <div><span className="font-medium">Askim:</span> MonSun 11:0021:00</div>
<div><span className="font-medium">Backaplan:</span> Check Instagram for current hours</div> <div><span className="font-medium">Backaplan:</span> MonSun 11:0021:00</div>
</div> </div>
</div> </div>
+6 -6
View File
@@ -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"
/> />
+2 -2
View File
@@ -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()}
+24
View File
@@ -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.
+87
View File
@@ -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 "=========================================="