GoogleChromeLabs/houdini.how

Filtering Functionality

Opened this issue · 5 comments

una commented

Add functionality to filter by tag for both Resources and Worklets pages.

Hello @una, Can I work on this?

una commented

Sure, thanks—that would be great! Feel free to open a PR :)

Is there any easier or finer way to implement this apart from adding route for each tag?

Hello @Kartik1397

This is possible without adding a new route for each tag. Here is a working proof of concept example to help you get started.

Defaults to show all resources with filter tag buttons at top of page

image

Click or tap to filtered by tag

image

Notes and Code

Additionally all Worklets have the same tag to it seems this would only need to go on the Resources page for now (but I'm not a site maintainer) so I can't be certain on that or future plans of how Worklet tags should work.

The above images were created by modifying this one file with the code below. However, if you end up adding this feature you would want to properly structure the code to separate component files, add CSS, etc.

https://github.com/GoogleChromeLabs/houdini.how/blob/main/public/pages/resources/index.js

import { useState } from 'preact/hooks';
import Resource from '../../components/Resource/index.js'
import resources from '../../resource-data.js'
import style from '../../components/CardMeta/style.module.css'

const selectedStyle = (selectedTag, tag) => {
  if (selectedTag === tag) {
    return { 'transform': 'scale(1.3)' };
  }
  return null;
}

const buildTag = (tag, selectedTag, setFilter) => {
  if (tag === 'paint') {
    return (<li class={style.paint}  style={selectedStyle(selectedTag, tag)}><a href="#" onClick={() => setFilter(tag)}>Paint</a></li>)
  } else if (tag === 'properties and values') {
    return (<li class={style.props}  style={selectedStyle(selectedTag, tag)}><a href="#" onClick={() => setFilter(tag)}>Properties & Values</a></li>)
  } else if (tag === 'typed object model') {
    return (<li class={style.typed}  style={selectedStyle(selectedTag, tag)}><a href="#" onClick={() => setFilter(tag)}>Typed Object Model</a></li>)
  } else if (tag === 'layout') {
    return (<li class={style.layout}  style={selectedStyle(selectedTag, tag)}><a href="#" onClick={() => setFilter(tag)}>Layout</a></li>)
  } else if (tag === 'animation') {
    return (<li class={style.animation}  style={selectedStyle(selectedTag, tag)}><a href="#" onClick={() => setFilter(tag)}>Animation</a></li>)
  }
  else return
}

export default function ResourcesPage() {
  const [selectedTag, setFilter] = useState(null);

  const allTags = new Set();
  resources.forEach(resource => {
    resource.tags.forEach(tag => {
      allTags.add(tag);
    });
  });

  const displayResources = (
    selectedTag === null ?
    resources :
    resources.filter(resource => { return resource.tags.includes(selectedTag)} )
  );

  return (
    <div>
      <div class={style.tags} style={{'align-items':'center', 'padding-bottom':'4rem', 'padding-top':'2rem'}}>
        <ul style={{'justify-content':'center', 'gap':'25px'}}>
          {selectedTag === null ?
            <strong>Filter</strong> :
            <li class={style.paint} style={{'background-color': '#66ff66', 'border-color':'transparent'}}><a href="#" onClick={() => setFilter(null)}>Show All</a></li>
          }
          {Array.from(allTags).map((tag) =>
            buildTag(tag, selectedTag, setFilter)
          )}
        </ul>
      </div>
      <div>
        {displayResources.map(resource => (
          <Resource resource={resource} />
        ))}
      </div>
    </div>
  );
}

Compared to the original file you can see I added a lot of code and mixed styles within the components, etc which why I call this a proof of concept even though it works.

From the above code example const buildTag = ... was copied and modified from here.
https://github.com/GoogleChromeLabs/houdini.how/blob/main/public/components/CardMeta/index.js

Hope this helps, Good Luck! 😄

Thank You @ConradSollitt :)