diff --git a/ svgr.d.ts b/ svgr.d.ts new file mode 100644 index 0000000..277089a --- /dev/null +++ b/ svgr.d.ts @@ -0,0 +1,10 @@ +declare module '*.svg' { + import { FC, SVGProps } from 'react' + const content: FC> + export default content +} + +declare module '*.svg?url' { + const content: any + export default content +} \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index 45cbc5d..c2a45b7 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,13 +1,31 @@ -import type { NextConfig } from "next"; +module.exports = { + webpack(config:any) { + // Grab the existing rule that handles SVG imports + const fileLoaderRule = config.module.rules.find((rule:any) => + rule.test?.test?.('.svg'), + ) -const nextConfig: NextConfig = { - webpack(config) { - config.module.rules.push({ - test: /\.svg$/, - use: ['@svgr/webpack'], - }); - return config; + config.module.rules.push( + // Reapply the existing rule, but only for svg imports ending in ?url + { + ...fileLoaderRule, + test: /\.svg$/i, + resourceQuery: /url/, // *.svg?url + }, + // Convert all other *.svg imports to React components + { + test: /\.svg$/i, + issuer: fileLoaderRule.issuer, + resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url + use: ['@svgr/webpack'], + }, + ) + + // Modify the file loader rule to ignore *.svg, since we have it handled now. + fileLoaderRule.exclude = /\.svg$/i + + return config }, -}; -export default nextConfig; + // ...other config +} \ No newline at end of file diff --git a/package.json b/package.json index 9607b6a..e747e7f 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,8 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "15.2.3", + "install": "^0.13.0", + "npm": "^11.2.0", "tailwindcss": "^4", "typescript": "^5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 286735a..c286591 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,6 +81,12 @@ importers: eslint-config-next: specifier: 15.2.3 version: 15.2.3(eslint@9.23.0(jiti@2.4.2))(typescript@5.8.2) + install: + specifier: ^0.13.0 + version: 0.13.0 + npm: + specifier: ^11.2.0 + version: 11.2.0 tailwindcss: specifier: ^4 version: 4.0.15 @@ -2633,6 +2639,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + install@0.13.0: + resolution: {integrity: sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==} + engines: {node: '>= 0.10'} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -3011,6 +3021,78 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + npm@11.2.0: + resolution: {integrity: sha512-PcnFC6gTo9VDkxVaQ1/mZAS3JoWrDjAI+a6e2NgfYQSGDwftJlbdV0jBMi2V8xQPqbGcWaa7p3UP0SKF+Bhm2g==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + bundledDependencies: + - '@isaacs/string-locale-compare' + - '@npmcli/arborist' + - '@npmcli/config' + - '@npmcli/fs' + - '@npmcli/map-workspaces' + - '@npmcli/package-json' + - '@npmcli/promise-spawn' + - '@npmcli/redact' + - '@npmcli/run-script' + - '@sigstore/tuf' + - abbrev + - archy + - cacache + - chalk + - ci-info + - cli-columns + - fastest-levenshtein + - fs-minipass + - glob + - graceful-fs + - hosted-git-info + - ini + - init-package-json + - is-cidr + - json-parse-even-better-errors + - libnpmaccess + - libnpmdiff + - libnpmexec + - libnpmfund + - libnpmorg + - libnpmpack + - libnpmpublish + - libnpmsearch + - libnpmteam + - libnpmversion + - make-fetch-happen + - minimatch + - minipass + - minipass-pipeline + - ms + - node-gyp + - nopt + - normalize-package-data + - npm-audit-report + - npm-install-checks + - npm-package-arg + - npm-pick-manifest + - npm-profile + - npm-registry-fetch + - npm-user-validate + - p-map + - pacote + - parse-conflict-json + - proc-log + - qrcode-terminal + - read + - semver + - spdx-expression-parse + - ssri + - supports-color + - tar + - text-table + - tiny-relative-date + - treeverse + - validate-npm-package-name + - which + nprogress@0.2.0: resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} @@ -6463,6 +6545,8 @@ snapshots: imurmurhash@0.1.4: {} + install@0.13.0: {} + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -6815,6 +6899,8 @@ snapshots: node-releases@2.0.19: {} + npm@11.2.0: {} + nprogress@0.2.0: {} nth-check@2.1.1: diff --git a/src/app/admin/admins/page.tsx b/src/app/admin/admins/page.tsx new file mode 100644 index 0000000..3c50529 --- /dev/null +++ b/src/app/admin/admins/page.tsx @@ -0,0 +1,8 @@ + + +export default function Admins (){ + return ( + <> + + ) +} \ No newline at end of file diff --git a/src/app/admin/layout.tsx b/src/app/admin/layout.tsx index 90a195a..16e68aa 100644 --- a/src/app/admin/layout.tsx +++ b/src/app/admin/layout.tsx @@ -1,7 +1,7 @@ import { ReactNode } from "react"; import "../../assets/css/admin.css" -import Sidebar from "../components/sidebar"; -import Header from "../components/adminHeader"; +import Sidebar from "../../components/admin/sidebar"; +import Header from "../../components/admin/adminHeader"; export default function Dashboard({ children }: { children: ReactNode }) { diff --git a/src/app/admin/organizations/page.tsx b/src/app/admin/organizations/page.tsx new file mode 100644 index 0000000..a5fc92e --- /dev/null +++ b/src/app/admin/organizations/page.tsx @@ -0,0 +1,8 @@ + + +export default function Organizations (){ + return ( + <> + + ) +} \ No newline at end of file diff --git a/src/app/components/sidebar.tsx b/src/app/components/sidebar.tsx deleted file mode 100644 index e093e6a..0000000 --- a/src/app/components/sidebar.tsx +++ /dev/null @@ -1,38 +0,0 @@ -"use client" -import Image from "next/image"; -import { icons } from "#/assets/icons" -import NavItem from "./navItem"; -import { useState } from "react"; - - -export default function Sidebar() { - - const [activeItem, setActiveItem] = useState("home") - - const handleNavMenu = (item:string) => { - setActiveItem(item) - console.log("active: ", item); - - } - - - return ( - <> -
-
- Logo -
-
- handleNavMenu("home") } /> - handleNavMenu("organizations") } /> - handleNavMenu("admins") } /> -
-
- -
-
- - ) -} \ No newline at end of file diff --git a/src/app/components/theme.tsx b/src/app/components/theme.tsx deleted file mode 100644 index a6fafc1..0000000 --- a/src/app/components/theme.tsx +++ /dev/null @@ -1,46 +0,0 @@ -"use client" -import Image from "next/image"; -import { useEffect, useState } from "react"; -import { icons } from "#/assets/icons" - -export default function Theme() { - - const [theme, setTheme] = useState( - localStorage.getItem("theme") || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light") - ); - - useEffect(() => { - document.body.setAttribute("data-theme", theme); - localStorage.setItem("theme", theme); - - const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); - const handleChange = (e: MediaQueryListEvent) => { - const newTheme = e.matches ? "dark" : "light"; - setTheme(newTheme); - }; - - mediaQuery.addEventListener("change", handleChange); - - return () => { - mediaQuery.removeEventListener("change", handleChange); - }; - }, [theme]); - - const handleTheme = () => { - setTheme(theme === "light" ? "dark" : "light"); - }; - - return ( - <> -
handleTheme()} className="theme"> - -
- - ) -} \ No newline at end of file diff --git a/src/app/page.tsx b/src/app/page.tsx deleted file mode 100644 index 3a74f13..0000000 --- a/src/app/page.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import Image from "next/image"; -import Link from "next/link"; - -export default function Home() { - return ( -
- See the admin page -
- ); -} diff --git a/src/assets/icons.zip b/src/assets/icons.zip new file mode 100644 index 0000000..4a8ab2a Binary files /dev/null and b/src/assets/icons.zip differ diff --git a/src/assets/icons/index2.ts b/src/assets/icons/index2.ts new file mode 100644 index 0000000..d740c72 --- /dev/null +++ b/src/assets/icons/index2.ts @@ -0,0 +1,62 @@ +import { GeneralHtmlAttr } from "#/lib/declarations"; + +const icons = { + CalendarMark: "Calendar Mark.svg", + Document: "Document.svg", + Ellipse2: "Ellipse 2.svg", + Group1: "Group (1).svg", + Group: "Group.svg", + Icons1: "Icons (1).svg", + Icons: "Icons.svg", + LineDuotone: "Line Duotone.svg", + MenuDots: "Menu Dots.svg", + NavItem: "NavItem.svg", + Path1: "Path (1).svg", + Path: "Path.svg", + Rectangle: "Rectangle.svg", + Search: "Search.svg", + Vector: "Vector.svg", + Add: "add.svg", + Archives: "archives.svg", + ArrowLeft: "arrowLeft.svg", + ArrowRight: "arrowRight.svg", + Buildings: "buildings.svg", + Checked: "checked.svg", + Cross: "cross.svg", + DocumentText: "document-text.svg", + Edit2: "edit-2.svg", + Element3White: "element-3-white.svg", + Element3: "element-3.svg", + EyeSlash: "eye-slash.svg", + Eye: "eye.svg", + IconAdd: "icon-add.svg", + Logo: "logo.svg", + LogoutRed: "logout-red.svg", + Logout: "logout.svg", + Maximize3: "maximize-3.svg", + Message: "message.svg", + Notifications: "notifications.svg", + PhFiles: "ph_files.svg", + PrimeFilePdf: "prime_file-pdf.svg", + PrimeFileWord: "prime_file-word.svg", + Profile2UserBlue: "profile-2user-blue.svg", + Profile2User: "profile-2user.svg", + Profile: "profile.svg", + Setting2: "setting-2.svg", + Setting3: "setting-3.svg", + Share: "share.svg", + Star: "star.svg", + Moon: "moon.svg", + Sun: "sun.svg", +}; + +export const Icon = ({ name, ...props }: { name: keyof typeof icons } & GeneralHtmlAttr) => { + const IconComponent = icons[name]; + if (!IconComponent) return null; + + return ( +
+ {name} +
+ ); +}; diff --git a/src/assets/icons/profile.svg b/src/assets/icons/profile.svg index 3c1321c..96c4612 100644 --- a/src/assets/icons/profile.svg +++ b/src/assets/icons/profile.svg @@ -1,4 +1,4 @@ - - + + diff --git a/src/app/components/adminHeader.tsx b/src/components/admin/adminHeader.tsx similarity index 96% rename from src/app/components/adminHeader.tsx rename to src/components/admin/adminHeader.tsx index b0c03fc..2e31708 100644 --- a/src/app/components/adminHeader.tsx +++ b/src/components/admin/adminHeader.tsx @@ -7,6 +7,7 @@ import { DropdownMenu } from "radix-ui"; import Link from "next/link"; import Theme from "./theme"; +import ProfilePicture from "../../assets/icons/profile.svg" export default function AdminHeader() { const [open, setOpen] = React.useState(false); @@ -17,6 +18,8 @@ export default function AdminHeader() {

Bienvenue, Ken B.

+ {/* */} + diff --git a/src/app/components/navItem.tsx b/src/components/admin/navItem.tsx similarity index 69% rename from src/app/components/navItem.tsx rename to src/components/admin/navItem.tsx index 9c1acd1..a14b287 100644 --- a/src/app/components/navItem.tsx +++ b/src/components/admin/navItem.tsx @@ -7,13 +7,12 @@ interface ItemProps { label: string; isActive: boolean; isNavHome?: boolean; - onClick: () => void; } -export default function NavItem({ link, iconSrc, label, isActive, isNavHome, onClick }: ItemProps) { +export default function NavItem({ link, iconSrc, label, isActive, isNavHome }: ItemProps) { return ( <> - + {label} diff --git a/src/components/admin/sidebar.tsx b/src/components/admin/sidebar.tsx new file mode 100644 index 0000000..a17fbf1 --- /dev/null +++ b/src/components/admin/sidebar.tsx @@ -0,0 +1,32 @@ +"use client" +import Image from "next/image"; +import { icons } from "#/assets/icons" +import NavItem from "./navItem"; +import { usePathname } from "next/navigation"; +import Link from "next/link"; + + +export default function Sidebar() { + + const pathname = usePathname(); + + return ( + <> +
+
+ Logo +
+
+ + + +
+
+ + Logout + +
+
+ + ) +} \ No newline at end of file diff --git a/src/components/admin/theme.tsx b/src/components/admin/theme.tsx new file mode 100644 index 0000000..ea429c4 --- /dev/null +++ b/src/components/admin/theme.tsx @@ -0,0 +1,54 @@ +"use client" +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { icons } from "#/assets/icons" + +export default function Theme() { + const [theme, setTheme] = useState(null); + + useEffect(() => { + if (typeof window !== "undefined") { + const savedTheme = localStorage.getItem("theme") || + (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light"); + + setTheme(savedTheme); + document.body.setAttribute("data-theme", savedTheme); + } + }, []); + + const handleTheme = () => { + const newTheme = theme === "light" ? "dark" : "light"; + setTheme(newTheme); + localStorage.setItem("theme", newTheme); + document.body.setAttribute("data-theme", newTheme); + }; + + useEffect(() => { + if (theme === null) return; + + const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); + const handleChange = (e: MediaQueryListEvent) => { + const newTheme = e.matches ? "dark" : "light"; + setTheme(newTheme); + localStorage.setItem("theme", newTheme); + document.body.setAttribute("data-theme", newTheme); + }; + + mediaQuery.addEventListener("change", handleChange); + return () => mediaQuery.removeEventListener("change", handleChange); + }, [theme]); + + if (theme === null) return null; + + return ( +
+ +
+ ); +} diff --git a/src/lib/declarations.ts b/src/lib/declarations.ts new file mode 100644 index 0000000..7fffba8 --- /dev/null +++ b/src/lib/declarations.ts @@ -0,0 +1,3 @@ +// src/lib/declarations.ts + +export type GeneralHtmlAttr = React.HTMLProps | React.HTMLProps; diff --git a/tsconfig.json b/tsconfig.json index 7c255f4..705f497 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,9 +19,10 @@ } ], "paths": { - "#/*": ["./src/*"] + "#/*": ["./src/*"], + "@/*": ["./src/*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "include": ["svgr.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] }