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 { Geist } from "next/font/google";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
|
import { OfflineIndicator } from "@/components/ui/offline-indicator";
|
||||||
|
|
||||||
const geist = Geist({ subsets: ["latin"], variable: "--font-sans" });
|
const geist = Geist({ subsets: ["latin"], variable: "--font-sans" });
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Cognis",
|
title: "Cognis",
|
||||||
description: "Self-hosted freelancer operating dashboard",
|
description: "Self-hosted freelancer operating dashboard",
|
||||||
|
manifest: "/manifest.json",
|
||||||
|
themeColor: "#ffffff",
|
||||||
|
appleWebApp: {
|
||||||
|
capable: true,
|
||||||
|
statusBarStyle: "default",
|
||||||
|
title: "Cognis",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@@ -24,6 +32,7 @@ export default function RootLayout({
|
|||||||
>
|
>
|
||||||
<body>
|
<body>
|
||||||
{children}
|
{children}
|
||||||
|
<OfflineIndicator />
|
||||||
<Toaster position="top-right" />
|
<Toaster position="top-right" />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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 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 = {
|
const nextConfig: NextConfig = {
|
||||||
output: "standalone",
|
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/openai": "^3.0.68",
|
||||||
"@ai-sdk/react": "^3.0.199",
|
"@ai-sdk/react": "^3.0.199",
|
||||||
"@base-ui/react": "^1.5.0",
|
"@base-ui/react": "^1.5.0",
|
||||||
|
"@ducanh2912/next-pwa": "^10.2.9",
|
||||||
"@hookform/resolvers": "^5.4.0",
|
"@hookform/resolvers": "^5.4.0",
|
||||||
"@iconify/react": "^6.0.2",
|
"@iconify/react": "^6.0.2",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
"@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