Skip to content

Commit

Permalink
@thunderstore/cyberstorm: replace CurrentFilters with CategoryTagCloud
Browse files Browse the repository at this point in the history
- Connect TagCloud to the data managed by PackageSearch and shared with
  CategoryMenu
- PackageListing is still disconnected from this data source

Refs TS-1860
  • Loading branch information
anttimaki committed Oct 24, 2023
1 parent c29daa7 commit ccb6b02
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.root {
display: flex;
flex-flow: row wrap;
gap: var(--space--8);
list-style: none;
}

.tag {
display: flex;
flex: none;
gap: var(--gap--4);
align-items: center;
justify-content: center;
padding: var(--space--6) var(--space--8);
border-radius: var(--border-radius--8);
color: var(--text-color);
font-weight: 700;
font-size: var(--font-size--s);
background-color: var(--bg-color);

--text-color: var(--color-text--default);
--bg-color: var(--color-surface--5);
}

.tag.exclude {
--text-color: var(--color-red--3);
--bg-color: var(--color-red--10);
}

.icon {
height: var(--space--16);
color: var(--text-color);
}

.tag.exclude .icon {
--text-color: var(--color-red--3);
}

.clearAll {
margin-left: var(--space--4);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Dispatch, SetStateAction } from "react";

import styles from "./CategoryTagCloud.module.css";
import { CategorySelection, CATEGORY_STATES } from "../types";
import * as Button from "../../Button";
import { Icon } from "../../Icon/Icon";

const OFF = CATEGORY_STATES[0];

interface Props {
categories: CategorySelection[];
setCategories: Dispatch<SetStateAction<CategorySelection[]>>;
}

/**
* Show currently selected category filters.
*/
export const CategoryTagCloud = (props: Props) => {
const { categories, setCategories } = props;
const visible = categories.filter((c) => c.selection !== "off");

if (!visible.length) {
return null;
}

const clearCategory = (slug: string) =>
setCategories(
categories.map((c) => (c.slug === slug ? { ...c, selection: OFF } : c))
);

const clearAll = () =>
setCategories(categories.map((c) => ({ ...c, selection: OFF })));

return (
<ol className={styles.root}>
{visible.map((c) => (
<li key={c.slug} className={`${styles.tag} ${styles[c.selection]}`}>
<span>{c.name}</span>
<Button.Root
onClick={() => clearCategory(c.slug)}
colorScheme="transparentDefault"
paddingSize="none"
>
<Button.ButtonIcon>
<Icon>
<FontAwesomeIcon icon={faXmark} className={styles.icon} />
</Icon>
</Button.ButtonIcon>
</Button.Root>
</li>
))}

<li className={styles.clearAll}>
<Button.Root onClick={clearAll} colorScheme="transparentTertiary">
<Button.ButtonLabel>Clear all</Button.ButtonLabel>
</Button.Root>
</li>
</ol>
);
};

CategoryTagCloud.displayName = "CategoryTagCloud";
80 changes: 8 additions & 72 deletions packages/cyberstorm/src/components/PackageSearch/PackageSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,20 @@ import {
faSearch,
faStar,
faThumbsUp,
faXmark,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { PackageCategory } from "@thunderstore/dapper/types";
import { Suspense, useState, createContext } from "react";
import { useDebounce } from "use-debounce";

import { CategoryMenu } from "./CategoryMenu/CategoryMenu";
import { CategoryTagCloud } from "./CategoryTagCloud/CategoryTagCloud";
import styles from "./PackageSearch.module.css";
import { CategorySelection } from "./types";
import * as Button from "../Button/";
import { Icon } from "../Icon/Icon";
import { Pagination } from "../Pagination/Pagination";
import { PackageList } from "../PackageList/PackageList";
import { Select } from "../Select/Select";
import { Tag } from "../Tag/Tag";
import { TextInput } from "../TextInput/TextInput";

interface CategoriesProps {
Expand Down Expand Up @@ -52,48 +50,6 @@ export function FiltersProvider(props: ContextProps) {
);
}

const RemoveFilterIcon = (onClick: () => void) => (
<button onClick={onClick} style={{ backgroundColor: "transparent" }}>
<Icon>
<FontAwesomeIcon icon={faXmark} />
</Icon>
</button>
);

interface TagListProps {
filters: Filters;
}

function CurrentFilters(props: TagListProps) {
const { filters } = props;

function removeFilter(key: string) {
const cats = { ...filters.availableCategories };
Object.values(cats).forEach((c) => {
if (c.label === key) {
c.value = undefined;
}
});

filters.setAvailableCategories(cats);
}

return (
<>
{Object.values(filters.availableCategories)
.filter((category) => category.value !== undefined)
.map((cat, index) => (
<Tag
key={`categorySearch_${cat.label}_${index}`}
label={cat.label}
rightIcon={RemoveFilterIcon(() => removeFilter(cat.label))}
colorScheme="borderless_removable"
/>
))}
</>
);
}

interface Props {
communityId?: string;
packageCategories: PackageCategory[];
Expand Down Expand Up @@ -123,14 +79,6 @@ export function PackageSearch(props: Props) {
.map((c) => ({ ...c, selection: "off" }))
);

const clearFilters = () => {
setSearchValue("");

const cats = { ...filters.availableCategories };
Object.values(cats).forEach((cat) => (cat.value = undefined));
filters.setAvailableCategories(cats);
};

return (
<div className={styles.root}>
<TextInput
Expand All @@ -143,12 +91,19 @@ export function PackageSearch(props: Props) {
</Icon>
}
/>

<div className={styles.contentWrapper}>
<div className={styles.sidebar}>
<CategoryMenu categories={categories} setCategories={setCategories} />
</div>

<div className={styles.content}>
<div className={styles.listTopNavigation}>
<CategoryTagCloud
categories={categories}
setCategories={setCategories}
/>

<div className={styles.showing}>
{/* TODO: use real values */}
Showing <strong>1-20</strong> of <strong>327</strong> results
Expand All @@ -157,25 +112,6 @@ export function PackageSearch(props: Props) {
: ""}
</div>

{Object.keys(filters.availableCategories).some(
(k) => filters.availableCategories[k].value !== undefined
) ? (
<div className={styles.selectedTags}>
<CurrentFilters filters={filters} />
<Button.Root
key="clearAllButton"
paddingSize="small"
colorScheme="transparentTertiary"
border-width="0px"
onClick={clearFilters}
>
<Button.ButtonLabel fontSize="small">
Clear all
</Button.ButtonLabel>
</Button.Root>
</div>
) : null}

<div className={styles.displayAndSort}>
<div className={styles.displayButtons}></div>
<div className={styles.sort}>
Expand Down

0 comments on commit ccb6b02

Please sign in to comment.