diff --git a/media/images/2025-03-12-115205_hyprshot-1024x1143.png b/media/images/2025-03-12-115205_hyprshot-1024x1143.png new file mode 100644 index 0000000..33b5d54 Binary files /dev/null and b/media/images/2025-03-12-115205_hyprshot-1024x1143.png differ diff --git a/media/images/2025-03-12-115205_hyprshot-400x300.png b/media/images/2025-03-12-115205_hyprshot-400x300.png new file mode 100644 index 0000000..0580bf0 Binary files /dev/null and b/media/images/2025-03-12-115205_hyprshot-400x300.png differ diff --git a/media/images/2025-03-12-115205_hyprshot-768x1024.png b/media/images/2025-03-12-115205_hyprshot-768x1024.png new file mode 100644 index 0000000..483a776 Binary files /dev/null and b/media/images/2025-03-12-115205_hyprshot-768x1024.png differ diff --git a/media/images/2025-03-12-115205_hyprshot.png b/media/images/2025-03-12-115205_hyprshot.png new file mode 100644 index 0000000..937dd6c Binary files /dev/null and b/media/images/2025-03-12-115205_hyprshot.png differ diff --git a/media/images/ial-white-transp-1024x449.png b/media/images/ial-white-transp-1024x449.png new file mode 100644 index 0000000..5393559 Binary files /dev/null and b/media/images/ial-white-transp-1024x449.png differ diff --git a/media/images/ial-white-transp-400x300.png b/media/images/ial-white-transp-400x300.png new file mode 100644 index 0000000..2fa0420 Binary files /dev/null and b/media/images/ial-white-transp-400x300.png differ diff --git a/media/images/ial-white-transp-768x1024.png b/media/images/ial-white-transp-768x1024.png new file mode 100644 index 0000000..df0083c Binary files /dev/null and b/media/images/ial-white-transp-768x1024.png differ diff --git a/media/images/ial-white-transp.png b/media/images/ial-white-transp.png new file mode 100644 index 0000000..1427814 Binary files /dev/null and b/media/images/ial-white-transp.png differ diff --git a/next.config.ts b/next.config.ts index a8f60af..dc4cf9e 100644 --- a/next.config.ts +++ b/next.config.ts @@ -3,6 +3,12 @@ import withPayload from "@payloadcms/next/withPayload"; const nextConfig: NextConfig = { /* config options here */ + images: { + remotePatterns: [ + new URL("http://localhost:3000/**"), + new URL("https://inzight.co.nz/**"), + ], + }, }; export default withPayload(nextConfig); diff --git a/package.json b/package.json index 05c4ccb..0caf2ed 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@tailwindcss/postcss": "^4.1.4", "clsx": "^2.1.1", "graphql": "^16.10.0", + "motion": "^12.15.0", "next": "15.3.1", "payload": "^3.35.1", "pg": "8.11.3", diff --git a/payload-types.ts b/payload-types.ts index 9983911..41f960a 100644 --- a/payload-types.ts +++ b/payload-types.ts @@ -93,10 +93,12 @@ export interface Config { defaultIDType: number; }; globals: { + general: General; homeHero: HomeHero; homeProjects: HomeProject; }; globalsSelect: { + general: GeneralSelect | GeneralSelect; homeHero: HomeHeroSelect | HomeHeroSelect; homeProjects: HomeProjectsSelect | HomeProjectsSelect; }; @@ -549,6 +551,16 @@ export interface PayloadMigrationsSelect { updatedAt?: T; createdAt?: T; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "general". + */ +export interface General { + id: number; + logo: number | Image; + updatedAt?: string | null; + createdAt?: string | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "homeHero". @@ -618,6 +630,16 @@ export interface HomeProject { updatedAt?: string | null; createdAt?: string | null; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "general_select". + */ +export interface GeneralSelect { + logo?: T; + updatedAt?: T; + createdAt?: T; + globalType?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "homeHero_select". diff --git a/payload.config.ts b/payload.config.ts index 01847d6..7c2a792 100644 --- a/payload.config.ts +++ b/payload.config.ts @@ -1,16 +1,20 @@ -import sharp from 'sharp' -import { FixedToolbarFeature, lexicalEditor } from '@payloadcms/richtext-lexical' -import { postgresAdapter } from '@payloadcms/db-postgres' -import { buildConfig } from 'payload' +import sharp from "sharp"; +import { + FixedToolbarFeature, + lexicalEditor, +} from "@payloadcms/richtext-lexical"; +import { postgresAdapter } from "@payloadcms/db-postgres"; +import { buildConfig } from "payload"; -import { HomeHero } from '@/globals/Home/Hero' +import { HomeHero } from "@/globals/Home/Hero"; -import { News } from './src/collections/News' -import { Projects } from '@/collections/Projects' -import { Images } from '@/collections/media/Images' -import { Documents } from '@/collections/media/Documents' -import { Data } from '@/collections/media/Data' -import { HomeProjects } from '@/globals/Home/Projects' +import { News } from "./src/collections/News"; +import { Projects } from "@/collections/Projects"; +import { Images } from "@/collections/media/Images"; +import { Documents } from "@/collections/media/Documents"; +import { Data } from "@/collections/media/Data"; +import { HomeProjects } from "@/globals/Home/Projects"; +import { General } from "@/globals/General"; export default buildConfig({ // If you'd like to use Rich Text, pass your editor here @@ -18,28 +22,28 @@ export default buildConfig({ features: ({ defaultFeatures }) => [ ...defaultFeatures, FixedToolbarFeature(), - ] + ], }), - serverURL: process.env.SERVER_URL || 'http://localhost:3000', + serverURL: process.env.SERVER_URL || "http://localhost:3000", - globals: [HomeHero, HomeProjects], + globals: [General, HomeHero, HomeProjects], // Define and configure your collections in this array collections: [Projects, News, Images, Documents, Data], // Your Payload secret - should be a complex and secure string, unguessable - secret: process.env.PAYLOAD_SECRET || '', + secret: process.env.PAYLOAD_SECRET || "", // Whichever Database Adapter you're using should go here // Mongoose is shown as an example, but you can also use Postgres db: postgresAdapter({ pool: { - connectionString: process.env.DATABASE_URI, - } + connectionString: process.env.DATABASE_URI, + }, }), // If you want to resize images, crop, set focal point, etc. // make sure to install it and pass it to the config. // This is optional - if you don't need to do these things, // you don't need it! sharp, -}) +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f11bd0..05b01dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: graphql: specifier: ^16.10.0 version: 16.10.0 + motion: + specifier: ^12.15.0 + version: 12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next: specifier: 15.3.1 version: 15.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.77.4) @@ -2053,6 +2056,20 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + framer-motion@12.15.0: + resolution: {integrity: sha512-XKg/LnKExdLGugZrDILV7jZjI599785lDIJZLxMiiIFidCsy0a4R2ZEf+Izm67zyOuJgQYTHOmodi7igQsw3vg==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -2619,6 +2636,26 @@ packages: monaco-editor@0.52.2: resolution: {integrity: sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==} + motion-dom@12.15.0: + resolution: {integrity: sha512-D2ldJgor+2vdcrDtKJw48k3OddXiZN1dDLLWrS8kiHzQdYVruh0IoTwbJBslrnTXIPgFED7PBN2Zbwl7rNqnhA==} + + motion-utils@12.12.1: + resolution: {integrity: sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w==} + + motion@12.15.0: + resolution: {integrity: sha512-HLouXyIb1uQFiZgJTYGrtEzbatPc6vK+HP+Qt6afLQjaudiGiLLVsoy71CwzD/Stlh06FUd5OpyiXqn6XvqjqQ==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -5544,6 +5581,15 @@ snapshots: dependencies: is-callable: 1.2.7 + framer-motion@12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + motion-dom: 12.15.0 + motion-utils: 12.12.1 + tslib: 2.8.1 + optionalDependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + fsevents@2.3.3: optional: true @@ -6212,6 +6258,20 @@ snapshots: monaco-editor@0.52.2: {} + motion-dom@12.15.0: + dependencies: + motion-utils: 12.12.1 + + motion-utils@12.12.1: {} + + motion@12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + framer-motion: 12.15.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + tslib: 2.8.1 + optionalDependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + ms@2.1.3: {} nanoid@3.3.11: {} diff --git a/src/app/(payload)/admin/importMap.js b/src/app/(payload)/admin/importMap.js index 37acad6..090c3af 100644 --- a/src/app/(payload)/admin/importMap.js +++ b/src/app/(payload)/admin/importMap.js @@ -1,5 +1,6 @@ import { RscEntryLexicalCell as RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc' import { RscEntryLexicalField as RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc' +import { LexicalDiffComponent as LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e } from '@payloadcms/richtext-lexical/rsc' import { FixedToolbarFeatureClient as FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { InlineToolbarFeatureClient as InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' import { HorizontalRuleFeatureClient as HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864 } from '@payloadcms/richtext-lexical/client' @@ -25,6 +26,7 @@ import { ItalicFeatureClient as ItalicFeatureClient_e70f5e05f09f93e00b997edb1ef0 export const importMap = { "@payloadcms/richtext-lexical/rsc#RscEntryLexicalCell": RscEntryLexicalCell_44fe37237e0ebf4470c9990d8cb7b07e, "@payloadcms/richtext-lexical/rsc#RscEntryLexicalField": RscEntryLexicalField_44fe37237e0ebf4470c9990d8cb7b07e, + "@payloadcms/richtext-lexical/rsc#LexicalDiffComponent": LexicalDiffComponent_44fe37237e0ebf4470c9990d8cb7b07e, "@payloadcms/richtext-lexical/client#FixedToolbarFeatureClient": FixedToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#InlineToolbarFeatureClient": InlineToolbarFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, "@payloadcms/richtext-lexical/client#HorizontalRuleFeatureClient": HorizontalRuleFeatureClient_e70f5e05f09f93e00b997edb1ef0c864, diff --git a/src/app/(website)/brand/page.tsx b/src/app/(website)/brand/page.tsx index ee1738c..0634ab1 100644 --- a/src/app/(website)/brand/page.tsx +++ b/src/app/(website)/brand/page.tsx @@ -12,7 +12,7 @@ const BUTTON_VARIANTS: Parameters[0]["variant"][] = [ export default function Page() { return ( -
+

iNZight Analytics Brand

@@ -20,9 +20,9 @@ export default function Page() {

Colours

-
-
-
+
+
+
diff --git a/src/app/(website)/components/Button/index.tsx b/src/app/(website)/components/Button/index.tsx index 366f10f..21ec46a 100644 --- a/src/app/(website)/components/Button/index.tsx +++ b/src/app/(website)/components/Button/index.tsx @@ -22,16 +22,16 @@ export default function Button({ variant === "filled" ? "" : "border", type === "primary" && (variant === "filled" - ? "bg-accent-800 text-accent-100" - : "border-accent-800 text-accent-800 hover:bg-accent-800 hover:text-accent-100"), + ? "bg-accent-600 text-accent-50 hover:bg-accent-700" + : "border-accent-600 text-accent-600 hover:bg-accent-600 hover:text-accent-50"), type === "secondary" && (variant === "filled" - ? "bg-secondary-800 text-secondary-100" - : "border-secondary-800 text-secondary-800 hover:bg-secondary-800 hover:text-secondary-100"), + ? "bg-secondary-600 text-secondary-50 hover:bg-secondary-700" + : "border-secondary-600 text-secondary-600 hover:bg-secondary-600 hover:text-secondary-50"), type === "alternate" && (variant === "filled" - ? "bg-black text-white" - : "border-black text-black hover:bg-black hover:text-white") + ? "bg-black text-white dark:bg-white dark:text-black" + : "border-black text-black hover:bg-black hover:text-white dark:border-white dark:text-white dark:hover:bg-white dark:hover:text-black") )} {...props} > diff --git a/src/app/(website)/components/Header/index.tsx b/src/app/(website)/components/Header/index.tsx new file mode 100644 index 0000000..a6a7952 --- /dev/null +++ b/src/app/(website)/components/Header/index.tsx @@ -0,0 +1,38 @@ +import { getPayload } from "payload"; +import config from "@payload-config"; +import Link from "next/link"; +import Image from "next/image"; +import { Image as PImage } from "@payload-types"; + +const isValidLogo = (image: number | PImage): image is PImage => { + return typeof image !== "number"; +}; + +export default async function Header() { + const payload = await getPayload({ config }); + const { logo } = await payload.findGlobal({ + slug: "general", + }); + + if (typeof logo === "number") throw "Bad image"; + + return ( +
+ {/* Left hand side - logo */} + + LOGO + {/* {logo.url && logo.alt && logo.width && logo.height && ( + {logo.alt} + )} */} + + + {/* Right hand size - nav */} + +
+ ); +} diff --git a/src/app/(website)/components/Hero/ScrollingNumbers.tsx b/src/app/(website)/components/Hero/ScrollingNumbers.tsx new file mode 100644 index 0000000..422d7fb --- /dev/null +++ b/src/app/(website)/components/Hero/ScrollingNumbers.tsx @@ -0,0 +1,44 @@ +"use client"; + +import { motion } from "motion/react"; +import { letters } from "./letters"; + +export default function ScrollingNumbers({ numbers }: { numbers: string[][] }) { + return ( +
+
+ {numbers.map((col, i) => ( + + ))} +
+
+
+ ); +} + +const NumberCol = ({ col }: { col: string[] }) => { + const range = [0, -100]; + const speed = Math.log(letters.indexOf(col[0]) + 10) * 100; + + return ( + + {col.map((num, j) => ( +
+ {num} +
+ ))} +
+ ); +}; diff --git a/src/app/(website)/components/Hero/letters.ts b/src/app/(website)/components/Hero/letters.ts new file mode 100644 index 0000000..4653e72 --- /dev/null +++ b/src/app/(website)/components/Hero/letters.ts @@ -0,0 +1,38 @@ +export const letters = [ + "a", + "b", + "c", + "d", + "e", + "f", + // "g", + // "h", + // "i", + // "j", + // "k", + // "l", + // "m", + // "n", + // "o", + // "p", + // "q", + // "r", + // "s", + // "t", + // "u", + // "v", + // "w", + // "x", + // "y", + // "z", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", +]; diff --git a/src/app/(website)/globals.css b/src/app/(website)/globals.css index 2b956ef..1973c74 100644 --- a/src/app/(website)/globals.css +++ b/src/app/(website)/globals.css @@ -31,4 +31,7 @@ --color-secondary-800: #344735; --color-secondary-900: #2c3b2d; --color-secondary-950: #141f16; + + /* Other vars */ + --header-height: 100px; } diff --git a/src/app/(website)/layout.tsx b/src/app/(website)/layout.tsx index fe9f311..0c1003f 100644 --- a/src/app/(website)/layout.tsx +++ b/src/app/(website)/layout.tsx @@ -1,9 +1,10 @@ import type { Metadata } from "next"; import "./globals.css"; +import Header from "./components/Header"; export const metadata: Metadata = { - title: "Create Next App", + title: "iNZight Analytics Ltd", description: "Generated by create next app", }; @@ -14,7 +15,10 @@ export default function RootLayout({ }>) { return ( - {children} + +
+ {children} + ); } diff --git a/src/app/(website)/page.tsx b/src/app/(website)/page.tsx index bb5b368..9f5fee0 100644 --- a/src/app/(website)/page.tsx +++ b/src/app/(website)/page.tsx @@ -1,3 +1,27 @@ -export default function Home() { - return
hello
; +import { getPayload } from "payload"; +import config from "@payload-config"; +import ScrollingNumbers from "./components/Hero/ScrollingNumbers"; +import { letters } from "./components/Hero/letters"; + +const randomNumbers = Array.from({ length: 50 }).map((i) => + Array.from({ length: 200 }).map( + (j) => letters[Math.floor(Math.random() * letters.length)] + ) +); + +export default async function Home() { + const payload = await getPayload({ config }); + const { titleGroup } = await payload.findGlobal({ + slug: "homeHero", + }); + + return ( +
+
+ +

{titleGroup.title}

+
+
hello
+
+ ); } diff --git a/src/globals/General.ts b/src/globals/General.ts new file mode 100644 index 0000000..629f274 --- /dev/null +++ b/src/globals/General.ts @@ -0,0 +1,15 @@ +import { GlobalConfig } from "payload"; + +export const General: GlobalConfig = { + slug: "general", + label: "General", + fields: [ + { + name: "logo", + required: true, + label: "Logo", + type: "upload", + relationTo: "images", + }, + ], +}; diff --git a/tsconfig.json b/tsconfig.json index d4a7c10..a1b9bbb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,8 @@ ], "paths": { "@/*": ["./src/*"], - "@payload-config": ["./payload.config.ts"] + "@payload-config": ["./payload.config.ts"], + "@payload-types": ["./payload-types.ts"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],