Skip to content

Recipes

Alex Ball edited this page Nov 8, 2022 · 3 revisions

Cookin' Up Tasty Features

Creating a New Page

Take a look at the pages/bills.tsx page:

export default createPage({
  title: "Browse",
  Page: () => {
    return (
      <Container>
        <h1>Browse</h1>
        ...
      </Container>
    );
  },
});

Your page content goes in Page, and will be wrapped in a layout component. The page is rendered by _app.tsx.

Creating a Component

A Template

Suppose you're adding a BillWidget to the bill detail page. Add your component to the components/bill folder:

// components/bill/BillWidget.tsx
import { FC } from "react";
import styled from "styled-components";

export const StyledWidget = styled.div`
  border-radius: 1rem;
  background: white;
  padding: 0.5rem 1rem 1rem 0.5rem;
  border: 1px solid var(--bs-red);
`;

export const BillWidget: FC<{ billId?: string }> = ({ billId }) => (
  <StyledWidget>
    {billId ? `This is bill ${billId}` : "No bill selected"}
  </StyledWidget>
);

Then create a story for it in stories/billDetail:

// stories/billDetail/BillWidget.stories.tsx
import { ComponentStory } from "@storybook/react";
import { BillWidget } from "components/bill/BillWidget";
import { createMeta } from "stories/utils";

export default createMeta({
  title: "Bill Detail/BillWidget",
  component: BillWidget,
});

const Template: ComponentStory<typeof BillWidget> = (args) => (
  <BillWidget {...args} />
);

export const WithBillId = Template.bind({});
WithBillId.args = { billId: "H1234" };

export const WithoutBillId = Template.bind({});
WithoutBillId.args = {};

File Organization

All components should live in the components directory and be grouped by feature. For example, components related to the bill detail page live under components/bill, and auth modals live under auth. There are many components that do not follow this pattern, but the goal is to consolidate around this in the future. For example there are several About* component folders that could be grouped under an about feature folder.

Files that export a single component should be named in title case after that component, like bill/BillDetails.tsx. The component should be exported as a named export, not a default export, for better intellisense:

// bill/BillDetails.tsx
export const BillDetails = ({ billId }: { billId: string }) => { ... }

Other files should be named using camelCase. For example, bills/types.ts exports types shared across components. Files that export a mix of components and support functions like hooks should be named with camelCase, such as legislatorSearch.tsx, which exports both UI components and hooks.

Within a folder, modules can import other modules directly, such as import { ChooseStance } from "./ChooseStance" from publish/SubmitTestimonyForm.tsx. To import something between feature folders, use an index.ts file to re-export modules for easier importing:

// bill/index.ts
export * from "./BillDetails"

// pages/bill.tsx
import { BillDetails } from "../components/bill"
...

When in doubt, do whatever makes sense to you. Contributions are more important than conventions.

Styling

We heavily use react-bootstrap components and bootstrap v5 utility classes for spacing and CSS variables for color.

We have a small amount of global CSS for customizing our Bootstrap theme and external libraries.

All other styling should use either CSS modules or Styled Components. You can use style props directly for dynamically changing styling.

Storybook

You should create stories for your components to make it easy to see the UI in different states. All stories should go under the stories directory. See stories/components/cards/Card.stories.tsx for an example story.