mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Introduce new TreeView for use in CatalogMenu to fix tests
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
8025471eee
commit
0f72c118f2
@ -16,14 +16,15 @@ import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import filteredCategoriesInjectable from "../../../common/catalog/filtered-categories.injectable";
|
||||
import { TreeGroup, TreeItem, TreeView } from "../tree-view/tree-view";
|
||||
import { browseCatalogTab } from "./catalog-browse-tab";
|
||||
import { HorizontalLine } from "../horizontal-line/horizontal-line";
|
||||
|
||||
export interface CatalogMenuProps {
|
||||
activeTab: string | undefined;
|
||||
onItemClick: (id: string) => void;
|
||||
}
|
||||
|
||||
function getCategoryIcon(category: CatalogCategory) {
|
||||
const { icon } = category.metadata ?? {};
|
||||
function CategoryIcon(props: { category: CatalogCategory }) {
|
||||
const { icon } = props.category.metadata ?? {};
|
||||
|
||||
if (typeof icon === "string") {
|
||||
return Icon.isSvg(icon)
|
||||
@ -42,41 +43,38 @@ const NonInjectedCatalogMenu = observer(({
|
||||
activeTab,
|
||||
filteredCategories,
|
||||
onItemClick,
|
||||
}: CatalogMenuProps & Dependencies) => {
|
||||
console.log(treeStyles);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full">
|
||||
<div className={styles.catalog}>Catalog</div>
|
||||
<TreeView>
|
||||
<TreeItem
|
||||
label="Browse"
|
||||
data-testid="*-tab"
|
||||
onClick={() => onItemClick("*")}
|
||||
selected={activeTab === browseCatalogTab} />
|
||||
<TreeGroup
|
||||
classes={treeStyles}
|
||||
label={<div className={styles.parent}>Categories</div>}
|
||||
>
|
||||
{filteredCategories.get()
|
||||
.map(category => (
|
||||
<TreeItem
|
||||
key={category.getId()}
|
||||
label={(
|
||||
<>
|
||||
{getCategoryIcon(category)}
|
||||
<CatalogCategoryLabel category={category} />
|
||||
</>
|
||||
)}
|
||||
selected={activeTab === category.getId()}
|
||||
data-testid={`${category.getId()}-tab`}
|
||||
onClick={() => onItemClick(category.getId())} />
|
||||
))}
|
||||
</TreeGroup>
|
||||
</TreeView>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}: CatalogMenuProps & Dependencies) => (
|
||||
<div className="flex flex-col w-full">
|
||||
<div className={styles.catalog}>Catalog</div>
|
||||
<TreeView>
|
||||
<TreeItem
|
||||
classes={treeStyles}
|
||||
label="Browse"
|
||||
data-testid="*-tab"
|
||||
onClick={() => onItemClick("*")}
|
||||
selected={activeTab === browseCatalogTab}
|
||||
/>
|
||||
<HorizontalLine size="xxs" />
|
||||
<TreeGroup
|
||||
classes={treeStyles}
|
||||
label={<div className={styles.parent}>Categories</div>}
|
||||
>
|
||||
{filteredCategories.get()
|
||||
.map(category => (
|
||||
<TreeItem
|
||||
classes={treeStyles}
|
||||
key={category.getId()}
|
||||
icon={<CategoryIcon category={category} />}
|
||||
label={<CatalogCategoryLabel category={category} />}
|
||||
selected={activeTab === category.getId()}
|
||||
data-testid={`${category.getId()}-tab`}
|
||||
onClick={() => onItemClick(category.getId())}
|
||||
/>
|
||||
))}
|
||||
</TreeGroup>
|
||||
</TreeView>
|
||||
</div>
|
||||
));
|
||||
|
||||
export const CatalogMenu = withInjectables<Dependencies, CatalogMenuProps>(NonInjectedCatalogMenu, {
|
||||
getProps: (di, props) => ({
|
||||
|
||||
@ -23,39 +23,8 @@
|
||||
.content {
|
||||
min-height: 26px;
|
||||
line-height: 1.3;
|
||||
padding: 2px var(--padding) 2px 0;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--sidebarItemHoverBackground);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: white;
|
||||
background-color: var(--blue);
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
margin-left: 0px;
|
||||
|
||||
.iconContainer {
|
||||
margin-left: 28px;
|
||||
margin-top: 2px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
& > *:first-child {
|
||||
background-color: var(--blue);
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.iconContainer {
|
||||
width: 21px;
|
||||
margin-left: 5px;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@ -177,7 +177,6 @@ class NonInjectedCatalog extends React.Component<Dependencies> {
|
||||
}
|
||||
|
||||
onTabChange = action((tabId: string | null) => {
|
||||
console.log(tabId);
|
||||
const activeCategory = this.categories.find(category => category.getId() === tabId);
|
||||
|
||||
this.props.emitEvent({
|
||||
|
||||
@ -20,6 +20,9 @@
|
||||
|
||||
$baseline: 8px;
|
||||
|
||||
@include horizontalLineSize('xxs', 0.5 * $baseline);
|
||||
@include horizontalLineSize('xs', 1 * $baseline);
|
||||
@include horizontalLineSize('sm', 2 * $baseline);
|
||||
@include horizontalLineSize('md', 3 * $baseline);
|
||||
@include horizontalLineSize('lg', 4 * $baseline);
|
||||
@include horizontalLineSize('xl', 5 * $baseline);
|
||||
|
||||
@ -7,7 +7,7 @@ import styles from "./horizontal-line.module.scss";
|
||||
import { cssNames } from "../../utils";
|
||||
|
||||
interface HorizontalLineProps {
|
||||
size?: "sm" | "md" | "xl";
|
||||
size?: "xxs" | "xs" | "sm" | "md" | "lg" | "xl";
|
||||
}
|
||||
|
||||
export const HorizontalLine = ({ size = "xl" }: HorizontalLineProps = { size: "xl" }) => {
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
.treeItem {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 2px var(--padding) 2px 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--sidebarItemHoverBackground);
|
||||
}
|
||||
|
||||
&.selected:hover {
|
||||
background-color: var(--blue);
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: var(--blue);
|
||||
color: white;
|
||||
border-radius: 2px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.treeGroup {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.contents {
|
||||
padding-left: 25px;
|
||||
transition: all 300ms ease;
|
||||
overflow: hidden;
|
||||
|
||||
&.expanded {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
&:not(.expanded) {
|
||||
max-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
color: white;
|
||||
background-color: var(--blue);
|
||||
}
|
||||
|
||||
.group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.iconContainer {
|
||||
align-self: flex-start;
|
||||
width: 21px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.treeView {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import styles from "./tree-view.module.scss";
|
||||
import type { MouseEventHandler } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { cssNames } from "../../utils";
|
||||
@ -20,7 +21,7 @@ export interface TreeViewProps {
|
||||
export function TreeView(props: TreeViewProps) {
|
||||
return (
|
||||
<ul
|
||||
className={props.classes?.root}
|
||||
className={cssNames(props.classes?.root, styles.treeView)}
|
||||
role="tree"
|
||||
>
|
||||
{props.children}
|
||||
@ -31,10 +32,14 @@ export function TreeView(props: TreeViewProps) {
|
||||
export interface TreeItemClasses {
|
||||
root?: string;
|
||||
label?: string;
|
||||
selected?: string;
|
||||
hover?: string;
|
||||
iconContainer?: string;
|
||||
}
|
||||
|
||||
export interface TreeItemProps {
|
||||
classes?: TreeItemClasses;
|
||||
icon?: JSX.Element;
|
||||
label: JSX.Element | string;
|
||||
testId?: string;
|
||||
selected?: boolean;
|
||||
@ -42,15 +47,31 @@ export interface TreeItemProps {
|
||||
}
|
||||
|
||||
export function TreeItem(props: TreeItemProps) {
|
||||
const [hovering, setHovering] = useState(false);
|
||||
const optionalCssNames: Partial<Record<string, any>> = {};
|
||||
|
||||
if (props.classes?.selected) {
|
||||
optionalCssNames[props.classes.selected] = props.selected ?? false;
|
||||
}
|
||||
|
||||
if (props.classes?.hover) {
|
||||
optionalCssNames[props.classes.hover] = hovering;
|
||||
}
|
||||
|
||||
return (
|
||||
<li
|
||||
className={cssNames(props.classes?.root, {
|
||||
selected: props.selected ?? false,
|
||||
className={cssNames(props.classes?.root, optionalCssNames, styles.treeItem, {
|
||||
[styles.selected]: props.selected ?? false,
|
||||
})}
|
||||
role="treeitem"
|
||||
data-testid={props.testId}
|
||||
onClick={props.onClick}
|
||||
onMouseOver={() => setHovering(true)}
|
||||
onMouseLeave={() => setHovering(false)}
|
||||
>
|
||||
<div className={cssNames(props.classes?.iconContainer, styles.iconContainer)}>
|
||||
{props.icon}
|
||||
</div>
|
||||
<div className={props.classes?.label}>
|
||||
{props.label}
|
||||
</div>
|
||||
@ -60,7 +81,7 @@ export function TreeItem(props: TreeItemProps) {
|
||||
|
||||
export interface TreeGroupClasses {
|
||||
root?: string;
|
||||
header?: string;
|
||||
group?: string;
|
||||
iconContainer?: string;
|
||||
label?: string;
|
||||
contents?: string;
|
||||
@ -81,12 +102,15 @@ export function TreeGroup(props: TreeGroupProps) {
|
||||
|
||||
return (
|
||||
<li
|
||||
className={props.classes?.root}
|
||||
className={cssNames(props.classes?.root, styles.treeGroup)}
|
||||
role="group"
|
||||
data-testid={props.testId}
|
||||
>
|
||||
<div className={props.classes?.header} onClick={() => setExpanded(!expanded)}>
|
||||
<div className={props.classes?.iconContainer}>
|
||||
<div
|
||||
className={cssNames(props.classes?.group, styles.group)}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
>
|
||||
<div className={cssNames(props.classes?.iconContainer, styles.iconContainer)}>
|
||||
{
|
||||
expanded
|
||||
? props.collapseIcon ?? <Icon material="expand_more" />
|
||||
@ -97,13 +121,13 @@ export function TreeGroup(props: TreeGroupProps) {
|
||||
{props.label}
|
||||
</div>
|
||||
</div>
|
||||
<div className={props.classes?.contents}>
|
||||
{
|
||||
expanded
|
||||
? props.children
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
<ul
|
||||
className={cssNames(props.classes?.contents, styles.contents, {
|
||||
[styles.expanded]: expanded,
|
||||
})}
|
||||
>
|
||||
{props.children}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
"skipLibCheck": true,
|
||||
"allowJs": false,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"importsNotUsedAsValues": "error",
|
||||
"traceResolution": false,
|
||||
"resolveJsonModule": true,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user