{"id":21044975,"url":"https://github.com/quansight/quansight-website","last_synced_at":"2025-04-06T19:12:42.419Z","repository":{"id":36996869,"uuid":"459632491","full_name":"Quansight/Quansight-website","owner":"Quansight","description":"💻 Source code for Quansight Labs website","archived":false,"fork":false,"pushed_at":"2025-03-20T15:01:48.000Z","size":229010,"stargazers_count":21,"open_issues_count":71,"forks_count":54,"subscribers_count":22,"default_branch":"main","last_synced_at":"2025-03-30T17:11:21.245Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://labs.quansight.org","language":"TypeScript","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/Quansight.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":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-15T15:16:35.000Z","updated_at":"2025-03-20T15:01:52.000Z","dependencies_parsed_at":"2023-09-25T20:22:41.459Z","dependency_job_id":"d9c703c9-2554-43b7-9764-36523dafcf79","html_url":"https://github.com/Quansight/Quansight-website","commit_stats":{"total_commits":887,"total_committers":55,"mean_commits":16.12727272727273,"dds":0.7508455467869222,"last_synced_commit":"81bfb09c21007ab42ce1e63a2f27ede1c838272a"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quansight%2FQuansight-website","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quansight%2FQuansight-website/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quansight%2FQuansight-website/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Quansight%2FQuansight-website/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Quansight","download_url":"https://codeload.github.com/Quansight/Quansight-website/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247535519,"owners_count":20954576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-11-19T14:19:24.147Z","updated_at":"2025-04-06T19:12:37.411Z","avatar_url":"https://github.com/Quansight.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Quansight Website\n\n- [Quansight Website](#quansight-website)\n  - [How to publish a new blog post 📝](#how-to-publish-a-new-blog-post-)\n  - [Running the website locally 🖥](#running-the-website-locally-)\n  - [Orientation 🗺](#orientation-)\n  - [Deployment Schedule 📆](#deployment-schedule-)\n  - [How to make changes to the website 👨🏿‍💻](#how-to-make-changes-to-the-website-)\n    - [Content changes (Storyblok) 📰](#content-changes-storyblok-)\n    - [Code changes (GitHub) 💻](#code-changes-github-)\n  - [A word about the word \"preview\" 🤔](#a-word-about-the-word-preview-)\n  - [Integrations 🛠](#integrations-)\n    - [GitHub](#github)\n    - [Storyblok](#storyblok)\n    - [Vercel](#vercel)\n    - [Slack](#slack)\n    - [Next.js plus the codebase in this repo](#nextjs-plus-the-codebase-in-this-repo)\n  - [Ways to view the site at different stages 🔍](#ways-to-view-the-site-at-different-stages-)\n  - [System design decisions 🏗](#system-design-decisions-)\n  - [Adding new components 🧩](#adding-new-components-)\n  - [Adding new queries 🗃](#adding-new-queries-)\n  - [GitHub-based blog workflow (Labs blog) 💻](#github-based-blog-workflow-labs-blog-)\n    - [Structure of the blog post](#structure-of-the-blog-post)\n      - [Example of blog post meta section](#example-of-blog-post-meta-section)\n    - [Adding a new blog category](#adding-a-new-blog-category)\n    - [Adding new components for usage inside `.mdx` posts](#adding-new-components-for-usage-inside-mdx-posts)\n    - [Specifications for Hero images](#specifications-for-hero-images)\n\n## How to publish a new blog post 📝\n\n1. Create a new feature branch. Example: `feature/new-hello-world-post`.\n2. Choose a good, human-readable slug for your blog post. This slug will be used\n   both in the URL path to your blog post and in the folder and file names in\n   the next steps.\n3. Add feature and hero images plus any other images contained in your blog\n   post to `apps/labs/public/posts/\u003cpost-slug\u003e/`. The feature image is used for\n   sharing on social media and in the blog index. The hero image is the big\n   banner above the blog post.\n4. Add a new `.md|.mdx` file inside the `app/labs/posts` directory (careful:\n   this is not the same directory as the images). Make sure to\n   read the [Structure of the blog post section](#structure-of-the-blog-post) in\n   this file to ensure that the post is properly structured.\n5. Your commit tree should have the following structure:\n   - apps/labs/posts/\n     - new-hello-world-post.mdx\n   - apps/labs/public/posts/new-hello-world-post/\n     - descriptive-name-of-feature-image.png\n     - descriptive-name-of-hero-image.png\n     - any other images needed within your blog post\n6. Commit and push your changes to the repository. For commits please follow the\n   format of the [conventional\n   commit](https://www.conventionalcommits.org/en/v1.0.0/).\n7. Create a pull request to the `main` branch. Make sure to add the `type: content 📝`\n   and `labs 🔭` labels to the PR.\n8. Wait for someone to review the new blog post.\n   \u003e TIP: Look for the Vercel preview URL posted by a bot to the pull request so\n   \u003e you can check that the blog post looks okay before publishing to the world\n   \u003e wide web.\n9. Once your pull request is approved, you should be able to merge your PR into\n   the `main` branch.\n10. Once merged into the `main` branch, your blog post should appear within a few\n    minutes on labs.quansight.org.\n\n## Running the website locally 🖥\n\nPrerequisites:\n\n- [Node](https://nodejs.org/en/)\n\n### Short version (Labs site)\n\nCopy and paste the following commands:\n\n```sh\ngit clone git@github.com:Quansight/Quansight-website.git\ncd Quansight-website\nnpm install\ncp apps/labs/.env.example apps/labs/.env\nnpm run start:labs\n```\n\n### Longer version\n\nTo run the website locally on your machine, you must first clone this git repo,\n`cd` into the repo, then run `npm install`.\n\nThis repo contains two projects (websites): Consulting and Labs. (We are not\ncurrently using the Consulting project.) You must create a `.env` file for each\nproject that you want to develop locally. For example, for Quansight Labs, you\nwill need to create `apps/labs/.env`. You can do this by copying the example\nenvironment file:\n\n```bash\ncp apps/labs/.env.example apps/labs/.env\n```\n\nNote: You should **not** modify the example environment file.\n\nRun `npm run start:labs` to start a corresponding dev server. Navigate to\n\u003chttp://localhost:4200/\u003e or use `localhost` in the Storyblok preview panel. On\nthe local host, the app will automatically reload if you change any of the\nsource files, whereas in the Storyblok panel you need to refresh the page\nmanually.\n\nImportant: whenever the website's dependencies change or are updated, the lock\nfile `package-lock.json` will be updated. Whenever `package-lock.json` is\nupdated, you should re-run `npm install` (on CI, `npm ci`), so that your local\nenvironment's dependencies will match the production environment.\n\n## Orientation 🗺\n\nHere is some basic info to help orient you to this repo.\n\n- This repo holds the **code** for two websites:\n  - `./apps/labs/` holds code for Quansight Labs: \u003chttps://labs.quansight.org\u003e\n  - `./apps/consulting/` holds code for the previous Quansight Consulting website.\n    It is now just an archive.\n  - `./libs` holds code shared by both websites.\n- Labs website **content** lives in [Storyblok](https://app.storyblok.com)\n  (requires login).\n  - But Labs **blog posts** live under `./apps/labs/posts`\n- The websites are hosted and deployed via\n  [Vercel](https://vercel.com/quansight) (requires login).\n- The repo's default branch is `main`\n  - Most pull requests (i.e., Labs blog posts) will be opened against\n    `main`.\n  - Riskier pull requests will be opened against the `develop` branch.\n  - `main` is used for production (i.e., the live website).\n  - You can think of `develop` as staging.\n  - Pushing commits to `main` triggers a deployment of both websites via Vercel.\n\n## Deployment Schedule 📆\n\nThere used to be a deployment schedule but now the website is deployed whenever\na new blog post is approved and merged to the main branch. All other changes are\ndeployed as needed.\n\n## How to make changes to the website 👨🏿‍💻\n\n\u003e **Note**\n\u003e Before reading this section, familiarize yourself with [Vercel\n\u003e environments](https://vercel.com/docs/concepts/deployments/environments).\n\nThere are primarily two types of website changes, each with its process:\n\n- Content changes ([Storyblok](https://www.storyblok.com/home), our CMS - Content Management System)\n- Code changes (this GitHub repo)\n\nNote that Labs blog posts are a bit of an exception. Categorically they are\ncontent changes, but the content lives in the Git repo -- so technically they are\ncode changes, and they follow the process for code changes.\n\nThis section will cover the process for each type of change.\n\n### Content changes (Storyblok) 📰\n\nContent in Storyblok moves through several stages: drafting -\u003e reviewing -\u003e ready to\npublish -\u003e published -\u003e deployed.\nIt's confusing, but \"published\" in our Storyblok\nconfiguration does not mean that the content has gone live on the\ncorresponding public website. However, you should never publish any content in\nStoryblok if it is not ready for public presentation. In our configuration,\npublishing content in Storyblok is a signal to the rest of the team that says:\nthis content is ready at any time to appear on the public website. **If it's not\nready, don't hit the publish button.**\n\nThe Storyblok process is covered in more detail in the [GitHub repo's wiki](https://github.com/Quansight/Quansight-website/wiki).\nA simplified version is presented here.\n\nThe process for creating, updating, or deleting content in Storyblok is the\nsame. There are three major stages, each with distinct steps.\n\n1. **Editing**\n   1. Make your changes in Storyblok.\n   2. Preview how your changes will look on the site using Storyblok's preview\n      iframe. You should see a yellow overlay at the top of the page telling you\n      that you can see draft content.\n   3. Save your changes.\n2. **Publishing**\n   1. Subscribe to Slack channel `#website-vercel-bot-log` if you are not already\n      subscribed.\n   2. Once your content changes are approved, click the publish button in\n      Storyblok. Remember, clicking \"publish\" means that you are certifying that\n      to the best of your knowledge, these changes should be ready to be\n      deployed at any time to the live website. When you click the publish\n      button, Storyblok will make a request to Vercel to start a preview\n      deployment.\n   3. Look for deployment notifications in Slack. Vercel will send a message to\n      the [#website-vercel-bot-log][slack-channel] channel containing a link to the preview URL.\n   4. Visit the Vercel preview URL to review and double-check your changes.\n3. **Going live**\n   1. When you want your changes to go to the live production site, coordinate\n      with the dev team to open a merge pull request to the `main` branch on\n      GitHub.\n   2. When the Vercel GitHub app comments on the merge PR with a preview URL,\n      visit that preview URL to check your changes. (You should also be able to\n      get the Vercel preview URL from the Slack channel.)\n   3. If it all looks good, coordinate with the dev team to merge the PR to the\n      `main` branch.\n   4. Once that PR is merged to `main`, wait for the production build to finish\n      deploying (check our internal Slack channel,\n      [#website-vercel-bot-log][slack-channel], for notifications), then check\n      your changes against the live site. You may need to clear your browser's\n      cache before you can see your changes.\n\n### Code changes (GitHub) 💻\n\nCode changes move through three stages, each of which corresponds to a branch in\ngit: a feature branch (PR), then the `develop` branch, then `main`. When your\ncode gets merged to the `main` branch, Vercel deploys it to the public website.\n\n\u003e **Note**\n\u003e You should never merge your code into the `develop` branch unless it's ready for\n\u003e deployment (via merge to `main`).\n\u003e Putting your code into the `develop` branch is a signal to the rest of your team that says:\n\u003e this code is ready to run on the public website.\n\nThese are the concrete steps to follow to move your code from branch to branch:\n\n1. Open a pull request against the `develop` branch. This will kick off preview\n   deployments in Vercel. Vercel will add a comment to your pull request with\n   links to the preview URL.\n2. Check preview URL.\n3. Once your pull request has been reviewed and approved, commit it to the\n   `develop` branch.\n   - Consider doing a\n     [squash-merge](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-pull-request-commits),\n     especially if your pull request is relatively small, to keep a\n     clean commit history.\n4. When you want your code change to go live, cut a release branch from\n   `develop`, then open a pull request to merge the release branch into `main`.\n   From the command line:\n\n   ```sh\n   git checkout develop\n   git pull\n   git checkout -b release-YYYYMMDD\n   git push -u origin release-YYYYMMDD\n   ```\n\n   Be sure to use `main` as the base branch of your release PR and not `develop`.\n\n5. Review preview URL that Vercel will add to your Pull Request.\n6. If all looks good and your Pull Request has gotten approval, then merge it\n   into `main`. This will kick off a production deployment on Vercel. Check the\n   live public websites once the deployment is finished. (Vercel will send a\n   notification to the [#website-vercel-bot-log][slack-channel] slack channel.)\n   You may need to clear your browser's cache before you can see your changes.\n7. Delete the release branch if GitHub did not automatically delete it when you\n   merged your Pull Request.\n\n## A word about the word \"preview\" 🤔\n\nThere is a semantic trap in the word \"preview.\" Storyblok, Next.js, and Vercel\nall use the word preview, and it means different things to each of them.\n\nStoryblok has two kinds of API keys: a preview key and a public key. With the\nStoryblok preview key, you can pass either `version=draft` or\n`version=published` to the Storyblok content API, where `version=draft`\nshows the _Saved_ version of content from Storyblok and `version=published`\nshows the _Published_ version from Storyblok. (Side note: Storyblok has\nmultiple APIs, but the main API we are concerned with is the content API). In contrast, [the public\nkey only allows access to published\ncontent](https://www.storyblok.com/docs/api/content-delivery#topics/authentication).\n\nNext.js supports a preview mode. The framework provides a method to set a cookie\non the client. When this cookie is set, Next.js renders pages dynamically\ninstead of statically and passes a boolean to the runtime. This allows the site\nto switch its behavior at runtime -- for example, passing `version=draft` to the\nStoryblok API when Next.js preview mode is activated versus `version=published` when it\nis not.\n\nFinally, Vercel has preview URLs and a preview environment. Preview URLs point\nto builds (or deployments) that were performed in a preview environment.\n\nIt would be nice if all of these different uses of preview mapped cleanly to\neach other, but they do not. For example, you may be on a Vercel preview URL,\nbut you may or may not be in Next.js preview mode. The Vercel preview\nenvironment uses the Storyblok preview key, but if it's not in Next.js preview\nmode, it passes `version=published` to the Storyblok API and you will see\nonly Published content from Storyblok.\n\nEverything has been configured so that you shouldn't have to think about this\ntoo much, but just in case you find yourself confused, hopefully, this section\nwill help clear things up.\n\n## Integrations 🛠\n\nMaking changes to the website relies on the ability of several services\nto interact with each other. This section is for developers and covers each service\none by one and how it integrates with some other services.\n\n### GitHub\n\nThe Vercel app is installed on GitHub. The app kicks off deployments on Vercel\nwhenever someone opens a pull request or pushes a commit to the repo. All of\nthese deployments are [preview\ndeployments](https://vercel.com/docs/concepts/deployments/environments#preview)\n(meaning they use the preview environment in Vercel and associated environment\nvariables), except for commits to the `main` branch. Commits to the `main`\nbranch are specially recognized by Vercel as a signal to deploy the live\nwebsite.\n\n### Storyblok\n\nEach website has its own \"space\" and configuration in Storyblok.\n\nEach website has a unique pair of API keys: preview and public. The preview\nAPI key allows API access to both published and draft content. The public key\nonly allows access to published content. The Vercel production environment is\nconfigured with the value of the public API key so that it cannot accidentally\naccess the draft content. The Vercel preview environment (as well as the local\ndevelopment environment) uses the preview API key so that the website team can\npreview draft content.\n\nEach website's publish function in Storyblok is connected to a webhook on\nVercel. When this Vercel webhook is called, it does a preview deployment based\non the current commit of the `develop` branch on GitHub.\n\nThe Storyblok preview iframe is configured to show content previews against the\nVercel URL that points to the latest build off the `develop` branch. This was\ndone to help ensure that if there are any possible issues or conflicts between\ncode changes and content changes, they will be caught early on. The Storyblok\neditor automatically passes cache-busting query string parameters (as in\n`?_storyblok=\u003ctimestamp\u003e`) to the preview URL, so it should be okay to use a\nconstant URL base, such as\n`quansight-consulting-git-develop-quansight.vercel.app`, rather than the always\nchanging SHA-based Vercel preview URLs\n(`quansight-consulting-\u003cSHA\u003e-quansight.vercel.app`).\n\nThere is a fair amount of code in the codebase that integrates with Storyblok.\nFor example, there is a bridge that syncs the site with changes coming from the\nStoryblok editor.\n\nSome middleware checks if the HTTP referrer is\n\u003chttps://app.storyblok.com/\u003e. In that case, the code assumes that the end user\nis coming to the site from within the Storyblok iframe. So it puts the user in\nNext.js preview mode. When the user is in preview mode, the website shows a\nyellow overlay at the top of the page, letting the user know that they are seeing\ndraft content on the site.\n\n### Vercel\n\nThe Labs website corresponds to the `quansight-labs` project in Vercel.\n\nThe Vercel project has settings that allow it to integrate with Storyblok,\nNext.js, and GitHub. The Vercel project has three separate environments:\ndevelopment, preview, and production. The development and preview environments\ncontain the preview key to Storyblok. The production environment contains the\npublic key to Storyblok, which only allows access to the published\nversion of the content, not the draft version.\n\nThe Vercel project is also configured with a webhook that Storyblok uses to\nkick off a preview deployment of the `develop` branch whenever new content is published\nin Storyblok.\n\n### Slack\n\nThere is a Vercel app for Slack. It is set up to send deployment notifications\nto the `#website-vercel-bot-log` channel.\n\n### Next.js plus the codebase in this repo\n\nThe code in this repo is built on top of the Next.js framework. Next.js has a\nfeature called preview mode. When preview mode is turned on (via a cookie), the\nNext.js framework dynamically renders each page; otherwise, it serves a static,\npre-rendered page (except when doing local development, and then it always\ndynamically renders each page).\n\nThe code in this repo takes advantage of the Next.js preview mode to integrate\nbetter with Storyblok and Vercel. When the code detects preview mode, it defaults to passing\n`{\"version\": \"draft\"}` to the Storyblok API to preview content that has\nbeen saved but not yet published -- in other words, `draft` content.\n\nThere is also code that detects when the request comes from a Storyblok iframe.\nIn this case, the code forces the browser to automatically enter into Next.js\npreview mode.\n\n**To help the end user distinguish which view of the site they are seeing, the\ncodebase defines a visual overlay at the top of each page.** When the site is in\npreview mode, the overlay turns yellow and displays a message telling the user\nthat they can see draft content. When the site is not in preview mode, the\noverlay turns gray and tells the user that they can see published content. The\noverlay provides a clickable link to switch in and out of Next.js preview mode.\nThis switch is turned off when the user is viewing the page via the Storyblok UI because when\nthey are working within Storyblok, they should always see the site in Next.js preview\nmode so that they can see changes that are being worked on.\nThe overlay does not show at all if the site was built in a\nproduction environment.\n\nThe codebase takes advantage of [Vercel environment\nvariables](https://vercel.com/docs/concepts/projects/environment-variables) at\nbuild time. For example, the preview mode overlay links to the git branch that\nthe site was built from (when that environment variable is available at build\ntime).\n\n## Ways to view the site at different stages 🔍\n\nThroughout the develop-deploy process, there are several ways to view the\nwebsite. The following table summarizes the important ways in which those views\ndiffer from each other.\n\n| Name                        | How to access          | GitHub branch  | Vercel env | Storyblok API key | Next.js preview? | Storyblok version param | Display top overlay? | Top overlay color | Button to enter/exit preview? |\n| --------------------------- | ---------------------- | -------------- | ---------- | ----------------- | ---------------- | ----------------------- | -------------------- | ----------------- | ----------------------------- |\n| Production                  | .com/.org URL          | `main`         | production | public            | off              | `published`             | No                   | n/a               | n/a                           |\n| Storyblok (yellow overlay)  | via Storyblok UI       | `develop`      | preview    | preview           | on               | `draft`                 | Yes                  | yellow            | No                            |\n| Vercel URL (gray overlay)   | via link to Vercel URL | any non-`main` | preview    | preview           | off              | `published`             | Yes                  | gray              | Yes                           |\n| Vercel URL (yellow overlay) | via enter-preview      | any non-`main` | preview    | preview           | on               | `draft`                 | Yes                  | yellow            | Yes                           |\n\nLet's take the row labeled \"Vercel URL (gray overlay).\" This view is accessed by\nclicking on a Vercel SHA-style URL, which looks like\n`https://labs-{SHA}-quansight.vercel.app`. Typically, this URL is found\neither on a GitHub pull request or in `#website-vercel-bot-log` in Slack. The site served by that URL can be\nbuilt from any branch or commit on GitHub except `main`, which is reserved for\nproduction. It is built with the \"preview\" Vercel environment. It does not start\nin Next.js preview mode (though the end user can switch to it). The preview\nVercel environment contains the preview Storyblok API key. The site passes\n`version=published` to the Storyblok API. It displays a gray overlay at the top\nof each page, and that gray overlay contains a way for the end user to switch to and out of the Next.js preview mode.\n\nNote that within Storyblok, there is no button to switch out of preview mode.\nThis was done by design because the whole point of the Storyblok UI is to be\nable to preview content that hasn't been published yet.\n\n## System design decisions 🏗\n\nEach website should have only one project in Vercel. Having more than one\nproject results in several preview URLs being posted to each pull request on\nGitHub, which makes it hard for reviewers to know which preview URL they should\nreview. With only one project per website, you get one preview URL (per website)\nposted to the pull request. If it's not clear from the pull request title or\ncode which website the PR affects, the author should clarify in the PR\ndescription. Ideally, the PR author should add one or both of the (`Labs`,\n`Consulting`) GitHub labels, as appropriate, to mark the site(s) that the changes\nare meant to affect.\n\nCode in the `main` branch should only be used by the production Vercel\nenvironment, and it should show only published content from Storyblok. While it may be tempting\nto want to see draft content against the `main` branch code, it creates the\npotential for confusion, and it is better not to allow it.\nFor example, if someone takes a screenshot of a\nwebpage, and in the screenshot, you can see in the browser address bar that the\nURL is on the live production site (such as quansight.com), then there is no doubt\nthat you're seeing content that was **published** in\nStoryblok at the time the `main` branch was deployed to production. The other\nreason for this discipline is that it's better to limit reviewers and content\neditors to previewing draft content against the `develop` branch to help catch\nany potential code/content conflicts before merging to `main`.\n\nWhen viewing the site in local development or at a Vercel preview URL, there\nshould be an overlay that explains that you are looking at a preview of the site.\nThis helps reduce confusion when screenshots are shared. This overlay should not\nbe present on a production build of the site.\n\nThe preview/development environment overlay should allow the user to toggle\nbetween seeing published versus draft/saved Storyblok content. The overlay should\nchange colors to indicate which of the two content preview modes the user is in\n(that is, whether they are seeing draft or published content from Storyblok).\n\nThe above should hold _except_ when the user is using the Storyblok web\ninterface; then the website should always be in \"draft\" mode, showing saved (but\nnot published) content. And as mentioned previously, it should show this content\nagainst the latest code from the `develop` branch (not the `main` branch).\nRelated: The content team shouldn't have to think about which URL to use with\nthe Storyblok editor. It should be only one default URL, and this URL should\nshow draft content against the latest code in `develop`.\n\nHitting the publish button in Storyblok should not push that content to the\npublic-facing site; rather, it should queue up the content for the next production deployment.\nThis prevents bypassing any GitHub workflows that have been\nset up for quality control.\n\nContent that is marked as \"published\" in Storyblok should be ready to be pushed\nto production at any time. Likewise, code that is merged into the `develop`\nbranch on GitHub should also be ready to be pushed to `main` at any time.\nRespecting this discipline should allow anyone to deploy a new version of the\nsite to production at any time.\n\nAll production deploys should happen via commits or merges to the `main` branch.\nVercel is opinionated about this. We should follow the conventions and opinions\nof the systems we integrate. If there is a content change that needs to bypass\ncode changes in the `develop` branch, a pull request can be made to\nupdate a log file. That single commit can then be merged into the `main` branch\nto kick off a deployment. This is a hotfix for content. A hotfix for code can be\ndone similarly.\n\n## Adding new components 🧩\n\n1. Create the component with its schema in Storyblok components.\n2. Create the React component. The components are located in\n   `/apps/consulting/components` (Consulting components), `/apps/labs/components` (Labs\n   components), or `/libs/shared/ui-components/src` (shared components).\n   The name of the Storyblok component should be the same as the name of the React\n   component.\n3. (Only if you're adding a shared component) Add a component and `types imports`\n   in the `/libs/shared/ui-components/src/index.ts` file to make it available in the\n   apps.\n4. Add Storyblok raw data types to the `/apps/.../types/storyblok` folder.\n5. Import these raw data types to the `/apps/.../types/storyblok/rawBlok.ts` file\n   and add them to the collective `TRawBlock` type.\n6. Add Storyblok props mapper to `/apps/.../components/BlokProvider/mappers`\n   folder.\n7. Import this props mapper to\n   `/apps/.../components/BlockProvider/utils/getPropsByType.ts` file and add the\n   case to the switch statement.\n8. Import the Next component to the\n   `/apps/.../components/BlockProvider/componentsMap.ts` file and add it to the\n   `componentsMap` variable.\n9. Import the Next.js component types to the\n   `/apps/.../components/BlockProvider/types.ts` file, add the component name to the\n   `ComponentType` `enum` and add the props types to the `TBlokComponentPropsMap`\n   type.\n\n## Adding new queries 🗃\n\nYou can fetch data from Storyblok directly using queries. To add the query:\n\n1. Add the query schema `.graphql` file to the `/apps/.../api/queries` folder.\n2. Run `npm run codegen:quansight` or `npm run codegen:labs` command, depending on\n   which site are you adding the query to.\n3. Create the data retrieval function in the `/apps/.../api/utils` folder using the\n   function, type, and hook created by the code gen script.\n\n## GitHub-based blog workflow (Labs blog) 💻\n\nAll the **Quansight Labs** blog posts are located inside `apps/labs/post`,\nand therefore, any new posts _must_ be added to this same folder.\n\n\u003e **Note**\n\u003e For now, all posts should be\n\u003e contributed using a branch-and-merge strategy within the website repo itself,\n\u003e instead of a fork-and-merge strategy. This may change in the future.\n\nEvery post is a `.md` or [`.mdx` file](https://mdxjs.com/docs/using-mdx/). The\n`posts` directory also contains a [`categories.json`\nfile](./apps/labs/posts/categories.json) containing the posts categories.\n\nThe `categories.json` file is also used for displaying category filters on the\n`/blog` page so after adding a new category, it will also be visible on that\npage.\n\nFor more details about `.mdx` please see:\n\n- \u003chttps://mdxjs.com/\u003e\n- \u003chttps://github.com/hashicorp/next-mdx-remote\u003e\n\n### Structure of the blog post\n\nEvery post is structured with two main sections: `meta` and `content`.\nThe `content` section is the body of the post added in Markdown format.\nThe `meta` section is a `YAML` like structure and should be wrapped with `---`\nsigns. The meta section contains post-related information like:\n\n- `title` (required) - Title of the blog post. Used also as the title of the page inside\n  `\u003ctitle\u003e\u003c/title\u003e` tag\n- `description` (required) - Description of the blog post. Used inside `\u003cmeta name=\"description\" /\u003e` tag\n- `published` (required) - Publishing date of the blog post. Used also for sorting posts by\n  date (the format should be `Month d, yyyy` for example `January 1, 2023`)\n- `authors` (required) - Array of unique author slugs (from Storyblok). Usually\n  the blog post will have only one author and the value of this field will look\n  like `[tania-allard]`, but when the same blog post has multiple authors it\n  will look like `[tania-allard, ralf-gommers]`. Based on this property, the\n  blog post page will display proper info about the author(s) (and their\n  avatars). The author(s) must be present in Storyblok in order for the post to\n  build without error.\n- `category` (required) - Array of categories for example `[Machine Learning]`. All\n  categories should be the same as in the previously mentioned\n  [`categories.json`](./apps/labs/posts/categories.json) file.\n  **Important note:** categories are case-sensitive.\n- `featuredImage` (required) - Object with two required properties: `src` and `alt`.\n  - The `src` property is a path to the featured image. The image is displayed both\n    (a) in the posts gallery on the`/blog` page and (b) in rich social media\n    preview cards (on Twitter, Slack, LinkedIn, etc.). The image should be added\n    to the `apps/labs/public/posts/\u003cpost-slug\u003e` directory and the `src` property\n    should be `/posts/\u003cpost-slug\u003e/\u003cimage-filename-with-extension\u003e`. For example,\n    if the filename of your blog post is `hello-world.md` and the filename of\n    your featured image is `featured-image.png`, then you save the image at\n    `apps/labs/public/posts/hello-world/featured-image.png`, and `src` would be\n    `/posts/hello-world/featured-image.png`. This image should (a) be in PNG or\n    JPEG format and (b) have close to a 2:1 aspect ratio and a minimum height of\n    627 pixels. If you're unsure about how your image will appear in social\n    media preview cards, you can open a PR for your blog post, get the preview\n    build URL to your post, then paste the preview URL in a draft social media\n    post to see how the card will look on that social media platform.[^1]\n    [^1]: Note that Twitter post previews can be flaky and\n    [LinkedIn has a useful post-inspector tool](linkedin.com/post-inspector).\n  - The `alt` property is alternative text for the image for use by blind and\n    low vision readers.\n- `hero` (required) - the object for the Hero section of the post. This can have\n  two different structures:\n  - The first structure is an object with `imageSrc` and `imageAlt`. The\n    `imageSrc` property is a path to the hero image, which is displayed on the\n    blog post page between the nav bar and the blog heading title. The\n    `imageAlt` property is alternative text for the image. The image should be\n    added to the `apps/labs/public/posts/\u003cpost-name\u003e` directory, for example,\n    `apps/labs/public/posts/hello-world-post`.\n  - The second structure is an object with properties:\n    `imageMobile`,`imageTablet`, and `imageDesktop`. Each of these properties\n    also contain `imageSrc` and `imageAlt` properties.\n  - The src should begin with `/posts/` (not apps/labs/public/posts/).\n\n#### Example of blog post meta section\n\nFor a blog post with the file name, `hello-world-post.mdx`:\n\n```yaml\ntitle: 'This is hello world post!'\nauthors: [anirrudh-krishnan]\npublished: October 14, 2022\ndescription: 'Lorem ipsum dolor sit amet'\ncategory: [Machine Learning]\nfeaturedImage:\n  src: /posts/hello-world-post/featured.png\n  alt: 'Excellent alt-text describing the featured image'\nhero:\n  imageSrc: /posts/hello-world-post/hero.jpeg\n  imageAlt: 'Excellent alt-text describing the hero image'\n```\n\n### Adding a new blog category\n\n1. Create a new feature branch.\n2. Open the `apps/labs/posts/categories.json` file.\n3. Add a new category to the array. Make sure to follow the same format as the\n   other categories.\n4. Commit and push your changes to the repository. For commits please follow the\n   format of the [conventional\n   commit](https://www.conventionalcommits.org/en/v1.0.0/).\n5. Wait for someone in the website team to review the new blog post. If\n   everything is ok, the PR will be merged to the `develop` branch.\n\n### Adding new components for usage inside `.mdx` posts\n\n1. Open `apps/labs/services/blogAllowedComponents.ts` file\n2. Import the component from the codebase\n3. Add a new component to `blogAllowedComponents` object.\n\n### Specifications for Hero Images in Storyblok\n\nThere are two options to add images to the Hero component in Storyblok,\nfor non-blog pages of both the Consulting and Labs sites.\n\n1. The first one is to add the image in the `General` tab of the Hero component -\n   this image will be used for all screen sizes.\n2. The second one is to add different images for the three screen sizes in their\n   respective tabs: Image Mobile, Image Tablet, and Image Desktop. When choosing\n   this second option, you **MUST** add images for all three screen sizes.\n\nBy default, the images in the Hero component adjust their size to fill the full\nwidth of the container box (`objectFit: cover`). You can customize this behavior\nby choosing a different `objectFit` property.\n\n- `Contain`: the image is scaled to maintain its aspect ratio while fitting within the\n  element's content box (height).\n- `Cover`: the image is sized to maintain its aspect ratio while filling the element's\n  entire content box (width).\n\n\u003c!-- reusable urls --\u003e\n\n[slack-channel]: https://quansight.slack.com/archives/C03PG5SFG5P\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquansight%2Fquansight-website","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquansight%2Fquansight-website","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquansight%2Fquansight-website/lists"}