19 |
20 | A project from JimNielsen. Got suggestions or corrections? Source is on Github.
21 |
22 |
23 | Note: some colors are official, others are approximations. Learn more.
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Loading... Not loading? You’re probably on an old browser or have Javascript disabled. You can still view the raw data.
33 |
34 |
35 |
36 |
37 |
38 |
49 |
50 |
--------------------------------------------------------------------------------
/public/img/nfl/arizona-cardinals.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nhl/winnipeg-jets.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nfl/new-york-giants.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/mlb/pittsburgh-pirates.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import uniq from "./utils/uniq.js";
4 | import App from "./components/App.js";
5 | import convertNameToId from "./utils/convertNameToId.js";
6 | import { rgbToHex, hexToRgb } from "./utils/rgbHexConversion.js";
7 | import json from "./teams.json";
8 |
9 | // Massage the team data as needed
10 | const teams = massageTeamsData(json);
11 |
12 | // Render the App
13 | ReactDOM.render(
14 | ,
22 | document.getElementById("root")
23 | );
24 |
25 | /**
26 | * Massage JSON by looping through all the teams and:
27 | * 1. Add a team ID
28 | * 2. If there's no HEX, convert the RGB to HEX and add it
29 | * 3. If there's no RGB, convert the HEX to RGB and add it
30 | * 4. Sort by team id
31 | *
32 | * @param {Object[]} - Original JSON values of teams
33 | * @return {Object[]} - Modified to include `id` and `hex` or `rgb` key/value
34 | * pairs (if missing) and sorted by team `id`
35 | */
36 | function massageTeamsData(data) {
37 | let out = data.map(team => {
38 | team.id = convertNameToId(team.name);
39 | if (!team.colors.hex) {
40 | team.colors.hex = team.colors.rgb.map(color => rgbToHex(color));
41 | }
42 | if (!team.colors.rgb) {
43 | team.colors.rgb = team.colors.hex.map(color => hexToRgb(color));
44 | }
45 |
46 | return team;
47 | });
48 |
49 | out.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
50 |
51 | return out;
52 | }
53 |
54 | /**
55 | * Pluck out a unique list of leagues from the team data
56 | * @param {Object[]} - List of all teams
57 | * @return {Array.} - List of leagues
58 | */
59 | function getLeagues(teams) {
60 | return uniq(teams.map(team => team.league));
61 | }
62 |
63 | /**
64 | * Pluck out a unique list of color modes from the team data
65 | * @param {Object[]} - List of all teams
66 | * @return {Array.} - List of leagues
67 | */
68 | function getColors(teams) {
69 | return uniq(
70 | teams.map(team => Object.keys(team.colors)).reduce((a, b) => a.concat(b))
71 | );
72 | }
73 |
74 | /**
75 | * Generate a unique list of leagues from the team data
76 | * Object mapping color support
77 | */
78 | function getColorsByLeague(teams) {
79 | let colorsByLeague = {};
80 | teams.forEach(({ colors, league }) => {
81 | if (!colorsByLeague[league]) {
82 | colorsByLeague[league] = Object.keys(colors);
83 | }
84 | });
85 | return colorsByLeague;
86 | }
87 |
--------------------------------------------------------------------------------
/public/img/nfl/seattle-seahawks.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nhl/carolina-hurricanes.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/mlb/chicago-cubs.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nfl/indianapolis-colts.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/leagues/nba.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/leagues/nfl.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nfl/denver-broncos.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nfl/san-francisco-49ers.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/mlb/los-angeles-angels-of-anaheim.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nhl/new-jersey-devils.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nhl/minnesota-wild.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/TeamFilters.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { array, func, object } from "prop-types";
3 | import debounce from "../utils/debounce.js";
4 |
5 | export default class TeamFilters extends Component {
6 | static propTypes = {
7 | activeFilters: object.isRequired,
8 | leagues: array.isRequired,
9 | colors: array.isRequired,
10 | colorsByLeague: object.isRequired,
11 | onUserInput: func.isRequired
12 | };
13 |
14 | // Debounce the keyup event
15 | // http://stackoverflow.com/questions/23123138/perform-debounce-in-react-js/24679479#24679479
16 | componentWillMount() {
17 | this.delayedHandleChange = debounce(this.handleChange, 125);
18 | }
19 |
20 | handleKeyUp = e => {
21 | e.persist();
22 | this.delayedHandleChange();
23 | };
24 |
25 | handleChange = () => {
26 | this.props.onUserInput({
27 | league: this.refs.leagueInput.value,
28 | color: this.refs.colorInput.value,
29 | search: this.refs.searchInput.value
30 | });
31 | };
32 |
33 | render() {
34 | const {
35 | leagues,
36 | colors,
37 | colorsByLeague,
38 | activeFilters: {
39 | league: activeLeague,
40 | color: activeColor,
41 | search: activeSearch
42 | }
43 | } = this.props;
44 |
45 | return (
46 |
108 | );
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/public/img/nfl/atlanta-falcons.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nhl/philadelphia-flyers.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/mlb/cincinnati-reds.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nfl/new-orleans-saints.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nhl/st-louis-blues.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/nfl/new-england-patriots.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/mls/vancouver-whitecaps-fc.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/img/mlb/boston-red-sox.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Team Colors
2 |
3 | 
4 |
5 | [Team Colors](http://jim-nielsen.com/teamcolors) is a reference of HEX, RGB, CMYK, and Pantone color values of major league sports teams.
6 |
7 | ## How-To
8 |
9 | Install: `yarn install`
10 | Development: `yarn start`
11 | Build: `yarn build`
12 |
13 | ## How It Works
14 |
15 | Site is built on the react framework. `index.html` is the shell container for react app. If javascript is not supported, a link is shown to the raw JSON data which has all color information.
16 |
17 | Color data is housed in a single `.json` file `src/teams.json`. Any changes to team colors can be done there. _Note on colors_: Color definitions for each team are in arrays and grouped by color mode. Color values should match index position in the array across color modes, for example:
18 |
19 | ```
20 | colors:
21 | rgb: TEAMS-RGB-BLUE, TEAMS-RGB-RED
22 | hex: TEAMS-HEX-BLUE, TEAMS-HEX-RED
23 | ```
24 |
25 | Source artwork for each team is grouped by league in `sketch`. Production versions of these logo should be in `.svg` format in `public/img`.
26 |
27 | ### Edit Team Color or Name
28 |
29 | Find teams `.json` file in `src/teams.json`, and edit the info you need.
30 |
31 | ### Add a Team
32 |
33 | 1. Determine the team’s league
34 | 2. Following the established pattern, add the team’s name and colors the `.json` file
35 | 3. Add a vector logo for the team in its corresponding `.sketch` league file in `sketch` with the team’s name (as referenced in its `.json` file) in lowercase with hyphens, i.e. "utah-jazz"
36 | 4. Export the team’s `.svg` logo to `public/img/`
37 | 5. Preferably, optimize the svg (with a tool like [SVGO](https://github.com/svg/svgo))
38 | 6. Run `yarn build`, commit, push
39 |
40 | ## Official Color References
41 |
42 | ### NBA
43 |
44 | All NBA colors are official ([source](http://courtside.nba.com/QuickPlace/nbalogo/Main.nsf/$defaultview/AD4C002C7D0F37A285257D660058EAED/$File/NBA%20Primary%20Composite_14-15PLAYOFFS.pdf?OpenElement) user & pass: nbamedia).
45 |
46 | The NBA only provides RGB, CMYK, and Pantone colors for each team, so the HEX color is a programmatic conversion of the RGB color.
47 |
48 | ### NFL
49 |
50 | All NFL colors are official (see sources below).
51 |
52 | The NFL provides official RGB, HEX, CMYK, and Pantone colors (so none of the colors you see on Team Colors are conversions).
53 |
54 | The NFL has logo slicks which detail team color values. These are provided on a per-conference basis. _Note_: each of these source links are over 100MB in size, so they take a while to download.
55 |
56 | - [AFC North](http://www.nflmedia.com/afc_north.zip)
57 | - [AFC South](http://www.nflmedia.com/afc_south.zip)
58 | - [AFC East](http://www.nflmedia.com/afc_east.zip)
59 | - [AFC West](http://www.nflmedia.com/afc_west.zip)
60 | - [NFC North](http://www.nflmedia.com/nfc_north.zip)
61 | - [NFC South](http://www.nflmedia.com/nfc_south.zip)
62 | - [NFC East](http://www.nflmedia.com/nfc_east.zip)
63 | - [NFC West](http://www.nflmedia.com/nfc_west.zip)
64 |
65 | ### MLB
66 |
67 | MLB colors have been extracted from the official “RGB Digital Art” spot color logo slicks provided at [MLB Press Box](http://mlbpressbox.mlbstyleguide.com) (user account required). They were not explicitly stated values, but they are color values pulled from individual team logos in an _official_ MLB document.
68 |
69 | The extracted colors are in HEX form and their RGB counterparts are generated programmatically.
70 |
71 | - [American League logo slick](http://i.imgur.com/RP5kBSI.png)
72 | - [National League logo slick](http://i.imgur.com/FcuizSx.png)
73 |
74 | ### NHL
75 |
76 | NHL colors are official. As per [Michael Sharer](https://github.com/epitaphmike) of the NHL.
77 |
78 | ### MLS
79 |
80 | MLS colors are currently approximations, with the exceptions listed below. I am working on getting official colors of the remaining teams.
81 |
82 | - [Philadelphia Union](http://portfolios.scad.edu/gallery/36587433/Philadelphia-Union-Brand-Guidelines)
83 |
84 | ### EPL
85 |
86 | These leagues’ teams and colors are currently approximations. I am working on getting official colors. If you know how/where to find them, please open an issue here in Github.
87 |
88 | ## To-Dos
89 |
90 | - [ ] Switch to `flex` for layout
91 | - [ ] Improve filtering with fuzzy string search
92 | - [ ] Improve error states for when data doesn't render
93 | - [ ] Consider alternatives to no-js users rather than just "here's the raw data" (something that doesn't required a build if a single color in the JSON file is changed)
94 | - [ ] Possibly add team `id` manually to JSON file ??
95 |
--------------------------------------------------------------------------------
/public/img/nfl/tennessee-titans.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { array, object, number, string } from "prop-types";
3 | import fuzzy from "fuzzy";
4 | import TeamList from "./TeamList.js";
5 | import TeamFilters from "./TeamFilters.js";
6 |
7 | export default class App extends Component {
8 | static propTypes = {
9 | teams: array.isRequired,
10 | leagues: array.isRequired,
11 | colors: array.isRequired,
12 | colorsByLeague: object.isRequired,
13 | threshold: number.isRequired,
14 | initialColor: string,
15 | initialLeague: string,
16 | initialSearch: string
17 | };
18 |
19 | constructor(props) {
20 | super(props);
21 |
22 | // @TODO Add ability to pass these initial state via the URL
23 | // Intial filters
24 | const activeFilters = {
25 | color: props.initialColor || "",
26 | league: props.initialLeague || "",
27 | search: props.initialSearch || ""
28 | };
29 |
30 | // Filter teams by passed in vals
31 | const filteredTeams = this.getFilteredTeams(activeFilters);
32 |
33 | this.state = {
34 | activeFilters: activeFilters,
35 | visibleTeams: filteredTeams.slice(0, props.threshold),
36 | allTeams: filteredTeams
37 | };
38 | }
39 |
40 | componentDidMount() {
41 | // Handle scroll
42 | // Throttle the scroll event and detect if we're at the bottom of the page
43 | // If we are, show more teams
44 | var throttle = function(fn, threshhold, scope) {
45 | threshhold || (threshhold = 250);
46 | var last, deferTimer;
47 | return function() {
48 | var context = scope || this;
49 |
50 | var now = +new Date(),
51 | args = arguments;
52 | if (last && now < last + threshhold) {
53 | // hold on to it
54 | clearTimeout(deferTimer);
55 | deferTimer = setTimeout(function() {
56 | last = now;
57 | fn.apply(context, args);
58 | }, threshhold);
59 | } else {
60 | last = now;
61 | fn.apply(context, args);
62 | }
63 | };
64 | };
65 | window.onscroll = throttle(
66 | function() {
67 | if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
68 | this.handleShowMore();
69 | }
70 | },
71 | 150,
72 | this
73 | );
74 | }
75 |
76 | handleShowMore = () => {
77 | const sliceBegin = this.state.visibleTeams.length;
78 | const sliceEnd = sliceBegin + this.props.threshold;
79 | const newTeams = this.state.allTeams.slice(sliceBegin, sliceEnd);
80 | this.setState({
81 | visibleTeams: this.state.visibleTeams.concat(newTeams)
82 | });
83 | };
84 |
85 | // User input filters
86 | handleUserInput = activeFilters => {
87 | const filteredTeams = this.getFilteredTeams(activeFilters);
88 | this.setState({
89 | activeFilters: activeFilters,
90 | visibleTeams: filteredTeams.slice(0, this.props.threshold),
91 | allTeams: filteredTeams
92 | });
93 | };
94 |
95 | // Return an array of teams (filtered if relevant)
96 | getFilteredTeams = activeFilters => {
97 | const { teams } = this.props;
98 | return teams.filter(team => {
99 | if (activeFilters.league !== "") {
100 | if (activeFilters.league !== team.league) {
101 | return false;
102 | }
103 | }
104 |
105 | if (activeFilters.color !== "") {
106 | if (!(activeFilters.color in team.colors)) {
107 | return false;
108 | }
109 | }
110 |
111 | // @TODO possibly fix to fit array of multiple, not single, items
112 | if (activeFilters.search !== "") {
113 | if (fuzzy.filter(activeFilters.search, [team.name]).length === 0) {
114 | return false;
115 | }
116 | }
117 |
118 | return true;
119 | });
120 | };
121 |
122 | render() {
123 | const { activeFilters, allTeams, visibleTeams } = this.state;
124 |
125 | const { leagues, colors, colorsByLeague } = this.props;
126 |
127 | return (
128 |