From 2b3feaed21748a72809d73da6b24b4606b83acf1 Mon Sep 17 00:00:00 2001 From: Julia Dai <125892682+juliadai8@users.noreply.github.com> Date: Thu, 23 Jan 2025 10:50:25 +0100 Subject: [PATCH] Vf 166 lag tab komponent (#385) * vf-166 update team division cards styling * vf-166 Create new tab component * vf-166 Add light blue global color * vf-166 Fix styling of contact page * vf-166 Use global colors on team tabs * vf-166 Fix responsive design on teampage * vf-166 Install shadcn dropdown menu component * vf-166 Update responsive design for Kontakt page * VF-166 Refactor KontaktTabs layout * VF-166 Update colors in TeamTabs and Kontakt divisions * VF-166 Move Tab-component to component folder --- package.json | 1 + pnpm-lock.yaml | 15 ++ src/components/DropdownMenu.tsx | 200 ++++++++++++++++++ src/components/Tabs.tsx | 111 ++++++++++ .../public/Kontakt/components/Division.tsx | 18 +- .../public/Kontakt/components/KontaktOss.tsx | 49 ++--- src/pages/public/Team/components/Division.tsx | 91 ++++---- src/pages/public/Team/components/Team.tsx | 6 +- src/pages/public/Team/components/TeamTabs.tsx | 138 +++++------- tailwind.config.ts | 1 + 10 files changed, 445 insertions(+), 185 deletions(-) create mode 100644 src/components/DropdownMenu.tsx create mode 100644 src/components/Tabs.tsx diff --git a/package.json b/package.json index eda86646..36c25574 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@radix-ui/react-accordion": "^1.2.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-separator": "^1.1.0", + "@radix-ui/react-dropdown-menu": "^2.1.2", "@types/node": "^20.12.2", "@types/react": "^18.2.79", "@types/react-dom": "^18.2.25", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b20499f..4121588e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -570,6 +570,21 @@ packages: cpu: [x64] os: [win32] + '@floating-ui/core@1.6.8': + resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} + + '@floating-ui/dom@1.6.12': + resolution: {integrity: sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==} + + '@floating-ui/react-dom@2.1.2': + resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.8': + resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} + '@esbuild/win32-x64@0.24.0': resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} engines: {node: '>=18'} diff --git a/src/components/DropdownMenu.tsx b/src/components/DropdownMenu.tsx new file mode 100644 index 00000000..0fc4c0e0 --- /dev/null +++ b/src/components/DropdownMenu.tsx @@ -0,0 +1,200 @@ +"use client" + +import * as React from "react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "@/lib/utils" + +const DropdownMenu = DropdownMenuPrimitive.Root + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger + +const DropdownMenuGroup = DropdownMenuPrimitive.Group + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal + +const DropdownMenuSub = DropdownMenuPrimitive.Sub + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)) +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +} diff --git a/src/components/Tabs.tsx b/src/components/Tabs.tsx new file mode 100644 index 00000000..8f20236a --- /dev/null +++ b/src/components/Tabs.tsx @@ -0,0 +1,111 @@ +import { useEffect, useState } from "react"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@radix-ui/react-dropdown-menu"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faAngleDown } from "@fortawesome/free-solid-svg-icons"; + +interface TabProps { + divisions: DivisionList[]; + tabstate: number; + setOpenTab: (number: number) => void; +}; + +interface DivisionList { + name: string; + number: number; +} + +const Tabs = ({divisions, tabstate, setOpenTab}: TabProps): JSX.Element => { + const [isSmallScreen, setIsSmallScreen] = useState(false); + const [isOpen, setIsOpen] = useState(false); + + useEffect(() => { + const checkScreenSize = () => { + const isSmall = window.matchMedia("(max-width: 860px)").matches; + setIsSmallScreen(isSmall); + } + + checkScreenSize(); + window.addEventListener("resize", checkScreenSize); + + return () => { + window.removeEventListener("resize", checkScreenSize); + } + + + }, []) + + if (isSmallScreen) { + return ( + + + + + + {divisions.map((data) => { + const chosenStyle = + tabstate === data.number + ? "font-semibold text-vektor-darkblue" + : "hover:text-vektor-light-blue"; + return ( +
+ { + e.preventDefault(); + setOpenTab(data.number); + setIsOpen(false); + }} + > + {data.name} + + +
+ ); + })} +
+
+ ); + } + + + return ( +
+ {divisions.map((data) => { + const chosenStyle = + tabstate === data.number + ? "bg-vektor-darkblue text-white hover:bg-vektor-darkblue" + : "bg-transparent hover:bg-vektor-light-blue dark:text-white"; + return ( +
+ +
+ ); + })} +
+ ) +} + +export default Tabs; \ No newline at end of file diff --git a/src/pages/public/Kontakt/components/Division.tsx b/src/pages/public/Kontakt/components/Division.tsx index a568d625..03512df9 100644 --- a/src/pages/public/Kontakt/components/Division.tsx +++ b/src/pages/public/Kontakt/components/Division.tsx @@ -28,12 +28,12 @@ const Division = ({ }: DivisionProps): JSX.Element => { return ( <> -
+
{name}
{subtitle &&
{subtitle}
} {description &&
{description}
} -
+ {address && ( -
+
)} {members && ( -
+
@@ -116,7 +116,7 @@ const Division = ({
{contactInfos[id].name}
{contactInfos[id].title &&
{contactInfos[id].title}
} {contactInfos[id].mail} @@ -127,7 +127,7 @@ const Division = ({
{contact && ( -
+
{`Kontakt styret i ${name}`}
@@ -185,7 +185,7 @@ const Division = ({
diff --git a/src/pages/public/Kontakt/components/KontaktOss.tsx b/src/pages/public/Kontakt/components/KontaktOss.tsx index 51ed4db3..217589cb 100644 --- a/src/pages/public/Kontakt/components/KontaktOss.tsx +++ b/src/pages/public/Kontakt/components/KontaktOss.tsx @@ -1,7 +1,8 @@ import React, { useEffect } from "react"; import Division from "./Division.js"; +import Tabs from "@/components/Tabs.js"; -interface TabProps { +interface KontaktTabProps { divisions: DivisionList[]; } @@ -12,12 +13,12 @@ interface DivisionList { const TrondheimTab = ({ open }: { open: boolean }): JSX.Element => { return ( -
+
{ const AasTab = ({ open }: { open: boolean }): JSX.Element => { return ( -
+
{ const BergenTab = ({ open }: { open: boolean }): JSX.Element => { return ( -
+
{ const HovedstyretTab = ({ open }: { open: boolean }): JSX.Element => { return ( -
+
{ ); }; -const Tabs = ({ divisions }: TabProps): JSX.Element => { +const KontaktTabs = ({ divisions }: KontaktTabProps): JSX.Element => { const initialTabState = () => { const storedTab = sessionStorage.getItem("kontaktTab"); return storedTab ? Number.parseInt(storedTab, 10) : 1; @@ -159,35 +160,11 @@ const Tabs = ({ divisions }: TabProps): JSX.Element => { sessionStorage.setItem("kontaktTab", openTab.toString()); }, [openTab]); return ( -
-
- {divisions.map((data) => { - const chosenStyle = - openTab === data.number - ? "border-t-gray-200 border-l-gray-200 border-r-gray-200 border-b-white text-vektor-darblue z-50 dark:bg-neutral-800 dark:text-neutral-200 dark:border-t-white dark:border-l-white dark:border-r-white" - : "text-vektor-darblue z-50 dark:hover:bg-neutral-700 dark:border-b-white"; - return ( -
- -
- ); - })} +
+
+
-
+
@@ -197,4 +174,4 @@ const Tabs = ({ divisions }: TabProps): JSX.Element => { ); }; -export default Tabs; +export default KontaktTabs; diff --git a/src/pages/public/Team/components/Division.tsx b/src/pages/public/Team/components/Division.tsx index 77bfb0ce..72c9ab63 100644 --- a/src/pages/public/Team/components/Division.tsx +++ b/src/pages/public/Team/components/Division.tsx @@ -18,66 +18,49 @@ const Division = ({ url, }: Props): JSX.Element => { const navigate = useNavigate(); + + const chosenStyle = + title === "Styret" + ? "w-64" + : "w-64"; + return ( -
-
- {title} +
navigate(`/team/${url}`)}> +
+

+ {title} +

-
- {text} -
-
- - - - - - - {mail} - -
-
- - - -
{`${numberOfMembers} medlemmer`}
-
-
+
+

{text}

-
-
- ); -}; + ) +} -export default Division; +export default Division; \ No newline at end of file diff --git a/src/pages/public/Team/components/Team.tsx b/src/pages/public/Team/components/Team.tsx index 9c1e33fb..77e87c39 100644 --- a/src/pages/public/Team/components/Team.tsx +++ b/src/pages/public/Team/components/Team.tsx @@ -1,5 +1,5 @@ import TeamCard from "./TeamCard"; -import Tabs from "./TeamTabs"; +import TeamTabs from "./TeamTabs"; const teamInfo = { title: "Våre team", @@ -18,7 +18,7 @@ const teamInfo = { const Team = (): JSX.Element => { return ( -
+
{

{teamInfo.title}

- { return (
{ url="trondheim/styret" /> { url="trondheim/evaluering" /> { url="trondheim/rekruttering" /> { url="trondheim/skolekoordinering" /> { url="trondheim/sponsor" /> { url="trondheim/IT" /> { const AasTab = ({ open }: { open: boolean }): JSX.Element => { return (
{ url="aas/styret" /> { url="aas/sponsor-okonomi" /> { url="aas/skolekoordinering" /> { url="aas/evaluering-rekruttering-profilering" /> { const BergenTab = ({ open }: { open: boolean }): JSX.Element => { return (
{ url="bergen/styret" /> { url="bergen/skolekoordinering" /> { const navigate = useNavigate(); return (
-
-

+
+

Hovedstyret

-
+

Hovedstyret er det nasjonale styret i vektorprogrammet. De er et overordnet organ med ansvar for drifting av hele organisasjonen. -

-
+

+ -
+
{
- - Team1 +
+ Hovedstyret +
); }; -const Tabs = ({ divisions }: TabProps): JSX.Element => { + +const TeamTabs = ({ divisions }: TeamTabProps): JSX.Element => { const initialTabState = () => { const storedTab = sessionStorage.getItem("teamTab"); return storedTab ? Number.parseInt(storedTab, 10) : 1; }; - const [openTab, setOpenTab] = React.useState(initialTabState); + const [openTab, setOpenTab] = React.useState(initialTabState); + useEffect(() => { sessionStorage.setItem("teamTab", openTab.toString()); }, [openTab]); + return ( -
-
- -
- - - - -
+
+
+ +
+
+ + + +
- ); -}; + ) +} -export default Tabs; +export default TeamTabs; diff --git a/tailwind.config.ts b/tailwind.config.ts index bb30fee3..46942ff0 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -25,6 +25,7 @@ export default { "vektor-bg-dark": "#2a2a2a", "text-light": "#000", "text-dark": "#fff", + "vektor-light-blue": "#c7ecf8", }, keyframes: { "accordion-down": {