* 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 <[email protected]> * 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 <[email protected]>
8.6 KiB
8.6 KiB
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 viaindex.ts - Pages are exported from
src/lib/features/[feature]/pages/index.ts
Directory Structure
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:
- Page structure using
@cio/ui/base/pagecomponents - Import and render the feature page component
- Page metadata (title, etc.)
Example Route File
<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.BodyHeaderin feature page)
Feature Page Pattern (pages/[feature].svelte)
The feature page contains all the business logic, state management, and UI components.
Feature Page Structure
<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.BodyHeaderfor filters, search, and view toggles - ✅ DO: Use
Emptycomponent from@cio/ui/custom/emptyfor empty states - ✅ DO: Use
Searchcomponent from@cio/ui/custom/searchfor search inputs - ✅ DO: Handle loading states with skeleton/loader components
- ✅ DO: Export the page component from
pages/index.tsas[Feature]Page - ✅ DO: Keep all business logic in the feature page
- ❌ DON'T: Use
Page.HeaderorPage.Actionin 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:
components/
├── feature-card.svelte
├── feature-loader.svelte
├── feature-modal.svelte
└── index.ts
Components Index (components/index.ts)
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)
export { default as FeaturePage } from './feature.svelte';
Complete Example
Route File: routes/org/[slug]/community/+page.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
<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
- Separation of Concerns: Route files handle routing structure, feature pages handle business logic
- Reusability: Feature pages can be imported and used in different contexts
- Consistency: All pages follow the same structure for maintainability
- Design System: Use
Page.BodyHeaderfor filters,Emptyfor empty states,Searchfor search inputs - 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.tswith exports - Create
pages/index.tswith page export - Update route file to be minimal wrapper
- Add
Page.BodyHeaderfor filters/search if needed - Replace custom empty states with
Emptycomponent - Replace custom search inputs with
Searchcomponent - Test all functionality works correctly