fix: board and workspace URL links and copy behavior (#357)
- Use /boards/{id} for private board links so copied link works; keep pretty URL for public boards
- Show matching path in board header (pretty path for public, boards/id for private)
- Copy link button copies URL to clipboard instead of opening in new tab (opening a new tab seems redundant since we're already on it)
- Edit workspace URL button links to /settings/workspace instead of account settings
This commit is contained in:
@@ -1,24 +1,40 @@
|
|||||||
import Link from "next/link";
|
import { Fragment } from "react";
|
||||||
import { t } from "@lingui/core/macro";
|
import { t } from "@lingui/core/macro";
|
||||||
import { env } from "next-runtime-env";
|
import { env } from "next-runtime-env";
|
||||||
import { HiLink } from "react-icons/hi";
|
import { HiLink } from "react-icons/hi";
|
||||||
|
|
||||||
import { Tooltip } from "~/components/Tooltip";
|
import { Tooltip } from "~/components/Tooltip";
|
||||||
|
import { usePopup } from "~/providers/popup";
|
||||||
|
|
||||||
|
const displayBaseUrl =
|
||||||
|
env("NEXT_PUBLIC_KAN_ENV") === "cloud"
|
||||||
|
? "kan.bn"
|
||||||
|
: env("NEXT_PUBLIC_BASE_URL");
|
||||||
|
|
||||||
|
const linkBaseUrl = env("NEXT_PUBLIC_BASE_URL");
|
||||||
|
|
||||||
|
const pathSeparator = (
|
||||||
|
<div className="mx-1.5 h-4 w-px rotate-[20deg] bg-gray-300 dark:bg-dark-600" />
|
||||||
|
);
|
||||||
|
|
||||||
const UpdateBoardSlugButton = ({
|
const UpdateBoardSlugButton = ({
|
||||||
handleOnClick,
|
handleOnClick,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
boardSlug,
|
boardSlug,
|
||||||
|
boardPublicId,
|
||||||
|
visibility,
|
||||||
isLoading,
|
isLoading,
|
||||||
canEdit,
|
canEdit,
|
||||||
}: {
|
}: {
|
||||||
handleOnClick: () => void;
|
handleOnClick: () => void;
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
boardSlug: string;
|
boardSlug: string;
|
||||||
|
boardPublicId: string;
|
||||||
|
visibility: "public" | "private";
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
canEdit: boolean;
|
canEdit: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
if (!isLoading && (!workspaceSlug || !boardSlug)) return <></>;
|
const { showPopup } = usePopup();
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
@@ -26,44 +42,55 @@ const UpdateBoardSlugButton = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!workspaceSlug || !boardSlug || !boardPublicId) return <></>;
|
||||||
|
|
||||||
|
const isPublic = visibility === "public";
|
||||||
|
const boardUrl = isPublic
|
||||||
|
? `${linkBaseUrl}/${workspaceSlug}/${boardSlug}`
|
||||||
|
: `${linkBaseUrl}/boards/${boardPublicId}`;
|
||||||
|
|
||||||
|
const pathSegments = isPublic
|
||||||
|
? [displayBaseUrl, workspaceSlug, boardSlug]
|
||||||
|
: [displayBaseUrl, "boards", boardPublicId];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={!canEdit && !isLoading ? t`You don't have permission` : undefined}
|
content={!canEdit ? t`You don't have permission` : undefined}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
onClick={canEdit ? handleOnClick : undefined}
|
onClick={canEdit ? handleOnClick : undefined}
|
||||||
disabled={!canEdit || isLoading}
|
disabled={!canEdit || isLoading}
|
||||||
className="hidden cursor-pointer items-center gap-2 rounded-full border-[1px] bg-light-50 p-1 pl-4 pr-1 text-sm text-light-950 hover:bg-light-100 disabled:cursor-not-allowed disabled:opacity-60 dark:border-dark-600 dark:bg-dark-50 dark:text-dark-900 dark:hover:bg-dark-100 xl:flex"
|
className="hidden cursor-pointer items-center gap-2 rounded-full border-[1px] bg-light-50 p-1 pl-4 pr-1 text-sm text-light-950 hover:bg-light-100 disabled:cursor-not-allowed disabled:opacity-60 dark:border-dark-600 dark:bg-dark-50 dark:text-dark-900 dark:hover:bg-dark-100 xl:flex"
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span>
|
{pathSegments.map((segment, i) => (
|
||||||
{env("NEXT_PUBLIC_KAN_ENV") === "cloud"
|
<Fragment key={i}>
|
||||||
? "kan.bn"
|
{i > 0 && pathSeparator}
|
||||||
: env("NEXT_PUBLIC_BASE_URL")}
|
<span>{segment}</span>
|
||||||
</span>
|
</Fragment>
|
||||||
<div className="mx-1.5 h-4 w-px rotate-[20deg] bg-gray-300 dark:bg-dark-600"></div>
|
))}
|
||||||
<span>{workspaceSlug}</span>
|
</div>
|
||||||
<div className="mx-1.5 h-4 w-px rotate-[20deg] bg-gray-300 dark:bg-dark-600"></div>
|
<button
|
||||||
<span>{boardSlug}</span>
|
type="button"
|
||||||
</div>
|
onClick={(e) => {
|
||||||
<Link
|
e.stopPropagation();
|
||||||
href={`${env("NEXT_PUBLIC_BASE_URL")}/${workspaceSlug}/${boardSlug}`}
|
navigator.clipboard.writeText(boardUrl).then(
|
||||||
target="_blank"
|
() =>
|
||||||
rel="noopener noreferrer"
|
showPopup({
|
||||||
onClick={(e) => {
|
header: t`Link copied`,
|
||||||
e.stopPropagation();
|
icon: "success",
|
||||||
if (!canEdit) {
|
message: t`Board URL copied to clipboard`,
|
||||||
e.preventDefault();
|
}),
|
||||||
}
|
).catch(() => undefined);
|
||||||
}}
|
}}
|
||||||
className="flex h-7 w-7 items-center justify-center rounded-full hover:bg-light-200 dark:hover:bg-dark-200"
|
className="flex h-7 w-7 items-center justify-center rounded-full hover:bg-light-200 dark:hover:bg-dark-200"
|
||||||
>
|
aria-label={t`Copy board link`}
|
||||||
<HiLink className="h-[13px] w-[13px]" />
|
>
|
||||||
</Link>
|
<HiLink className="h-[13px] w-[13px]" />
|
||||||
</button>
|
</button>
|
||||||
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default UpdateBoardSlugButton;
|
export default UpdateBoardSlugButton;
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export function UpdateBoardSlugForm({
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
href="/settings?tab=workspace"
|
href="/settings/workspace"
|
||||||
onClick={closeModal}
|
onClick={closeModal}
|
||||||
>
|
>
|
||||||
{t`Edit workspace URL`}
|
{t`Edit workspace URL`}
|
||||||
|
|||||||
@@ -443,6 +443,8 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
|
|||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
workspaceSlug={workspace.slug ?? ""}
|
workspaceSlug={workspace.slug ?? ""}
|
||||||
boardSlug={boardData?.slug ?? ""}
|
boardSlug={boardData?.slug ?? ""}
|
||||||
|
boardPublicId={boardId ?? ""}
|
||||||
|
visibility={boardData?.visibility ?? "private"}
|
||||||
canEdit={canEditBoard}
|
canEdit={canEditBoard}
|
||||||
/>
|
/>
|
||||||
<VisibilityButton
|
<VisibilityButton
|
||||||
|
|||||||
Reference in New Issue
Block a user