SkillAgentSearch skills...

Remix.infonomic.io

A Remix demo app with CSS, Tailwind, Radix UI and other headless UI components.

Install / Use

/learn @infonomic/Remix.infonomic.io
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

A Remix Demo App

A Remix demo app based on the Remix Indie Stack quick-start project (a simple note-taking application)

A Remix Note-taking App

Learn more about Remix Stacks.

The original README is further below (with some modifications)

Rationale

The quick-start Indie stack example is a great way to get started with Remix, however, we wanted to create a fuller example with a few goals in mind:

  1. We wanted to learn more about Remix.
  2. We also wanted to experiment with headless UI systems, in particular Radix and Radix with Tailwind CSS - as a non-CSS-in-JS approach seemed like a better fit for the Remix Philosophy.
  3. We also wanted to use Tailwind CSS, combined with 'regular' CSS - configured via postcss to allow the creation of .css sidecar files for any route or component. We've followed the styling guide at Remix for 'surfacing' component-level styles in routes.
  4. With the above, we wanted to create a 'skeletal' UI system with core components styled for our basic light and dark themes (with a theme provider courtesy Matt Stobbs and his excellent The Complete Guide to Dark Mode with Remix blog post). Material UI, Bootstrap and others, represent great value and are a good way to kick start a project. The MUI team in particular produce an amazing collection of free-to-use components. But we wanted to try and create a 'back to basics' design system. It's far from perfect, and far from complete - but it was an interesting exercise in hand rolling components, as well as hand picking some of the best available headless components out there and adapting them to suit our needs.

Getting Started

  1. Clone or fork this repo.
  2. Run npm install to install dependencies. If you don't want package-lock.json to be 'touched', or are planning on submitting a PR - please use npm ci instead.
  3. Copy the .env.example file to .env - and optionally fill in your reCAPTCHA keys from Google reCAPTCHA.
  4. Run node makeSessionSecret.js to generate your session secret and place it in your .env file above.
  5. Copy the prisma/users.example.json file to prisma/users.json - these are the seed user accounts, including an admin user.
  6. Run npm run setup to initialize the local SQLite database and seed users.
  7. Run npm run dev to start your local development environment.
  8. Run rm -rf build and npm run build and npm run start to run a production build.
  9. If you'd like to deploy the application to Fly.io - follow the instructions below in the original README. Be sure to rename the application (and unique Fly.io app code) in the name section of package.json and the app section of fly.toml.

Approach

Remix

Remix is pretty cool, and we've tried to do things the Remix way - but, obviously we're new to Remix and so suggestions are welcome. There are a few good example Remix projects out there - including (but not limited to)...

https://github.com/remix-run/react-router-website
https://github.com/jacob-ebey/remix-dashboard-template
https://github.com/jacob-ebey/remix-ecommerce
https://github.com/kentcdodds/kentcdodds.com
https://github.com/epicweb-dev/rocket-rental
https://github.com/mcansh/mcan.sh

Directory Structure

We've seen a few different ways to organize both routes and the overall Remix directory structure. We've mostly followed the original quick-start structure, with the addition of a modules directory (called route-containers, or even components in other projects).

For us modules represent any functional or feature area of the application associated with a route. It's where route-specific React components live - like the Hero.tsx component in the home module for the home / index route.

See the Style System section below for the directory structure of our style system

Data Layer

As in the original quick-start app, this project uses Prisma with User and Note Prisma models for data access. Prisma looks great, and we should probably spent more time with this - but we're new to Prisma as well, having relied on Knex and plain SQL for relational database query building for years now.

We've updated the Prisma /prisma/schema.prisma User model to include an isAdmin field. We've also created a /prisma/users.example.json source user file for seeding users, including an admin account. Follow the Getting Started instructions above to rename this file and seed your database.

Again, as in the original project - we're using SQLite as the database, which makes experimenting with Remix and deploying to Fly.io a breeze.

Style System

The project is configured to use Tailwind CSS and plain CSS via postcss and postcss-cli. There is a 'SMACSS-like' CSS bundle in the root level /shared/css directory - along with the main /shared/css/tailwind.css and /shared/css/app.css source stylesheets. The 'root-level' shared CSS files and imports are processed and placed in the 'app level' styles directory with a corresponding directory structure. We've named the root-level styles directory shared for a reason. ;-)

We've configured postcss-cli with the --base switch, which will re-create the source directory structure in the target output directory. And we've configured the postcss tasks to look for 'side car' stylesheets sitting next to route or module components (see Directory Structure above).

So...

CSS files in the root level /shared directory are processed and placed in the /app/styles/shared app-level styles directory. Any .css files that appear next to components or routes in the routes or modules directories are also processed and placed in the /app/styles/app directory.

The entire system can be illustrated as follows:

Source

/shared
└── css
    ├── app.css
    ├── base
    │   ├── autofill.css
    │   ├── base.css
    │   ├── fonts.css
    │   ├── reset.css
    │   ├── scrollbars.css
    │   └── typography.css
    ├── components
    │   ├── components.css
    │   ├── icon-element.css
    │   └── theme-switcher.css
    ├── layouts
    │   ├── global.css
    │   └── layouts.css
    └── tailwind.css
/app
├── modules
│   ├── home
│   │   ├── hero.css
│   │   ├── hero.tsx
│   │   └── index.ts
└── routes
    ├── index.css
    └── index.tsx

Output

/app
└── styles
   ├── app
   │   ├── modules
   │   │   └── home
   │   │   └── hero.css
   │   └── routes
   │   └── index.css
   └── shared
   └── css
   ├── app.css
   └── tailwind.css

This means of course that you will need to import stylesheets from the /app/styles directory, and not the source route, module or shared CSS directories. In order to 'surface' module-level stylesheets in a route, we followed the styling guide at Remix. It's not a perfect 'co-located' setup - but it works, and it was the best we could come up with for now. Again - suggestions welcome. You can see an example that combines the Hero.css stylesheet with the index.css stylesheet here in the index.tsx route.

Components and Design System

Building a complete design system including design language and tokens is not a small task and we've barely scratched the surface. We've mostly relied on Tailwind CSS utility classes and Tailwind plugins for typography, spacing and color. No effort was made to extract a configurable theme system (apart from the light and dark mode switcher). We simply built what worked. We also think there's value in 'intents' - such as 'primary', 'secondary', 'info', 'success', 'warning', 'danger' - and so button, alert and toast components implement an 'intent' system. We may create mapping definitions for these in tailwind.config.js to make swapping out a base color theme and color system easier.

Below is a brief introduction to the core components, where they came from, and how they've been configured. And here's what's on our current TODO list if you felt like lending a hand (take a look at the Contributions section).

Alert - supports 'intents', and is based on the Radix @radix-ui/react-primitive - which in turn means it supports 'slots' and the asChild prop - allowing you to takeover the alert completely, merging default alert styles and props with your own styles and props ('slot' uses React.cloneElement and mergeProps under the hood. It's very cool). Alerts are animated via Headless UI Transition.

[BreadcrumbTrail](https://github.com/infonomic/remix.infonomic.io/

Related Skills

View on GitHub
GitHub Stars47
CategoryDevelopment
Updated10mo ago
Forks5

Languages

TypeScript

Security Score

87/100

Audited on Jun 2, 2025

No findings