Chapter 1: Layout

Page

The Page component is the main container for each screen. It manages:

  • Page title
  • Transition animations
  • Scroll

Basic Syntax

import { Page } from '@cap-rel/smartcommon';

function HomePage() {
    return (
        <Page title="Home">
            <p>Page content</p>
        </Page>
    );
}

Main Props

Prop Type Default Description
title string - Title displayed in the navbar
subtitle string - Optional subtitle
className string - Additional CSS classes
onRefresh function - Pull-to-refresh callback

Page with Refresh

function ItemsPage() {
    const [items, setItems] = useState([]);

    const handleRefresh = async () => {
        const data = await api.private.get('items').json();
        setItems(data);
    };

    return (
        <Page title="My Items" onRefresh={handleRefresh}>
            {items.map(item => (
                <div key={item.id}>{item.label}</div>
            ))}
        </Page>
    );
}

Block

The Block component structures content into distinct visual sections.

Basic Syntax

import { Page, Block } from '@cap-rel/smartcommon';

function ProfilePage() {
    return (
        <Page title="Profile">
            <Block>
                <h2>Personal Information</h2>
                <p>Name: John Doe</p>
            </Block>

            <Block>
                <h2>Preferences</h2>
                <p>Language: French</p>
            </Block>
        </Page>
    );
}

Props

Prop Type Default Description
title string - Block title
className string - Additional CSS classes
padding boolean true Add internal padding

Block with Title

<Block title="Information">
    <p>Block content</p>
</Block>

Panel

The Panel component displays a sliding panel from the side of the screen.

Syntax

import { useState } from 'react';
import { Page, Block, Button, Panel } from '@cap-rel/smartcommon';

function MyPage() {
    const [isPanelOpen, setIsPanelOpen] = useState(false);

    return (
        <Page title="My Page">
            <Block>
                <Button onClick={() => setIsPanelOpen(true)}>
                    Open Panel
                </Button>
            </Block>

            <Panel
                isOpen={isPanelOpen}
                onClose={() => setIsPanelOpen(false)}
                position="right"
            >
                <h2>Panel Content</h2>
                <p>Additional information</p>
            </Panel>
        </Page>
    );
}

Props

Prop Type Default Description
isOpen boolean false Controls display
onClose function - Close callback
position string 'right' 'left', 'right', 'top', 'bottom'
title string - Panel title

The Popup component displays a centered modal window.

Syntax

import { useState } from 'react';
import { Page, Block, Button, Popup } from '@cap-rel/smartcommon';

function MyPage() {
    const [isPopupOpen, setIsPopupOpen] = useState(false);

    return (
        <Page title="My Page">
            <Block>
                <Button onClick={() => setIsPopupOpen(true)}>
                    Delete
                </Button>
            </Block>

            <Popup
                isOpen={isPopupOpen}
                onClose={() => setIsPopupOpen(false)}
                title="Confirmation"
            >
                <p>Are you sure you want to delete this item?</p>
                <div className="flex gap-2 mt-4">
                    <Button onClick={() => setIsPopupOpen(false)}>
                        Cancel
                    </Button>
                    <Button variant="danger" onClick={handleDelete}>
                        Delete
                    </Button>
                </div>
            </Popup>
        </Page>
    );
}

Props

Prop Type Default Description
isOpen boolean false Controls display
onClose function - Close callback
title string - Popup title
closeOnOverlay boolean true Close on overlay click

Complete Example

import { useState } from 'react';
import {
    Page,
    Block,
    Panel,
    Popup,
    Button,
    List,
    ListItem
} from '@cap-rel/smartcommon';

export const ProductsPage = () => {
    const [selectedProduct, setSelectedProduct] = useState(null);
    const [showDeletePopup, setShowDeletePopup] = useState(false);
    const [showFilters, setShowFilters] = useState(false);

    const products = [
        { id: 1, label: 'Product A', price: 29.99 },
        { id: 2, label: 'Product B', price: 49.99 },
        { id: 3, label: 'Product C', price: 19.99 }
    ];

    const handleDelete = async () => {
        // Delete product
        console.log('Deleting', selectedProduct);
        setShowDeletePopup(false);
        setSelectedProduct(null);
    };

    return (
        <Page title="Products">
            {/* Actions */}
            <Block>
                <Button onClick={() => setShowFilters(true)}>
                    Filters
                </Button>
            </Block>

            {/* List */}
            <Block title="Catalog">
                <List>
                    {products.map(product => (
                        <ListItem
                            key={product.id}
                            title={product.label}
                            subtitle={`${product.price} €`}
                            onClick={() => setSelectedProduct(product)}
                            actions={
                                <Button
                                    size="sm"
                                    variant="danger"
                                    onClick={(e) => {
                                        e.stopPropagation();
                                        setSelectedProduct(product);
                                        setShowDeletePopup(true);
                                    }}
                                >
                                    Delete
                                </Button>
                            }
                        />
                    ))}
                </List>
            </Block>

            {/* Filter Panel */}
            <Panel
                isOpen={showFilters}
                onClose={() => setShowFilters(false)}
                title="Filters"
                position="right"
            >
                <p>Filter options here</p>
            </Panel>

            {/* Confirmation Popup */}
            <Popup
                isOpen={showDeletePopup}
                onClose={() => setShowDeletePopup(false)}
                title="Confirm Deletion"
            >
                <p>
                    Delete "{selectedProduct?.label}"?
                </p>
                <div className="flex gap-2 mt-4">
                    <Button onClick={() => setShowDeletePopup(false)}>
                        Cancel
                    </Button>
                    <Button variant="danger" onClick={handleDelete}>
                        Delete
                    </Button>
                </div>
            </Popup>
        </Page>
    );
};

Best Practices

  1. One Page per route component
  2. Use Block to group content logically
  3. Panel for secondary actions (filters, details)
  4. Popup for confirmations and critical actions

Key Points to Remember

  1. Page = main container with title and animations
  2. Block = content section with styling
  3. Panel = sliding side panel
  4. Popup = centered modal for confirmations

Back to Module | Next Chapter: Navigation ->