diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml
index c3ef532..1a34357 100644
--- a/.github/workflows/CD.yml
+++ b/.github/workflows/CD.yml
@@ -7,11 +7,6 @@ on:
workflow_dispatch:
-permissions:
- contents: read
- pages: write
- id-token: write
-
concurrency:
group: "pages"
cancel-in-progress: false
@@ -52,7 +47,12 @@ jobs:
runs-on: ubuntu-latest
needs: build
+ permissions:
+ contents: read
+ pages: write
+ id-token: write
+
steps:
- name: Deploy to GitHub Pages
id: deployment
- uses: actions/deploy-pages@v4
\ No newline at end of file
+ uses: actions/deploy-pages@v4
diff --git a/README.md b/README.md
index 0f37274..985c8f5 100644
--- a/README.md
+++ b/README.md
@@ -171,8 +171,7 @@ Here is a breakdown of the key i18n directories and files:
│ │ ├── SocialMediaCTA.tsx
│ │ ├── ThemeToggle.tsx
│ │ └── providers/
-│ │ ├── lenis-provider.tsx
-│ │ └── theme-provider.tsx
+│ │ └── lenis-provider.tsx
│ │ └── ui/
│ │ ├── Navbar.tsx
│ │ └── button.tsx
@@ -191,7 +190,6 @@ Here is a breakdown of the key i18n directories and files:
│ │ └── hi.json
│ └── proxy.ts
├── tsconfig.json
-├── eslint.config.mjs
└── .gitignore
```
@@ -380,7 +378,7 @@ This compiles optimized static pages under the `/[locale]` path and checks all T
### Running in Production
-Start the optimized server:
+Start the optimized server(This is optional if you are deploying to a static hosting service like GitHub Pages):
```bash
npm run start
diff --git a/Tasks.md b/Tasks.md
index 67b7122..c9df92e 100644
--- a/Tasks.md
+++ b/Tasks.md
@@ -10,7 +10,7 @@ In the checklist below, mark the items that have been completed for your project
- [x] Has proper open graph metadata, to ensure that it is shown well when shared in social media.
- [x] Has a footer and header with AOSSIE logos and social handles.
- [x] Uses Next.js Server Components by default with Client Components (`"use client"`) introduced only where interactive state is required.
- - [x] Is deployed to GitHub Pages via a GitHub Workflow (`.github/workflows/nextjs.yml`).
+ - [x] Is deployed to GitHub Pages via a GitHub Workflow (`.github/workflows/CD.yml`).
- [x] Has automated CI build and lint validation (`.github/workflows/ci.yml`).
- [x] Has CodeRabbit automated AI code review (`.coderabbit.yml`).
- [x] Has open-source legal compliance (`DCO.md`, `COPYRIGHT.md`, `Contributors.md`).
diff --git a/src/components/Download.tsx b/src/components/Download.tsx
index dc83063..8a9347f 100644
--- a/src/components/Download.tsx
+++ b/src/components/Download.tsx
@@ -77,7 +77,7 @@ function DownloadButton({ value }: DownloadButtonProps) {
disabled={loading}
onClick={() => {
if (link) {
- window.open(link, "_blank");
+ window.open(link, "_blank", "noopener,noreferrer");
}
}}
className="h-9 px-3 rounded-lg flex items-center gap-2 text-sm font-medium transition"
diff --git a/src/components/MockUp.tsx b/src/components/MockUp.tsx
index fbb079c..0982e33 100644
--- a/src/components/MockUp.tsx
+++ b/src/components/MockUp.tsx
@@ -1,4 +1,4 @@
-import Image, { StaticImageData } from "next/image";
+import Image, { type StaticImageData } from "next/image";
import { FaApple } from "react-icons/fa";
import { FaWifi } from "react-icons/fa6";
import { IoBatteryFullOutline } from "react-icons/io5";
diff --git a/src/components/ShuffleGrid.tsx b/src/components/ShuffleGrid.tsx
index e688c41..d14447b 100644
--- a/src/components/ShuffleGrid.tsx
+++ b/src/components/ShuffleGrid.tsx
@@ -22,7 +22,7 @@ const shuffle = (array: (typeof squareData)[0][]) => {
const ShuffleGrid = () => {
- const timeoutRef = useRef(null);
+ const timeoutRef = useRef | null>(null);
const [squares, setSquares] = useState(squareData);
useEffect(() => {
const shuffleSquares = () => {
@@ -32,7 +32,11 @@ const ShuffleGrid = () => {
shuffleSquares();
- return () => clearTimeout(timeoutRef.current);
+ return () => {
+ if (timeoutRef.current) {
+ clearTimeout(timeoutRef.current);
+ }
+ };
}, []);
return (
diff --git a/src/components/SocialMediaCTA.tsx b/src/components/SocialMediaCTA.tsx
index 8506185..8d48af3 100644
--- a/src/components/SocialMediaCTA.tsx
+++ b/src/components/SocialMediaCTA.tsx
@@ -76,6 +76,7 @@ export default function SocialMediaCTA() {
@@ -185,7 +186,7 @@ function MobileSidebar({ sidebarOpen, setSidebarOpen }: MobileSidebarProps) {
return (
<>
{/* Overlay */}
- ({
toggleTheme: () => {},
});
-function getInitialTheme(): ThemeOptions {
- if (typeof window === "undefined") return ThemeOptions.Light;
+export function ThemeProvider({ children }: { children: React.ReactNode }) {
+ const [theme, setTheme] = useState(ThemeOptions.Light);
- const storedTheme = localStorage.getItem("theme");
+ useEffect(() => {
+ const storedTheme = localStorage.getItem("theme");
- if (storedTheme === "dark") return ThemeOptions.Dark;
- if (storedTheme === "light") return ThemeOptions.Light;
+ let resolvedTheme: ThemeOptions;
- return window.matchMedia("(prefers-color-scheme: dark)").matches
- ? ThemeOptions.Dark
- : ThemeOptions.Light;
-}
+ if (storedTheme === "dark") {
+ resolvedTheme = ThemeOptions.Dark;
+ } else if (storedTheme === "light") {
+ resolvedTheme = ThemeOptions.Light;
+ } else {
+ resolvedTheme = window.matchMedia("(prefers-color-scheme: dark)").matches
+ ? ThemeOptions.Dark
+ : ThemeOptions.Light;
+ }
-export function ThemeProvider({ children }: { children: React.ReactNode }) {
- const [theme, setTheme] = useState(getInitialTheme);
+ const setThemeForState = (theme: ThemeOptions) => {
+ setTheme(theme);
+ };
+
+ setThemeForState(resolvedTheme);
+ }, []);
useEffect(() => {
const root = document.documentElement;
@@ -46,7 +55,7 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
const toggleTheme = () => {
setTheme((prev) =>
- prev === ThemeOptions.Dark ? ThemeOptions.Light : ThemeOptions.Dark
+ prev === ThemeOptions.Dark ? ThemeOptions.Light : ThemeOptions.Dark,
);
};
@@ -55,4 +64,4 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
{children}
);
-}
\ No newline at end of file
+}
diff --git a/src/hooks/usePlatform.ts b/src/hooks/usePlatform.ts
index dbb4bf8..04476a7 100644
--- a/src/hooks/usePlatform.ts
+++ b/src/hooks/usePlatform.ts
@@ -7,14 +7,14 @@ export function usePlatform() {
return useMemo(() => {
const ua = navigator.userAgent.toLowerCase();
- const isMobile =
- /android|iphone|ipad|ipod|mobile/i.test(ua);
+ const isMobile = /android|iphone|ipad|ipod|mobile/i.test(ua);
let platform: Platform = "linux";
-
+
+ if (!ua) platform = "windows";
if (ua.includes("mac")) platform = "mac";
else if (ua.includes("win")) platform = "windows";
return { platform, isMobile };
}, []);
-}
\ No newline at end of file
+}
diff --git a/src/messages/hi.json b/src/messages/hi.json
index 34b1b7f..02bb5da 100644
--- a/src/messages/hi.json
+++ b/src/messages/hi.json
@@ -15,7 +15,7 @@
"featureBadge": "नई सुविधा: AI टैगिंग",
"downloadNow": "अभी डाउनलोड करें",
- "heroTitle": "सबसे उन्नत ओपन-सोर्स गैलरी",
+ "heroTitle": "सबसे उन्नत",
"heroSubtitle": "ओपन-सोर्स गैलरी",
"heroDescription": "स्मार्ट गैलरी प्रबंधन। उन्नत AI आपकी तस्वीरों का स्थानीय रूप से विश्लेषण और व्यवस्थित करता है, जिससे आपकी सभी फाइलें सुरक्षित और आपके नियंत्रण में रहती हैं।"
},