From 3bc12fdfdbb7f0d6ddedfa362144c010c8444ca6 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Fri, 2 Jun 2023 18:22:09 +0100 Subject: [PATCH] Updated home ui with portfolio status --- package-lock.json | 348 ++++++++++++++++++++ package.json | 1 + src/app/components/home/Card.tsx | 91 ++++- src/app/components/home/CardTiles.tsx | 3 + src/app/home/page.tsx | 16 +- src/app/shadcn_components/ui/badge.tsx | 36 ++ src/app/shadcn_components/ui/hover-card.tsx | 29 ++ src/types/portfolio.ts | 12 + tsconfig.json | 1 + 9 files changed, 532 insertions(+), 5 deletions(-) create mode 100644 src/app/shadcn_components/ui/badge.tsx create mode 100644 src/app/shadcn_components/ui/hover-card.tsx create mode 100644 src/types/portfolio.ts diff --git a/package-lock.json b/package-lock.json index acea992..4ab5586 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@headlessui/react": "^1.7.14", "@heroicons/react": "^2.0.18", + "@radix-ui/react-hover-card": "^1.0.6", "@radix-ui/react-slot": "^1.0.2", "@tanstack/react-query": "^4.29.12", "@types/node": "20.2.3", @@ -107,6 +108,31 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.6.tgz", + "integrity": "sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg==" + }, + "node_modules/@floating-ui/dom": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.9.tgz", + "integrity": "sha512-sosQxsqgxMNkV3C+3UqTS6LxP7isRLwX8WMepp843Rb3/b0Wz8+MdUkxJksByip3C2WwLugLHN1b4ibn//zKwQ==", + "dependencies": { + "@floating-ui/core": "^1.2.6" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.0.tgz", + "integrity": "sha512-Ke0oU3SeuABC2C4OFu2mSAwHIP5WUiV98O9YWoHV4Q5aT6E9k06DV0Khi5uYspR8xmmBk08t8ZDcz3TR3ARkEg==", + "dependencies": { + "@floating-ui/dom": "^1.2.7" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@headlessui/react": { "version": "1.7.14", "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.14.tgz", @@ -415,6 +441,37 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@radix-ui/primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", + "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz", + "integrity": "sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", @@ -432,6 +489,183 @@ } } }, + "node_modules/@radix-ui/react-context": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz", + "integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.4.tgz", + "integrity": "sha512-7UpBa/RKMoHJYjie1gkF1DlK8l1fdU/VKDpoS3rCCo8YBJR294GwcEHyxHw72yvphJ7ld0AXEcSLAzY2F/WyCg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-escape-keydown": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-hover-card": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.0.6.tgz", + "integrity": "sha512-2K3ToJuMk9wjwBOa+jdg2oPma+AmLdcEyTNsG/iC4BDVG3E0/mGCjbY8PEDSLxJcUi+nJi2QII+ec/4kWd88DA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.4", + "@radix-ui/react-popper": "1.1.2", + "@radix-ui/react-portal": "1.0.3", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.2.tgz", + "integrity": "sha512-1CnGGfFi/bbqtJZZ0P/NQY20xdG3E0LALJaLUEoKwPLwl6PPPfbeiCqMVQnhoFRAxjJj4RpBRJzDmUgsex2tSg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1", + "@radix-ui/react-use-rect": "1.0.1", + "@radix-ui/react-use-size": "1.0.1", + "@radix-ui/rect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.3.tgz", + "integrity": "sha512-xLYZeHrWoPmA5mEKEfZZevoVRK/Q43GfzRXkWV6qawIWWK8t6ifIiLQdd7rmQ4Vk1bmI21XhqF9BN3jWf+phpA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz", + "integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz", + "integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", @@ -450,6 +684,120 @@ } } }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", + "integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz", + "integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz", + "integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz", + "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz", + "integrity": "sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/rect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz", + "integrity": "sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz", + "integrity": "sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.0.tgz", diff --git a/package.json b/package.json index 1dcc122..00dbe6f 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "dependencies": { "@headlessui/react": "^1.7.14", "@heroicons/react": "^2.0.18", + "@radix-ui/react-hover-card": "^1.0.6", "@radix-ui/react-slot": "^1.0.2", "@tanstack/react-query": "^4.29.12", "@types/node": "20.2.3", diff --git a/src/app/components/home/Card.tsx b/src/app/components/home/Card.tsx index 0b2b8a2..75bcf90 100644 --- a/src/app/components/home/Card.tsx +++ b/src/app/components/home/Card.tsx @@ -1,5 +1,12 @@ +import { PortfolioStage } from "@/types/portfolio"; import Link from "next/link"; import React from "react"; +import { Badge } from "@/app/shadcn_components/ui/badge"; +import { + HoverCard, + HoverCardContent, + HoverCardTrigger, +} from "@/app/shadcn_components/ui/hover-card"; const styles = { wrapper: @@ -8,7 +15,7 @@ const styles = { imageWrapper: "h-56 rounded-2xl overflow-hidden flex items-center", wrapperAnime: "transition-all duration-500 ease-in-out", image: "object-cover w-1/3 mx-auto", - textWrapper: "pt-10 pb-6 w-full px-4 flex justify-between items-center", + textWrapper: "pt-6 pb-3 w-full px-4 flex justify-between items-center", }; interface CardProps { @@ -16,9 +23,88 @@ interface CardProps { title: string; image: string; budget: string; + status: PortfolioStage; } -const Card = ({ id, title, image, budget }: CardProps) => { +function StatusBadge({ status }: { status: PortfolioStage }) { + const statusConfig = statusColor[status]; + + return ( +
+ + + {statusConfig.text} + + +
+
+
+
+

+ {statusConfig.hoverText} +

+
+ + +
+ ); +} + +const statusColor: { + [key in PortfolioStage]: { class: string; text: string; hoverText: string }; +} = { + scoping: { + class: "bg-emerald-500 hover:bg-emerald-500", + text: "scoping", + hoverText: "This portfolio is currently in scoping", + }, + assessment: { + class: "bg-emerald-500 hover:bg-emerald-500", + text: "assessment", + hoverText: "This portfolio is currently in the assessment stage", + }, + tendering: { + class: "bg-emerald-500 hover:bg-emerald-500", + text: "tendering", + hoverText: "This portfolio is currently in the tendering stage", + }, + "project underway": { + class: "bg-emerald-500 hover:bg-emerald-500", + text: "project underway", + hoverText: "This portfolio has begun works", + }, + "completion; status 'on track'": { + class: "bg-emerald-500 hover:bg-emerald-500", + text: "on track", + hoverText: "This portfolio is on track to be completed on time", + }, + "completion; status 'delayed'": { + class: "bg-orange-400 hover:bg-orange-400", + text: "delayed", + hoverText: + "This portfolio is delayed and one or more properties require attention", + }, + "completion; status 'at risk'": { + class: "bg-red-400 hover:bg-red-400", + text: "at risk", + hoverText: + "This portfolio is at risk. One or more properties require attention", + }, + "completion; status 'completed'": { + class: "bg-gray-400 hover:bg-gray-400", + text: "completed", + hoverText: "This portfolio has been completed", + }, + "needs review": { + class: "bg-emerald-300 hover:bg-emerald-300", + text: "needs review", + hoverText: "The works in this portfolio has been completed and need review", + }, +}; + +const Card = ({ id, title, image, budget, status }: CardProps) => { return (
@@ -31,6 +117,7 @@ const Card = ({ id, title, image, budget }: CardProps) => {

{`${title}`}

{budget}
+
); diff --git a/src/app/components/home/CardTiles.tsx b/src/app/components/home/CardTiles.tsx index 048853c..3d2eaab 100644 --- a/src/app/components/home/CardTiles.tsx +++ b/src/app/components/home/CardTiles.tsx @@ -2,11 +2,13 @@ import Card from "./Card"; import AddNewCard from "./AddNewCard"; +import type { PortfolioStage } from "@/types/portfolio"; type PortfoliosType = Array<{ id: string; title: string; budget: string; + status: PortfolioStage; }>; export default function CardTiles({ @@ -27,6 +29,7 @@ export default function CardTiles({ title={portfolio.title} image={`house-icon-${image_idx}.svg`} budget={portfolio.budget} + status={portfolio.status} /> ); })} diff --git a/src/app/home/page.tsx b/src/app/home/page.tsx index f1b6399..f9582f4 100644 --- a/src/app/home/page.tsx +++ b/src/app/home/page.tsx @@ -1,5 +1,5 @@ -import Nav from "../components/Navbar"; import CardTiles from "../components/home/CardTiles"; +import type { PortfolioStage } from "@/types/portfolio"; const Home = async () => { const Portfolios = [ @@ -7,51 +7,61 @@ const Home = async () => { id: "d290f1ee-6c54-4b01-90e6-d701748f0851", title: "Portfolio 1", budget: "£500k", + status: "scoping" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0852", title: "Portfolio 2", budget: "£150k", + status: "assessment" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0853", title: "Portfolio 3", budget: "£1m", + status: "tendering" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0854", title: "Portfolio 4", budget: "£2m", + status: "tendering" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0855", title: "Portfolio 5", - budget: "£25k", + budget: "250000", + status: "project underway" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0856", title: "Portfolio 6", - budget: "£10k", + budget: "£410k", + status: "completion; status 'on track'" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0857", title: "Portfolio 7", budget: "£233k", + status: "completion; status 'delayed'" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0858", title: "Portfolio 8", budget: "£670k", + status: "completion; status 'at risk'" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0859", title: "Portfolio 9", budget: "£240k", + status: "completion; status 'completed'" as PortfolioStage, }, { id: "d290f1ee-6c54-4b01-90e6-d701748f0860", title: "Portfolio 10", budget: "93k", + status: "needs review" as PortfolioStage, }, ]; diff --git a/src/app/shadcn_components/ui/badge.tsx b/src/app/shadcn_components/ui/badge.tsx new file mode 100644 index 0000000..a0847a1 --- /dev/null +++ b/src/app/shadcn_components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center border rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "bg-primary hover:bg-primary/80 border-transparent text-primary-foreground", + secondary: + "bg-secondary hover:bg-secondary/80 border-transparent text-secondary-foreground", + destructive: + "bg-destructive hover:bg-destructive/80 border-transparent text-destructive-foreground", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ) +} + +export { Badge, badgeVariants } diff --git a/src/app/shadcn_components/ui/hover-card.tsx b/src/app/shadcn_components/ui/hover-card.tsx new file mode 100644 index 0000000..8abff5a --- /dev/null +++ b/src/app/shadcn_components/ui/hover-card.tsx @@ -0,0 +1,29 @@ +"use client" + +import * as React from "react" +import * as HoverCardPrimitive from "@radix-ui/react-hover-card" + +import { cn } from "@/lib/utils" + +const HoverCard = HoverCardPrimitive.Root + +const HoverCardTrigger = HoverCardPrimitive.Trigger + +const HoverCardContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + +)) +HoverCardContent.displayName = HoverCardPrimitive.Content.displayName + +export { HoverCard, HoverCardTrigger, HoverCardContent } diff --git a/src/types/portfolio.ts b/src/types/portfolio.ts new file mode 100644 index 0000000..e28511a --- /dev/null +++ b/src/types/portfolio.ts @@ -0,0 +1,12 @@ +type PortfolioStage = + | "scoping" + | "assessment" + | "tendering" + | "project underway" + | "completion; status 'on track'" + | "completion; status 'delayed'" + | "completion; status 'at risk'" + | "completion; status 'completed'" + | "needs review"; + +export type { PortfolioStage }; diff --git a/tsconfig.json b/tsconfig.json index 0c7555f..d71946f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "allowSyntheticDefaultImports": true, "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true,