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

File Structure
src/
├── mod_sample/          # Your module
│   └── @routes/         # The routing entry point
│       ├── page.tsx     # -> http://localhost:3000/
│       └── about/
│           └── page.tsx # -> http://localhost:3000/about

Why 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.

src/mod_sample/@routes/hello/page.tsx
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

File Structure
src/
└── mod_sample/
    └── @routes/
        └── hello/
            └── world/
                └── page.tsx  <-- http://localhost:3000/hello/world

This 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):

Button.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.