Skip to content

Commit

Permalink
WEB-21: Add button states
Browse files Browse the repository at this point in the history
  • Loading branch information
vinnie4k committed Dec 12, 2024
1 parent 1873875 commit 0864693
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 79 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"clsx": "^2.1.1",
"cmdk": "1.0.0",
"date-fns": "^4.1.0",
"framer-motion": "^11.13.1",
"framer-motion": "^11.14.0",
"lucide-react": "^0.468.0",
"next": "^15.0.4-canary.36",
"react": "^18",
Expand Down
2 changes: 1 addition & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@layer base {
/* Effects */
.opacity-hover {
@apply cursor-pointer hover:opacity-80 transition-all;
@apply cursor-pointer hover:opacity-80 transition-all duration-300;
}

/* Mobile */
Expand Down
6 changes: 3 additions & 3 deletions src/components/announcement/announcementCell.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import AppIcon from "@/icons/appIcon";
import ButtonTertiary from "../system/button/buttonTertiary";
import { Announcement } from "@/models/announcement";
import { DateFormat } from "@/models/enums/dateFormat";
import { dateInRange, filterActiveAnnouncements, formatDate } from "@/utils/utils";
import ButtonTertiary from "../system/button/buttonTertiary";
import AnnouncementIndicator from "./announcementIndicator";
import { DateFormat } from "@/models/enums/dateFormat";

interface Props {
announcement: Announcement;
Expand All @@ -16,7 +16,7 @@ export default function AnnouncementCell({ announcement, onClick, onEditClick }:

return (
<div
className="flex flex-col p-6 items-start md:items-end md:flex-row justify-center gap-6 md:gap-8 self-stretch bg-neutral-white rounded-lg border border-other-stroke relative cursor-pointer"
className="flex flex-col p-6 items-start md:items-end md:flex-row justify-center gap-6 md:gap-8 self-stretch bg-neutral-white rounded-lg border border-other-stroke relative transition-all duration-300 cursor-pointer hover:bg-neutral-50"
onClick={onClick}
>
<img src={announcement.imageUrl} className="rounded-lg md:size-[108px]" />
Expand Down
12 changes: 6 additions & 6 deletions src/components/announcement/announcementForm.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import CrossThinIcon from "@/icons/crossThinIcon";
import SpeakerIcon from "@/icons/speakerIcon";
import AnnouncementBanner from "./announcementBanner";
import { useEffect, useMemo, useState } from "react";
import { Announcement } from "@/models/announcement";
import InputText from "../system/input/inputText";
import { useUserStore } from "@/stores/useUserStore";
import { addDays } from "date-fns";
import { useMemo, useState } from "react";
import ButtonPrimary1 from "../system/button/buttonPrimary1";
import InputDatePicker from "../system/input/inputDatePicker";
import InputMultiSelect from "../system/input/inputMultiselect";
import InputText from "../system/input/inputText";
import InputUpload from "../system/input/inputUpload";
import ButtonPrimary1 from "../system/button/buttonPrimary1";
import { useUserStore } from "@/stores/useUserStore";
import { addDays } from "date-fns";
import AnnouncementBanner from "./announcementBanner";

const dummyAnnouncement: Announcement = {
id: "",
Expand Down
10 changes: 5 additions & 5 deletions src/components/announcement/announcementModal.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Announcement } from "@/models/announcement";
import AnnouncementBanner from "./announcementBanner";
import AppIcon from "@/icons/appIcon";
import CrossThinIcon from "@/icons/crossThinIcon";
import { dateInRange, formatDate } from "@/utils/utils";
import AnnouncementIndicator from "./announcementIndicator";
import { Announcement } from "@/models/announcement";
import { DateFormat } from "@/models/enums/dateFormat";
import ButtonSecondary2 from "../system/button/buttonSecondary2";
import { dateInRange, formatDate } from "@/utils/utils";
import ButtonPrimary2 from "../system/button/buttonPrimary2";
import ButtonSecondary2 from "../system/button/buttonSecondary2";
import AnnouncementBanner from "./announcementBanner";
import AnnouncementIndicator from "./announcementIndicator";

interface AnnouncementModalProps {
onClose: () => void;
Expand Down
6 changes: 3 additions & 3 deletions src/components/landing/landingPastSection.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import CalendarPlainIcon from "@/icons/calendarPlainIcon";
import { Announcement } from "@/models/announcement";
import { Constants } from "@/utils/constants";
import { filterPastAnnouncements, sortAnnouncementsByStartDate } from "@/utils/utils";
import { useRouter } from "next/navigation";
import { useState } from "react";
import AnnouncementCell from "../announcement/announcementCell";
import AnnouncementModal from "../announcement/announcementModal";
import { useState } from "react";
import ButtonSecondary1 from "../system/button/buttonSecondary1";
import { Constants } from "@/utils/constants";
import { useRouter } from "next/navigation";

interface Props {
announcements?: Announcement[];
Expand Down
6 changes: 3 additions & 3 deletions src/components/past/pastFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { AppName } from "@/models/enums/appName";
import InputDatePicker from "../system/input/inputDatePicker";
import { useState } from "react";
import { DateRange } from "react-day-picker";
import InputMultiSelect from "../system/input/inputMultiselect";
import ButtonPrimary2 from "../system/button/buttonPrimary2";
import ButtonPrimary3 from "../system/button/buttonPrimary3";
import { useState } from "react";
import InputDatePicker from "../system/input/inputDatePicker";
import InputMultiSelect from "../system/input/inputMultiselect";

interface Props {
initialDateRange: DateRange | undefined;
Expand Down
100 changes: 86 additions & 14 deletions src/components/system/button/buttonPrimary1.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,109 @@
"use client";

import CaretRightIcon from "@/icons/caretRightIcon";
import { motion } from "framer-motion";
import { Loader2 } from "lucide-react";
import { useState } from "react";

interface Props {
text: string;
action: () => void;
disabled?: boolean;
className?: string;
textStyle?: string;
isLoading?: boolean;
}

export default function ButtonPrimary1({ text, action, disabled = false, className, textStyle }: Props) {
export default function ButtonPrimary1({
text,
action,
disabled = false,
className,
textStyle,
isLoading = false,
}: Props) {
const [isHovered, setIsHovered] = useState<boolean>(false);
const [isPressed, setIsPressed] = useState<boolean>(false);

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation(); // Prevent event from bubbling up
action();
};

const iconVariants = {
chevron: { x: 0 },
arrow: { x: 1 },
};

const lineVariants = {
hidden: { scaleX: 0, originX: 1 },
visible: { scaleX: 1, originX: 1 },
};

return (
<button
className={`flex p-4 justify-center items-center gap-1 rounded-md w-full ${className} ${
disabled ? "bg-other-background" : "bg-red-600"
}`}
onClick={handleClick}
className={`flex p-4 justify-center items-center gap-2 rounded-md w-full transition-all duration-300 ${
disabled ? "bg-other-background" : isPressed ? "bg-red-500" : "bg-red-600"
} ${isLoading ? "cursor-default" : ""} ${className}`}
onClick={(event) => {
if (!isLoading) handleClick(event);
}}
disabled={disabled}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
onMouseDown={() => {
if (!isLoading) setIsPressed(true);
}}
onMouseUp={() => {
if (!isLoading) setIsPressed(false);
}}
>
<p
className={`text-center ${disabled ? "text-neutral-400" : "text-neutral-white"} ${
textStyle ? textStyle : "s2"
}`}
>
{text}
</p>
{!disabled ? <CaretRightIcon className="h-[20px] w-[20px] shrink-0 fill-neutral-white" /> : null}
{isLoading ? (
<div className="animate-spin">
<Loader2 className="stroke-neutral-white" />
</div>
) : (
<>
<p
className={`text-center ${disabled ? "text-neutral-400" : "text-neutral-white"} ${
textStyle ? textStyle : "s2"
}`}
>
{text}
</p>
{!disabled && (
<motion.svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
animate={isHovered ? "arrow" : "chevron"}
>
<motion.path
d="M9 18L15 12L9 6"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
variants={iconVariants}
/>
<motion.line
x1="3"
y1="12"
x2="14"
y2="12"
stroke="white"
strokeWidth="2"
strokeLinecap="round"
variants={lineVariants}
initial="hidden"
animate={isHovered ? "visible" : "hidden"}
transition={{ duration: 0.2 }}
/>
</motion.svg>
)}
</>
)}
</button>
);
}
36 changes: 33 additions & 3 deletions src/components/system/button/buttonPrimary2.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
"use client";

import { Loader2 } from "lucide-react";

interface Props {
text: string;
action: () => void;
disabled?: boolean;
className?: string;
textStyle?: string;
isLoading?: boolean;
}

export default function ButtonPrimary2({ text, action, disabled = false, className, textStyle }: Props) {
export default function ButtonPrimary2({
text,
action,
disabled = false,
className,
textStyle,
isLoading = false,
}: Props) {
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation(); // Prevent event from bubbling up
action();
};

return (
<button className={`p-4 bg-red-600 rounded-md w-full ${className}`} onClick={handleClick} disabled={disabled}>
<p className={`text-neutral-white text-center ${textStyle ? textStyle : "s2"}`}>{text}</p>
<button
className={`flex p-4 justify-center items-center rounded-md w-full transition-all duration-300 ${
disabled ? "bg-other-background" : "bg-red-600"
} ${!disabled && !isLoading ? "hover:bg-red-500" : "cursor-default"} ${className}`}
onClick={(event) => {
if (!isLoading) handleClick(event);
}}
disabled={disabled}
>
{isLoading ? (
<div className="animate-spin">
<Loader2 className="stroke-neutral-white" />
</div>
) : (
<p
className={`text-center ${disabled ? "text-neutral-400" : "text-neutral-white"} ${
textStyle ? textStyle : "s2"
}`}
>
{text}
</p>
)}
</button>
);
}
43 changes: 39 additions & 4 deletions src/components/system/button/buttonPrimary3.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,61 @@
"use client";

import { Loader2 } from "lucide-react";
import { useState } from "react";

interface Props {
text: string;
action: () => void;
disabled?: boolean;
className?: string;
textStyle?: string;
isLoading?: boolean;
}

export default function ButtonPrimary3({ text, action, disabled = false, className, textStyle }: Props) {
export default function ButtonPrimary3({
text,
action,
disabled = false,
className,
textStyle,
isLoading = false,
}: Props) {
const [isPressed, setIsPressed] = useState<boolean>(false);

const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation(); // Prevent event from bubbling up
action();
};

return (
<button
className={`p-4 bg-other-background rounded-md w-full ${className}`}
onClick={handleClick}
className={`flex p-4 justify-center items-center rounded-md w-full transition-all duration-300 ${
!disabled && !isLoading ? "hover:opacity-80" : "cursor-default"
} ${isPressed ? "bg-neutral-100" : "bg-other-background"} ${className}`}
onClick={(event) => {
if (!isLoading) handleClick(event);
}}
disabled={disabled}
onMouseDown={() => {
if (!isLoading) setIsPressed(true);
}}
onMouseUp={() => {
if (!isLoading) setIsPressed(false);
}}
>
<p className={`text-neutral-700 text-center ${textStyle ? textStyle : "s2"}`}>{text}</p>
{isLoading ? (
<div className="animate-spin">
<Loader2 className="stroke-neutral-700" />
</div>
) : (
<p
className={`text-center ${
disabled ? "text-neutral-400" : isPressed ? "text-neutral-500" : "text-neutral-700"
} ${textStyle ? textStyle : "s2"}`}
>
{text}
</p>
)}
</button>
);
}
Loading

0 comments on commit 0864693

Please sign in to comment.