Skip to content

Commit

Permalink
refactor: tabs navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
ankormoreankor committed Feb 3, 2025
1 parent 8274a24 commit 55e6d23
Show file tree
Hide file tree
Showing 20 changed files with 250 additions and 146 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"[ignore]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"prettier.trailingComma": "none"
"prettier.trailingComma": "none",
"eslint.workingDirectories": [{ "pattern": "./apps/*/" }, { "pattern": "./packages/*/" }]
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { FC, HTMLAttributes, PropsWithChildren } from 'react'
import { Route } from 'react-router-dom'

import { ProjectSettingsPage } from '@harnessio/ui/views'
import { useTranslationsStore } from '@utils/viewUtils'

import { ProjectSettingsTabNav } from '@harnessio/ui/views'

import RootViewWrapper from './root-view-wrapper'

const Layout = () => {
return (
<div className="bg-background-1 sticky top-[55px] z-40">
<ProjectSettingsPage />
<div className="bg-background-1 top-14.5 sticky z-40">
<ProjectSettingsTabNav useTranslationStore={useTranslationsStore} />
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const RepoViewWrapper: FC<PropsWithChildren<React.HTMLAttributes<HTMLElement>>>
path="*"
element={
<>
<div className="layer-high bg-background-1 sticky top-[55px]">
<div className="layer-high bg-background-1 top-14.5 sticky">
<RepoSubheader useTranslationStore={useTranslationsStore} />
</div>
{children}
Expand Down
19 changes: 19 additions & 0 deletions apps/gitness/src/pages-v2/profile-settings/settings-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Outlet, useLocation } from 'react-router-dom'

import { ProfileSettingsTabNav } from '@harnessio/ui/views'

import { useTranslationStore } from '../../i18n/stores/i18n-store'

export const SettingsLayout = () => {
const location = useLocation()
const activeTab = location.pathname.split('/').pop() || 'general'

return (
<>
<div className="bg-background-1 top-14.5 sticky z-40">
<ProfileSettingsTabNav activeTab={activeTab} useTranslationStore={useTranslationStore} />
</div>
<Outlet />
</>
)
}
16 changes: 16 additions & 0 deletions apps/gitness/src/pages-v2/project/project-settings-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Outlet } from 'react-router-dom'

import { ProjectSettingsTabNav } from '@harnessio/ui/views'

import { useTranslationStore } from '../../i18n/stores/i18n-store'

export const ProjectSettingsLayout = () => {
return (
<>
<div className="bg-background-1 top-14.5 sticky z-40">
<ProjectSettingsTabNav useTranslationStore={useTranslationStore} />
</div>
<Outlet />
</>
)
}
2 changes: 1 addition & 1 deletion apps/gitness/src/pages-v2/repo/repo-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const RepoLayout = () => {

return (
<>
<div className="layer-high sticky top-[55px] bg-background-1">
<div className="layer-high bg-background-1 top-14.5 sticky">
<RepoSubheader showPipelinesTab={!isMFE} useTranslationStore={useTranslationStore} />
</div>
<Outlet />
Expand Down
7 changes: 6 additions & 1 deletion packages/ui/locales/en/views.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,12 @@
},
"removeMember": "Remove member",
"inviteNewMember": "Invite new member",
"members": "Members"
"members": "Members",
"tabs": {
"general": "General",
"members": "Members",
"labels": "Labels"
}
},
"landingPage": {
"selectProject": "Select a project to get started",
Expand Down
7 changes: 6 additions & 1 deletion packages/ui/locales/es/views.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,12 @@
},
"removeMember": "Remove member",
"inviteNewMember": "Invite new member",
"members": ""
"members": "",
"tabs": {
"general": "General",
"members": "Members",
"labels": "Labels"
}
},
"landingPage": {
"selectProject": "Select a project to get started",
Expand Down
7 changes: 6 additions & 1 deletion packages/ui/locales/fr/views.json
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,12 @@
},
"removeMember": "Remove member",
"inviteNewMember": "Invite new member",
"members": ""
"members": "",
"tabs": {
"general": "General",
"members": "Members",
"labels": "Labels"
}
},
"landingPage": {
"selectProject": "Sélectionnez un projet pour commencer",
Expand Down
51 changes: 27 additions & 24 deletions packages/ui/src/components/repo-subheader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMemo } from 'react'
import { NavLink, useLocation } from 'react-router-dom'
import { useCallback, useMemo } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'

import { Tabs, TabsList, TabsTrigger } from '@/components'
import { SandboxLayout, TranslationStore } from '@/views'
Expand All @@ -23,9 +23,12 @@ export const RepoSubheader = ({
useTranslationStore: () => TranslationStore
showPipelinesTab?: boolean
}) => {
const navigate = useNavigate()
const location = useLocation()
const { t } = useTranslationStore()

const makeHandleTabChange = useCallback((tab: string) => () => navigate(tab), [navigate])

const activeTab = useMemo(() => {
// Prioritize 'pulls' over 'commits' if both are present in the pathname
if (location.pathname.includes(RepoTabsKeys.PULLS)) {
Expand All @@ -36,32 +39,32 @@ export const RepoSubheader = ({
}, [location.pathname])

return (
<SandboxLayout.SubHeader className="h-[45px] overflow-hidden">
<SandboxLayout.SubHeader className="top-14.5 h-11">
<Tabs variant="navigation" value={activeTab}>
<TabsList>
<NavLink to={RepoTabsKeys.SUMMARY}>
<TabsTrigger value="summary">{t('views:repos.summary', 'Summary')}</TabsTrigger>
</NavLink>
<NavLink to={RepoTabsKeys.CODE}>
<TabsTrigger value="code">{t('views:repos.files', 'Files')}</TabsTrigger>
</NavLink>
<TabsTrigger role="link" value="summary" onClick={makeHandleTabChange(RepoTabsKeys.SUMMARY)}>
{t('views:repos.summary', 'Summary')}
</TabsTrigger>
<TabsTrigger role="link" value="code" onClick={makeHandleTabChange(RepoTabsKeys.CODE)}>
{t('views:repos.files', 'Files')}
</TabsTrigger>
{showPipelinesTab && (
<NavLink to={RepoTabsKeys.PIPELINES}>
<TabsTrigger value="pipelines">{t('views:repos.pipelines', 'Pipelines')}</TabsTrigger>
</NavLink>
<TabsTrigger role="link" value="pipelines" onClick={makeHandleTabChange(RepoTabsKeys.PIPELINES)}>
{t('views:repos.pipelines', 'Pipelines')}
</TabsTrigger>
)}
<NavLink to={RepoTabsKeys.COMMITS}>
<TabsTrigger value="commits">{t('views:repos.commits', 'Commits')}</TabsTrigger>
</NavLink>
<NavLink to={RepoTabsKeys.PULLS}>
<TabsTrigger value="pulls">{t('views:repos.pull-requests', 'Pull Requests')}</TabsTrigger>
</NavLink>
<NavLink to={RepoTabsKeys.BRANCHES}>
<TabsTrigger value="branches">{t('views:repos.branches', 'Branches')}</TabsTrigger>
</NavLink>
<NavLink to={RepoTabsKeys.SETTINGS}>
<TabsTrigger value="settings">{t('views:repos.settings', 'Settings')}</TabsTrigger>
</NavLink>
<TabsTrigger role="link" value="commits" onClick={makeHandleTabChange(RepoTabsKeys.COMMITS)}>
{t('views:repos.commits', 'Commits')}
</TabsTrigger>
<TabsTrigger role="link" value="pulls" onClick={makeHandleTabChange(RepoTabsKeys.PULLS)}>
{t('views:repos.pull-requests', 'Pull Requests')}
</TabsTrigger>
<TabsTrigger role="link" value="branches" onClick={makeHandleTabChange(RepoTabsKeys.BRANCHES)}>
{t('views:repos.branches', 'Branches')}
</TabsTrigger>
<TabsTrigger role="link" value="settings" onClick={makeHandleTabChange(RepoTabsKeys.SETTINGS)}>
{t('views:repos.settings', 'Settings')}
</TabsTrigger>
</TabsList>
</Tabs>
</SandboxLayout.SubHeader>
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/topbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const Topbar = {
return (
<div
className={cx(
`grid w-full ${gridCols} font-regular h-[55px] items-center gap-6 border-b border-borders-5 px-5 text-sm`,
`grid w-full ${gridCols} font-regular h-14.5 items-center gap-6 border-b border-borders-5 px-5 text-sm`,
className
)}
>
Expand Down
100 changes: 47 additions & 53 deletions packages/ui/src/views/layouts/PullRequestLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { NavLink, Outlet } from 'react-router-dom'
import { useCallback } from 'react'
import { Outlet, useLocation, useNavigate } from 'react-router-dom'

import { Badge, Icon, Spacer, Tabs, TabsList, TabsTrigger } from '@components/index'
import { TabsTriggerProps } from '@radix-ui/react-tabs'
import { TranslationStore } from '@views/repo'
import { PullRequestHeader } from '@views/repo/pull-request/components/pull-request-header'
import { IPullRequestStore } from '@views/repo/pull-request/pull-request.types'
Expand Down Expand Up @@ -30,6 +32,22 @@ const PullRequestLayout: React.FC<PullRequestLayoutProps> = ({
}) => {
const { pullRequest } = usePullRequestStore()
const { t } = useTranslationStore()
const navigate = useNavigate()
const location = useLocation()

const getIsActiveTab = useCallback(
(tab: string) => (location.pathname.endsWith(tab) ? 'active' : 'inactive'),
[location.pathname]
)
const makeHandleTabChange = useCallback((tab: string) => () => navigate(tab), [navigate])

const getTabProps = (tab: PullRequestTabsKeys): TabsTriggerProps => ({
value: tab,
...{ 'data-state': getIsActiveTab(tab) },
onClick: makeHandleTabChange(tab),
className: 'group gap-x-1.5',
role: 'link'
})

return (
<SandboxLayout.Main fullWidth>
Expand Down Expand Up @@ -59,59 +77,35 @@ const PullRequestLayout: React.FC<PullRequestLayoutProps> = ({
)}
<Tabs variant="tabnav">
<TabsList className="before:left-1/2 before:w-screen before:-translate-x-1/2">
<NavLink to={PullRequestTabsKeys.CONVERSATION}>
{({ isActive }) => (
<TabsTrigger
className="group gap-x-1.5"
value={PullRequestTabsKeys.CONVERSATION}
data-state={isActive ? 'active' : 'inactive'}
>
<div className="flex items-center gap-x-1">
<Icon className="text-icons-1 group-data-[state=active]:text-icons-2" size={14} name="comments" />
{t('views:pullRequests.conversation')}
</div>
{pullRequest?.stats?.conversations && (
<Badge className="font-normal text-foreground-2" variant="quaternary" size="xs" borderRadius="base">
{pullRequest.stats.conversations}
</Badge>
)}
</TabsTrigger>
)}
</NavLink>
<NavLink to={PullRequestTabsKeys.COMMITS}>
{({ isActive }) => (
<TabsTrigger
className="group gap-x-1.5"
value={PullRequestTabsKeys.COMMITS}
data-state={isActive ? 'active' : 'inactive'}
>
<div className="flex items-center gap-x-1">
<Icon className="text-icons-1 group-data-[state=active]:text-icons-2" size={14} name="tube-sign" />
{t('views:repos.commits')}
</div>
<Badge className="font-normal text-foreground-2" variant="quaternary" size="xs" borderRadius="base">
{pullRequest?.stats?.commits}
</Badge>
</TabsTrigger>
)}
</NavLink>
<NavLink to={PullRequestTabsKeys.CHANGES}>
{({ isActive }) => (
<TabsTrigger
className="group gap-x-1.5"
value={PullRequestTabsKeys.CHANGES}
data-state={isActive ? 'active' : 'inactive'}
>
<div className="flex items-center gap-x-1">
<Icon className="text-icons-1 group-data-[state=active]:text-icons-2" size={14} name="changes" />
{t('views:pullRequests.changes')}
</div>
<Badge className="font-normal text-foreground-2" variant="quaternary" size="xs" borderRadius="base">
{pullRequest?.stats?.files_changed}
</Badge>
</TabsTrigger>
<TabsTrigger {...getTabProps(PullRequestTabsKeys.CONVERSATION)}>
<div className="flex items-center gap-x-1">
<Icon className="text-icons-1 group-data-[state=active]:text-icons-2" size={14} name="comments" />
{t('views:pullRequests.conversation')}
</div>
{pullRequest?.stats?.conversations && (
<Badge className="text-foreground-2 font-normal" variant="quaternary" size="xs" borderRadius="base">
{pullRequest.stats.conversations}
</Badge>
)}
</NavLink>
</TabsTrigger>
<TabsTrigger {...getTabProps(PullRequestTabsKeys.COMMITS)}>
<div className="flex items-center gap-x-1">
<Icon size={14} name="tube-sign" />
{t('views:repos.commits')}
</div>
<Badge className="text-foreground-2 font-normal" variant="quaternary" size="xs" borderRadius="base">
{pullRequest?.stats?.commits}
</Badge>
</TabsTrigger>
<TabsTrigger {...getTabProps(PullRequestTabsKeys.CHANGES)}>
<div className="flex items-center gap-x-1">
<Icon size={14} name="changes" />
{t('views:pullRequests.changes')}
</div>
<Badge className="text-foreground-2 font-normal" variant="quaternary" size="xs" borderRadius="base">
{pullRequest?.stats?.files_changed}
</Badge>
</TabsTrigger>
</TabsList>
</Tabs>
<Spacer size={7} />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useCallback } from 'react'
import { useNavigate } from 'react-router-dom'

import { Tabs, TabsList, TabsTrigger } from '@/components'
import { SandboxLayout, TranslationStore } from '@/views'

function ProfileSettingsTabNav({
activeTab,
useTranslationStore
}: {
activeTab: string
useTranslationStore: () => TranslationStore
}) {
const { t } = useTranslationStore()
const navigate = useNavigate()

const makeHandleTabChange = useCallback((tab: string) => () => navigate(tab), [navigate])

return (
<>
<SandboxLayout.SubHeader className="h-11">
<Tabs variant="navigation" value={activeTab}>
<TabsList fontSize="xs">
<TabsTrigger role="link" value="general" onClick={makeHandleTabChange('general')}>
{t('views:profileSettings.GeneralTab', 'General')}
</TabsTrigger>
<TabsTrigger role="link" value="keys" onClick={makeHandleTabChange('keys')}>
{t('views:profileSettings.KeysTab', 'Keys and Tokens')}
</TabsTrigger>
</TabsList>
</Tabs>
</SandboxLayout.SubHeader>
</>
)
}

export { ProfileSettingsTabNav }
2 changes: 1 addition & 1 deletion packages/ui/src/views/project/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export * from '@views/project/project-general/project-general-page'

// project types
export * from '@views/project/project.types'
export * from './project-settings-page'
export * from './project-settings-tab-nav'

// project import
export * from '@views/project/project-import'
Loading

0 comments on commit 55e6d23

Please sign in to comment.