Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 6 additions & 62 deletions src/components/organisms/editorTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,13 @@ import {
import { MessageTypes } from "@src/types";
import { Project } from "@src/types/models";
import { navigateToProject } from "@src/utilities/navigation";
import {
cn,
getPreference,
processBulkCodeFixSuggestions,
generateBulkCodeFixSummary,
abbreviateFilePath,
} from "@utilities";
import { getPreference, processBulkCodeFixSuggestions, generateBulkCodeFixSummary } from "@utilities";

import { Button, IconButton, IconSvg, Loader, MermaidDiagram, Spinner, Tab, Typography } from "@components/atoms";
import { CodeFixDiffEditorModal, FileTabMenu, RenameFileModal } from "@components/organisms";
import { Button, IconSvg, Loader, MermaidDiagram, Spinner, Typography } from "@components/atoms";
import { CodeFixDiffEditorModal, FileTabMenu, RenameFileModal, ScrollableTabs } from "@components/organisms";

import { AKRoundLogo } from "@assets/image";
import { Close, SaveIcon } from "@assets/image/icons";
import { SaveIcon } from "@assets/image/icons";

import "react-pdf/dist/Page/AnnotationLayer.css";
import "react-pdf/dist/Page/TextLayer.css";
Expand Down Expand Up @@ -86,7 +80,7 @@ export const EditorTabs = () => {
}, [projectId]);

const addToast = useToastStore((state) => state.addToast);
const { openFiles, openFileAsActive, closeOpenedFile } = useFileStore();
const { openFiles, openFileAsActive } = useFileStore();
const { closeModal } = useModalStore();
const { cursorPositionPerProject, setCursorPosition, selectionPerProject } = useSharedBetweenProjectsStore();

Expand Down Expand Up @@ -813,23 +807,6 @@ export const EditorTabs = () => {
handleCloseCodeFixModal,
]);

const activeCloseIcon = (fileName: string) => {
const isActiveFile = openFiles[projectId]?.find(({ isActive, name }) => name === fileName && isActive);

return cn("size-4 p-0.5 opacity-50 hover:bg-gray-1100 group-hover:opacity-100", {
"opacity-100": isActiveFile,
});
};

const handleCloseButtonClick = (
event: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>,
name: string
): void => {
event.stopPropagation();

closeOpenedFile(name);
};

const handleTabContextMenu = (event: React.MouseEvent<HTMLDivElement>, fileName: string) => {
event.preventDefault();
event.stopPropagation();
Expand All @@ -845,40 +822,7 @@ export const EditorTabs = () => {
{projectId ? (
<>
<div className="absolute left-0 top-0 flex w-full justify-between" id="editor-tabs">
<div
className={
`flex h-8 select-none items-center gap-1 uppercase xl:gap-2 2xl:gap-4 3xl:gap-5 ` +
`scrollbar overflow-x-auto overflow-y-hidden whitespace-nowrap`
}
>
{projectId
? openFiles[projectId]?.map(({ name }) => {
return (
<div key={name} onContextMenu={(e) => handleTabContextMenu(e, name)}>
<Tab
activeTab={activeEditorFileName}
className="group flex items-center gap-1 normal-case"
onClick={() => openFileAsActive(name)}
title={name}
value={name}
>
{abbreviateFilePath(name)}

<IconButton
ariaLabel={t("buttons.ariaCloseFile")}
className={activeCloseIcon(name)}
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
handleCloseButtonClick(event, name)
}
>
<Close className="size-3 fill-gray-750 transition group-hover:fill-white" />
</IconButton>
</Tab>
</div>
);
})
: null}
</div>
<ScrollableTabs onTabContextMenu={handleTabContextMenu} />

{openFiles[projectId]?.length ? (
<div
Expand Down
1 change: 1 addition & 0 deletions src/components/organisms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { DashboardProjectsTable } from "@components/organisms/dashboard";
export { SessionsTable } from "@components/organisms/deployments";
export { DeploymentsTable } from "@components/organisms/deployments/table";
export { EditorTabs } from "@components/organisms/editorTabs";
export { ScrollableTabs } from "@components/organisms/scrollableTabs";
export { EventsTable, EventViewer } from "@components/organisms/events";
export { IntroMainBlock } from "@components/organisms/introMainBlock";
export { NewProjectModal, ImportProjectModal } from "@components/organisms/modals";
Expand Down
83 changes: 83 additions & 0 deletions src/components/organisms/scrollableTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from "react";

import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";

import { useSticky } from "@src/hooks";
import { useFileStore } from "@src/store";
import { abbreviateFilePath, cn } from "@utilities";

import { IconButton, Tab } from "@components/atoms";

import { Close } from "@assets/image/icons";

interface ScrollableTabsProps {
onTabContextMenu?: (event: React.MouseEvent<HTMLDivElement>, fileName: string) => void;
}

export const ScrollableTabs = ({ onTabContextMenu }: ScrollableTabsProps) => {
const { t } = useTranslation("tabs", { keyPrefix: "editor" });
const { projectId } = useParams();
const { closeOpenedFile, openFileAsActive, openFiles } = useFileStore();

const { ref: activeTabRef } = useSticky();
const activeEditorFileName = (projectId && openFiles[projectId]?.find(({ isActive }) => isActive)?.name) || "";

const activeCloseIcon = (fileName: string) => {
const isActiveFile = openFiles[projectId!]?.find(({ isActive, name }) => name === fileName && isActive);

return cn("size-4 p-0.5 opacity-50 hover:bg-gray-1100 group-hover:opacity-100", {
"opacity-100": isActiveFile,
});
};

const handleCloseButtonClick = (
event: React.MouseEvent<HTMLButtonElement | HTMLDivElement, MouseEvent>,
name: string
): void => {
event.stopPropagation();
closeOpenedFile(name);
};

return (
<div className="scrollbar relative flex w-full select-none items-center gap-1 overflow-x-auto overflow-y-hidden whitespace-nowrap uppercase xl:gap-2 2xl:gap-4 3xl:gap-5">
{projectId
? openFiles[projectId]?.map(({ name }) => {
const isActive = name === activeEditorFileName;

return (
<div
className={cn("flex h-8 items-center", {
"sticky left-0 right-0 top-0 z-popover px-3 bg-black before:absolute before:left-0 before:top-0 before:h-full before:w-3 before:bg-black after:absolute after:right-0 after:top-0 after:h-full after:w-3 after:bg-black":
isActive,
})}
key={name}
onContextMenu={(e) => onTabContextMenu?.(e, name)}
ref={isActive ? activeTabRef : null}
>
<Tab
activeTab={activeEditorFileName}
className="group flex items-center gap-1 bg-black normal-case"
onClick={() => openFileAsActive(name)}
title={name}
value={name}
>
{abbreviateFilePath(name)}

<IconButton
ariaLabel={t("buttons.ariaCloseFile")}
className={activeCloseIcon(name)}
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
handleCloseButtonClick(event, name)
}
>
<Close className="size-3 fill-gray-750 transition group-hover:fill-white" />
</IconButton>
</Tab>
</div>
);
})
: null}
</div>
);
};
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export { useCodeFixSuggestions } from "./useCodeFixSuggestions";
export { useMonacoEditorCleanup } from "./useMonacoEditorCleanup";
export { useProjectFilesVisibility } from "./useProjectFilesVisibility";
export { useAutoRefresh } from "./useAutoRefresh";
export { useSticky } from "./useSticky";
23 changes: 23 additions & 0 deletions src/hooks/useSticky.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useEffect, useRef, useState } from "react";

export function useSticky() {
const ref = useRef<HTMLDivElement>(null);

const [isSticky, setIsSticky] = useState(false);

useEffect(() => {
if (!ref.current) {
return;
}

const observer = new IntersectionObserver(([event]) => setIsSticky(event.intersectionRatio < 1), {
threshold: [1],
rootMargin: "-1px 0px 0px 0px",
});
observer.observe(ref.current);

return () => observer.disconnect();
}, []);

return { ref, isSticky };
}
Loading