feat: add PWA support with manifest configuration and offline connectivity indicator
This commit is contained in:
@@ -3,12 +3,20 @@ import "./globals.css";
|
||||
import { Geist } from "next/font/google";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
import { OfflineIndicator } from "@/components/ui/offline-indicator";
|
||||
|
||||
const geist = Geist({ subsets: ["latin"], variable: "--font-sans" });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Cognis",
|
||||
description: "Self-hosted freelancer operating dashboard",
|
||||
manifest: "/manifest.json",
|
||||
themeColor: "#ffffff",
|
||||
appleWebApp: {
|
||||
capable: true,
|
||||
statusBarStyle: "default",
|
||||
title: "Cognis",
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -24,6 +32,7 @@ export default function RootLayout({
|
||||
>
|
||||
<body>
|
||||
{children}
|
||||
<OfflineIndicator />
|
||||
<Toaster position="top-right" />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { WifiOff } from "lucide-react";
|
||||
|
||||
export function OfflineIndicator() {
|
||||
const [isOnline, setIsOnline] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
// Sadece client-side'da çalışır
|
||||
setIsOnline(navigator.onLine);
|
||||
|
||||
const handleOnline = () => setIsOnline(true);
|
||||
const handleOffline = () => setIsOnline(false);
|
||||
|
||||
window.addEventListener("online", handleOnline);
|
||||
window.addEventListener("offline", handleOffline);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("online", handleOnline);
|
||||
window.removeEventListener("offline", handleOffline);
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (isOnline) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-4 right-4 z-50 flex items-center gap-2 rounded-lg bg-destructive px-4 py-2 text-sm font-medium text-destructive-foreground shadow-lg animate-in fade-in slide-in-from-bottom-4">
|
||||
<WifiOff className="h-4 w-4" />
|
||||
Çevrimdışı moddasınız. Değişiklikler senkronize edilmeyecek.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+9
-1
@@ -1,4 +1,12 @@
|
||||
import type { NextConfig } from "next";
|
||||
import withPWAInit from "@ducanh2912/next-pwa";
|
||||
|
||||
const withPWA = withPWAInit({
|
||||
dest: "public",
|
||||
disable: process.env.NODE_ENV === "development",
|
||||
register: true,
|
||||
skipWaiting: true,
|
||||
});
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
@@ -9,4 +17,4 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
export default withPWA(nextConfig);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@ai-sdk/openai": "^3.0.68",
|
||||
"@ai-sdk/react": "^3.0.199",
|
||||
"@base-ui/react": "^1.5.0",
|
||||
"@ducanh2912/next-pwa": "^10.2.9",
|
||||
"@hookform/resolvers": "^5.4.0",
|
||||
"@iconify/react": "^6.0.2",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
|
||||
Generated
+2146
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "Cognis",
|
||||
"short_name": "Cognis",
|
||||
"description": "Self-hosted freelancer operating dashboard",
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"scope": "/",
|
||||
"start_url": "/",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/logo/LogoWithBg.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/logo/LogoWithBg.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user