Files
classroomio/apps/dashboard/ai/ROUTE_PAGE_SETUP.md
T
Rotimi BestandAbdulmuizz Hamzat 9fb6c7cbaa feat: migrate course UI from supabase (#615)
* chore: fix storybook build

* chore: implement theming

* community list not showing properly

* refactor: migrate Chip component to @cio/ui/custom/chip

- Updated imports for the Chip component across multiple files to use the new location in the @cio/ui package.
- Replaced the previous Chip implementation with a new version that utilizes a Badge for better styling and functionality.
- Adjusted related components to ensure consistent usage of the updated Chip component.

* fix: align course sidebar design to match organization design (#611)

* fix: align course sidebar design to match organization design

* feat: add hideSearch prop to AppHeader and update sidebar layout

---------

Co-authored-by: Rotimi Best <best@classroomio.com>

* refactor: replace PrimaryButton with Button component across multiple files

- Updated various components to use the new Button component from @cio/ui/base/button instead of the deprecated PrimaryButton.
- Ensured consistent button usage throughout the application for improved styling and functionality.
- Removed the PrimaryButton component and its associated constants from the codebase.

* refactor: standardize button and input usage across components

- Replaced instances of deprecated components such as TextField, TextArea, and IconButton with their updated counterparts (InputField, TextareaField, and updated IconButton).
- Ensured consistent event handling by changing `onClick` to `onclick` for better alignment with Svelte's event binding conventions.
- Removed unused components and streamlined imports to enhance code maintainability and readability.

* chore: themeing, course card, use $features

* refactor: centralize UI components and update modal implementations

- Refactored various components to centralize UI elements, improving discoverability and maintainability.
- Replaced deprecated modal components with the new Dialog component for consistent modal behavior across the application.
- Removed unused components and streamlined imports to enhance code clarity and reduce complexity.

* feat: add new documentation and refactor org and lms UI components

- Introduced new documentation files for Auth Flow, Breadcrumbs Refactoring, Page and Route Creation, and Route Page Setup to enhance developer onboarding and reference.
- Refactored various UI components, including the Course Sidebar and Lesson Modal, to improve layout and functionality.
- Removed deprecated components and streamlined imports for better maintainability.
- Updated translations across multiple languages to ensure consistency in user experience.

* refactor: update UI components and improve styling consistency

- Refactored various components to enhance styling consistency, including updates to button and text color classes.
- Removed deprecated components and streamlined imports for better maintainability.
- Replaced instances of PageBody with a more flexible Page component structure across multiple routes.
- Updated translations and UI elements to align with the new design system.
- Deleted unused components to reduce code complexity and improve clarity.

* update output.css

---------

Co-authored-by: Abdulmuizz Hamzat <103611443+canhamzacode@users.noreply.github.com>
2025-12-22 02:36:48 +01:00

288 lines
8.6 KiB
Markdown

# Route Page Setup Documentation
This document outlines the pattern for setting up page routes in the dashboard application. Follow this structure to maintain consistency across the codebase.
## Overview
The application follows a feature-based architecture where:
- **Route files** (`src/routes/org/[slug]/[feature]/+page.svelte`) are minimal wrappers that set up the Page structure
- **Feature pages** (`src/lib/features/[feature]/pages/[feature].svelte`) contain all business logic, state management, and UI components
- **Components** are organized in `src/lib/features/[feature]/components/` and exported via `index.ts`
- **Pages** are exported from `src/lib/features/[feature]/pages/index.ts`
## Directory Structure
```bash
apps/dashboard/src/
├── routes/
│ └── org/
│ └── [slug]/
│ └── [feature]/
│ └── +page.svelte # Minimal route wrapper
└── lib/
└── features/
└── [feature]/
├── components/
│ ├── [component].svelte
│ └── index.ts # Export all components
├── pages/
│ ├── [feature].svelte # Main feature page with all logic
│ └── index.ts # Export page component
├── utils/ # Feature-specific utilities
└── api/ # Feature-specific API calls
```
## Route File Pattern (`+page.svelte`)
The route file should be minimal and only contain:
1. **Page structure** using `@cio/ui/base/page` components
2. **Import and render** the feature page component
3. **Page metadata** (title, etc.)
### Example Route File
```svelte
<script>
import { FeaturePage } from '$features/[feature]/pages';
import { FeatureActionButton } from '$features/[feature]/components';
import { t } from '$lib/utils/functions/translations';
import * as Page from '@cio/ui/base/page';
</script>
<svelte:head>
<title>Feature Name - ClassroomIO</title>
</svelte:head>
<Page.Root class="w-full">
<Page.Header>
<Page.HeaderContent>
<Page.Title>{$t('feature.title')}</Page.Title>
</Page.HeaderContent>
<Page.Action>
<FeatureActionButton />
</Page.Action>
</Page.Header>
<Page.Body>
{#snippet child()}
<FeaturePage />
{/snippet}
</Page.Body>
</Page.Root>
```
### Route File Rules
- ✅ DO: Keep it minimal - only Page structure
- ✅ DO: Import feature page from `$features/[feature]/pages`
- ✅ DO: Import action buttons/components from `$features/[feature]/components`
- ✅ DO: Use `Page.Root`, `Page.Header`, `Page.HeaderContent`, `Page.Title`, `Page.Action`, `Page.Body`
- ❌ DON'T: Put business logic in route files
- ❌ DON'T: Put state management in route files
- ❌ DON'T: Put data fetching in route files
- ❌ DON'T: Put filters/search in route files (use `Page.BodyHeader` in feature page)
## Feature Page Pattern (`pages/[feature].svelte`)
The feature page contains all the business logic, state management, and UI components.
### Feature Page Structure
```svelte
<script lang="ts">
// 1. UI Component Imports
import { Empty } from '@cio/ui/custom/empty';
import { Search } from '@cio/ui/custom/search';
import * as Page from '@cio/ui/base/page';
import * as Select from '@cio/ui/base/select';
import { SomeIcon } from '@lucide/svelte/icons/...';
// 2. Feature Component Imports
import { FeatureCard, FeatureLoader, FeatureModal } from '../components';
// 3. Utility Imports
import { t } from '$lib/utils/functions/translations';
import { someStore } from '../utils/store';
import { fetchFeatureData } from '../api';
// 4. State Management
let isLoading = $state(false);
let searchValue = $state('');
let selectedId = $state('');
</script>
<FeatureModal />
<Page.BodyHeader align="right">
<Search placeholder="Search..." bind:value={searchValue} />
<Select.Root bind:value={selectedId}>
<!-- Select options -->
</Select.Root>
</Page.BodyHeader>
<!-- Main Content with States -->
<div class="w-full">
{#if isLoading}
<!-- Loading State -->
<FeatureLoader />
<FeatureLoader />
<FeatureLoader />
{:else if !data.length}
<!-- Empty State -->
<Empty
title={$t('feature.empty_title')}
description={$t('feature.empty_description')}
icon={SomeIcon}
variant="page"
>
<FeatureActionButton />
</Empty>
{:else}
<!-- Content -->
{#each data as item}
<FeatureCard {item} />
{/each}
{/if}
</div>
```
### Feature Page Rules
- ✅ DO: Use `Page.BodyHeader` for filters, search, and view toggles
- ✅ DO: Use `Empty` component from `@cio/ui/custom/empty` for empty states
- ✅ DO: Use `Search` component from `@cio/ui/custom/search` for search inputs
- ✅ DO: Handle loading states with skeleton/loader components
- ✅ DO: Export the page component from `pages/index.ts` as `[Feature]Page`
- ✅ DO: Keep all business logic in the feature page
- ❌ DON'T: Use `Page.Header` or `Page.Action` in feature pages (these are in route files)
- ❌ DON'T: Put route-specific logic in feature pages
## Component Organization
### Components Directory
Create reusable components specific to the feature:
```bash
components/
├── feature-card.svelte
├── feature-loader.svelte
├── feature-modal.svelte
└── index.ts
```
### Components Index (`components/index.ts`)
```typescript
export { default as FeatureCard } from './feature-card.svelte';
export { default as FeatureLoader } from './feature-loader.svelte';
export { default as FeatureModal } from './feature-modal.svelte';
export { default as FeatureActionButton } from './feature-action-button.svelte';
```
## Pages Index (`pages/index.ts`)
```typescript
export { default as FeaturePage } from './feature.svelte';
```
## Complete Example
### Route File: `routes/org/[slug]/community/+page.svelte`
```svelte
<script>
import { CommunityPage } from '$features/community/pages';
import { AskCommunityButton } from '$features/community/components';
import { t } from '$lib/utils/functions/translations';
import * as Page from '@cio/ui/base/page';
</script>
<svelte:head>
<title>Community - ClassroomIO</title>
</svelte:head>
<Page.Root class="w-full">
<Page.Header>
<Page.HeaderContent>
<Page.Title>{$t('community.title')}</Page.Title>
</Page.HeaderContent>
<Page.Action>
<AskCommunityButton />
</Page.Action>
</Page.Header>
<Page.Body>
{#snippet child()}
<CommunityPage />
{/snippet}
</Page.Body>
</Page.Root>
```
### Feature Page: `lib/features/community/pages/community.svelte`
```svelte
<script lang="ts">
import { Search } from '@cio/ui/custom/search';
import { Empty } from '@cio/ui/custom/empty';
import * as Page from '@cio/ui/base/page';
import * as Select from '@cio/ui/base/select';
import MessageSquareMoreIcon from '@lucide/svelte/icons/message-square-more';
import { CommunityListLoader, AskCommunityButton } from '../components';
// ... other imports
let isLoading = $state(false);
let searchValue = $state('');
let discussions = $state([]);
// ... logic
</script>
<Page.BodyHeader>
<Search placeholder="Search..." bind:value={searchValue} />
<Select.Root>
<!-- Select options -->
</Select.Root>
</Page.BodyHeader>
{#if isLoading}
<CommunityListLoader />
{:else}
{#each discussions as discussion}
<!-- Discussion content -->
{:else}
<Empty
title={$t('community.no_question')}
description={$t('community.ask_a_question')}
icon={MessageSquareMoreIcon}
>
<AskCommunityButton />
</Empty>
{/each}
{/if}
```
## Key Patterns
1. **Separation of Concerns**: Route files handle routing structure, feature pages handle business logic
2. **Reusability**: Feature pages can be imported and used in different contexts
3. **Consistency**: All pages follow the same structure for maintainability
4. **Design System**: Use `Page.BodyHeader` for filters, `Empty` for empty states, `Search` for search inputs
5. **State Management**: Keep state local to feature pages or use feature-specific stores
## Migration Checklist
When refactoring an existing route:
- [ ] Create feature directory structure (`lib/features/[feature]/`)
- [ ] Move business logic from route file to feature page
- [ ] Extract components to `components/` directory
- [ ] Create `components/index.ts` with exports
- [ ] Create `pages/index.ts` with page export
- [ ] Update route file to be minimal wrapper
- [ ] Add `Page.BodyHeader` for filters/search if needed
- [ ] Replace custom empty states with `Empty` component
- [ ] Replace custom search inputs with `Search` component
- [ ] Test all functionality works correctly