diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx
index c6c68e6..86c19f8 100644
--- a/frontend/app/layout.tsx
+++ b/frontend/app/layout.tsx
@@ -1,21 +1,28 @@
import type { Metadata } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
+import { Open_Sans, Roboto_Mono } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider";
-const geistSans = Geist({
- variable: "--font-geist-sans",
+const openSans = Open_Sans({
subsets: ["latin"],
+ display: "swap",
+ variable: "--font-opensans",
});
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
+const robotoMono = Roboto_Mono({
subsets: ["latin"],
+ display: "swap",
+ variable: "--font-roboto-mono",
});
+// const geistMono = Geist_Mono({
+// variable: "--font-geist-mono",
+// subsets: ["latin"],
+// });
+
export const metadata: Metadata = {
- title: "Create Next App",
- description: "Generated by create next app",
+ title: "ForFarm - Smart Farming Solutions",
+ description: "Optimize your agricultural business with AI-driven insights and real-time data.",
};
export default function RootLayout({
@@ -26,7 +33,7 @@ export default function RootLayout({
return (
+
{children}
diff --git a/frontend/app/page.tsx b/frontend/app/page.tsx
index 9007252..1d68f3c 100644
--- a/frontend/app/page.tsx
+++ b/frontend/app/page.tsx
@@ -1,100 +1,68 @@
import Image from "next/image";
+import Link from "next/link";
+import { ArrowRight, Cloud, BarChart, Zap } from "lucide-react";
+import { Leaf } from "lucide-react";
+
+import { Button } from "@/components/ui/button";
export default function Home() {
return (
-
-
-
-
- -
- Get started by editing{" "}
-
- app/page.tsx
-
- .
-
- - Save and see your changes instantly.
-
+
+
+
+
+
+ ForFarm
+
+
+
+
+ Documentation
+
+
+ Get started
+
+
+
-
-
-
- Deploy now
-
-
- Read our docs
-
+
+
+
+
Your Smart Farming Platform
+
+ It's a smart and easy way to optimize your agricultural business, with the help of AI-driven insights and
+ real-time data.
+
+
+
+
-
);
diff --git a/frontend/components/ui/checkbox.tsx b/frontend/components/ui/checkbox.tsx
new file mode 100644
index 0000000..c6fdd07
--- /dev/null
+++ b/frontend/components/ui/checkbox.tsx
@@ -0,0 +1,30 @@
+"use client"
+
+import * as React from "react"
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
+import { Check } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Checkbox = React.forwardRef<
+ React.ElementRef
,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+
+))
+Checkbox.displayName = CheckboxPrimitive.Root.displayName
+
+export { Checkbox }
diff --git a/frontend/package.json b/frontend/package.json
index 486fb23..50ec67f 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -10,6 +10,7 @@
},
"dependencies": {
"@radix-ui/react-avatar": "^1.1.3",
+ "@radix-ui/react-checkbox": "^1.1.4",
"@radix-ui/react-dialog": "^1.1.6",
"@radix-ui/react-dropdown-menu": "^2.1.6",
"@radix-ui/react-label": "^2.1.2",
@@ -17,6 +18,7 @@
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/typography": "^0.5.16",
+ "@tanstack/react-query": "^5.66.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.475.0",
@@ -24,8 +26,10 @@
"next-themes": "^0.4.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "react-hook-form": "^7.54.2",
"tailwind-merge": "^3.0.1",
- "tailwindcss-animate": "^1.0.7"
+ "tailwindcss-animate": "^1.0.7",
+ "zod": "^3.24.2"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index cf6eea5..7b5ccec 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -11,6 +11,9 @@ importers:
'@radix-ui/react-avatar':
specifier: ^1.1.3
version: 1.1.3(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-checkbox':
+ specifier: ^1.1.4
+ version: 1.1.4(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@radix-ui/react-dialog':
specifier: ^1.1.6
version: 1.1.6(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -32,6 +35,9 @@ importers:
'@tailwindcss/typography':
specifier: ^0.5.16
version: 0.5.16(tailwindcss@3.4.17)
+ '@tanstack/react-query':
+ specifier: ^5.66.0
+ version: 5.66.0(react@19.0.0)
class-variance-authority:
specifier: ^0.7.1
version: 0.7.1
@@ -53,12 +59,18 @@ importers:
react-dom:
specifier: ^19.0.0
version: 19.0.0(react@19.0.0)
+ react-hook-form:
+ specifier: ^7.54.2
+ version: 7.54.2(react@19.0.0)
tailwind-merge:
specifier: ^3.0.1
version: 3.0.1
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.17)
+ zod:
+ specifier: ^3.24.2
+ version: 3.24.2
devDependencies:
'@eslint/eslintrc':
specifier: ^3
@@ -400,6 +412,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-checkbox@1.1.4':
+ resolution: {integrity: sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-collection@1.1.2':
resolution: {integrity: sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==}
peerDependencies:
@@ -672,6 +697,15 @@ packages:
'@types/react':
optional: true
+ '@radix-ui/react-use-previous@1.1.0':
+ resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@radix-ui/react-use-rect@1.1.0':
resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==}
peerDependencies:
@@ -723,6 +757,14 @@ packages:
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
+ '@tanstack/query-core@5.66.0':
+ resolution: {integrity: sha512-J+JeBtthiKxrpzUu7rfIPDzhscXF2p5zE/hVdrqkACBP8Yu0M96mwJ5m/8cPPYQE9aRNvXztXHlNwIh4FEeMZw==}
+
+ '@tanstack/react-query@5.66.0':
+ resolution: {integrity: sha512-z3sYixFQJe8hndFnXgWu7C79ctL+pI0KAelYyW+khaNJ1m22lWrhJU2QrsTcRKMuVPtoZvfBYrTStIdKo+x0Xw==}
+ peerDependencies:
+ react: ^18 || ^19
+
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
@@ -1798,6 +1840,12 @@ packages:
peerDependencies:
react: ^19.0.0
+ react-hook-form@7.54.2:
+ resolution: {integrity: sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18 || ^19
+
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
@@ -2171,6 +2219,9 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
+ zod@3.24.2:
+ resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==}
+
snapshots:
'@alloc/quick-lru@5.2.0': {}
@@ -2427,6 +2478,22 @@ snapshots:
'@types/react': 19.0.8
'@types/react-dom': 19.0.3(@types/react@19.0.8)
+ '@radix-ui/react-checkbox@1.1.4(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.1
+ '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0)
+ '@radix-ui/react-context': 1.1.1(@types/react@19.0.8)(react@19.0.0)
+ '@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-primitive': 2.0.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.8)(react@19.0.0)
+ '@radix-ui/react-use-previous': 1.1.0(@types/react@19.0.8)(react@19.0.0)
+ '@radix-ui/react-use-size': 1.1.0(@types/react@19.0.8)(react@19.0.0)
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+ optionalDependencies:
+ '@types/react': 19.0.8
+ '@types/react-dom': 19.0.3(@types/react@19.0.8)
+
'@radix-ui/react-collection@1.1.2(@types/react-dom@19.0.3(@types/react@19.0.8))(@types/react@19.0.8)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.8)(react@19.0.0)
@@ -2692,6 +2759,12 @@ snapshots:
optionalDependencies:
'@types/react': 19.0.8
+ '@radix-ui/react-use-previous@1.1.0(@types/react@19.0.8)(react@19.0.0)':
+ dependencies:
+ react: 19.0.0
+ optionalDependencies:
+ '@types/react': 19.0.8
+
'@radix-ui/react-use-rect@1.1.0(@types/react@19.0.8)(react@19.0.0)':
dependencies:
'@radix-ui/rect': 1.1.0
@@ -2735,6 +2808,13 @@ snapshots:
postcss-selector-parser: 6.0.10
tailwindcss: 3.4.17
+ '@tanstack/query-core@5.66.0': {}
+
+ '@tanstack/react-query@5.66.0(react@19.0.0)':
+ dependencies:
+ '@tanstack/query-core': 5.66.0
+ react: 19.0.0
+
'@types/estree@1.0.6': {}
'@types/json-schema@7.0.15': {}
@@ -4008,6 +4088,10 @@ snapshots:
react: 19.0.0
scheduler: 0.25.0
+ react-hook-form@7.54.2(react@19.0.0):
+ dependencies:
+ react: 19.0.0
+
react-is@16.13.1: {}
react-remove-scroll-bar@2.3.8(@types/react@19.0.8)(react@19.0.0):
@@ -4497,3 +4581,5 @@ snapshots:
yaml@2.7.0: {}
yocto-queue@0.1.0: {}
+
+ zod@3.24.2: {}
diff --git a/frontend/tailwind.config.ts b/frontend/tailwind.config.ts
index 95e1903..3cc13e4 100644
--- a/frontend/tailwind.config.ts
+++ b/frontend/tailwind.config.ts
@@ -8,84 +8,88 @@ export default {
"./app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
- extend: {
- colors: {
- background: 'hsl(var(--background))',
- foreground: 'hsl(var(--foreground))',
- card: {
- DEFAULT: 'hsl(var(--card))',
- foreground: 'hsl(var(--card-foreground))'
- },
- popover: {
- DEFAULT: 'hsl(var(--popover))',
- foreground: 'hsl(var(--popover-foreground))'
- },
- primary: {
- DEFAULT: 'hsl(var(--primary))',
- foreground: 'hsl(var(--primary-foreground))'
- },
- secondary: {
- DEFAULT: 'hsl(var(--secondary))',
- foreground: 'hsl(var(--secondary-foreground))'
- },
- muted: {
- DEFAULT: 'hsl(var(--muted))',
- foreground: 'hsl(var(--muted-foreground))'
- },
- accent: {
- DEFAULT: 'hsl(var(--accent))',
- foreground: 'hsl(var(--accent-foreground))'
- },
- destructive: {
- DEFAULT: 'hsl(var(--destructive))',
- foreground: 'hsl(var(--destructive-foreground))'
- },
- border: 'hsl(var(--border))',
- input: 'hsl(var(--input))',
- ring: 'hsl(var(--ring))',
- chart: {
- '1': 'hsl(var(--chart-1))',
- '2': 'hsl(var(--chart-2))',
- '3': 'hsl(var(--chart-3))',
- '4': 'hsl(var(--chart-4))',
- '5': 'hsl(var(--chart-5))'
- },
- sidebar: {
- DEFAULT: 'hsl(var(--sidebar-background))',
- foreground: 'hsl(var(--sidebar-foreground))',
- primary: 'hsl(var(--sidebar-primary))',
- 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
- accent: 'hsl(var(--sidebar-accent))',
- 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
- border: 'hsl(var(--sidebar-border))',
- ring: 'hsl(var(--sidebar-ring))'
- }
- },
- borderRadius: {
- lg: 'var(--radius)',
- md: 'calc(var(--radius) - 2px)',
- sm: 'calc(var(--radius) - 4px)'
- },
- keyframes: {
- dropAnimation: {
- '0%': {
- transform: 'translateY(-50px)',
- borderRadius: '50%',
- width: '1.5rem',
- height: '1.5rem'
- },
- '100%': {
- transform: 'translateY(100vh)',
- borderRadius: '50% 50% 50% 50%',
- width: '1rem',
- height: '2rem'
- }
- }
- },
- animation: {
- drop: 'dropAnimation 2s ease-in-out infinite'
- }
- }
+ extend: {
+ fontFamily: {
+ sans: ["var(--font-opensans)"],
+ mono: ["var(--font-roboto-mono)"],
+ },
+ colors: {
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ chart: {
+ "1": "hsl(var(--chart-1))",
+ "2": "hsl(var(--chart-2))",
+ "3": "hsl(var(--chart-3))",
+ "4": "hsl(var(--chart-4))",
+ "5": "hsl(var(--chart-5))",
+ },
+ sidebar: {
+ DEFAULT: "hsl(var(--sidebar-background))",
+ foreground: "hsl(var(--sidebar-foreground))",
+ primary: "hsl(var(--sidebar-primary))",
+ "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
+ accent: "hsl(var(--sidebar-accent))",
+ "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
+ border: "hsl(var(--sidebar-border))",
+ ring: "hsl(var(--sidebar-ring))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ dropAnimation: {
+ "0%": {
+ transform: "translateY(-50px)",
+ borderRadius: "50%",
+ width: "1.5rem",
+ height: "1.5rem",
+ },
+ "100%": {
+ transform: "translateY(100vh)",
+ borderRadius: "50% 50% 50% 50%",
+ width: "1rem",
+ height: "2rem",
+ },
+ },
+ },
+ animation: {
+ drop: "dropAnimation 2s ease-in-out infinite",
+ },
+ },
},
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
} satisfies Config;