This documentation is for Etherpad-next collaborator.
docker compose up -d
docker compose exec app npm i
# creates db structure without using migrations
docker compose exec app npx prisma db push
docker compose exec app npx turbo dev
We uses React as a Frontend Library to develop the Website. React allows us to create user interfaces with a modern take on Web Development.
If you're unfamiliar with React or Web Development in general, we encourage a read before taking on complex issues and tasks as this repository is not for educational purposes and we expect you to have a basic understanding of the technologies used.
We also recommend getting familiar with technologies such as Next.js, PostCSS, and "concepts" such as "CSS Modules" and "CSS-in-JS".
As mentioned, we write all Component-styles in separate .module.css
files. This is like writing any CSS in a separate file (besides the fact that we use PostCSS).
This concept of writing styles on dedicated CSS files and importing them within JavaScript (or React) is a pattern named CSS Module.
These allow us to write PostCSS (or regular CSS, or any flavor of CSS if you have a way of interpreting it) within a .module.css
and import the class names directly to our React Components.
We recommend reading guides on "Styling React Components with CSS Modules", which there are many available on the web.
It's important to mention that we use Tailwind as a CSS Framework. Hence, margins, paddings, font sizes, font weights, colors, and other sorts of styles are all provided with Tailwind. We recommend reading Tailwind Docs to get familiar with Tailwind's styles. We also recommend reading this guide for setting up Tailwind on your IDE.
Finally, if you're unfamiliar with how to use Tailwind or how to use Tailwind within CSS Modules, we recommend reading this guide.
.myComponent {
@apply some
tailwind
classes;
}
- We use camelCase for defining CSS classes
- We use Tailwind's
@apply
selector to apply Tailwind Tokens- We discourage the usage of any plain CSS styles and tokens, when in doubt ask for help
- We require that you define one Tailwind Token per line, just as shown on the example above, since this improves readability
- Only write CSS within CSS Modules, avoid writing CSS within JavaScript files
- We recommend creating mixins for reusable animations, effects and more
- You can create Mixins within the
styles/mixins
folder
- You can create Mixins within the
Note
Tailwind is already configured for this repository. You don't need to import any Tailwind module within your CSS module.
You can apply Tailwind Tokens with Tailwind's @apply
CSS rule. Read more about applying Tailwind classes with @apply
.
- All React Components should be placed within the
components
folder. - Each Component should be placed, whenever possible, within a sub-folder, which we call the "Domain" of the Component
- The domain represents where these Components belong to or where they will be used.
- For example, Components used within Article Pages or that are part of the structure of an Article or the Article Layouts,
should be placed within
components/Article
- Each component should have its folder with the name of the Component
- The structure of each component folder follows the following template:
- ComponentName - index.tsx // the component itself - index.module.css // all styles of the component are placed there - index.stories.tsx // component Storybook stories
- React Hooks belonging to a single Component should be placed within the Component's folder
- If the Hook as a wider usability or can be used by other components, it should be placed in the root
hooks
folder.
- If the Hook as a wider usability or can be used by other components, it should be placed in the root
- If the Component has "sub-components" they should follow the same philosophy as the Component itself.
- For example, if the Component
ComponentName
has a sub-component calledSubComponentName
, then it should be placed withinComponentName/SubComponentName
- For example, if the Component
import styles from './index.module.css';
import type { FC } from 'react';
type MyComponentProps = {}; // The types of the Props of your Component
const MyComponent: FC<MyComponentProps> = ({ prop1, prop2... }) => (
// Actual code of my Component
);
export default MyComponent;
- Only spread props
{ ... }
on the definition of the Component (Avoid having a variable namedprops
) - Avoid importing
React
, only import the modules from React that you need - When importing types, use
import type { NameOfImport } from 'module'
- When defining a Component, use the
FC
type from React to define the type of the Component- When using
children
as a prop, use theFC<PropsWithChildren<MyComponentProps>>
type instead - Alternatively you can define your type as
type MyComponentProps = PropsWithChildren<{ my other props }>
(Recommended)
- When using
- Each Props type should be prefixed by the name of the Component
- Components should always be the
default
export of a React Component file - Avoid using DOM/Web APIs/
document
/window
API access within a React Component. Use utilities or Hooks when you need a Reactive state - Avoid making your Component too big. Deconstruct it into smaller Components/Hooks whenever possible
We use Storybook to document our components. Each component should have a storybook story that documents the component's usage.
We use vitetest to run our tests. It's a fast and reliable test runner that comes with Vite.
Storybooks are an essential part of our development process. They help us to document our components and to ensure that the components are working as expected.
They also allow Developers to preview Components and be able to test them manually/individually to the smallest unit of the Application. (The individual Component itself).
Storybooks should be fully typed and follow the following template:
import NameOfComponent from '@components/PathTo/YourComponent';
import type { Meta as MetaObj, StoryObj } from '@storybook/react';
type Story = StoryObj<typeof NameOfComponent>;
type Meta = MetaObj<typeof NameOfComponent>;
// If the component has any props that are interactable, they should be passed here
// We recommend reading Storybook docs for args: https://storybook.js.org/docs/react/writing-stories/args
export const Default: Story = {};
// If the Component has more than one State/Layout/Variant, there should be one Story for each variant
export const AnotherStory: Story = {
args: {},
};
export default { component: NameOfComponent } as Meta;
- Stories should have
args
whenever possible, we want to be able to test the different aspects of a Component - Please follow the template above to keep the Storybooks as consistent as possible
- We recommend reading previous Storybooks from the codebase for inspiration and code guidelines.
- If you need to decorate/wrap your Component/Story with a Container/Provider, please use Storybook Decorators
A brief explanation of why we chose the technologies we use.
React is a trendy and modern library for building user interfaces. It allows us to create reusable components and to manage the state of our application in a more predictable way.
We chose React because it's a widely used library and has a large community. This means that we can find a lot of resources and help online and we can also find a lot of people who are familiar with React.
npm is the default package manager for Node.js. It allows us to install and manage the dependencies of our project. It also allows us to run scripts and to publish our packages. We selected 'cause dev shouldn't have to install another package manager.
Also the key packageManager
in package.json
is set to npm
so we can't use yarn
in this project.
Read more about packageManager
in package.json
- We have
.nvmrc
file in the root of the project. This file is used bynvm
to set the correct version of Node.js for the project. If you havenvm
installed, you can runnvm use
to set the correct version of Node.js for the project. - We use turbo to speed up the development process using caching and incremental builds.