diff --git a/next.config.ts b/next.config.ts index d390838..578372d 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,13 @@ -import type { NextConfig } from "next"; +import type { NextConfig } from 'next' +import withSerwistInit from '@serwist/next' + +const withSerwist = withSerwistInit({ + swSrc: 'src/sw.ts', + swDest: 'public/sw.js', +}) const nextConfig: NextConfig = { - output: process.env.NETLIFY === "true" ? undefined : "standalone", -}; + output: process.env.NETLIFY === 'true' ? undefined : 'standalone', +} -export default nextConfig; +export default withSerwist(nextConfig) diff --git a/package.json b/package.json index eda6668..20dc290 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ }, "dependencies": { "@prisma/client": "^5.22.0", + "@serwist/cli": "^9.5.11", + "@serwist/next": "^9.5.11", "@types/bcryptjs": "^2.4.6", "@types/leaflet": "^1.9.14", "bcryptjs": "^3.0.3", @@ -21,6 +23,7 @@ "react": "19.2.4", "react-dom": "19.2.4", "react-leaflet": "^5.0.0", + "serwist": "^9.5.11", "stripe": "^17.0.0" }, "devDependencies": { diff --git a/public/icons/icon-192.svg b/public/icons/icon-192.svg new file mode 100644 index 0000000..fe42260 --- /dev/null +++ b/public/icons/icon-192.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/icons/icon-512.svg b/public/icons/icon-512.svg new file mode 100644 index 0000000..e99a3fd --- /dev/null +++ b/public/icons/icon-512.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..f06fcde --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "Falah", + "short_name": "Falah", + "description": "Your Islamic lifestyle companion", + "start_url": "/home", + "display": "standalone", + "background_color": "#0a0a0f", + "theme_color": "#0a0a0f", + "icons": [ + { + "src": "/icons/icon-192.svg", + "sizes": "192x192", + "type": "image/svg+xml", + "purpose": "any maskable" + }, + { + "src": "/icons/icon-512.svg", + "sizes": "512x512", + "type": "image/svg+xml", + "purpose": "any maskable" + } + ] +} diff --git a/src/app/globals.css b/src/app/globals.css index 2d4a136..98c98f4 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,25 +1,40 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; + +@theme { + --color-bg-deep: #0a0a0f; + --color-bg-card: #111118; + --color-gold: #D4AF37; + --color-gold-light: #e2c55e; + --color-nur-purple: #A78BFA; + --color-nur-bg: #1a1a2e; + --color-emerald: #10B981; + --color-border: #222; + --color-border-light: #333; + --color-text-primary: #fff; + --color-text-secondary: #999; + --color-text-muted: #666; + + --color-gold-gradient-start: #D4AF37; + --color-gold-gradient-end: #B8860B; + + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + --font-arabic: "Noto Naskh Arabic", "Traditional Arabic", serif; +} :root { - --background: #f5f4f0; - --foreground: #111827; - --gold: #D4AF37; - --emerald: #059669; - --nav-height: 64px; + --nav-floating-bottom: 24px; } html { height: 100%; - color-scheme: light; + color-scheme: dark; } body { height: 100%; - color: var(--foreground); - background: var(--background); - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + color: var(--color-text-primary); + background: var(--color-bg-deep); + font-family: var(--font-sans); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overscroll-behavior: none; @@ -42,11 +57,61 @@ input, select, textarea { font-size: 16px; } +/* Scrollbar hidden utility */ +.scrollbar-none::-webkit-scrollbar { display: none; } +.scrollbar-none { -ms-overflow-style: none; scrollbar-width: none; } + +/* Chat scroll */ .chat-scroll { scroll-behavior: smooth; -webkit-overflow-scrolling: touch; } -/* Hide scrollbar on category strips */ -.scrollbar-none::-webkit-scrollbar { display: none; } -.scrollbar-none { -ms-overflow-style: none; scrollbar-width: none; } +/* Glassmorphism utility */ +.glass { + background: rgba(17, 17, 24, 0.95); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.glass-light { + background: rgba(255, 255, 255, 0.05); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border: 1px solid rgba(255, 255, 255, 0.06); +} + +/* Gold gradient */ +.gold-gradient { + background: linear-gradient(135deg, #D4AF37, #B8860B); +} + +/* Nur purple gradient */ +.nur-gradient { + background: linear-gradient(135deg, #A78BFA, #7C3AED); +} + +/* Gold-purple combined gradient (for center Nur tab) */ +.gold-purple-gradient { + background: linear-gradient(135deg, #D4AF37, #A78BFA); +} + +/* Prayer countdown ring SVG */ +.prayer-ring { + transform: rotate(-90deg); +} + +.prayer-ring-bg { + fill: none; + stroke: rgba(255, 255, 255, 0.08); + stroke-width: 4; +} + +.prayer-ring-fg { + fill: none; + stroke: #D4AF37; + stroke-width: 4; + stroke-linecap: round; + transition: stroke-dashoffset 1s ease; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 94960c0..52e8771 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,22 +1,31 @@ -import type { Metadata } from 'next' +import type { Metadata, Viewport } from 'next' import { AuthProvider } from '@/lib/AuthContext' import BottomNav from '@/components/BottomNav' import './globals.css' export const metadata: Metadata = { - title: 'Falah — Islamic Lifestyle', - description: 'Nur AI coaching, Halal marketplace, community & wallet', + title: 'Falah — Your Islamic Lifestyle Companion', + description: 'Nur AI coaching, daily spiritual digest, prayer times, halal marketplace & community', + manifest: '/manifest.json', + appleWebApp: { + capable: true, + statusBarStyle: 'black-translucent', + title: 'Falah', + }, +} + +export const viewport: Viewport = { + width: 'device-width', + initialScale: 1, + viewportFit: 'cover', + themeColor: '#0a0a0f', } export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - - - - - + diff --git a/src/components/BottomNav.tsx b/src/components/BottomNav.tsx index 0c35fd5..a20d974 100644 --- a/src/components/BottomNav.tsx +++ b/src/components/BottomNav.tsx @@ -2,43 +2,67 @@ import Link from 'next/link' import { usePathname } from 'next/navigation' -import { Home, Moon, Bot, Repeat2, User } from 'lucide-react' +import { House, Brain, User } from 'lucide-react' const tabs = [ - { href: '/home', icon: Home, label: 'Home' }, - { href: '/prayer', icon: Moon, label: 'Prayer' }, - { href: '/nur', icon: Bot, label: 'Nur', center: true }, - { href: '/dhikr', icon: Repeat2, label: 'Dhikr' }, - { href: '/profile',icon: User, label: 'Profile' }, + { href: '/home', icon: House, label: 'Home' }, + { href: '/nur', icon: Brain, label: 'Nur', center: true }, + { href: '/profile', icon: User, label: 'Profile' }, ] export default function BottomNav() { const pathname = usePathname() + + // Hide on auth pages if (pathname === '/login' || pathname === '/register') return null return ( -