mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: space ui component revamp and bug fixes (#2980)
* chore: replace space ui component with plane ui component * fix: space project icon and user pic bug * chore: code refactor * fix: profile section navbar fix
This commit is contained in:
parent
dbc8150852
commit
e6eef7eb0b
@ -11,7 +11,7 @@ import useToast from "hooks/use-toast";
|
|||||||
import useTimer from "hooks/use-timer";
|
import useTimer from "hooks/use-timer";
|
||||||
|
|
||||||
// ui
|
// ui
|
||||||
import { Input, PrimaryButton } from "components/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
type EmailCodeFormValues = {
|
type EmailCodeFormValues = {
|
||||||
@ -133,7 +133,7 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
|
|||||||
id="email"
|
id="email"
|
||||||
type="email"
|
type="email"
|
||||||
placeholder="Enter your email address..."
|
placeholder="Enter your email address..."
|
||||||
className="border-custom-border-300 h-[46px]"
|
className="border-custom-border-300 h-[46px] w-full"
|
||||||
{...register("email", {
|
{...register("email", {
|
||||||
required: "Email address is required",
|
required: "Email address is required",
|
||||||
validate: (value) =>
|
validate: (value) =>
|
||||||
@ -154,7 +154,7 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
|
|||||||
required: "Code is required",
|
required: "Code is required",
|
||||||
})}
|
})}
|
||||||
placeholder="Enter code..."
|
placeholder="Enter code..."
|
||||||
className="border-custom-border-300 h-[46px]"
|
className="border-custom-border-300 h-[46px] w-full"
|
||||||
/>
|
/>
|
||||||
{errors.token && <div className="text-sm text-red-500">{errors.token.message}</div>}
|
{errors.token && <div className="text-sm text-red-500">{errors.token.message}</div>}
|
||||||
<button
|
<button
|
||||||
@ -185,20 +185,22 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{codeSent ? (
|
{codeSent ? (
|
||||||
<PrimaryButton
|
<Button
|
||||||
|
variant="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full text-center h-[46px]"
|
className="w-full"
|
||||||
size="md"
|
size="xl"
|
||||||
onClick={handleSubmit(handleSignin)}
|
onClick={handleSubmit(handleSignin)}
|
||||||
disabled={!isValid && isDirty}
|
disabled={!isValid && isDirty}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
>
|
>
|
||||||
{isLoading ? "Signing in..." : "Sign in"}
|
{isLoading ? "Signing in..." : "Sign in"}
|
||||||
</PrimaryButton>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<PrimaryButton
|
<Button
|
||||||
className="w-full text-center h-[46px]"
|
variant="primary"
|
||||||
size="md"
|
className="w-full"
|
||||||
|
size="xl"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
handleSubmit(onSubmit)().then(() => {
|
handleSubmit(onSubmit)().then(() => {
|
||||||
setResendCodeTimer(30);
|
setResendCodeTimer(30);
|
||||||
@ -208,7 +210,7 @@ export const EmailCodeForm = ({ handleSignIn }: any) => {
|
|||||||
loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
>
|
>
|
||||||
{isSubmitting ? "Sending code..." : "Send sign in code"}
|
{isSubmitting ? "Sending code..." : "Send sign in code"}
|
||||||
</PrimaryButton>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
|
@ -5,7 +5,8 @@ import { useForm } from "react-hook-form";
|
|||||||
// components
|
// components
|
||||||
import { EmailResetPasswordForm } from "./email-reset-password-form";
|
import { EmailResetPasswordForm } from "./email-reset-password-form";
|
||||||
// ui
|
// ui
|
||||||
import { Input, PrimaryButton } from "components/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
type EmailPasswordFormValues = {
|
type EmailPasswordFormValues = {
|
||||||
email: string;
|
email: string;
|
||||||
@ -58,7 +59,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
|||||||
) || "Email address is not valid",
|
) || "Email address is not valid",
|
||||||
})}
|
})}
|
||||||
placeholder="Enter your email address..."
|
placeholder="Enter your email address..."
|
||||||
className="border-custom-border-300 h-[46px]"
|
className="border-custom-border-300 h-[46px] w-full"
|
||||||
/>
|
/>
|
||||||
{errors.email && <div className="text-sm text-red-500">{errors.email.message}</div>}
|
{errors.email && <div className="text-sm text-red-500">{errors.email.message}</div>}
|
||||||
</div>
|
</div>
|
||||||
@ -70,7 +71,7 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
|||||||
required: "Password is required",
|
required: "Password is required",
|
||||||
})}
|
})}
|
||||||
placeholder="Enter your password..."
|
placeholder="Enter your password..."
|
||||||
className="border-custom-border-300 h-[46px]"
|
className="border-custom-border-300 h-[46px] w-full"
|
||||||
/>
|
/>
|
||||||
{errors.password && <div className="text-sm text-red-500">{errors.password.message}</div>}
|
{errors.password && <div className="text-sm text-red-500">{errors.password.message}</div>}
|
||||||
</div>
|
</div>
|
||||||
@ -92,14 +93,16 @@ export const EmailPasswordForm: React.FC<Props> = ({ onSubmit }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<PrimaryButton
|
<Button
|
||||||
|
variant="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-full text-center h-[46px]"
|
size="xl"
|
||||||
|
className="w-full"
|
||||||
disabled={!isValid && isDirty}
|
disabled={!isValid && isDirty}
|
||||||
loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
>
|
>
|
||||||
{isSignUpPage ? (isSubmitting ? "Signing up..." : "Sign up") : isSubmitting ? "Signing in..." : "Sign in"}
|
{isSignUpPage ? (isSubmitting ? "Signing up..." : "Sign up") : isSubmitting ? "Signing in..." : "Sign in"}
|
||||||
</PrimaryButton>
|
</Button>
|
||||||
{!isSignUpPage && (
|
{!isSignUpPage && (
|
||||||
<Link href="/sign-up">
|
<Link href="/sign-up">
|
||||||
<span className="block text-custom-text-200 hover:text-custom-primary-100 text-xs mt-4">
|
<span className="block text-custom-text-200 hover:text-custom-primary-100 text-xs mt-4">
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
// ui
|
// ui
|
||||||
import { Input } from "components/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
import { Button } from "@plane/ui";
|
|
||||||
// types
|
// types
|
||||||
type Props = {
|
type Props = {
|
||||||
setIsResettingPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsResettingPassword: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
@ -66,15 +65,15 @@ export const EmailResetPasswordForm: React.FC<Props> = ({ setIsResettingPassword
|
|||||||
) || "Email address is not valid",
|
) || "Email address is not valid",
|
||||||
})}
|
})}
|
||||||
placeholder="Enter registered email address.."
|
placeholder="Enter registered email address.."
|
||||||
className="h-[46px] border-custom-border-300"
|
className="h-[46px] border-custom-border-300 w-full"
|
||||||
/>
|
/>
|
||||||
{errors.email && <div className="text-sm text-red-500">{errors.email.message}</div>}
|
{errors.email && <div className="text-sm text-red-500">{errors.email.message}</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5 flex flex-col-reverse items-center gap-2 sm:flex-row">
|
<div className="mt-5 flex flex-col-reverse items-center gap-2 sm:flex-row">
|
||||||
<Button variant="neutral-primary" className="w-full" onClick={() => setIsResettingPassword(false)}>
|
<Button variant="neutral-primary" className="w-full" size="xl" onClick={() => setIsResettingPassword(false)}>
|
||||||
Go Back
|
Go Back
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="primary" className="w-full" type="submit" loading={isSubmitting}>
|
<Button variant="primary" className="w-full" size="xl" type="submit" loading={isSubmitting}>
|
||||||
{isSubmitting ? "Sending link..." : "Send reset link"}
|
{isSubmitting ? "Sending link..." : "Send reset link"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,7 +13,7 @@ import useToast from "hooks/use-toast";
|
|||||||
// services
|
// services
|
||||||
import UserService from "services/user.service";
|
import UserService from "services/user.service";
|
||||||
// ui
|
// ui
|
||||||
import { Input, PrimaryButton } from "components/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
|
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
first_name: "",
|
first_name: "",
|
||||||
@ -173,9 +173,9 @@ export const OnBoardingForm: React.FC<Props> = observer(({ user }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PrimaryButton type="submit" size="md" disabled={!isValid} loading={isSubmitting}>
|
<Button variant="primary" type="submit" className="w-full" size="xl" disabled={!isValid} loading={isSubmitting}>
|
||||||
{isSubmitting ? "Updating..." : "Continue"}
|
{isSubmitting ? "Updating..." : "Continue"}
|
||||||
</PrimaryButton>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
// mobx
|
// mobx
|
||||||
@ -11,7 +10,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { NavbarIssueBoardView } from "./issue-board-view";
|
import { NavbarIssueBoardView } from "./issue-board-view";
|
||||||
import { NavbarTheme } from "./theme";
|
import { NavbarTheme } from "./theme";
|
||||||
// ui
|
// ui
|
||||||
import { PrimaryButton } from "components/ui";
|
import { Avatar, Button } from "@plane/ui";
|
||||||
|
import { Briefcase } from "lucide-react";
|
||||||
// lib
|
// lib
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// store
|
// store
|
||||||
@ -87,10 +87,24 @@ const IssueNavbar = observer(() => {
|
|||||||
{/* project detail */}
|
{/* project detail */}
|
||||||
<div className="flex flex-shrink-0 items-center gap-2">
|
<div className="flex flex-shrink-0 items-center gap-2">
|
||||||
<div className="flex h-4 w-4 items-center justify-center">
|
<div className="flex h-4 w-4 items-center justify-center">
|
||||||
{projectStore?.project && projectStore?.project?.emoji ? (
|
{projectStore.project ? (
|
||||||
renderEmoji(projectStore?.project?.emoji)
|
projectStore.project?.emoji ? (
|
||||||
|
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded uppercase">
|
||||||
|
{renderEmoji(projectStore.project.emoji)}
|
||||||
|
</span>
|
||||||
|
) : projectStore.project?.icon_prop ? (
|
||||||
|
<div className="h-7 w-7 flex-shrink-0 grid place-items-center">
|
||||||
|
{renderEmoji(projectStore.project.icon_prop)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded bg-gray-700 uppercase text-white">
|
||||||
|
{projectStore.project?.name.charAt(0)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<Image src="/plane-logo.webp" alt="plane logo" className="h-[24px] w-[24px]" height="24" width="24" />
|
<span className="grid h-7 w-7 flex-shrink-0 place-items-center rounded uppercase">
|
||||||
|
<Briefcase className="h-4 w-4" />
|
||||||
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="line-clamp-1 max-w-[300px] overflow-hidden text-lg font-medium">
|
<div className="line-clamp-1 max-w-[300px] overflow-hidden text-lg font-medium">
|
||||||
@ -113,26 +127,13 @@ const IssueNavbar = observer(() => {
|
|||||||
|
|
||||||
{user ? (
|
{user ? (
|
||||||
<div className="flex items-center gap-2 rounded border border-custom-border-200 p-2">
|
<div className="flex items-center gap-2 rounded border border-custom-border-200 p-2">
|
||||||
{user.avatar && user.avatar !== "" ? (
|
<Avatar name={user?.display_name} src={user?.avatar} size={24} shape="square" className="!text-base" />
|
||||||
<div className="h-5 w-5 rounded-full">
|
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
||||||
<img src={user.avatar} alt={user.display_name ?? ""} className="rounded-full" />
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="grid h-5 w-5 place-items-center rounded-full bg-custom-background-80 text-[10px] capitalize">
|
|
||||||
{(user.display_name ?? "A")[0]}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<h6 className="text-xs font-medium">{user.display_name}</h6>
|
<h6 className="text-xs font-medium">{user.display_name}</h6>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<Link href={`/login/?next_path=${router.asPath}`}>
|
<Link href={`/login/?next_path=${router.asPath}`}>
|
||||||
<span>
|
<Button variant="outline-primary">Sign in</Button>
|
||||||
<PrimaryButton className="flex-shrink-0" outline>
|
|
||||||
Sign in
|
|
||||||
</PrimaryButton>
|
|
||||||
</span>
|
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -6,7 +6,8 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// ui
|
// ui
|
||||||
import { ReactionSelector, Tooltip } from "components/ui";
|
import { ReactionSelector } from "components/ui";
|
||||||
|
import { Tooltip } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { groupReactions, renderEmoji } from "helpers/emoji.helper";
|
import { groupReactions, renderEmoji } from "helpers/emoji.helper";
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
PeekOverviewIssueProperties,
|
PeekOverviewIssueProperties,
|
||||||
} from "components/issues/peek-overview";
|
} from "components/issues/peek-overview";
|
||||||
// types
|
// types
|
||||||
import { Loader } from "components/ui/loader";
|
import { Loader } from "@plane/ui";
|
||||||
import { IIssue } from "types/issue";
|
import { IIssue } from "types/issue";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -10,7 +10,8 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
// components
|
// components
|
||||||
import { CommentCard, AddComment } from "components/issues/peek-overview";
|
import { CommentCard, AddComment } from "components/issues/peek-overview";
|
||||||
// ui
|
// ui
|
||||||
import { Icon, PrimaryButton } from "components/ui";
|
import { Icon } from "components/ui";
|
||||||
|
import { Button } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types/issue";
|
import { IIssue } from "types/issue";
|
||||||
|
|
||||||
@ -55,9 +56,7 @@ export const PeekOverviewIssueActivity: React.FC<Props> = observer(() => {
|
|||||||
Sign in to add your comment
|
Sign in to add your comment
|
||||||
</p>
|
</p>
|
||||||
<Link href={`/?next_path=${router.asPath}`}>
|
<Link href={`/?next_path=${router.asPath}`}>
|
||||||
<span>
|
<Button variant="primary">Sign in</Button>
|
||||||
<PrimaryButton className="flex-shrink-0 !px-7">Sign in</PrimaryButton>
|
|
||||||
</span>
|
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -6,7 +6,8 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
// helpers
|
// helpers
|
||||||
import { groupReactions, renderEmoji } from "helpers/emoji.helper";
|
import { groupReactions, renderEmoji } from "helpers/emoji.helper";
|
||||||
// components
|
// components
|
||||||
import { ReactionSelector, Tooltip } from "components/ui";
|
import { ReactionSelector } from "components/ui";
|
||||||
|
import { Tooltip } from "@plane/ui";
|
||||||
|
|
||||||
export const IssueEmojiReactions: React.FC = observer(() => {
|
export const IssueEmojiReactions: React.FC = observer(() => {
|
||||||
// router
|
// router
|
||||||
|
@ -6,7 +6,8 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// lib
|
// lib
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
import { Tooltip } from "components/ui";
|
// ui
|
||||||
|
import { Tooltip } from "@plane/ui";
|
||||||
|
|
||||||
export const IssueVotes: React.FC = observer(() => {
|
export const IssueVotes: React.FC = observer(() => {
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
PeekOverviewIssueProperties,
|
PeekOverviewIssueProperties,
|
||||||
} from "components/issues/peek-overview";
|
} from "components/issues/peek-overview";
|
||||||
|
|
||||||
import { Loader } from "components/ui/loader";
|
import { Loader } from "@plane/ui";
|
||||||
import { IIssue } from "types/issue";
|
import { IIssue } from "types/issue";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -1,8 +1,3 @@
|
|||||||
export * from "./dropdown";
|
export * from "./dropdown";
|
||||||
export * from "./input";
|
|
||||||
export * from "./loader";
|
|
||||||
export * from "./primary-button";
|
|
||||||
export * from "./secondary-button";
|
|
||||||
export * from "./icon";
|
export * from "./icon";
|
||||||
export * from "./reaction-selector";
|
export * from "./reaction-selector";
|
||||||
export * from "./tooltip";
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
import React, { forwardRef, Ref } from "react";
|
|
||||||
|
|
||||||
// types
|
|
||||||
interface Props extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
||||||
mode?: "primary" | "transparent" | "trueTransparent";
|
|
||||||
error?: boolean;
|
|
||||||
inputSize?: "rg" | "lg";
|
|
||||||
fullWidth?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Input = forwardRef((props: Props, ref: Ref<HTMLInputElement>) => {
|
|
||||||
const { mode = "primary", error, className = "", type, fullWidth = true, id, inputSize = "rg", ...rest } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
id={id}
|
|
||||||
ref={ref}
|
|
||||||
type={type}
|
|
||||||
className={`block rounded-md bg-transparent text-sm focus:outline-none placeholder-custom-text-400 ${
|
|
||||||
mode === "primary"
|
|
||||||
? "rounded-md border border-custom-border-200"
|
|
||||||
: mode === "transparent"
|
|
||||||
? "rounded border-none bg-transparent ring-0 transition-all focus:ring-1 focus:ring-custom-primary"
|
|
||||||
: mode === "trueTransparent"
|
|
||||||
? "rounded border-none bg-transparent ring-0"
|
|
||||||
: ""
|
|
||||||
} ${error ? "border-red-500" : ""} ${error && mode === "primary" ? "bg-red-500/20" : ""} ${
|
|
||||||
fullWidth ? "w-full" : ""
|
|
||||||
} ${inputSize === "rg" ? "px-3 py-2" : inputSize === "lg" ? "p-3" : ""} ${className}`}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Input.displayName = "Input";
|
|
||||||
|
|
||||||
export default Input;
|
|
@ -1,25 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
children: React.ReactNode;
|
|
||||||
className?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Loader = ({ children, className = "" }: Props) => (
|
|
||||||
<div className={`${className} animate-pulse`} role="status">
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
type ItemProps = {
|
|
||||||
height?: string;
|
|
||||||
width?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Item: React.FC<ItemProps> = ({ height = "auto", width = "auto" }) => (
|
|
||||||
<div className="rounded-md bg-custom-background-80" style={{ height: height, width: width }} />
|
|
||||||
);
|
|
||||||
|
|
||||||
Loader.Item = Item;
|
|
||||||
|
|
||||||
export { Loader };
|
|
@ -1,35 +0,0 @@
|
|||||||
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
||||||
size?: "sm" | "md" | "lg";
|
|
||||||
outline?: boolean;
|
|
||||||
loading?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PrimaryButton: React.FC<ButtonProps> = ({
|
|
||||||
children,
|
|
||||||
className = "",
|
|
||||||
onClick,
|
|
||||||
type = "button",
|
|
||||||
disabled = false,
|
|
||||||
loading = false,
|
|
||||||
size = "sm",
|
|
||||||
outline = false,
|
|
||||||
}) => (
|
|
||||||
<button
|
|
||||||
type={type}
|
|
||||||
className={`${className} border border-custom-primary font-medium duration-300 ${
|
|
||||||
size === "sm"
|
|
||||||
? "rounded px-3 py-2 text-xs"
|
|
||||||
: size === "md"
|
|
||||||
? "rounded-md px-3.5 py-2 text-sm"
|
|
||||||
: "rounded-lg px-4 py-2 text-base"
|
|
||||||
} ${disabled ? "cursor-not-allowed opacity-70 hover:opacity-70" : ""} ${
|
|
||||||
outline
|
|
||||||
? "bg-transparent text-custom-primary hover:bg-custom-primary hover:text-white"
|
|
||||||
: "text-white bg-custom-primary hover:border-opacity-90 hover:bg-opacity-90"
|
|
||||||
} ${loading ? "cursor-wait" : ""}`}
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled || loading}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</button>
|
|
||||||
);
|
|
@ -1,35 +0,0 @@
|
|||||||
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
||||||
size?: "sm" | "md" | "lg";
|
|
||||||
outline?: boolean;
|
|
||||||
loading?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SecondaryButton: React.FC<ButtonProps> = ({
|
|
||||||
children,
|
|
||||||
className = "",
|
|
||||||
onClick,
|
|
||||||
type = "button",
|
|
||||||
disabled = false,
|
|
||||||
loading = false,
|
|
||||||
size = "sm",
|
|
||||||
outline = false,
|
|
||||||
}) => (
|
|
||||||
<button
|
|
||||||
type={type}
|
|
||||||
className={`${className} border border-custom-border-200 font-medium duration-300 ${
|
|
||||||
size === "sm"
|
|
||||||
? "rounded px-3 py-2 text-xs"
|
|
||||||
: size === "md"
|
|
||||||
? "rounded-md px-3.5 py-2 text-sm"
|
|
||||||
: "rounded-lg px-4 py-2 text-base"
|
|
||||||
} ${disabled ? "cursor-not-allowed border-custom-border-200 bg-custom-background-90" : ""} ${
|
|
||||||
outline
|
|
||||||
? "bg-transparent hover:bg-custom-background-80"
|
|
||||||
: "bg-custom-background-100 hover:border-opacity-70 hover:bg-opacity-70"
|
|
||||||
} ${loading ? "cursor-wait" : ""}`}
|
|
||||||
onClick={onClick}
|
|
||||||
disabled={disabled || loading}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</button>
|
|
||||||
);
|
|
@ -1,70 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
// next-themes
|
|
||||||
import { useTheme } from "next-themes";
|
|
||||||
// tooltip2
|
|
||||||
import { Tooltip2 } from "@blueprintjs/popover2";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
tooltipHeading?: string;
|
|
||||||
tooltipContent: string | React.ReactNode;
|
|
||||||
position?:
|
|
||||||
| "top"
|
|
||||||
| "right"
|
|
||||||
| "bottom"
|
|
||||||
| "left"
|
|
||||||
| "auto"
|
|
||||||
| "auto-end"
|
|
||||||
| "auto-start"
|
|
||||||
| "bottom-left"
|
|
||||||
| "bottom-right"
|
|
||||||
| "left-bottom"
|
|
||||||
| "left-top"
|
|
||||||
| "right-bottom"
|
|
||||||
| "right-top"
|
|
||||||
| "top-left"
|
|
||||||
| "top-right";
|
|
||||||
children: JSX.Element;
|
|
||||||
disabled?: boolean;
|
|
||||||
className?: string;
|
|
||||||
openDelay?: number;
|
|
||||||
closeDelay?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Tooltip: React.FC<Props> = ({
|
|
||||||
tooltipHeading,
|
|
||||||
tooltipContent,
|
|
||||||
position = "top",
|
|
||||||
children,
|
|
||||||
disabled = false,
|
|
||||||
className = "",
|
|
||||||
openDelay = 200,
|
|
||||||
closeDelay,
|
|
||||||
}) => {
|
|
||||||
const { theme } = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip2
|
|
||||||
disabled={disabled}
|
|
||||||
hoverOpenDelay={openDelay}
|
|
||||||
hoverCloseDelay={closeDelay}
|
|
||||||
content={
|
|
||||||
<div
|
|
||||||
className={`relative z-50 max-w-xs gap-1 rounded-md border border-custom-border-200 p-2 text-xs shadow-md ${
|
|
||||||
theme === "custom" ? "bg-custom-background-100 text-custom-text-200" : "bg-black text-gray-400"
|
|
||||||
} overflow-hidden break-words ${className}`}
|
|
||||||
>
|
|
||||||
{tooltipHeading && (
|
|
||||||
<h5 className={`font-medium ${theme === "custom" ? "text-custom-text-100" : "text-white"}`}>
|
|
||||||
{tooltipHeading}
|
|
||||||
</h5>
|
|
||||||
)}
|
|
||||||
{tooltipContent}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
position={position}
|
|
||||||
renderTarget={({ isOpen: isTooltipOpen, ref: eleReference, ...tooltipProps }) =>
|
|
||||||
React.cloneElement(children, { ref: eleReference, ...tooltipProps, ...children.props })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
@ -51,7 +51,7 @@ export const ProfileNavbar: React.FC<Props> = (props) => {
|
|||||||
{tabsList.map((tab) => (
|
{tabsList.map((tab) => (
|
||||||
<Link key={tab.route} href={`/${workspaceSlug}/profile/${userId}/${tab.route}`}>
|
<Link key={tab.route} href={`/${workspaceSlug}/profile/${userId}/${tab.route}`}>
|
||||||
<span
|
<span
|
||||||
className={`border-b-2 p-4 text-sm font-medium outline-none whitespace-nowrap ${
|
className={`flex border-b-2 p-4 text-sm font-medium outline-none whitespace-nowrap ${
|
||||||
router.pathname === tab.selected
|
router.pathname === tab.selected
|
||||||
? "border-custom-primary-100 text-custom-primary-100"
|
? "border-custom-primary-100 text-custom-primary-100"
|
||||||
: "border-transparent"
|
: "border-transparent"
|
||||||
|
Loading…
Reference in New Issue
Block a user