Skip to content

Giving-Tuesday/co-collection-themes

Repository files navigation

Co-Collection Themes

A React component library providing themed collection views for Giving Tuesday's data embedding system. TypeScript, Rollup, CSS Modules, Storybook.

Architecture

Theme System

The library is transitioning from a Card + ItemPage model to a List composition model where each theme owns its full collection layout.

Legacy pattern — themes export a Card and ItemPage. The consuming app builds the surrounding UI (filters, sort, grid). Used by: gtrex, datamarts, datasets, african-giving-traditions, gtdc, posterchild, problems-solutions, viz-database.

New pattern — themes export a List component that composes a complete collection view: filters, sort, map, and card grid. The consuming app passes data and callbacks via ListProps; the theme controls the layout. Used by: map-theme. Legacy themes will transition to this pattern over time.

List Composition (map-theme reference)

List (ListProps)
├── FilterPills        — active filter tags with remove/clear
├── SortDropdown       — passed in by consumer
├── FilterPane         — sidebar of MultiSelect dropdowns
├── MapFilter          — interactive map with pins + country clusters
└── ListItems          — card grid
    └── Card           — theme-specific card

Theme Resolution

// Legacy — individual cards
const CardComponent = getThemeCard('gtrex');
const ItemPageComponent = getThemeItemPage('datasets');

// New — full list composition
const ListComponent = getThemeList('map-theme');

Multiple aliases can map to one theme:

['giving-lab', 'givinglab', 'gtrex']; // all resolve to GtrexCard

Shared Components

Component Location Purpose
BaseCard / CardContent src/BaseCard/, src/CardContent/ Card shell and content layout
MapFilter src/MapFilter/ MapLibre GL map with pins and country counts
MultiSelect src/MultiSelect/ Checkbox dropdown filter
FilterPills src/FilterPills/ Active filter tag pills
ListItems src/ListItems/ Card grid accepting a CardComponent
Widget src/Widget/ Embeddable card grid with modal (legacy)

Project Structure

src/
├── index.tsx                  # Package exports
├── types/index.ts             # All type definitions
├── themes/
│   ├── cards.tsx              # Card theme registry (legacy)
│   ├── item-pages.tsx         # ItemPage theme registry (legacy)
│   ├── lists.tsx              # List theme registry (new)
│   └── <theme-name>/
│       ├── List.tsx           # List composition (new themes)
│       ├── Card.tsx           # Card component
│       ├── ItemPage.tsx       # Item page (legacy themes)
│       └── *.module.css       # Scoped styles
├── MapFilter/                 # Map visualization
├── MultiSelect/               # Filter dropdowns
├── FilterPills/               # Active filter pills
├── ListItems/                 # Card grid
├── BaseCard/                  # Card shell
├── CardContent/               # Card content layout
├── Widget/                    # Embeddable widget (legacy)
├── utils/                     # Theme resolution, text processing
└── hooks/                     # useConvertToHtml, useItemModal

geo-config/                    # Country ISO → name/subregion config
stories/                       # Storybook stories and mock data

Development Setup

Prerequisites

  • Node.js 20+
  • npm

Installation

git clone https://github.com/Giving-Tuesday/co-collection-themes.git
cd co-collection-themes
npm install

npm install triggers a build automatically via the prepare script.

Scripts

# Development
npm run dev             # Clean + rollup watch mode
npm run storybook       # Storybook dev server on localhost:6006

# Build
npm run build           # Clean + production build → dist/
npm run build:stories   # Build static Storybook

# Quality
npm run lint            # ESLint check
npm run lint:fix        # ESLint auto-fix
npm run format          # Prettier format
npm run type-check      # TypeScript validation (tsc --noEmit)

# Utilities
npm run generate:geo-config  # Regenerate geo-config/config.json

Workflow

  1. Run npm run storybook for component development
  2. Run npm run dev to rebuild on changes
  3. Validate before committing: npm run lint && npm run type-check

Deployment & Publishing

Publishing

NPM Package (GitHub Packages):

Can be published automatically with contained .github/publish.yml file.

For beta releases:

# Update version in package.json
npm version prepatch --preid beta  # or patch, minor, etc.
npm version prerelease --preid beta
# This creates a tag like v0.6.1-beta.1
# Push the tag
git push --follow-tags
# Or push tag explicitly
git push origin v0.6.1-beta.1

For stable releases:

# Update version in package.json
npm version patch  # or minor, major
# Push the tag
git push --follow-tags
# Or push tag explicitly
git push origin v0.6.2

Publishing Configuration

  • Registry: GitHub Packages (https://npm.pkg.github.com)
  • Scope: @giving-tuesday/co-collection-themes
  • Access: Public within Giving Tuesday organization

Build Output

  • dist/index.cjs.js - CommonJS build for Node.js environments
  • dist/index.esm.js - ES Module build for modern bundlers
  • Source maps for both builds
  • CSS modules are inlined and scoped

Usage

Installation

npm install @giving-tuesday/co-collection-themes

Peer Dependencies

{
  "react": ">=18 <20",
  "react-dom": ">=18 <20",
  "react-icons": ">=4.0.0",
  "react-router-dom": ">=6.0.0"
}

Examples

// New pattern — full list composition
import { getThemeList } from '@giving-tuesday/co-collection-themes';

const ListComponent = getThemeList('map-theme');
<ListComponent
  listItems={{ items, buildHref, CustomLink }}
  search={{ searchTerm, onSearch, onClear }}
  filterPills={{ filterParams, onRemove, onReset }}
  filterPane={{ filters, selectedValues, onChange, onReset }}
  SortDropdown={SortDropdown}
  defaultSort="title-asc"
  mapFilter={{ locations, onCountryFilter, onClearFilter }}
/>

// Legacy — individual cards
import { getThemeCard, Widget } from '@giving-tuesday/co-collection-themes';

const CardComponent = getThemeCard('gtrex');
<CardComponent item={itemData} href="/items/123" />

<Widget items={collectionItems} widgetTheme="datasets" maxCardsPerRow={3} />

Data Format

// Item (for cards)
{
  _id: string;
  title: string;
  author: string[];
  desc: string;
  custom_fields: { /* theme-specific */ };
}

// Location (for map)
{
  _id: string;
  title: string;
  desc: string;
  slug: string;
  coordinates?: [number, number];
  geoCountry?: string;
  geoSubregion?: string;
}

Adding a Theme

New pattern (List composition — preferred)

  1. Create src/themes/<name>/ with List.tsx, Card.tsx, index.tsx, CSS modules
  2. List.tsx accepts ListProps and composes shared components
  3. Register in src/themes/lists.tsx (listThemeEntries)
  4. Export from src/themes/index.tsx and src/index.tsx
  5. Add mock data and Storybook stories

Legacy pattern (Card + ItemPage)

  1. Create src/themes/<name>/ with Card.tsx, ItemPage.tsx, index.tsx, CSS modules
  2. Register in src/themes/cards.tsx and src/themes/item-pages.tsx
  3. Export from src/index.tsx
  4. Add mock data and Storybook stories

About

Collection of components for usei n DARO and GivingTuesday projects

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors