Skip to content

Commit

Permalink
feat: use chip layout for custom categories on software page
Browse files Browse the repository at this point in the history
  • Loading branch information
dmijatovic committed Feb 3, 2025
1 parent edbef62 commit 0c074cf
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 167 deletions.
33 changes: 0 additions & 33 deletions frontend/components/category/CategoriesWithHeadlines.tsx

This file was deleted.

33 changes: 33 additions & 0 deletions frontend/components/category/CategoryIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2025 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2025 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import MuiCategoryIcon from '@mui/icons-material/Category'
import MuiQuestionMarkIcon from '@mui/icons-material/QuestionMark'
import MuiScienceIcon from '@mui/icons-material/Science'

/**
* Use lower case name of the icon import. For example '@mui/icons-material/QuestionMark' name is questionmark.
* Additional icons can be added here by importing them from library and extending MuiIconName type.
*/
export type MuiIconName = 'questionmark'|'category'|'science' | 'none'

export default function CategoryIcon({name}:{name?:MuiIconName}) {
// default is category icon
if (!name) return <MuiCategoryIcon />

// select based on name
switch(name.toLocaleLowerCase()){
case 'category':
return <MuiCategoryIcon />
case 'science':
return <MuiScienceIcon />
case 'questionmark':
return <MuiQuestionMarkIcon />
case 'none':
return null
default:
return <MuiCategoryIcon />
}
}
52 changes: 29 additions & 23 deletions frontend/components/category/CategoryTree.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-FileCopyrightText: 2023 - 2024 Felix Mühlbauer (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2023 - 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 - 2025 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center
// SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) <[email protected]>
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -35,25 +35,31 @@ type TreeLevelProps = {
onRemoveHandler? : (event: React.MouseEvent<HTMLElement>) => void
}
const TreeLevel = ({items, showLongNames, onRemoveHandler}: TreeLevelProps) => {
return <ul className={'list-disc list-outside pl-6'}>
{items.map((item) => {
const category = item.getValue()

const children = item.children()
return (
<li key={category.id}>
<div className='flex flex-row justify-between items-start'>
<Tooltip title={showLongNames ? category.short_name : category.name} placement='left'>
<span className='pb-1'>{showLongNames ? category.name : category.short_name}</span>
</Tooltip>
{onRemoveHandler && children.length === 0 &&
<IconButton sx={{top: '-0.25rem'}} data-id={category.id} size='small'
onClick={onRemoveHandler}><CancelIcon fontSize='small'/></IconButton>}
</div>
{children.length > 0 &&
<TreeLevel items={children} showLongNames={showLongNames} onRemoveHandler={onRemoveHandler}/>}
</li>
)
})}
</ul>
return (
<ul className={'list-disc list-outside pl-6'}>
{items.map((item) => {
const category = item.getValue()
const children = item.children()
return (
<li key={category.id}>
<div className='flex flex-row justify-between items-start'>
<Tooltip title={showLongNames ? category.short_name : category.name} placement='left'>
<span className='pb-1'>{showLongNames ? category.name : category.short_name}</span>
</Tooltip>
{ onRemoveHandler && children.length === 0 ?
<IconButton sx={{top: '-0.25rem'}} data-id={category.id} size='small'onClick={onRemoveHandler}>
<CancelIcon fontSize='small'/>
</IconButton>
:null
}
</div>
{children.length > 0 ?
<TreeLevel items={children} showLongNames={showLongNames} onRemoveHandler={onRemoveHandler}/>
: null
}
</li>
)
})}
</ul>
)
}
17 changes: 9 additions & 8 deletions frontend/components/category/apiCategories.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center
// SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) <[email protected]>
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2025 Dusan Mijatovic (Netherlands eScience Center)
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -9,13 +10,13 @@ import {TreeNode} from '~/types/TreeNode'
import {shuffle} from '~/utils/jest/utils'

it('generates the category tree correctly', () => {
const grandChild1: CategoryEntry = {id: 'grandChild1', parent: 'child1', short_name: '', name: '', community: null, provenance_iri: null, properties: {}}
const grandChild2: CategoryEntry = {id: 'grandChild2', parent: 'child1', short_name: '', name: '', community: null, provenance_iri: null, properties: {}}
const grandChild3: CategoryEntry = {id: 'grandChild3', parent: 'child2', short_name: '', name: '', community: null, provenance_iri: null, properties: {}}
const grandChild4: CategoryEntry = {id: 'grandChild4', parent: 'child2', short_name: '', name: '', community: null, provenance_iri: null, properties: {}}
const child1: CategoryEntry = {id: 'child1', parent: 'parent', short_name: '', name: '', community: null, provenance_iri: null, properties: {}}
const child2: CategoryEntry = {id: 'child2', parent: 'parent', short_name: '', name: '', community: null, provenance_iri: null, properties: {}}
const parent: CategoryEntry = {id: 'parent', parent: null, short_name: '', name: '', community: null, provenance_iri: null, properties: {}}
const grandChild1: CategoryEntry = {id: 'grandChild1', parent: 'child1', short_name: '', name: '', community: null, provenance_iri: null, organisation: null, allow_projects: false, allow_software:false, properties: {}}
const grandChild2: CategoryEntry = {id: 'grandChild2', parent: 'child1', short_name: '', name: '', community: null, provenance_iri: null, organisation: null, allow_projects: false, allow_software:false, properties: {}}
const grandChild3: CategoryEntry = {id: 'grandChild3', parent: 'child2', short_name: '', name: '', community: null, provenance_iri: null, organisation: null, allow_projects: false, allow_software:false, properties: {}}
const grandChild4: CategoryEntry = {id: 'grandChild4', parent: 'child2', short_name: '', name: '', community: null, provenance_iri: null, organisation: null, allow_projects: false, allow_software:false, properties: {}}
const child1: CategoryEntry = {id: 'child1', parent: 'parent', short_name: '', name: '', community: null, provenance_iri: null, organisation: null, allow_projects: false, allow_software:false, properties: {}}
const child2: CategoryEntry = {id: 'child2', parent: 'parent', short_name: '', name: '', community: null, provenance_iri: null, organisation: null, allow_projects: false, allow_software:false, properties: {}}
const parent: CategoryEntry = {id: 'parent', parent: null, short_name: '', name: '', community: null, provenance_iri: null, organisation: null, allow_projects: false, allow_software:false, properties: {}}

const entries = [
parent,
Expand Down
10 changes: 5 additions & 5 deletions frontend/components/software/AboutLanguages.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 - 2023 dv4all
// SPDX-FileCopyrightText: 2022 - 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 - 2025 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <[email protected]>
// SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 - 2025 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) (dv4all)
// SPDX-FileCopyrightText: 2023 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
Expand Down Expand Up @@ -92,8 +92,8 @@ export default function AboutLanguages({languages, platform}:
}

return (
<>
<div className="pt-8 pb-2">
<div>
<div className="pb-2">
<Code color="primary" />
<span className="text-primary pl-2">{label}</span>
</div>
Expand All @@ -103,6 +103,6 @@ export default function AboutLanguages({languages, platform}:
return <AboutLanguageItem key={props.language} {...props} />
})}
</ul>
</>
</div>
)
}
10 changes: 5 additions & 5 deletions frontend/components/software/AboutLicense.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2024 - 2025 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -12,8 +12,8 @@ import {LicenseForSoftware} from '~/types/SoftwareTypes'
export default function AboutLicense({licenses}:{licenses:LicenseForSoftware[]}) {
// console.log('AboutLicense...', licenses)
return (
<>
<div className="pt-8 pb-2">
<div>
<div className="pb-2">
<AttachFileIcon color="primary" sx={{transform:'rotate(45deg)'}} />
<span className="text-primary pl-2">License</span>
</div>
Expand Down Expand Up @@ -42,6 +42,6 @@ export default function AboutLicense({licenses}:{licenses:LicenseForSoftware[]})
})}
</ul>
}
</>
</div>
)
}
6 changes: 3 additions & 3 deletions frontend/components/software/AboutPackageManagers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ function PackageManagerItem({item}:{item:PackageManager}){
export default function AboutPackageManagers({packages}:AboutPackageManagersProps) {
if (packages?.length > 0){
return (
<>
<div className="pt-8 pb-2">
<div>
<div className="pb-2">
<span className="font-bold text-primary">
<WidgetsIcon />
</span>
Expand All @@ -54,7 +54,7 @@ export default function AboutPackageManagers({packages}:AboutPackageManagersProp
<div className="flex gap-4 flex-wrap">
{packages.map(item=><PackageManagerItem key={item.id} item={item} />)}
</div>
</>
</div>
)
}
// do not show section if no package managers
Expand Down
43 changes: 22 additions & 21 deletions frontend/components/software/AboutSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-FileCopyrightText: 2021 - 2023 dv4all
// SPDX-FileCopyrightText: 2022 - 2023 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2022 Christian Meeßen (GFZ) <[email protected]>
// SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2023 - 2025 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 - 2025 Netherlands eScience Center
// SPDX-FileCopyrightText: 2023 Felix Mühlbauer (GFZ) <[email protected]>
//
// SPDX-License-Identifier: Apache-2.0
Expand All @@ -12,9 +12,10 @@ import {
ProgramingLanguages,
CodePlatform, KeywordForSoftware,
CategoriesForSoftware,
LicenseForSoftware} from '~/types/SoftwareTypes'
import {CategoriesWithHeadlines} from '~/components/category/CategoriesWithHeadlines'
LicenseForSoftware
} from '~/types/SoftwareTypes'
import PageContainer from '~/components/layout/PageContainer'
import CategoriesSidebar from '~/components/software/CategoriesSidebar'
import {PackageManager} from './edit/package-managers/apiPackageManager'
import AboutStatement from './AboutStatement'
import SoftwareKeywords from './SoftwareKeywords'
Expand Down Expand Up @@ -44,40 +45,40 @@ export default function AboutSection(props:AboutSectionType) {
repository, languages, platform, description_type = 'markdown',
image_id, packages
} = props
if (brand_name==='') return null

// extract only license text
// const license = licenses?.map(item => item.license)

function getSoftwareLogo() {
if (image_id !== null) {
return (
<SoftwareLogo image_id={image_id} brand_name={brand_name} />
)
}
return null
}
if (brand_name==='') return null

return (
<PageContainer className="flex flex-col px-4 py-12 lg:flex-row lg:pt-0 lg:pb-12">
<div className="flex-[3] 2xl:flex-[4] md:pr-12 overflow-hidden">
<PageContainer className="flex flex-col px-4 py-12 lg:flex-row lg:gap-12 lg:pb-12">
<div className="flex-[3] overflow-hidden md:pb-12">
<AboutStatement
brand_name={brand_name}
description={description}
description_type={description_type}
/>
</div>
<div className="flex-1">
{getSoftwareLogo()}
<CategoriesWithHeadlines categories={categories} />

{/* SIDEBAR */}
<div className="flex-1 flex flex-col gap-8">
{
image_id ?
<SoftwareLogo image_id={image_id} brand_name={brand_name} />
: null
}

<SoftwareKeywords keywords={keywords || []} />

<AboutLanguages languages={languages} platform={platform} />

<AboutLicense licenses={licenses || []} />

<AboutSourceCode
repository={repository ?? null}
platform={platform}
/>
<AboutPackageManagers packages={packages} />

<CategoriesSidebar categories={categories} />
</div>
</PageContainer>
)
Expand Down
8 changes: 5 additions & 3 deletions frontend/components/software/AboutSourceCode.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2025 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2025 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

Expand Down Expand Up @@ -47,14 +49,14 @@ export default function AboutSourceCode({repository,platform}: { repository: str
}

return (
<>
<div className="pt-8 pb-2">
<div>
<div className="pb-2">
<span className="font-bold text-primary">{code}</span>
<span className="text-primary pl-2">Source code</span>
</div>
<div className="py-1">
{getIcon()}
</div>
</>
</div>
)
}
41 changes: 41 additions & 0 deletions frontend/components/software/CategoriesSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2024 - 2025 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {CategoryPath} from '~/types/Category'
import SidebarSection from '~/components/layout/SidebarSection'
import SidebarTitle from '~/components/layout/SidebarTitle'
import {CategoryChipFilter} from '~/components/category/CategoryChipFilter'
import {useCategoryTree} from '~/components/category/useCategoryTree'
import CategoryIcon from '~/components/category/CategoryIcon'

export default function CategoriesSidebar({categories}:{categories:CategoryPath[]}) {
const tree = useCategoryTree(categories)

// console.group('CategoriesSidebar')
// console.log('categories...', categories)
// console.log('tree...', tree)
// console.groupEnd()

// each root category is separate sidebar section
return tree.map(node => {
const category = node.getValue()
const children = node.children()

return (
<SidebarSection key={category.id}>
<SidebarTitle
title={category.name}
className='flex gap-2 items-center'
>
<span><CategoryIcon name={category.properties.icon} /></span>
<span>{category.short_name}</span>
</SidebarTitle>
<div className="flex flex-wrap gap-2">
<CategoryChipFilter nodes={children} />
</div>
</SidebarSection>
)
})
}
Loading

0 comments on commit 0c074cf

Please sign in to comment.