Unified mod sources display

Co-authored-by: felix-fx-top <253056634+felix-fx-top@users.noreply.github.com>
This commit is contained in:
gpt-engineer-app[bot] 2026-03-31 10:42:20 +00:00 committed by lovable
parent dd34789ca7
commit 9c7929d359
4 changed files with 96 additions and 51 deletions

View File

@ -1,13 +1,18 @@
import { Heart } from "lucide-react";
const Footer = () => {
return (
<footer className="border-t border-border bg-card/50 py-8">
<footer className="border-t border-border/50 bg-card/30 py-8">
<div className="container mx-auto px-4 text-center">
<div className="mb-2">
<span className="text-xl font-bold text-primary">FX</span>
<span className="text-xl font-bold text-foreground">Craft</span>
<div className="mb-3">
<span className="text-xl font-black text-primary">FX</span>
<span className="text-xl font-black text-foreground">Craft</span>
</div>
<p className="text-sm text-muted-foreground">
© {new Date().getFullYear()} FXCraft. جميع الحقوق محفوظة.
<p className="flex items-center justify-center gap-1 text-xs text-muted-foreground">
صُنع بـ <Heart className="h-3 w-3 text-destructive" /> لمجتمع ماين كرافت العربي
</p>
<p className="mt-1 text-xs text-muted-foreground/60">
© {new Date().getFullYear()} FXCraft
</p>
</div>
</footer>

View File

@ -1,31 +1,35 @@
import { Link } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Pickaxe, Download } from "lucide-react";
import { Pickaxe, Download, Sparkles } from "lucide-react";
const HeroSection = () => {
return (
<section className="relative overflow-hidden py-20 md:py-32">
{/* Glow effect */}
<div className="absolute left-1/2 top-0 -translate-x-1/2 h-[500px] w-[800px] rounded-full bg-primary/10 blur-[120px]" />
<section className="relative overflow-hidden py-16 sm:py-20 md:py-28">
{/* Background effects */}
<div className="absolute inset-0 bg-[radial-gradient(ellipse_at_center,hsl(var(--primary)/0.08)_0%,transparent_70%)]" />
<div className="absolute -left-32 -top-32 h-64 w-64 rounded-full bg-primary/5 blur-3xl" />
<div className="absolute -bottom-32 -right-32 h-64 w-64 rounded-full bg-primary/5 blur-3xl" />
<div className="container relative mx-auto px-4 text-center">
<div className="mx-auto max-w-3xl animate-fade-in">
<div className="mb-6 inline-flex items-center gap-2 rounded-full border border-primary/30 bg-primary/10 px-4 py-2 text-sm text-primary">
<Pickaxe className="h-4 w-4" />
<div className="mx-auto max-w-3xl">
<div className="mb-6 inline-flex items-center gap-2 rounded-full border border-primary/20 bg-primary/5 px-4 py-2 text-sm text-primary backdrop-blur-sm">
<Sparkles className="h-4 w-4" />
<span>أفضل إضافات ماين كرافت</span>
</div>
<h1 className="mb-6 text-4xl font-black leading-tight md:text-6xl">
<h1 className="mb-6 text-3xl font-black leading-tight sm:text-4xl md:text-6xl">
اكتشف عالماً جديداً من{" "}
<span className="text-primary">إضافات ماين كرافت</span>
<span className="bg-gradient-to-l from-primary to-emerald-400 bg-clip-text text-transparent">
إضافات ماين كرافت
</span>
</h1>
<p className="mb-8 text-lg text-muted-foreground md:text-xl">
<p className="mx-auto mb-8 max-w-xl text-base text-muted-foreground sm:text-lg md:text-xl">
تصفّح وحمّل أفضل المودات وحزم الموارد والإضافات لتحسين تجربة لعبك
</p>
<div className="flex flex-wrap items-center justify-center gap-4">
<Button asChild size="lg" className="gap-2 text-base font-bold">
<div className="flex flex-wrap items-center justify-center gap-3">
<Button asChild size="lg" className="gap-2 text-base font-bold shadow-lg shadow-primary/20">
<Link to="/search">
<Download className="h-5 w-5" />
تصفح الإضافات

View File

@ -1,36 +1,44 @@
import { Link, useNavigate } from "react-router-dom";
import { Search, Menu, X } from "lucide-react";
import { useState } from "react";
import { useState, useCallback } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
const Navbar = () => {
const [searchQuery, setSearchQuery] = useState("");
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [lastSearch, setLastSearch] = useState(0);
const navigate = useNavigate();
const handleSearch = (e: React.FormEvent) => {
const handleSearch = useCallback((e: React.FormEvent) => {
e.preventDefault();
if (searchQuery.trim()) {
navigate(`/search?q=${encodeURIComponent(searchQuery.trim())}`);
setSearchQuery("");
}
};
const trimmed = searchQuery.trim().slice(0, 200);
if (!trimmed) return;
// Anti-spam
const now = Date.now();
if (now - lastSearch < 800) return;
setLastSearch(now);
navigate(`/search?q=${encodeURIComponent(trimmed)}`);
setSearchQuery("");
setMobileMenuOpen(false);
}, [searchQuery, lastSearch, navigate]);
return (
<nav className="sticky top-0 z-50 border-b border-border bg-background/80 backdrop-blur-md">
<nav className="sticky top-0 z-50 border-b border-border/50 bg-background/90 backdrop-blur-lg">
<div className="container mx-auto flex items-center justify-between px-4 py-3">
<Link to="/" className="flex items-center gap-2">
<span className="text-2xl font-bold text-primary">FX</span>
<span className="text-2xl font-bold text-foreground">Craft</span>
<Link to="/" className="flex items-center gap-1.5 transition-opacity hover:opacity-80">
<span className="text-xl font-black text-primary sm:text-2xl">FX</span>
<span className="text-xl font-black text-foreground sm:text-2xl">Craft</span>
</Link>
{/* Desktop */}
<div className="hidden items-center gap-6 md:flex">
<Link to="/" className="text-muted-foreground transition-colors hover:text-foreground">
<div className="hidden items-center gap-5 md:flex">
<Link to="/" className="text-sm text-muted-foreground transition-colors hover:text-foreground">
الرئيسية
</Link>
<Link to="/search" className="text-muted-foreground transition-colors hover:text-foreground">
<Link to="/search" className="text-sm text-muted-foreground transition-colors hover:text-foreground">
تصفح
</Link>
<form onSubmit={handleSearch} className="relative">
@ -38,9 +46,10 @@ const Navbar = () => {
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="ابحث عن إضافة..."
className="w-64 bg-secondary pr-10"
className="w-56 bg-secondary/70 pr-9 text-sm lg:w-64"
maxLength={200}
/>
<Search className="absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Search className="absolute right-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
</form>
</div>
@ -50,25 +59,26 @@ const Navbar = () => {
size="icon"
className="md:hidden"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
aria-label="القائمة"
>
{mobileMenuOpen ? <X /> : <Menu />}
{mobileMenuOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
</Button>
</div>
{/* Mobile menu */}
{mobileMenuOpen && (
<div className="border-t border-border px-4 pb-4 md:hidden">
<div className="border-t border-border/50 px-4 pb-4 md:hidden animate-in slide-in-from-top-2 duration-200">
<div className="flex flex-col gap-3 pt-3">
<Link
to="/"
className="text-muted-foreground hover:text-foreground"
className="text-sm text-muted-foreground hover:text-foreground"
onClick={() => setMobileMenuOpen(false)}
>
الرئيسية
</Link>
<Link
to="/search"
className="text-muted-foreground hover:text-foreground"
className="text-sm text-muted-foreground hover:text-foreground"
onClick={() => setMobileMenuOpen(false)}
>
تصفح
@ -79,9 +89,10 @@ const Navbar = () => {
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="ابحث عن إضافة..."
className="bg-secondary pr-10"
className="bg-secondary/70 pr-9 text-sm"
maxLength={200}
/>
<Search className="absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Search className="absolute right-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
</div>
</form>
</div>

View File

@ -4,22 +4,22 @@
@layer base {
:root {
--background: 240 30% 11%;
--background: 240 30% 8%;
--foreground: 210 40% 96%;
--card: 240 25% 14%;
--card: 240 25% 12%;
--card-foreground: 210 40% 96%;
--popover: 240 25% 14%;
--popover: 240 25% 12%;
--popover-foreground: 210 40% 96%;
--primary: 122 39% 49%;
--primary-foreground: 240 30% 6%;
--secondary: 240 20% 20%;
--secondary: 240 20% 16%;
--secondary-foreground: 210 40% 96%;
--muted: 240 15% 18%;
--muted: 240 15% 14%;
--muted-foreground: 215 15% 55%;
--accent: 122 39% 49%;
@ -28,19 +28,19 @@
--destructive: 0 84% 60%;
--destructive-foreground: 210 40% 98%;
--border: 240 15% 22%;
--input: 240 15% 22%;
--border: 240 12% 18%;
--input: 240 12% 18%;
--ring: 122 39% 49%;
--radius: 0.75rem;
--sidebar-background: 240 25% 10%;
--sidebar-background: 240 25% 7%;
--sidebar-foreground: 210 40% 96%;
--sidebar-primary: 122 39% 49%;
--sidebar-primary-foreground: 240 30% 6%;
--sidebar-accent: 240 15% 18%;
--sidebar-accent: 240 15% 14%;
--sidebar-accent-foreground: 210 40% 96%;
--sidebar-border: 240 15% 22%;
--sidebar-border: 240 12% 18%;
--sidebar-ring: 122 39% 49%;
}
}
@ -51,6 +51,31 @@
}
body {
@apply bg-background text-foreground font-cairo;
@apply bg-background text-foreground font-cairo antialiased;
}
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
/* Better focus styles */
:focus-visible {
@apply outline-2 outline-offset-2 outline-ring;
}
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: hsl(var(--background));
}
::-webkit-scrollbar-thumb {
background: hsl(var(--border));
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: hsl(var(--muted-foreground));
}
}