UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: CTA создания проекта и полировка project-menu и cover-header

This commit is contained in:
DCCONSTRUCTIONS 2026-04-22 22:37:26 +03:00
parent b7b0388dc1
commit 49c32fccf1
3 changed files with 115 additions and 88 deletions

View File

@ -96,6 +96,7 @@ const ProjectsToolbarMenu = observer(function ProjectsToolbarMenu() {
const pathname = usePathname();
const { workspaceSlug } = useParams();
const { joinedProjectIds } = useProject();
const { toggleCreateProjectModal } = useCommandPalette();
const handleCopyText = (projectId: string) =>
copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/issues`).then(() => {
@ -139,6 +140,18 @@ const ProjectsToolbarMenu = observer(function ProjectsToolbarMenu() {
/>
))}
</div>
<div className="mt-2 border-t border-white/8 px-1 pt-2">
<Menu.Item>
<button
type="button"
className="nodedc-toolbar-primary nodedc-toolbar-primary-wide flex w-full items-center justify-center gap-2 text-13 font-medium"
onClick={() => toggleCreateProjectModal(true)}
>
<PlusIcon className="size-4" />
<span>{t("create_project")}</span>
</button>
</Menu.Item>
</div>
</div>
</Menu.Items>
</Menu>

View File

@ -197,7 +197,8 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
<CoverImage src={coverImage} alt="Project cover image" className="h-44 w-full rounded-md" />
<div className="absolute bottom-4 z-5 flex w-full items-end justify-between gap-3 px-4">
<div className="flex flex-grow gap-3 truncate">
<div className="flex min-w-0 flex-grow gap-3 truncate">
<div className="flex min-w-0 flex-1 items-center gap-3 rounded-[1.2rem] bg-white/10 px-2.5 py-2.5 backdrop-blur-2xl">
<Controller
control={control}
name="logo_props"
@ -208,7 +209,7 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
isOpen={isOpen}
handleToggle={(val: boolean) => setIsOpen(val)}
className="flex items-center justify-center"
buttonClassName="flex h-[52px] w-[52px] flex-shrink-0 items-center justify-center rounded-lg bg-white/10"
buttonClassName="flex h-[52px] w-[52px] flex-shrink-0 items-center justify-center rounded-lg bg-white/[0.06]"
label={<Logo logo={value} size={28} />}
// TODO: fix types
onChange={(val: any) => {
@ -245,6 +246,7 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
</span>
</div>
</div>
</div>
<div className="flex flex-shrink-0 justify-center">
<div>
<Controller
@ -397,7 +399,7 @@ export function ProjectDetailsForm(props: IProjectDetailsForm) {
)}
</div>
}
menuButtonWrapperClassName="nodedc-settings-select !h-12 font-medium"
menuButtonWrapperClassName="nodedc-settings-select !h-12 min-w-[12.75rem] px-4 font-medium"
disabled={!isAdmin}
/>
);

View File

@ -392,13 +392,12 @@ export const SidebarProjectsListItem = observer(function SidebarProjectsListItem
</button>
</Tooltip>
)}
<>
<ControlLink href={defaultTabUrl} className="flex flex-grow truncate" onClick={handleItemClick}>
{isAccordionMode ? (
<Disclosure.Button
as="button"
<div className="flex w-full items-center gap-1">
<button
type="button"
className={cn("flex w-full flex-grow items-center gap-1.5 text-left select-none", {})}
className="flex min-w-0 flex-1 items-center gap-3 text-left select-none"
onClick={() => setIsProjectListOpen(!isProjectListOpen)}
aria-label={
isProjectListOpen
? t("aria_labels.projects_sidebar.close_project_menu")
@ -409,18 +408,50 @@ export const SidebarProjectsListItem = observer(function SidebarProjectsListItem
<WorkItemsIcon className="size-4 text-tertiary" />
</div>
<p className="truncate text-13 font-medium text-secondary">{project.name}</p>
</Disclosure.Button>
<span className="ml-auto grid size-7 flex-shrink-0 place-items-center rounded-full text-placeholder transition-colors group-hover/project-item:bg-layer-transparent-hover">
<ChevronRightIcon
className={cn("size-4 transition-transform", {
"rotate-90": isProjectListOpen,
})}
/>
</span>
</button>
{!renderInToolbarMenu && (
<ActionDropdown
button={
<span className="grid place-items-center">
<MoreHorizontal className="h-3.5 w-3.5 text-placeholder" />
</span>
}
className={cn(
"pointer-events-none flex-shrink-0 opacity-0 group-hover/project-item:pointer-events-auto group-hover/project-item:opacity-100",
{
"pointer-events-auto opacity-100": isMenuActive,
}
)}
buttonClassName={cn(
"grid size-7 place-items-center rounded-full text-placeholder transition-colors hover:bg-layer-transparent-hover",
{
"bg-layer-transparent-hover": isMenuActive,
}
)}
placement="bottom-start"
onOpenChange={setIsMenuActive}
items={projectActionMenuItems}
/>
)}
</div>
) : (
<>
<ControlLink href={defaultTabUrl} className="flex flex-grow truncate" onClick={handleItemClick}>
<div className="flex w-full flex-grow items-center gap-3 text-left select-none">
<div className="grid size-8 flex-shrink-0 place-items-center rounded-full border border-white/8 bg-white/[0.04]">
<WorkItemsIcon className="size-4 text-tertiary" />
</div>
<p className="truncate text-13 font-medium text-secondary">{project.name}</p>
</div>
)}
</ControlLink>
<div className="flex items-center gap-1">
{!renderInToolbarMenu && (
<ActionDropdown
button={
<span className="grid place-items-center">
@ -444,28 +475,9 @@ export const SidebarProjectsListItem = observer(function SidebarProjectsListItem
onOpenChange={setIsMenuActive}
items={projectActionMenuItems}
/>
)}
{isAccordionMode && (
<IconButton
variant="ghost"
size="sm"
icon={ChevronRightIcon}
onClick={() => setIsProjectListOpen(!isProjectListOpen)}
className={cn("hidden text-placeholder group-hover/project-item:inline-flex", {
"inline-flex": isMenuActive,
})}
iconClassName={cn("transition-transform", {
"rotate-90": isProjectListOpen,
})}
aria-label={t(
isProjectListOpen
? "aria_labels.projects_sidebar.close_project_menu"
: "aria_labels.projects_sidebar.open_project_menu"
)}
/>
)}
</div>
</>
)}
</div>
{isAccordionMode && (
<Transition