{"id":47625345,"url":"https://github.com/goinvo/goinvo.com","last_synced_at":"2026-04-01T22:45:13.660Z","repository":{"id":37587726,"uuid":"146022257","full_name":"goinvo/goinvo.com","owner":"goinvo","description":"A static site for goinvo.com using GastbyJS","archived":false,"fork":false,"pushed_at":"2026-03-26T15:30:25.000Z","size":63326,"stargazers_count":4,"open_issues_count":75,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-03-27T05:52:39.431Z","etag":null,"topics":["boston","design","designers","healthcare","open-source","studio","user-experience","user-interface","ux","ux-agency","ux-company"],"latest_commit_sha":null,"homepage":"https://www.goinvo.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goinvo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-08-24T17:43:56.000Z","updated_at":"2026-03-26T15:36:23.000Z","dependencies_parsed_at":"2024-01-01T23:21:18.846Z","dependency_job_id":"68c72b9d-54dd-4ea8-a3af-e504e6099740","html_url":"https://github.com/goinvo/goinvo.com","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/goinvo/goinvo.com","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goinvo%2Fgoinvo.com","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goinvo%2Fgoinvo.com/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goinvo%2Fgoinvo.com/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goinvo%2Fgoinvo.com/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goinvo","download_url":"https://codeload.github.com/goinvo/goinvo.com/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goinvo%2Fgoinvo.com/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292695,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boston","design","designers","healthcare","open-source","studio","user-experience","user-interface","ux","ux-agency","ux-company"],"created_at":"2026-04-01T22:45:12.674Z","updated_at":"2026-04-01T22:45:13.641Z","avatar_url":"https://github.com/goinvo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# goinvo.com-2018\n\nA static site for goinvo.com built using [GatsbyJS](https://www.gatsbyjs.org/).\n\n## Getting started\n\n_NOTE:_ To work in this project, it is assumed you have basic familiarity with using the command line and Git/GitHub. If you are not comfortable with these tools, please reach out to a coworker for some help.\n\n_MORE NOTE:_ When copy/pasting the examples, do not include the `$`. This is used to represent your command line prompt, showing individual commands on new lines.\n\n_MANY NOTE:_ You may be required to install additional dependencies like XCode command line tools on Mac.\n\n### Install Brew\n\n[Homebrew](https://brew.sh/) is an easy way to install the system packages you'll need for this project on Mac. (Don't copy the $ :))\n\n```bash\n$ /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"\n```\nBefore you can use the brew command, you may have to add it to your path. If you are using a MacBook with an M1 or M2 chipset, try\n\n```bash\n$ echo 'eval \"$(/opt/homebrew/bin/brew shellenv)\"' \u003e\u003e ~/.bash_profile\"\n```\n\n### Install Node\n\nThis project uses [NodeJS](https://nodejs.org/en/) at its core.\n\n```bash\n$ brew update\n$ brew install node\n```\n\n### NVM\n\nYou may also find it helpful to use a tool to manage your Node installations. [nvm](https://github.com/creationix/nvm) is a good one. Follow the instructions there to install nvm. The command that looks like `curl -o- \u003curl\u003e | bash`\n\nAlternatively, brew can install nvm with `$ brew install nvm`\n\nThen you can check your Node versions with:\n\n```bash\n$ nvm ls\n```\n\nOpen a new terminal, and install the Node version the project wants by running:\n\n```\n$ nvm use\n```\n\nCheck for warnings or errors. If you don't have the right version installed, it will give you a command to run, such as:\n\n```\n$ nvm install lts/*\n```\n\n### Install Yarn\n\nNode comes with a package manager, [NPM](https://www.npmjs.com/), by default. However, this project chooses to use [Yarn](https://yarnpkg.com/en/) instead, namely because it's faster and more secure.\n\n```bash\n$ brew install yarn\n```\n\n### Clone repository\n\nUse the command line or your GitHub app to clone this project repository to your machine. When using the command line, make sure you're already in the folder you want the project downloaded to.\n\n```bash\n$ git clone https://github.com/goinvo/goinvo.com.git\n```\n\n### Install project dependencies\n\n```bash\n$ cd goinvo.com\n$ yarn\n```\n\n### Start it up\n\n```bash\n$ yarn develop\n```\n\nGive it a few seconds and you should see:\n\n```bash\nYou can now view goinvo.com in the browser.\n\nhttp://localhost:8000/\n```\n\nHead over to [http://localhost:8000/](http://localhost:8000/) and you should see the website.\n\n### Code editor\n\nThere are many editors to choose from, but most of the time you won't need elaborate features for testing or debugging with this project. The main things you'll use are syntax highlighting and some maybe some additional packages to help with code completion and formatting. Some editors to consider if you don't already have a preferred favorite:\n\n- [Atom](https://atom.io/)\n- [Sublime Text](https://www.sublimetext.com/)\n- [VSCode](https://code.visualstudio.com/)\n\n### Styling guidelines\n\nA thorough examination of best practices, tips, and resources related to coding at GoInvo can be found in our [Styling Guidelines](https://playbook.goinvo.com/styling-guidelines/).\n\n### Code formatting\n\nThis project uses [prettier](https://github.com/prettier/prettier) to format code. This formatting will be triggered automatically on any staged files when you make a commit, so don't be surprised if your code changes slightly. You can also manually run `yarn format` to run code formatting across the project.\n\nYou may also wish to make things easier by installing and using [EditorConfig](https://editorconfig.org/), which will apply many of the same rules from prettier directly in your code editor. This helps keep things like indentation in check as you code. If you use [Atom](https://atom.io/), there is an [Atom EditorConfig package](https://atom.io/packages/editorconfig) available.\n\n## Troubleshooting\n\n### Webpack chunk loading errors\n\nIf you encounter an error like \"Loading chunk component---src-pages-index-js failed\" or similar webpack chunk loading errors, this is usually caused by corrupted build cache. This is a common issue that can occur after making changes to dependencies or file structures.\n\nTo fix this issue:\n\n1. Stop the development server (Ctrl+C or Cmd+C)\n2. Clear the Gatsby cache:\n   ```bash\n   $ yarn clean\n   ```\n   or\n   ```bash\n   $ npm run clean\n   ```\n3. Restart the development server:\n   ```bash\n   $ yarn develop\n   ```\n\nThis will delete the `.cache` and `public` directories and rebuild everything from scratch. The page should then load without chunk loading errors.\n\nIf the issue persists after clearing the cache, you can also try:\n- Clearing your browser cache and doing a hard refresh (Ctrl+Shift+R or Cmd+Shift+R)\n- Deleting `node_modules` and running `yarn install` again\n- Checking for any syntax errors in recently modified files\n\n## Working with images\n\n**Do not add or commit images directly to this project!**\n\nContent images are managed with Dropbox and should not be added here. But now that that's clear, there _are_ a few exceptions. The only images found in this project are small images like icons and logos, many of which can often be included inline or as data URI's. When in doubt about where you should add an image, always ask for guidance!\n\n### Preparing your images\n\n**TODO:** Sharon to add details on picking proper images for the site.\n\nExport your image (Photoshop example steps):\n\n- Ensure the image is 2000px wide.\n- Select 'File' \u003e 'Save As'.\n- Name the image appropriately using all lowercase letters, numbers, and dashes (that means don't use uppercase or underscores, etc).\n- Use the 'JPEG' format (or 'PNG' if alpha channels are required), and click 'Save'.\n- Set the Quality to Maximum (12), or slightly lower if the file size will be too large. We aim for a file size around 1.2M or below, but this can be higher for more complex images. Use your best judgment here, but avoid massive file sizes.\n- Use 'Progressive' Format option with 3 scans.\n- Click 'OK' and your image will be saved.\n\n### Adding images through Dropbox\n\nAll the beautiful images you see throughout this site of our work, products, studio, and studioites are managed on our Dropbox account. Naturally you'll need access to our Dropbox account to work with these. Images for the website are stored in the `Graphics/goinvo.com/` folder.\n\nWhen adding an image, think about where it best belongs. The folders on Dropbox generally correspond with routes on the website. For instance, all photos for the 'About' page are in `Graphics/goinvo.com/images/about/`. In some cases, your image may be used in multiple spots throughout the site, but aim to place it where it feels most proper. For instance, if you have a hero image for the 'Vision' page, but it's also used in a card on the homepage, place it in the `vision/` folder. Do not add the same image file in two different locations, this is unnecessary and creates a slower loading experience for our visitors. When creating new folders, use the same naming conventions as we use for images (lowercase letters, numbers, and dashes only).\n\n**IMPORTANT:** You should not replace or remove images on Dropbox, and they cannot be replaced on S3 (it is possible to remove/replace on S3 but you must have [_the power_](https://metaphysicsspeaks.com/wp-content/uploads/2017/06/10265-powerglove.jpg)). If you want to change an image somewhere on the site, simply name the file something new (i.e. rather than trying to replace an image called `eric-beard.jpg`, instead add a new image in the same folder called `eric-beard-2.jpg`, or whatever. Keep in mind that you'll now have to update any reference of `eric-beard.jpg` in the codebase to `eric-beard-2.jpg`).\n\n_Again, remember that folders and file names should have no spaces or funky characters. Just stick with lowercase letters, numbers, and dashes. Use dashes where you might normally use a space._\n\nAfter moving your image(s) to Dropbox, you'll need to sync with S3. To do this, you need an Invo AWS account. If you don't have one, and you really want one, just say [\"Nickelodeon Magazine, PLEASE!\"](https://www.youtube.com/watch?v=Oel0zjpKCwE). You can also get a coworker who already has AWS access to help you sync the images.\n\n### Syncing images and videos from Dropbox to S3\n\nTo sync to S3, you'll need to add your AWS credentials to `~/.aws/credentials`. You can follow the instructions for that [here](https://aws.amazon.com/sdk-for-node-js/)].\n\nOnce those are in place, open up your command line and navigate to your `Graphics/goinvo.com` Dropbox folder, then run:\n\n```bash\n$ yarn upload\n```\n\nThat's it! You should see lots of messages like `Already exists: \u003cfile\u003e`. Make sure your files were uploaded by scanning for the message `Successfully uploaded: \u003cyour-file\u003e`. If so, your images are ready to use on the site. Note that the upload will fail if any of your images are not exported at exactly 2000px wide.\n\n### Using images\n\nIf you're looking to use an image in a case study, please skip to the next section. Otherwise...\n\nThe project has an `\u003cImage /\u003e` component which takes care of most of the image rendering process for you. Simply include the component with the path to your image (which corresponds to the Dropbox path) like so:\n\n```js\n\u003cImage src=\"/images/about/bowling.jpg\" /\u003e\n```\n\nBy default, the image assumes it will always render at the full width of the screen. You can make better use of the responsive image technique by passing in some sizes, of which there are some presets in the config file:\n\n```js\nimport config from '../../config'\n\n...\n\n\u003cImage src=\"/images/about/bowling.jpg\" sizes={config.sizes.fullToHalfAtLargeInsideMaxWidth} /\u003e\n```\n\nOr with custom sizes:\n\n```js\n\u003cImage\n  src=\"/images/about/bowling.jpg\"\n  sizes={['(min-width: 20em) 100px', '100vw']}\n/\u003e\n```\n\nLearn more about the `sizes` attribute in a [nice article](https://ericportis.com/posts/2014/srcset-sizes/) from Eric Portis.\n\n### Using images in case studies (Markdown)\n\nTo add images to your case study content, simply use the default markdown syntax. Use the path that corresponds with the directory structure in Dropbox. Be sure to include that meaningful [`alt text`](https://www.w3schools.com/tags/att_img_alt.asp)!\n\n```md\n![Invo employees happily pose as a group in a bowling alley](/images/about/bowling.jpg)\n```\n\n### Using icons, logos, and other small image files\n\nSometimes, images are so small in file size, or in a format we don't need to process with the image service (like SVG), that we can include them directly in the project. Images less than 10kb will be rendered with data URIs by Gatsby, which is beneficial because it removes the request the browser would have to make to fetch the image. So in general, if the image is less than 10kb, or an SVG file, it can be included in the project directly. If uncertain if an image meets these criteria, ask for guidance. Be confident your image should be housed in the project before committing it in git. These types of images can be added at an appropriate location inside `src/assets/images/`. In general, following our [styling guidelines](https://playbook.goinvo.com/styling-guidelines/), image file names in the project are prefixed by their type or purpose, like `icon-email.svg` or `logo-npr.png`.\n\nSince these images will not run through the image service, we can use regular `img` tags to include them (instead of the `\u003cImage /\u003e` React component). To use an image from the project, you can import it in your JavaScript file then use it as the `img` source:\n\n```js\nimport logoNpr from '../assets/images/publication-logos/logo-npr.png'\n\n...\n\n\u003cimg src={logoNpr} alt=\"Logo for National Public Radio\" /\u003e\n```\n\nSVG's can be used in a similar manner to above, but also can be included inline using a special syntax. This is similar to using SVG's from a sprite sheet in that it allows for adding classes and control of the SVG through CSS. The key here is to add `.inline` to your filename before `.svg`, like `icon-hamburger.inline.svg`. Then capitalize your import variable name, as you would with importing a JavaScript class or component, like so:\n\n```js\nimport Hamburger from '../assets/images/icon-hamburger.inline.svg'\n\n...\n\n\u003cHamburger className=\"icon icon-hamburger\" /\u003e\n```\n\nNow we can use CSS to style `icon` and `icon-hamburger`, like controlling the size or `fill` color of the icon, etc.\n\n## Image Optimization\n\nThis project uses a unified, optimized image system to improve performance and user experience. All image rendering is handled through a single `\u003cImage /\u003e` component that automatically provides the best optimization strategy.\n\n### The Unified Image Component\n\nThe project provides a single, intuitive image component in `src/components/image.js`:\n\n#### Basic Usage\n```js\nimport Image from '../components/image'\n\n// Standard lazy-loaded image (default)\n\u003cImage\n  src=\"/images/about/team-photo.jpg\"\n  alt=\"Team photo\"\n  className=\"image--max-width\"\n  sizes={config.sizes.fullToHalfAtLargeInsideMaxWidth}\n/\u003e\n\n// Above-the-fold image with high priority loading\n\u003cImage\n  src=\"/images/homepage/hero-image.jpg\"\n  alt=\"Hero image\"\n  className=\"image--max-width\"\n  aboveTheFold={true}\n/\u003e\n```\n\n#### Image Component Props\n\n- **`src`** (required): Path to the image\n- **`alt`** (required): Descriptive alt text for accessibility\n- **`aboveTheFold`** (optional): Set to `true` for images that should load immediately (default: `false`)\n- **`className`** (optional): CSS classes to apply\n- **`sizes`** (optional): Responsive image sizes configuration\n- **`externalImage`** (optional): Set to `true` for external URLs\n- **`placeholder`** (optional): Enable loading placeholder (default: `true`)\n- **`placeholderColor`** (optional): Placeholder color (default: `#f0f0f0`)\n\n### Automatic Smart Behavior\n\nThe unified component automatically:\n\n- **Detects image type**: Local vs external, SVG vs raster images\n- **Chooses optimal loading**: Eager loading for critical images, lazy loading otherwise\n- **Generates responsive images**: Creates multiple sizes with appropriate srcsets\n- **Provides loading placeholders**: Shows dominant color or custom placeholder while loading\n- **Uses configuration**: Pulls responsive breakpoints and dimensions from `config.js`\n\n### Performance Benefits\n\nThe optimized image system provides:\n\n- **Dominant color placeholders** for instant visual feedback\n- **Lazy loading** for better initial page load performance\n- **Proper priority handling** (critical vs lazy loading)\n- **Responsive image sizing** with automatic srcset generation\n- **Better LCP (Largest Contentful Paint)** scores\n- **Automatic format optimization** (WebP, AVIF when supported)\n\n### Usage Guidelines\n\n**For above-the-fold images** (hero images, critical content):\n```js\n\u003cImage \n  src=\"/images/homepage/hero.jpg\" \n  alt=\"Hero image\" \n  aboveTheFold={true} \n/\u003e\n```\n\n**For below-the-fold images** (content images, galleries):\n```js\n\u003cImage \n  src=\"/images/content/gallery.jpg\" \n  alt=\"Gallery image\" \n/\u003e\n```\n\n**For external images**:\n```js\n\u003cImage \n  src=\"https://example.com/image.jpg\" \n  alt=\"External image\"\n  externalImage={true}\n/\u003e\n```\n\n### Configuration\n\nImage dimensions and responsive breakpoints are configured in `config.js`:\n\n```js\n// config.js\nimageDimensions: [600, 900, 1200, 1500, 2000], // Responsive image sizes\nsizes: {\n  full: ['100vw'],\n  fullToHalfAtLarge: [`(min-width: ${mediaQueries.lg}) 50vw`, '100vw'],\n  // ... other responsive configurations\n}\n```\n\n### Using videos\n\nVideos are also managed through Dropbox and work similarly to images. The project makes use of a `\u003cVideo /\u003e` component. However, videos have a few extra requirements that images do not. First, videos need _two_ sources, one as `.mp4` filetype and one as `.webm` filetype. This is to make sure there is a video format that supports every browser's needs. Check the syntax below for how to include these formats in JavaScript. Also, videos should have a poster image (displayed before video plays, while the video is loading), and a fallback image (used if the video element is not supported by the browser). Use the component with the sources of your video (which corresponds to the Dropbox path), the poster image, and the fallback image, like so:\n\n```js\nimport Video from '../components/video'\n\nconst heroVideoSources = [\n  {src: \"/videos/homepage/sdoh-hero.mp4\", format: \"mp4\"},\n  {src: \"/videos/homepage/sdoh-hero.webm\", format: \"webm\"}\n]\n\n...\n\n\u003cVideo sources={heroVideoSources} poster=\"/images/homepage/doh-hero-poster.jpg\" fallback=\"/images/homepage/doh-hero-fallback.jpg\" /\u003e\n```\n\n## Adding a case study\n\nFirst and foremost, remember to make a new branch in Git. It is reasonable to name it something like `case-study-\u003cname\u003e`.\n\n### Make a new file\n\nOnce you're set up on a new branch, make a new Markdown file in the `src/case-studies` folder. Name the file with all lower-case letters and hyphens, with the `.md` extension. The convention is to list the client name then project name (e.g. `mitre-shr.md`, `fastercures-health-data-basics.md`). It's fine if the name is a bit long, but also probably best to not go crazy on it. Some clients have sensible abbreviations, like `jnj` for Johnson and Johnson. Invo projects can omit the client name portion of the file (e.g. `paintrackr.md`, `hgraph.md`).\n\n### Add the frontmatter\n\nInside the file, the first thing to do is add the frontmatter at the very top of the file. This is meta data associated with the case study, used throughout the rest of the website. It must be at the top and include the `---` syntax, as shown below:\n\n```md\n---\ntitle: 'Health Data Basics'\nimage: '/images/case-studies/fastercures/health-data-basics/hero.jpg'\nclient: 'FasterCures'\ncaption: 'Engaging patients to understand health.'\ncategories:\n  - 'public-health-and-policy'\n  - 'open-source'\nresults:\n  - stat: '97%'\n    description: 'Recall of educational concepts'\n  - stat: '90%'\n    description: 'Engagement with knowledge retention quiz'\n  - stat: '8,760'\n    description: 'Yearly views of new health data definition'\nupNext:\n  - 'code-ryte'\n  - 'acme'\n  - 'mitre-shr'\nhidden: false\n---\n```\n\nYou can also look at other existing case studies as examples.\n\nLet's break down the fields:\n\n1. `title` (required)\n   This is the title that will be shown on cards throughout the _rest_ of the site, not necessarily the title shown on the case study page (you'll make than with an h1 or `#` in Markdown).\n2. `image` (required)\n   The path to the image on Dropbox to be used as the hero and the card image on other pages.\n3. `client` (required)\n   The client we worked with on the project. For Invo projects you can use an empty string (`\"\"`).\n4. `caption` (required)\n   A one-liner describing the project.\n5. `categories` (required)\n   A YAML array of ID's for the categories (or 'tags') associated with the project. These must be selected from a predefined list, located in `src/data/categories.json`. The exact ID string must be used or it won't work. See the example above.\n6. `results`\n   A YAML array of objects including a `stat` and `description` for that stat. See the example above. Currently, the results only support text. In the future we'll work to add an option for including buttons/links.\n7. `upNext` (required)\n   A YAML array of ID's associated with other case studies to link to at the bottom of the page. The ID is simply the filename of the case study you'd like to link to without the extension. See the example above.\n8. `hidden`\n   Controls whether the case study should show up as a page and be included in lists of case studies throughout the site. Set to `true` if this case study is a work in progress. Keep in mind that even though it will be hidden from the site, this content is still publicly accessible on GitHub, so never include any content that we don't have client approval on.\n9. `metaDescription` (not required, but you should really include this)\n   A concise summary of the case study, usually only a sentence or two long, used for search engines and link details. For more information, read [how to create the right meta description](https://yoast.com/meta-descriptions/).\n\n_NOTE:_ If you don't include required frontmatter fields, the app may crash.\n\n### Viewing your case study as you author content\n\nWhen you add a new markdown file, it is necessary to restart your development server. Use `ctrl + c` to kill your process then start it up again with `yarn develop`. This will add your new markdown file in the list of case studies. The case study you're working on will become accessible through the 'Work' page, or at `http://localhost:8000/work/\u003cfilename\u003e` (filename without `.md` file extension).\n\n### Add the content\n\nFor the most part, just write plain old Markdown. If you're unfamiliar with Markdown, it's a very basic programming language, designed to make writing content a breeze. Read up on the syntax [here](https://daringfireball.net/projects/markdown/syntax).\n\nEach page should have exactly one `h1` title, written with markdown using `#` (e.g. `# This is the title`). Subsequent sections can get `h2` (`##`), `h3` (`###`), and so on.\n\n### Using React components inside the Markdown\n\nAll Markdown pages in this project make use of a wonderful plugin for Gatsby called [gatsby-mdx](https://github.com/ChristopherBiscardi/gatsby-mdx). This allows us to use React components inside our Markdown, inserting more complicated markup and code where we otherwise wouldn't be able to insert it. Though you can use virtually any component in the markdown, the ones used most frequently in case studies are `Divider`s and `Quote`s. To use these, you need to import them near the top of the file, underneath the frontmatter section:\n\n```js\n---\n... frontmatter stuff\n---\n\nimport Divider from 'components/divider'\nimport Quote from 'components/quote'\n```\n\nThen use them anywhere you like in your content:\n\n```md\nHere is some markdown paragraph content.\n\n\u003cDivider /\u003e\n\n## Hey a new section!\n\nWith some more content. And I sense a quote coming...\n\n\u003cQuote quotee=\"Merkin Muffley\" quoteeSub=\"President of the United States\"\u003e\nGentlemen, you can't fight in here. This is the war room.\n\u003c/Quote\u003e\n\nWow I was right. A quote.\n```\n\n### Wrapping up\n\nMake commits to your branch adding content to your case study as you go, and make sure to push your branch to the GitHub repo. Add your new case study to the `case-study-order` file, adding it to the appropriate order for each category. When finished, seek assistance getting your case study code reviewed and merged into the production website. \n\n## Adding a simple feature\n\nFirst and foremost, remember to make a new branch in Git. It is reasonable to name it something like `feature-\u003cname\u003e`. This section is mainly for adding simple features that follow the same general layout and styles as the rest of the GoInvo website.\n\n### Make a new file\n\nAs stated above, to review changes as you make them, just open a terminal and run `yarn develop`. Then you can view your work live at http://localhost:8000/\n\nOnce in your new branch, create your feature directory in `src/pages/vision/your-feature-url`. Create a new file in this folder called `index.js` and get started.\n\nAs you go, you may make several commits to your branch and push them up to Github. If you want to share your feature with folks to review before going live, you may locate your branch in the list of branches, and create a new pull request. If you're not ready to go live yet, you can add a tag for `don't merge yet` and that'll indicate to reviewers not to approve and merge just yet. After automatic checks have passed, a netlify url will be generated for your branch and you can use this to check that your feature works and looks how it should, and it can be shared to others to review your work before it goes live. After that, you can continue to work and push as normal. When you're ready to go live, just remove the `don't merge yet` tag and let a reviewer know that you're ready for their review.\n\n### Add the frontmatter\n\n```\nimport React, { Component } from 'react'\n\nimport Layout from '../../../components/layouts/layout'\nimport Hero from '../../../components/hero'\nimport Image from '../../../components/image'\nimport Divider from '../../../components/divider'\nimport References from '../../../components/references'\nimport Author from '../../../components/author'\nimport { mediaUrl } from '../../../helpers'\n\nimport config from '../../../../config'\n\nconst frontmatter = {\n  metaTitle: 'Your Feature Title',\n  metaDescription:\n    'Brief feature description.',\n  heroImage: '/images/features/your-feature-url/your-feature-hero.jpg',\n}\n```\n\nYou can also look at other existing features as examples.\n\nLet's break down the fields:\n\n1. `React` (required)\n   Allows React to work its magic.\n2. `Layout` (required)\n   More magic here. Layout magic.\n3. `Hero` (required)\n   Displays the hero standard to the rest of the GoInvo site.\n4. `Image`\n   Any good feature has an image. We'll go over how to add images below.\n5. `Divider`\n   If you want to use the `\u003cDivider /\u003e` graphic consistent with the rest of the GoInvo site.\n6. `References`\n   Any good feature also has references. We'll go over how to add images below.\n7. `Author`\n   A nifty component for easily adding team members as authors to the feature!\n8. `mediaURL`\n   Handles access to media items. For example, if we have a poster we want readers to be able to download, we store those in a media folder (covered below) and set up a download link or button.\n9. `config`\n   Needed when you have images. This helps with resizing images for different browser widths or mobile views.\n10. `metaTitle`\n    This is the title of your feature. You want to make this somewhat short, ideally \u003c30 characters. Should match the title feature in `features.json` (We'll cover this in a bit too)\n11. `metaDescription`\n    A brief description about your feature. With the title, date, and tags, this should fit comfortably in a small card on the Vision page. Should match the description in `features.json`\n12. `heroImage`\n    Link to the hero image for your feature. We'll cover adding this with images.\n\n### Starting the feature\n\n```\nclass YourFeatureName extends Component {\n  render() {\n    return (\n      \u003cLayout frontmatter={frontmatter}\u003e\n        \u003cHero image={frontmatter.heroImage} /\u003e\n        \u003cdiv className=\"{your-feature-name}\"\u003e\n          \u003cdiv className=\"pad-vertical--double\"\u003e\n            \u003cdiv className=\"max-width max-width--md content-padding\"\u003e\n\n            // start coding your feature\n\n            \u003c/div\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/Layout\u003e\n    )\n  }\n}\n\nexport default YourFeatureName\n```\n\n1. `Hero` (required)\n   Grabs the URL we defined in the frontmatter to display the Hero based on the Layout component\n2. `your-feature-name` (required)\n   Lets you create styles specifically for this feature without overwriting styles elsewhere on the GoInvo site or in other features.\n3. `pad-vertical--double` and `max-width max-width--md content-padding`\n   Anything inside of these divs will be constrained to the max width of content consistent with the rest of the site. If you want to set a style or image to bleed all the way to the edge, you'll want to close this and place it outside.\n4. `export` (required)\n   Actually exports your feature, should match the feature name in `class YourFeatureName extends Component`\n\nWriting up a feature is a little different from a case study, because instead of markdown, we're using straight-up html.\n\n### Basic Styling\n\nIn general, unless your feature needs specific styling, most of the website styles and utility classes should work for your feature. If you need specific styling, in `src/styles/vision`, add a new file `_your-feature-name.scss`. At the bottom of the `main.scss` add this stylesheet as `@import 'vision/your-feature-name';`. Start off the styles in your .scss file with `.your-feature-name { }`, consistent with the className you used at the beginning of your feature html, and add your feature's specific styles inside of the brackets.\n\nWe use classes to impart header styles defined in the GoInvo style guide. The typical breakdown is as follows:\n\n1. `h1 className=\"header--xl\"`\n   Adobe Jenson Pro, font-size: 2.25rem;\n2. `h2 className=\"header--lg\"`\n   Adobe Jenson Pro, font-size: 1.5rem;\n3. `h3 className=\"header-md\"`\n   Open Sans, font-size: 15px;, font-weight: 600;, text-transform: uppercase;,\n4. `h4 className=\"header-sm\"`\n   Open Sans, font-size: 16px;, font-weight: 600;\n\nTry to use one `\u003ch1\u003e` at the beginning of your feature to showcase the title. For following titles that you want to appear the same size, you can use an `\u003ch2\u003e` with the `header-xl` class. To center text, add `text--center`.\n\nTry to use `header-md` only for categories. For descriptive titles, use `header-sm`.\n\nAdding buttons is as straightforward as adding a `button` and `button-primary` classes to a link, but there's a `button-group` class to contain multiple buttons at once or centers a single button.\n\n```\n\u003cdiv className=\"button-group\"\u003e\n  \u003ca\n    href={mediaUrl(\n      '/pdf/vision/your-feature-url/your-feature.pdf'\n    )}\n    className=\"button button--secondary margin-top--double margin-bottom--double\"\n  \u003e\n    Download\n  \u003c/a\u003e\n\u003c/div\u003e\n```\n\n### Adding images\n\nPretty much the same as adding images for case studies. We'll just restate some of the basics. When exporting your images, you want them to be 2000px wide, progressive jpg, and ideally 72dpi (more px per inch will increase the filesize). Save them into our dropbox folder at `Graphics/goinvo.com/images/features/your-feature-url/[your-feature-image.jpg` using lowercase and dash separation. Add your hero image here too.\n\nYou'll need AWS permissions to do this, so if you don't have what you need, check with Craig, Eric, or Jen. To upload your images, open a terminal in the goinvo.com dropbox folder and run\n\n```\n$ yarn upload\n```\n\nWhen adding the image to your feature, it will look like this:\n\n```\n\u003cImage\n  src=\"/images/features/your-feature-url/your-feature-poster.jpg\"\n  className=\"image--max-width\"\n  sizes={config.sizes.fullInsideMediumMaxWidth}\n/\u003e\n```\n\nCaptioning your image is simple, with\n\n```\n\u003cp className=\"text--caption\"\u003eCaption away\u003c/p\u003e\n```\n\n### Adding links\n\nWhen linking away from the site, we generally want to open up a new tab to not disturb the reader's current position, so add `target=\"_blank\"`. When linking externally, or whenever using `target=\"_blank\"`, add `rel=\"noopener noreferrer\"`.\n\n```\n\u003ca\n  href=\"https://github.com/goinvo/HealthDeterminants/\"\n  target=\"_blank\"\n  rel=\"noopener noreferrer\"\n\u003e\n  GitHub\n\u003c/a\u003e\n```\n\n### Adding media\n\nSo far, media has included pdf downloads of posters or reports associated with the feature. Unlike when adding images, these are not relegated to 2000px width and jpg format. Instead, these would typically be printable pdf quality. You would save these out similarly to Dropbox, in `Graphics/goinvo.com/pdf/your-feature-url/your-feature-file.pdf`. These get uploaded with the `yarn upload` command as well.\n\nWhen adding a link to the media in your feature, use the following:\n\n```\n\u003ca href={mediaUrl(\n      '/pdf/vision/your-feature-url/your-feature-preview.pdf'\n    )}\n   target=\"_blank\"\n   rel=\"noopener noreferrer\"\n\u003eDownload\u003c/a\u003e\n```\n\n### Adding Authors\n\nThanks to the 'Authors' component we added earlier, adding authors is easier than ever. For active team members, all you need is their name to access their photo and bio. Optionally, you can include company and name on an author card.\n\n```\n\u003ch3 className=\"header--md\"\u003eAuthors\u003c/h3\u003e\n\u003cAuthor name=\"Jen Patel\" /\u003e\n\u003cAuthor name=\"Juhan Sonin\" company=\"GoInvo, MIT\" /\u003e\n```\n\nFor external contributors or authors, since we don't keep a photo and bio on hand for them, we have to write out the author card, which looks like this:\n\n```\n\u003cAuthor\n  name=\"Vanessa Li\"\n  company=\"University of Washington\"\n  image=\"/images/features/your-feature/headshot-vanessa-li.jpg\"\n\u003e\n  Vanessa specializes in health systems and public health\n  modeling, with an emphasis in substance abuse and disease\n  prevention research. She graduated from the University of\n  Southern California with a B.S. in Public Policy and a double\n  minor in Business Economics and Global Health. Vanessa is\n  working towards a graduate degree in biostatistics at the\n  University of Washington.\n\u003c/Author\u003e\n```\n\n### Adding references\n\nTo add linkable references in your text that, when clicked, will scroll down to the references section.\n\n```\n\u003csup\u003e\n  \u003ca href=\"#references\"\u003e8,18\u003c/a\u003e\n\u003c/sup\u003e\n```\n\nYou would list your references at the bottom of your feature, just after the Authors section, and preferably with a `\u003cDivider /\u003e` separating the two. When rendered, references will be listed in an ordered list format. For links, you need only add the url, such as https://github.com and the references component will take care of the rest. It is also helpful and good citation practice to indicate when the reference was last accessed during research for the feature.\n\n```\n\u003cDivider /\u003e\n\n\u003cdiv id=\"references\"\u003e\n  \u003cReferences\n    references={[\n      {\n        title: '[citation]',\n        link: '[url if there is one]'\n      },\n      {\n        title: '[citation]'\n      }\n    ]}\n  /\u003e\n\u003c/div\u003e\n\n```\n\n### Adding your feature to the vision page\n\nOpen up `src/data/features.json` and add your feature to the top as the following. Your title doesn't necessarily have to match the url, but they should be similar enough for readers to find it on the world wide web.\n\n```\n{\n  \"id\": \"your-feature-url\",\n  \"title\": \"Your Feature Title\",\n  \"date\": \"Feb.2019\",\n  \"client\": \"Feature\",\n  \"categories\": [\"open-source\", \"public-health-and-policy\"],\n  \"caption\": \"Brief feature description.\",\n  \"image\": \"/images/features/your-feature-url/your-feature-hero-2.jpg\",\n  \"link\": \"/vision/your-feature-url/\"\n},\n```\n\nIf your feature will be shown on the work page, also add your new case study to the `case-study-order` file, adding it to the appropriate order for each category\n\n### Adding team members\n\nWhen a new teammate starts, we ask them for a bio and photo. Once we have an approved bio and photo, we're ready to get them on the website.\n\nOriginal photos should be uploaded resources \u003e photos-people \u003e Headshots \u003e [name]\nPhotos for the team page should be resized to 2000px width, saved as optimized jpg, and uploaded to Dropbox: Graphics \u003e goinvo.com \u003e images \u003e about\nSomeone with AWS credentials (Craig, Eric, or Jen) should run yarn upload and the image should be ready to use.\n\nIn the data/team.json file, add a team member using the following:\n{\n\t\"name\": \" \",\n\t\"title\": \" \",\n\t\"bio\": \" \",\n\t\"social\": {\n  \t\"email\": \"name@goinvo.com\",\n  \t\"twitter\": \" \",\n  \t\"linkedin\": \" \"\n\t},\n\t\"image\": \"/images/about/headshot-first-lastname.jpg\"\n  }\n\n\n### Going live\n\nWhen your feature is ready to go live, make sure to push up any final changes to the branch. Then, on Github, you may locate your branch in the list of branches, and create a new pull request and let a reviewer know that you're ready for their review. Once approved, the final reviewer will merge it into master.\n\nOnce approved changes are merged into master, then do the following in terminal to go live.\n`yarn build`  \n`yarn upload`\n\n## 🔍 Semantic Search System\n\nThis website features an intelligent semantic search system that helps potential clients find relevant projects using natural language queries. The system uses enhanced keyword matching and semantic understanding to surface the most relevant existing projects for any buyer query.\n\n### How It Works\n\n1. **AI-Powered Analysis**: Each project is analyzed by GPT-3.5-turbo to extract metadata and generate buyer-focused descriptions\n2. **Semantic Embeddings**: OpenAI's text-embedding-3-small model creates vector representations of project content\n3. **Enhanced Keyword Matching**: 100+ semantic keyword mappings and domain-specific boosting algorithms\n4. **Client-Side Search**: Search runs entirely in the browser using intelligent keyword matching and concept mapping\n5. **Smart Caching**: Only changed content gets reprocessed, saving time and API costs\n\n### Search Features\n\n- **Natural Language Queries**: \"I need a UI for an AI platform for therapists\"\n- **Intelligent Keyword Expansion**: Automatically maps related terms (e.g., \"telemetry\" → \"monitoring\", \"vital signs\")\n- **Buyer-Focused Descriptions**: AI explains why each project is relevant to your specific needs\n- **Smart Filtering**: Filter by project type, industry, and complexity\n- **Real-Time Results**: Instant search with similarity scoring\n- **Domain-Specific Boosting**: Healthcare, enterprise, and government queries get specialized matching\n\n### Content Sources\n\n#### Case Studies (`src/case-studies/*.mdx`)\nDetailed completed projects with full descriptions, client information, and portfolio images.\n\n#### Features (`src/data/features.json`)\nPortfolio highlights and quick project overviews used throughout the site.\n\n### Enhanced Keyword Understanding\n\nThe search system recognizes and expands hundreds of related terms:\n\n- **Healthcare**: telemetry, oncology, therapy, hematology, radiology, FHIR, HIPAA\n- **Enterprise**: analytics, dashboards, IoT, fintech, logistics, SOC-2\n- **Government**: civic, municipal, permits, emergency, elections, FedRAMP\n- **Technology**: AI, platforms, systems, compliance, real-time\n\n## 🚀 Setup Instructions\n\n### Prerequisites\n\n1. **Node.js 16+** and npm\n2. **OpenAI API Key** for embedding generation\n3. **Gatsby CLI** (optional, for development commands)\n\n### Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/goinvo/goinvo.com.git\ncd goinvo.com\n\n# Install dependencies\nnpm install\n\n# Create environment file\ncp .env.example .env\n```\n\n### Environment Variables\n\nAdd your OpenAI API key to `.env`:\n\n```env\nOPENAI_API_KEY=your-api-key-here\n```\n\n\u003e **💡 API Key Setup**: Get your OpenAI API key from [OpenAI Platform](https://platform.openai.com/api-keys)\n\n### Generate Search Index\n\n**Required for search functionality**. Run this whenever you add or modify case studies:\n\n```bash\n# Generate embeddings and search index (uses cache for unchanged files)\nnpm run generate-embeddings\n\n# Force regeneration of ALL embeddings (ignores cache)\nnpm run generate-embeddings:force\n```\n\n**When to use force mode:**\n- 🔄 After upgrading the embedding system (like adding AI buyer descriptions)\n- 🧹 When you suspect cache corruption\n- ✨ To ensure all projects have the latest AI features\n\nThis command will:\n- ✅ Analyze all case studies and features with AI\n- 🧠 Generate OpenAI embeddings for semantic search  \n- 💼 Create buyer-focused descriptions for each project\n- 🗂️ Cache results to avoid reprocessing unchanged content (unless `--force` used)\n- 💰 Show estimated API costs (typically $2-5 for full regeneration)\n\n### Development\n\n```bash\n# Start development server\nnpm start\n\n# Build for production\nnpm run build\n\n# Serve production build locally\nnpm run serve\n```\n\n## 📝 Content Management\n\n### Adding New Case Studies\n\n1. **Create MDX file** in `src/case-studies/your-project.mdx`\n2. **Add frontmatter** with required fields:\n   ```yaml\n   ---\n   title: \"Your Project Title\"\n   client: \"Client Name\"\n   caption: \"Brief description\"\n   categories: [\"healthcare\", \"ui-design\"]\n   image: \"/path/to/image.jpg\"\n   ---\n   ```\n3. **Write content** in MDX format\n4. **Regenerate embeddings**:\n   ```bash\n   npm run generate-embeddings\n   ```\n\n### Adding Features\n\n1. **Edit** `src/data/features.json`\n2. **Add entry** with required fields\n3. **Regenerate embeddings**:\n   ```bash\n   npm run generate-embeddings\n   ```\n\n### Smart Caching\n\nThe embedding system automatically detects changes:\n\n- ✅ **Unchanged files**: Uses cached embeddings (instant)\n- 🔄 **Modified files**: Regenerates embeddings (uses API)\n- 📊 **Cost tracking**: Shows exactly what gets processed\n\nExample output:\n```\n📊 Found 33 projects:\n  ✅ 28 cached (unchanged)\n  🔄 5 need processing\n💰 Estimated cost: $0.02\n```\n\n## 🔧 Search System Architecture\n\n### Files Structure\n\n```\nsrc/\n├── components/\n│   └── project-search.js         # Main search component\n├── utils/\n│   └── semantic-search.js        # Search logic and utilities\n├── data/\n│   ├── search-index.json         # Generated search index\n│   └── embeddings-cache.json     # Cached embeddings\n└── styles/components/\n    └── _project-search.scss      # Search component styles\n\nscripts/\n└── generate-embeddings.js        # Embedding generation script\n\nstatic/\n└── search-index.json             # Public search index for browser\n```\n\n### Search Process\n\n1. **Load Index**: Browser fetches pre-generated search index\n2. **Extract Keywords**: Query is analyzed for relevant terms and concepts\n3. **Calculate Similarity**: Projects are scored using keyword matching and metadata\n4. **Add AI Descriptions**: Relevant buyer descriptions are attached to results\n5. **Rank Results**: Projects sorted by relevance with similarity scores\n\n### Cost Optimization\n\n- **One-time Generation**: Embeddings created once per content change\n- **Smart Caching**: Only reprocess modified files\n- **Client-Side Search**: No runtime API costs\n- **Efficient Model**: Uses cost-effective text-embedding-3-small\n\n**Typical Costs**:\n- Initial setup: $2-5 (all projects)\n- Adding one project: $0.003\n- Search queries: $0 (client-side)\n\n## 🎯 Search Query Examples\n\nThe enhanced system now handles a much broader range of buyer queries:\n\n### Healthcare Queries\n- *\"Need a telemetry dashboard to monitor ICU vitals remotely\"*\n- *\"Looking for an oncology treatment tracker that integrates genomic data\"*\n- *\"Self-guided CBT therapy app for veterans with PTSD\"*\n- *\"HIPAA-compliant radiology collaboration dashboard\"*\n- *\"AI-powered hematology results dashboard for lab technicians\"*\n\n### Enterprise Queries\n- *\"Enterprise expense-analysis dashboard for SaaS CFOs\"*\n- *\"Scalable data-ingest platform for IoT sensor fleets\"*\n- *\"Cross-team dashboard visualizing OKRs and KPIs\"*\n- *\"SOC-2 compliant customer analytics platform\"*\n- *\"Customer loyalty service that plugs into Shopify\"*\n\n### Government Queries\n- *\"Citizen complaint tracking dashboard for municipal services\"*\n- *\"Digital voter-registration tracker compliant with federal standards\"*\n- *\"Grant-management platform for federal research programs\"*\n- *\"FedRAMP authorized emergency response coordination system\"*\n\n### Original Examples (Still Work)\n- *\"I need a UI for an AI platform for therapists\"*\n- *\"Healthcare dashboard design for clinical workflows\"*\n- *\"Data visualization for government policy\"*\n- *\"Enterprise software user experience\"*\n- *\"Mobile health app interface design\"*\n\n## 🛠️ Development Workflow\n\n### For Developers\n\n```bash\n# Standard development\nnpm start                    # Start dev server\nnpm run build               # Build for production\n\n# Search system\nnpm run generate-embeddings  # Update search index (smart caching)\nnpm run generate-embeddings:force  # Force regenerate all (ignore cache)\n```\n\n### For Content Creators\n\n1. **Add/edit content** in `src/case-studies/` or `src/data/features.json`\n2. **Run embedding generation**:\n   ```bash\n   # Normal update (uses cache)\n   npm run generate-embeddings\n   \n   # Or force full regeneration\n   npm run generate-embeddings:force\n   ```\n3. **Test search** functionality on homepage\n\n### Performance Notes\n\n- **Search index size**: ~1.5MB (33 projects with embeddings)\n- **Load time**: Index loads asynchronously, search available in ~1-2 seconds\n- **Browser compatibility**: Works in all modern browsers\n- **Mobile friendly**: Responsive design with touch-friendly controls\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Add/modify content as needed\n4. Run `npm run generate-embeddings` if content changed\n5. Test search functionality\n6. Submit a pull request\n\n## 📞 Support\n\nFor questions about the search system or setup:\n\n- Check the console for detailed logging\n- Verify `.env` file has valid OpenAI API key\n- Ensure `search-index.json` exists in `static/` folder\n- Run embedding generation if search returns no results\n\n## 🎉 Features\n\n- ✅ **Semantic Search** with natural language queries\n- ✅ **AI-Generated Descriptions** for buyer relevance\n- ✅ **Smart Caching** to minimize API costs\n- ✅ **Real-Time Search** with instant results\n- ✅ **Advanced Filtering** by type, industry, complexity\n- ✅ **Mobile Responsive** design\n- ✅ **Cost Efficient** client-side architecture\n\n## Environment Setup\n\n### OpenAI API Key for Enhanced Search\n\nThe site uses AI-generated search descriptions to enhance the search functionality. To enable this:\n\n1. Create a `.env` file in the project root:\n   ```bash\n   touch .env\n   ```\n\n2. Add your OpenAI API key to the `.env` file:\n   ```\n   OPENAI_API_KEY=your-api-key-here\n   ```\n\n3. Get your API key from: https://platform.openai.com/api-keys\n\nThe `.env` file is gitignored and will not be committed to the repository.\n\n**Note:** Without an OpenAI API key, the search will still work but will use generic template descriptions instead of AI-generated ones.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoinvo%2Fgoinvo.com","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoinvo%2Fgoinvo.com","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoinvo%2Fgoinvo.com/lists"}