Add Website Pages
Learn how to create pages, add images, and style your JopiJS application.
Overview
In this guide, we will explore the core of building a JopiJS website: creating pages and styling them.
You will learn how to:
- Understand the project structure.
- Create new pages and nested routes.
- Add static assets like images.
- Style your components using CSS Modules.
1. Project Structure & Modules
JopiJS organizes code into Modules. Even a simple application has at least one module (e.g., mod_sample). Inside a module, the @routes folder is where the magic happens.
The @routes folder
Any file mapped inside a @routes folder becomes a page accessible via the browser.
src/mod_sample/@routes/about/page.tsx
src/
├── mod_sample/ # Your module
│ └── @routes/ # The routing entry point
│ ├── page.tsx # -> http://localhost:3000/
│ └── about/
│ └── page.tsx # -> http://localhost:3000/aboutWhy Modules?
Dividing your app into modules keeps features organized and decoupled.
As your application grows, you will find this structure invaluable for maintainability.
2. Creating Your First Page
Let's create a new page accessible at /hello.
Simply create a folder named hello inside @routes, and add a page.tsx file inside it.
import { usePageTitle } from "jopijs/ui";
import { JopiPageProps } from "jopijs/ui";
export default function HelloPage(props: JopiPageProps) {
// 1. Set the HTML <title> of the page
usePageTitle("Hello World");
// 2. Return standard React JSX
// Note: Tailwind CSS is available by default!
return (
<div className="p-10">
<h1 className="text-2xl font-bold text-blue-600">
Welcome to my new page!
</h1>
<p className="mt-4">
This page lives at <code>/hello</code>.
</p>
</div>
);
}Now, visit http://localhost:3000/hello to see your page.
3. Nested Routes
Creating nested URLs is as simple as creating nested folders.
To create a page at /hello/world, just create the corresponding folder structure:
src/mod_sample/@routes/hello/world/page.tsx
src/
└── mod_sample/
└── @routes/
└── hello/
└── world/
└── page.tsx <-- http://localhost:3000/hello/worldThis file-system based routing makes it easy to visualize your website's structure just by looking at your files.
4. Adding Images
JopiJS allows you to works with images in an easy way. You don't need to manually place files in a public folder. Instead, import them directly into your component.
// Import the image file directly
import logo from "./jopiLogo.png";
export default function ImagePage() {
return (
<div className="text-center">
<h3>My Awesome Logo</h3>
{/* Use the imported variable as the src */}
<img src={logo} alt="Jopi Logo" width={200} />
</div>
);
}Key benefits:
- Automatic Optimization: Small images might be inlined as base64 to save requests.
- Hashing: Files are hashed for efficient browser caching.
5. Styling with CSS Modules
While JopiJS supports Tailwind CSS out of the box, you might prefer writing custom CSS. For this, CSS Modules are the recommended approach.
Why CSS Modules?
Standard CSS files are global, meaning a class named .button could conflict with another .button style elsewhere. CSS Modules solve this by automatically treating classes as unique to that specific file.
Example
1. Create the style file (must end in .module.css):
/* This class will be strictly scoped to the component importing it */
.container {
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
}
.title {
color: royalblue;
font-size: 1.5rem;
}2. Use it in your component:
import { useCssModule } from "jopijs/ui";
// Import the module. 'styles' will contain the mapped class names.
import styles from "./Button.module.css";
export default function StyledPage() {
// Inject the styles into the page
useCssModule(styles);
return (
<div className={styles.container}>
<h1 className={styles.title}>Scoped CSS is great!</h1>
</div>
);
}Performance Tip: CSS Modules are inlined into the HTML. This reduces network requests (no separate .css file to fetch) and ensures the fastest possible initial paint, which is great for SEO.