diff --git a/components/Header.tsx b/components/Header.tsx
index 8e141cd..757d84e 100644
--- a/components/Header.tsx
+++ b/components/Header.tsx
@@ -2,7 +2,7 @@ import React from 'react';
import HostSwitcher from './HostSwitcher';
-export default function Header({ hosts, platformTotalCollectives, locale, host, categories, filter, setFilter }) {
+export default function Header({ hosts, locale, host, categories, filter, setFilter }) {
return (
- Discover {host.count.toLocaleString(locale)}
- {host.root && *}{' '}
- collectives {host.root ? 'on ' : 'hosted by '}
- {' '}
- making an impact in{' '}
+
+ Discover {host.count.toLocaleString(locale)} collectives
+ {host.root ? ' on ' : ' hosted by '}
+
+ making an impact in{' '}
{categories
.filter(c => !c.options && c.tag !== 'ALL')
@@ -44,12 +39,7 @@ export default function Header({ hosts, platformTotalCollectives, locale, host,
and more.
- {host.root && (
-
- * out of {platformTotalCollectives.toLocaleString(locale)} collectives on Open Collective. Displaying data
- from selected Fiscal Hosts.
-
- )}
+ {host.root &&
* Data from selected Fiscal Hosts.
}
);
}
diff --git a/components/HostSwitcher.tsx b/components/HostSwitcher.tsx
index ba2b5a9..2fd15b0 100644
--- a/components/HostSwitcher.tsx
+++ b/components/HostSwitcher.tsx
@@ -4,7 +4,7 @@ import { useRouter } from 'next/router';
import { ChevronUpDown, CloseIcon } from './Icons';
-export default function HostSwitcher({ host, hosts, platformTotalCollectives, locale }) {
+export default function HostSwitcher({ host, hosts, locale }) {
const router = useRouter();
const [isOpen, setIsOpen] = useState(false);
@@ -15,7 +15,7 @@ export default function HostSwitcher({ host, hosts, platformTotalCollectives, lo
function openModal() {
setIsOpen(true);
}
- const hostNameStyles = `relative underline decoration-3 underline-offset-3 transition-colors lg:decoration-4 lg:underline-offset-4 ${host.styles.text}`;
+ const hostNameStyles = `relative underline tracking-tight decoration-3 underline-offset-3 transition-colors lg:decoration-4 lg:underline-offset-4 ${host.styles.text}`;
return (
@@ -25,16 +25,20 @@ export default function HostSwitcher({ host, hosts, platformTotalCollectives, lo
const lastWord = i === arr.length - 1;
return (
-
- {word}
- {lastWord && (
+ {word}
+
+ {lastWord && (
+
+ {host.root && *}
- )}
-
+
+ )}
);
@@ -92,9 +96,9 @@ export default function HostSwitcher({ host, hosts, platformTotalCollectives, lo
{host.count.toLocaleString(locale)} collectives
- {host.root && (
+ {/* {host.root && (
out of {platformTotalCollectives.toLocaleString(locale)} in total
- )}
+ )} */}
))}
diff --git a/components/Updates.tsx b/components/Updates.tsx
index 781017d..dea22a1 100644
--- a/components/Updates.tsx
+++ b/components/Updates.tsx
@@ -3,7 +3,7 @@ import { gql, useQuery } from '@apollo/client';
import { FormattedDate } from 'react-intl';
import sanitizeHtml from 'sanitize-html';
-import { getAllPossibleTagValues } from '../utils/tag-transforms';
+import { getAllPossibleTagValues } from '../utils/tag-helpers';
import CollectiveButton from './CollectiveButton';
import { PaginationControls } from './PaginationControls';
diff --git a/lib/hosts.ts b/lib/hosts.ts
index 3540a45..d7432c7 100644
--- a/lib/hosts.ts
+++ b/lib/hosts.ts
@@ -12,8 +12,8 @@ const defaultExcludeCategoryTags = [
'community',
'association',
'movement',
- 'USA',
- 'midwestern USA',
+ 'usa',
+ 'midwestern usa',
'illinois',
'europe',
'chicago',
@@ -27,8 +27,15 @@ export const hosts: {
currency: string;
startYear: number;
logoSrc: string;
- color: string;
- styles: { text: string; groupHoverText: string; button: string; brandBox: string; box: string; border: string };
+ color: { hex: string; closestPaletteColor: string };
+ styles: {
+ text: string;
+ groupHoverText: string;
+ button: string;
+ brandBox: string;
+ box: string;
+ border: string;
+ };
website?: string;
cta?: { text: string; textLonger: string; href: string; buttonLabel: string };
groupTags: { [key: string]: string[] };
@@ -58,7 +65,7 @@ export const hosts: {
currency: 'USD',
startYear: 2016,
logoSrc: '/oc-logo.svg',
- color: 'blue',
+ color: { hex: '#0C2D66', closestPaletteColor: 'blue' },
website: 'https://opencollective.com',
styles: {
text: 'text-[#0C2D66]',
@@ -70,8 +77,8 @@ export const hosts: {
},
groupTags: {
...defaultGroupTags,
- education: ['education', 'meetup'],
'mutual aid': ['mutual aid', 'covid'],
+ education: ['education', 'meetup'],
},
includeCategoryTags: [],
excludeCategoryTags: [...defaultExcludeCategoryTags],
@@ -82,7 +89,7 @@ export const hosts: {
currency: 'USD',
startYear: 2018,
logoSrc: '/ocf-logo.svg',
- color: 'teal',
+ color: { hex: '#0C5559', closestPaletteColor: 'teal' },
styles: {
text: 'text-[#0C5559]',
groupHoverText: 'group-hover:text-[#0C5559]',
@@ -110,7 +117,7 @@ export const hosts: {
startYear: 2016,
logoSrc: '/osc-logo.svg',
website: 'https://opencollective.com/opensource',
- color: 'purple',
+ color: { hex: '#4B3084', closestPaletteColor: 'purple' },
styles: {
text: 'text-[#4B3084]',
groupHoverText: 'group-hover:text-[#4B3084]',
@@ -132,7 +139,7 @@ export const hosts: {
startYear: 2019,
logoSrc: '/oce-logo.svg',
website: 'https://opencollective.com/europe',
- color: 'blue',
+ color: { hex: '#0C2D66', closestPaletteColor: 'blue' },
styles: {
text: 'text-[#0C2D66]',
groupHoverText: 'group-hover:text-[#0C2D66]',
@@ -145,6 +152,6 @@ export const hosts: {
...defaultGroupTags,
},
includeCategoryTags: [],
- excludeCategoryTags: [...defaultExcludeCategoryTags, 'opencollectiveeu'],
+ excludeCategoryTags: [...defaultExcludeCategoryTags],
},
];
diff --git a/pages/[slug].tsx b/pages/[slug].tsx
index 8633edb..5e6bf95 100644
--- a/pages/[slug].tsx
+++ b/pages/[slug].tsx
@@ -9,7 +9,6 @@ import Layout from '../components/Layout';
import { createCategories } from '../utils/categories';
import { getLocation } from '../utils/location/get-location';
-import { getAllCollectiveStats } from '../utils/stats';
import { getStories } from '../utils/stories';
import { transformTags } from '../utils/tag-transforms';
@@ -32,15 +31,14 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
}
const collectives = accounts.nodes.map(collective => {
- const stats = getAllCollectiveStats(collective);
const location = getLocation(collective);
return {
name: collective.name,
slug: collective.slug,
imageUrl: collective.imageUrl.replace('-staging', ''),
host: { name: collective.host.name, slug: collective.host.slug },
- tags: transformTags(collective.tags),
- ...(stats && { stats }),
+ tags: transformTags(collective),
+ stats: collective.stats,
...(location && { location }),
};
});
@@ -76,16 +74,7 @@ export async function getStaticPaths() {
};
}
-export default function Page({
- categories,
- stories,
- host,
- hosts,
- collectives,
- currency,
- startYear,
- platformTotalCollectives,
-}) {
+export default function Page({ categories, stories, host, hosts, collectives, currency, startYear }) {
// eslint-disable-next-line no-console
const locale = 'en';
return (
@@ -102,7 +91,6 @@ export default function Page({
locale={locale}
host={host}
hosts={hosts}
- platformTotalCollectives={platformTotalCollectives}
/>
);
diff --git a/scripts/fetch-data.ts b/scripts/fetch-data.ts
index 38e46ad..9a3982e 100644
--- a/scripts/fetch-data.ts
+++ b/scripts/fetch-data.ts
@@ -21,6 +21,8 @@ for (const env of ['local', process.env.NODE_ENV || 'development']) {
import { initializeApollo } from '../lib/apollo-client';
import { accountsQuery, totalCountQuery } from '../lib/graphql/queries';
+import { getAllCollectiveStats } from '../utils/stats';
+
dayjs.extend(dayjsPluginUTC);
dayjs.extend(dayjsPluginIsoWeek);
@@ -158,13 +160,25 @@ async function run() {
};
} else {
data = await fetchDataForPage(host);
+
+ // add total stats to collectives, and filter away collectives with no stats data
+ data.accounts.nodes = data.accounts.nodes
+ .map(account => {
+ const stats = getAllCollectiveStats(account);
+ return {
+ ...account,
+ stats,
+ };
+ })
+ .filter(account => account.stats);
+
if (host.root) {
rootData = data;
}
}
if (data) {
- collectiveCounts[host.root ? 'ALL' : host.slug] = data.accounts.totalCount;
+ collectiveCounts[host.root ? 'ALL' : host.slug] = data.accounts.nodes.length;
// write data to file
const filename = path.join(directory, `${host.root ? 'ALL' : host.slug}.json`);
diff --git a/utils/categories.ts b/utils/categories.ts
index 84d299a..509606c 100644
--- a/utils/categories.ts
+++ b/utils/categories.ts
@@ -1,6 +1,6 @@
import { pickColorForCategory } from './colors';
import { getTagCounts } from './tag-counts';
-import { transformToGroupTags } from './tag-transforms';
+import { getGroupTagKeys } from './tag-helpers';
export const createCategories = ({
collectives,
@@ -47,7 +47,7 @@ export const createCategories = ({
// Filter away collectives that are part of the tag just added
collectivesNotCategorized = collectivesNotCategorized.filter(
- coll => !transformToGroupTags(coll.tags, groupTags)?.includes(tag),
+ coll => !getGroupTagKeys(coll.tags, groupTags)?.includes(tag),
);
}
@@ -78,6 +78,6 @@ export const createCategories = ({
return categories.map((category, i, arr) => ({
...category,
- color: pickColorForCategory('blue', i, arr.length),
+ color: pickColorForCategory(host.color.closestPaletteColor, i, arr.length),
}));
};
diff --git a/utils/colors.ts b/utils/colors.ts
index 49e20ff..c393376 100644
--- a/utils/colors.ts
+++ b/utils/colors.ts
@@ -20,6 +20,6 @@ const colors = [
export const pickColorForCategory = (startColor: string, i: number, numOfCategories: number) => {
const startColorIndex = colors.findIndex(c => c.name === startColor);
- const step = Math.floor(colors.length / numOfCategories);
- return colors[(startColorIndex + i * step) % colors.length];
+ const step = colors.length / numOfCategories;
+ return colors[(startColorIndex + Math.round(i * step)) % colors.length];
};
diff --git a/utils/tag-counts.ts b/utils/tag-counts.ts
index ed5c447..fb72c21 100644
--- a/utils/tag-counts.ts
+++ b/utils/tag-counts.ts
@@ -1,10 +1,10 @@
-import { transformToGroupTags } from './tag-transforms';
+import { getGroupTagKeys } from './tag-helpers';
// Function that returns tag counts for a list of collectives. if a tag is the key of a group, it will return the count of the group
export const getTagCounts = (collectives, groupTags?: { [key: string]: string[] }): { [key: string]: number } => {
const { groupedCounts, ungroupedCounts } = collectives.reduce(
(acc, collective) => {
- const groupedTags = transformToGroupTags(collective.tags, groupTags);
+ const groupedTags = getGroupTagKeys(collective.tags, groupTags);
const ungroupedTags = collective.tags;
groupedTags?.forEach(tag => {
diff --git a/utils/tag-helpers.ts b/utils/tag-helpers.ts
new file mode 100644
index 0000000..0699b76
--- /dev/null
+++ b/utils/tag-helpers.ts
@@ -0,0 +1,31 @@
+import { uniq } from 'lodash';
+
+import { tagTransforms } from './tag-transforms';
+
+// Transform tags to grouped tags, i.e. if a tag is in a group, return the group key otherwise return the tag
+export const getGroupTagKeys = (tags: string[], groupTags: { [key: string]: string[] }) => {
+ const groupedTagKey = Object.entries(groupTags).reduce((acc, [key, value]) => {
+ value.forEach(tag => {
+ acc[tag] = key;
+ });
+ return acc;
+ }, {});
+ return uniq(tags?.map(tag => groupedTagKey[tag] || tag)) ?? null;
+};
+
+// This is used to reverse the group tags AND the tag transforms when querying the API
+export const getAllPossibleTagValues = (tag: string, groupTags: { [key: string]: string[] }): string[] => {
+ const tags = groupTags[tag] || [tag];
+ const acc = [...tags];
+
+ const reverseTagTransforms = Object.entries(tagTransforms).reduce((acc, [key, value]) => {
+ if (tags.includes(value)) {
+ acc.push(key);
+ }
+ return acc;
+ }, []);
+
+ acc.push(...reverseTagTransforms);
+
+ return acc;
+};
diff --git a/utils/tag-transforms.ts b/utils/tag-transforms.ts
index b510f57..c2ae417 100644
--- a/utils/tag-transforms.ts
+++ b/utils/tag-transforms.ts
@@ -3,52 +3,17 @@ import { uniq } from 'lodash';
// Tag transforms that are applied to all accounts.
// These are intended to fix various inconsistencies of the same thing
// For grouping tags under each other, use defaultGroupTags or groupTags in the host config
-const tagTransforms = {
+export const tagTransforms = {
opensource: 'open source',
'open-source': 'open source',
- 'Open source': 'open source',
- 'Open Source': 'open source',
'covid-19': 'covid',
- Covid19: 'covid',
covid19: 'covid',
- 'COVID-19': 'covid',
- 'Covid-19': 'covid',
coronavirus: 'covid',
- 'Tech meetups': 'meetup',
- Climate: 'climate',
+ 'tech meetups': 'meetup',
};
-export const transformTags = (tags: string[]) => {
- if (!tags) {
- return null;
- }
- return uniq(tags.map(tag => tagTransforms[tag] || tag));
-};
-
-// Transform tags to grouped tags, i.e. if a tag is in a group, return the group key otherwise return the tag
-export const transformToGroupTags = (tags: string[], groupTags: { [key: string]: string[] }) => {
- const groupedTagKey = Object.entries(groupTags).reduce((acc, [key, value]) => {
- value.forEach(tag => {
- acc[tag] = key;
- });
- return acc;
- }, {});
- return uniq(tags?.map(tag => groupedTagKey[tag] || tag)) ?? null;
-};
-
-// This is used to reverse the group tags AND the tag transforms when querying the API
-export const getAllPossibleTagValues = (tag: string, groupTags: { [key: string]: string[] }): string[] => {
- const tags = groupTags[tag] || [tag];
- const acc = [...tags];
+export function transformTags(collective) {
+ const tags = collective.tags?.map(t => t.toLowerCase()).map(tag => tagTransforms[tag] || tag) || [];
- const reverseTagTransforms = Object.entries(tagTransforms).reduce((acc, [key, value]) => {
- if (tags.includes(value)) {
- acc.push(key);
- }
- return acc;
- }, []);
-
- acc.push(...reverseTagTransforms);
-
- return acc;
-};
+ return uniq(tags);
+}