feat: Add documentation and context for frontend architecture
Some checks failed
Lint / lint (20.x) (pull_request) Has been cancelled
Some checks failed
Lint / lint (20.x) (pull_request) Has been cancelled
This commit introduces several key improvements to the frontend architecture: - Created comprehensive documentation for TSDoc and TypeDoc usage - Added WalletContext for managing wallet connection state - Updated navigation and project components - Introduced layout and routing strategy documentation - Removed unused imports and commented code - Enhanced project search and navigation components
This commit is contained in:
parent
e1c2a8ce2c
commit
6f64513fc8
165
DOCUMENTATION.md
Normal file
165
DOCUMENTATION.md
Normal file
@ -0,0 +1,165 @@
|
||||
# Documentation Guide for Snowball Tools
|
||||
|
||||
This guide explains how to write and generate documentation for the Snowball Tools project.
|
||||
|
||||
## TSDoc and TypeDoc
|
||||
|
||||
We use [TSDoc](https://tsdoc.org/) for documenting our TypeScript code and [TypeDoc](https://typedoc.org/) for generating API documentation from those comments.
|
||||
|
||||
## Writing Documentation
|
||||
|
||||
### Basic Comment Structure
|
||||
|
||||
TSDoc comments start with `/**` and end with `*/`. Each line within the comment block typically starts with a `*`.
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* This is a TSDoc comment.
|
||||
*/
|
||||
```
|
||||
|
||||
### Documenting Functions
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Calculates the sum of two numbers.
|
||||
*
|
||||
* @param a - The first number
|
||||
* @param b - The second number
|
||||
* @returns The sum of a and b
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const result = add(1, 2);
|
||||
* console.log(result); // 3
|
||||
* ```
|
||||
*/
|
||||
function add(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
### Documenting Classes
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Represents a user in the system.
|
||||
*
|
||||
* @remarks
|
||||
* This class is used throughout the application to represent user data.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const user = new User('John', 'Doe');
|
||||
* console.log(user.fullName); // "John Doe"
|
||||
* ```
|
||||
*/
|
||||
class User {
|
||||
/**
|
||||
* Creates a new User instance.
|
||||
*
|
||||
* @param firstName - The user's first name
|
||||
* @param lastName - The user's last name
|
||||
*/
|
||||
constructor(
|
||||
/** The user's first name */
|
||||
public firstName: string,
|
||||
/** The user's last name */
|
||||
public lastName: string
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Gets the user's full name.
|
||||
*/
|
||||
get fullName(): string {
|
||||
return `${this.firstName} ${this.lastName}`;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Documenting Interfaces
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Configuration options for the application.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
interface AppConfig {
|
||||
/**
|
||||
* The port number the server should listen on.
|
||||
* @default 3000
|
||||
*/
|
||||
port: number;
|
||||
|
||||
/**
|
||||
* The host the server should bind to.
|
||||
* @default "localhost"
|
||||
*/
|
||||
host: string;
|
||||
|
||||
/**
|
||||
* Whether to enable debug mode.
|
||||
* @default false
|
||||
*/
|
||||
debug?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
## Common TSDoc Tags
|
||||
|
||||
| Tag | Description |
|
||||
|-----|-------------|
|
||||
| `@param` | Documents a function parameter |
|
||||
| `@returns` | Documents the return value |
|
||||
| `@throws` | Documents exceptions that might be thrown |
|
||||
| `@example` | Provides an example of usage |
|
||||
| `@remarks` | Adds additional information |
|
||||
| `@deprecated` | Marks an item as deprecated |
|
||||
| `@see` | Refers to related documentation |
|
||||
| `@default` | Documents the default value |
|
||||
| `@public`, `@protected`, `@private` | Visibility modifiers |
|
||||
| `@internal` | Marks an item as internal (not part of the public API) |
|
||||
| `@beta` | Marks an item as in beta stage |
|
||||
| `@alpha` | Marks an item as in alpha stage |
|
||||
| `@experimental` | Marks an item as experimental |
|
||||
|
||||
## Generating Documentation
|
||||
|
||||
To generate documentation for the project, run:
|
||||
|
||||
```bash
|
||||
yarn docs
|
||||
```
|
||||
|
||||
This will create a `docs` directory with the generated documentation.
|
||||
|
||||
To watch for changes and regenerate documentation automatically:
|
||||
|
||||
```bash
|
||||
yarn docs:watch
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Document Public APIs**: Always document public APIs thoroughly.
|
||||
2. **Include Examples**: Provide examples for complex functions or classes.
|
||||
3. **Be Concise**: Keep documentation clear and to the point.
|
||||
4. **Use Proper Grammar**: Use proper grammar and punctuation.
|
||||
5. **Update Documentation**: Keep documentation in sync with code changes.
|
||||
6. **Document Parameters**: Document all parameters, including their types and purpose.
|
||||
7. **Document Return Values**: Document what a function returns.
|
||||
8. **Document Exceptions**: Document any exceptions that might be thrown.
|
||||
|
||||
## Example Files
|
||||
|
||||
For reference, check out these example files that demonstrate proper TSDoc usage:
|
||||
|
||||
- `packages/backend/src/utils/tsdoc-example.ts`
|
||||
- `packages/frontend/src/utils/tsdoc-example.ts`
|
||||
|
||||
## Resources
|
||||
|
||||
- [TSDoc Official Documentation](https://tsdoc.org/)
|
||||
- [TypeDoc Official Documentation](https://typedoc.org/)
|
||||
- [TypeScript Documentation](https://www.typescriptlang.org/docs/)
|
@ -1,6 +1,5 @@
|
||||
import { cn } from '@/lib/utils';
|
||||
import { TopNavigation } from './TopNavigation';
|
||||
import { useGitHubAuth } from '@/hooks/useGitHubAuth';
|
||||
|
||||
/**
|
||||
* NavigationWrapperProps interface extends React.HTMLProps<HTMLDivElement> to include all standard HTML div attributes.
|
||||
@ -23,7 +22,7 @@ export function NavigationWrapper({
|
||||
className,
|
||||
...props
|
||||
}: NavigationWrapperProps) {
|
||||
const { isAuthenticated } = useGitHubAuth();
|
||||
// const { isAuthenticated } = useGitHubAuth();
|
||||
|
||||
return (
|
||||
<div className={cn('min-h-screen bg-background', className)} {...props}>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { Card, CardContent, CardHeader } from '@/components/ui/card';
|
||||
import { getInitials } from '@/utils/geInitials';
|
||||
import { Project } from 'gql-client';
|
||||
import { AlertTriangle } from 'lucide-react';
|
||||
@ -16,7 +16,7 @@ export type ProjectStatus = 'success' | 'in-progress' | 'failure' | 'pending';
|
||||
|
||||
/**
|
||||
* Props for the ProjectCard component
|
||||
*
|
||||
*
|
||||
* @property {Project} project - The project data to display
|
||||
* @property {ProjectStatus} [status='failure'] - The current deployment status of the project
|
||||
*/
|
||||
@ -27,7 +27,7 @@ interface ProjectCardProps extends ComponentPropsWithoutRef<'div'> {
|
||||
|
||||
/**
|
||||
* ProjectCard component
|
||||
*
|
||||
*
|
||||
* Displays a card with project information including:
|
||||
* - Project name and icon
|
||||
* - Domain URL (if available)
|
||||
@ -35,14 +35,14 @@ interface ProjectCardProps extends ComponentPropsWithoutRef<'div'> {
|
||||
* - Latest commit information
|
||||
* - Timestamp and branch information
|
||||
* - Actions menu for project settings and deletion
|
||||
*
|
||||
*
|
||||
* The card is clickable and navigates to the project details page.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <ProjectCard
|
||||
* project={projectData}
|
||||
* status="success"
|
||||
* <ProjectCard
|
||||
* project={projectData}
|
||||
* status="success"
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
@ -98,16 +98,19 @@ export const ProjectCard = ({
|
||||
</Avatar>
|
||||
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<p className="text-sm font-semibold text-foreground leading-none">{project.name}</p>
|
||||
<p className="text-sm font-semibold text-foreground leading-none">
|
||||
{project.name}
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground leading-5">
|
||||
{project.deployments[0]?.applicationDeploymentRecordData?.url ?? 'No domain'}
|
||||
{project.deployments[0]?.applicationDeploymentRecordData?.url ??
|
||||
'No domain'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
{hasError && <AlertTriangle className="text-destructive h-4 w-4" />}
|
||||
<ProjectCardActions
|
||||
<ProjectCardActions
|
||||
onSettingsClick={handleSettingsClick}
|
||||
onDeleteClick={handleDeleteClick}
|
||||
/>
|
||||
|
122
packages/frontend/src/context/WalletContext.tsx
Normal file
122
packages/frontend/src/context/WalletContext.tsx
Normal file
@ -0,0 +1,122 @@
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import React, {
|
||||
createContext,
|
||||
ReactNode,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
/**
|
||||
* @interface WalletContextType
|
||||
* @description Defines the structure of the WalletContext value.
|
||||
* @property {object | null} wallet - The wallet object containing id and address.
|
||||
* @property {boolean} isConnected - Indicates if the wallet is connected.
|
||||
* @property {function} connect - Function to connect the wallet.
|
||||
* @property {function} disconnect - Function to disconnect the wallet.
|
||||
*/
|
||||
interface WalletContextType {
|
||||
wallet: {
|
||||
id: string;
|
||||
address?: string;
|
||||
} | null;
|
||||
isConnected: boolean;
|
||||
connect: () => Promise<void>;
|
||||
disconnect: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @const WalletContext
|
||||
* @description Creates a context for managing wallet connection state.
|
||||
*/
|
||||
const WalletContext = createContext<WalletContextType | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* @component WalletProvider
|
||||
* @description Provides the WalletContext to its children.
|
||||
* @param {Object} props - Component props
|
||||
* @param {ReactNode} props.children - The children to render.
|
||||
*/
|
||||
export const WalletProvider: React.FC<{ children: ReactNode }> = ({
|
||||
children,
|
||||
}) => {
|
||||
const [wallet, setWallet] = useState<WalletContextType['wallet']>(null);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const { toast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
const handleWalletMessage = (event: MessageEvent) => {
|
||||
if (event.origin !== import.meta.env.VITE_WALLET_IFRAME_URL) return;
|
||||
|
||||
if (event.data.type === 'WALLET_ACCOUNTS_DATA') {
|
||||
const address = event.data.data[0].address;
|
||||
setWallet({
|
||||
id: address,
|
||||
address: address,
|
||||
});
|
||||
setIsConnected(true);
|
||||
toast({
|
||||
title: 'Wallet Connected',
|
||||
// variant: 'success',
|
||||
duration: 3000,
|
||||
// id: '',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', handleWalletMessage);
|
||||
return () => window.removeEventListener('message', handleWalletMessage);
|
||||
}, [toast]);
|
||||
|
||||
const connect = async () => {
|
||||
const iframe = document.getElementById('walletIframe') as HTMLIFrameElement;
|
||||
if (iframe?.contentWindow) {
|
||||
iframe.contentWindow.postMessage(
|
||||
{
|
||||
type: 'REQUEST_WALLET_ACCOUNTS',
|
||||
chainId: import.meta.env.VITE_LACONICD_CHAIN_ID,
|
||||
},
|
||||
import.meta.env.VITE_WALLET_IFRAME_URL,
|
||||
);
|
||||
} else {
|
||||
toast({
|
||||
title: 'Wallet Connection Failed',
|
||||
description: 'Wallet iframe not found or not loaded',
|
||||
// variant: 'error',
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const disconnect = () => {
|
||||
setWallet(null);
|
||||
setIsConnected(false);
|
||||
toast({
|
||||
title: 'Wallet Disconnected',
|
||||
// variant: 'info',
|
||||
duration: 3000,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<WalletContext.Provider
|
||||
value={{ wallet, isConnected, connect, disconnect }}
|
||||
>
|
||||
{children}
|
||||
</WalletContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @function useWallet
|
||||
* @description A hook that provides access to the WalletContext.
|
||||
* @returns {WalletContextType} The wallet context value.
|
||||
* @throws {Error} If used outside of a WalletProvider.
|
||||
*/
|
||||
export const useWallet = () => {
|
||||
const context = useContext(WalletContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useWallet must be used within a WalletProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
@ -1,6 +1,11 @@
|
||||
import { ScreenWrapper } from '@/components/layout';
|
||||
import { ProjectSearchBar } from '@/components/projects/ProjectSearchBar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useWallet } from '@/context';
|
||||
import { useGQLClient } from '@/context/GQLClientContext';
|
||||
import { useWallet } from '@/context/WalletContextProvider';
|
||||
import { formatAddress } from '@/utils/format';
|
||||
import { User } from 'gql-client';
|
||||
import { Bell, Plus } from 'lucide-react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
|
||||
@ -28,53 +33,50 @@ const ProjectSearchLayout = () => {
|
||||
}, [client]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Outlet />
|
||||
</>
|
||||
// <ScreenWrapper padded={false}>
|
||||
// <div className="flex flex-col h-full">
|
||||
// {/* Header */}
|
||||
// <div className="bg-background dark:bg-overlay hover:z-30 sticky top-0 border-b">
|
||||
// <div className="flex items-center gap-4 px-6 py-4">
|
||||
// <div className="flex-1">
|
||||
// <ProjectSearchBar
|
||||
// onChange={(project) => {
|
||||
// navigate(
|
||||
// `/${project.organization.slug}/projects/${project.id}`,
|
||||
// );
|
||||
// }}
|
||||
// />
|
||||
// </div>
|
||||
// <div className="flex items-center gap-3">
|
||||
// <Button
|
||||
// variant="secondary"
|
||||
// size="icon"
|
||||
// onClick={() => {
|
||||
// fetchOrgSlug().then((organizationSlug) => {
|
||||
// navigate(`/${organizationSlug}/projects/create`);
|
||||
// });
|
||||
// }}
|
||||
// >
|
||||
// <Plus className="w-4 h-4" />
|
||||
// </Button>
|
||||
// <Button variant="ghost" size="icon">
|
||||
// <Bell className="w-4 h-4" />
|
||||
// </Button>
|
||||
// {user?.name && (
|
||||
// <p className="text-sm tracking-[-0.006em] text-muted-foreground">
|
||||
// {formatAddress(user.name)}
|
||||
// </p>
|
||||
// )}
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
<ScreenWrapper padded={false}>
|
||||
<div className="flex flex-col h-full">
|
||||
{/* Header */}
|
||||
<div className="bg-background dark:bg-overlay hover:z-30 sticky top-0 border-b">
|
||||
<div className="flex items-center gap-4 px-6 py-4">
|
||||
<div className="flex-1">
|
||||
<ProjectSearchBar
|
||||
onChange={(project) => {
|
||||
navigate(
|
||||
`/${project.organization.slug}/projects/${project.id}`,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
onClick={() => {
|
||||
fetchOrgSlug().then((organizationSlug) => {
|
||||
navigate(`/${organizationSlug}/projects/create`);
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon">
|
||||
<Bell className="w-4 h-4" />
|
||||
</Button>
|
||||
{user?.name && (
|
||||
<p className="text-sm tracking-[-0.006em] text-muted-foreground">
|
||||
{formatAddress(user.name)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// {/* Content */}
|
||||
// <div className="flex-1 overflow-y-auto">
|
||||
// <Outlet />
|
||||
// </div>
|
||||
// </div>
|
||||
// </ScreenWrapper>
|
||||
{/* Content */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
</ScreenWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
|
110
qwrk/docs/frontend/SHADCN_MIGRATION.md
Normal file
110
qwrk/docs/frontend/SHADCN_MIGRATION.md
Normal file
@ -0,0 +1,110 @@
|
||||
# Shadcn Migration Plan
|
||||
|
||||
## Overview
|
||||
|
||||
Migration from legacy shared components to shadcn/ui components and lucide-react icons.
|
||||
|
||||
## 1. Icon Migration Phase
|
||||
|
||||
### Lucide Icon Mappings
|
||||
|
||||
| Current Custom Icon | Lucide Equivalent |
|
||||
| ------------------------- | ----------------- |
|
||||
| ArrowLeftCircleFilledIcon | ArrowLeftCircle |
|
||||
| ArrowRightCircleIcon | ArrowRight |
|
||||
| BranchIcon | GitBranch |
|
||||
| BuildingIcon | Building2 |
|
||||
| CalendarIcon | Calendar |
|
||||
| CheckIcon | Check |
|
||||
| ChevronDownIcon | ChevronDown |
|
||||
| ClockIcon | Clock |
|
||||
| CopyIcon | Copy |
|
||||
| CrossIcon | X |
|
||||
| EditBigIcon | Edit |
|
||||
| GearIcon | Settings |
|
||||
| GithubIcon | Github |
|
||||
| LoaderIcon | Loader2 |
|
||||
| LockIcon | Lock |
|
||||
| PlusIcon | Plus |
|
||||
| SearchIcon | Search |
|
||||
| TrashIcon | Trash2 |
|
||||
| WarningIcon | AlertTriangle |
|
||||
|
||||
### Steps
|
||||
|
||||
1. Install lucide-react
|
||||
2. Replace custom icons with Lucide equivalents
|
||||
3. Remove CustomIcon directory
|
||||
4. Update all icon imports
|
||||
|
||||
## 2. Component Migration Phase
|
||||
|
||||
### Direct Replacements
|
||||
|
||||
| Legacy Component | Shadcn Component |
|
||||
| ---------------- | ------------------ |
|
||||
| Button | ui/button.tsx |
|
||||
| Input | ui/input.tsx |
|
||||
| Select | ui/select.tsx |
|
||||
| Calendar | ui/calendar.tsx |
|
||||
| Checkbox | ui/checkbox.tsx |
|
||||
| Modal | ui/dialog.tsx |
|
||||
| Radio | ui/radio-group.tsx |
|
||||
| Switch | ui/switch.tsx |
|
||||
| Table | ui/table.tsx |
|
||||
| Tabs | ui/tabs.tsx |
|
||||
| Toast | ui/toast.tsx |
|
||||
| Tooltip | ui/tooltip.tsx |
|
||||
|
||||
### Steps
|
||||
|
||||
1. Remove each shared component
|
||||
2. Update imports to use shadcn components
|
||||
3. Fix TypeScript errors as they appear
|
||||
4. Test each component replacement
|
||||
|
||||
## 3. Special Components Phase
|
||||
|
||||
### Components Requiring Custom Handling
|
||||
|
||||
- AsyncSelect (needs custom implementation)
|
||||
- Any components with specific business logic
|
||||
|
||||
### Steps
|
||||
|
||||
1. Identify components needing special handling
|
||||
2. Create custom implementations where needed
|
||||
3. Test thoroughly
|
||||
|
||||
## 4. Theme Migration Phase
|
||||
|
||||
### Steps
|
||||
|
||||
1. Map theme properties to Tailwind classes
|
||||
2. Update component styling
|
||||
3. Remove .theme.ts files
|
||||
4. Verify visual consistency
|
||||
|
||||
## 5. Testing & Validation Phase
|
||||
|
||||
### Steps
|
||||
|
||||
1. Run TypeScript checks
|
||||
2. Visual testing of all components
|
||||
3. Test all interactive features
|
||||
4. Performance testing
|
||||
5. Cross-browser testing
|
||||
|
||||
## Progress Tracking
|
||||
|
||||
- [ ] Icon Migration Complete
|
||||
- [ ] Component Migration Complete
|
||||
- [ ] Special Components Handled
|
||||
- [ ] Theme Migration Complete
|
||||
- [ ] Testing & Validation Complete
|
||||
|
||||
## Notes
|
||||
|
||||
- Keep track of any components that need special attention
|
||||
- Document any deviations from the plan
|
||||
- Note any breaking changes
|
130
qwrk/docs/frontend/layouts/LAYOUT_STRATEGY.md
Normal file
130
qwrk/docs/frontend/layouts/LAYOUT_STRATEGY.md
Normal file
@ -0,0 +1,130 @@
|
||||
# Layout Strategy with Vite & React Router
|
||||
|
||||
## Core Principles
|
||||
|
||||
1. **NavigationWrapper**
|
||||
|
||||
- Top-level container for global navigation
|
||||
- Handles responsive mobile/desktop navigation
|
||||
- Manages global navigation state
|
||||
|
||||
2. **ScreenWrapper**
|
||||
|
||||
- Standard content area with consistent spacing
|
||||
- Responsive padding and margins
|
||||
- Handles viewport height calculations
|
||||
- Flex column layout by default
|
||||
|
||||
3. **Header Components**
|
||||
|
||||
- Consistent page headers with title and subtitle
|
||||
- Optional action buttons
|
||||
- Supports compact and default layouts
|
||||
- Responsive mobile/desktop behavior
|
||||
|
||||
4. **TabWrapper**
|
||||
- Standardized tabbed navigation
|
||||
- Supports horizontal and vertical orientations
|
||||
- Consistent styling and interactions
|
||||
- Built on shared tab components
|
||||
|
||||
## Implementation Guide
|
||||
|
||||
### 1. Basic Page Structure
|
||||
|
||||
```typescript
|
||||
import { NavigationWrapper, ScreenWrapper, Header } from '@/components/layout';
|
||||
|
||||
function BasicPage() {
|
||||
return (
|
||||
<NavigationWrapper>
|
||||
<ScreenWrapper>
|
||||
<Header
|
||||
title="Page Title"
|
||||
subtitle="Optional subtitle"
|
||||
actions={[<Button>Action</Button>]}
|
||||
/>
|
||||
<main>
|
||||
{/* Page content */}
|
||||
</main>
|
||||
</ScreenWrapper>
|
||||
</NavigationWrapper>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Tabbed Page Structure
|
||||
|
||||
```typescript
|
||||
import {
|
||||
NavigationWrapper,
|
||||
ScreenWrapper,
|
||||
Header,
|
||||
TabWrapper,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
TabsContent
|
||||
} from '@/components/layout';
|
||||
|
||||
function TabbedPage() {
|
||||
return (
|
||||
<NavigationWrapper>
|
||||
<ScreenWrapper>
|
||||
<Header title="Tabbed Page" />
|
||||
<TabWrapper defaultValue="tab1">
|
||||
<TabsList>
|
||||
<TabsTrigger value="tab1">Tab 1</TabsTrigger>
|
||||
<TabsTrigger value="tab2">Tab 2</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="tab1">
|
||||
Content 1
|
||||
</TabsContent>
|
||||
<TabsContent value="tab2">
|
||||
Content 2
|
||||
</TabsContent>
|
||||
</TabWrapper>
|
||||
</ScreenWrapper>
|
||||
</NavigationWrapper>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Component Usage**
|
||||
|
||||
- Always wrap pages with NavigationWrapper
|
||||
- Use ScreenWrapper for consistent spacing
|
||||
- Include Header component for page titles
|
||||
- Use TabWrapper for tabbed interfaces
|
||||
|
||||
2. **Layout Structure**
|
||||
|
||||
- Keep layouts shallow and composable
|
||||
- Use flex layouts for responsive design
|
||||
- Maintain consistent spacing patterns
|
||||
- Follow mobile-first approach
|
||||
|
||||
3. **Styling Guidelines**
|
||||
|
||||
- Use utility classes for minor adjustments
|
||||
- Leverage component variants for major changes
|
||||
- Maintain dark mode compatibility
|
||||
- Follow responsive design breakpoints
|
||||
|
||||
4. **Performance**
|
||||
- Use dynamic imports for route-based code splitting
|
||||
- Lazy load tab content when possible
|
||||
- Minimize layout shifts during loading
|
||||
- Optimize navigation transitions
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
- [x] Create unified layout components
|
||||
- [x] Standardize navigation patterns
|
||||
- [x] Implement consistent header styling
|
||||
- [x] Create TabWrapper component
|
||||
- [ ] Update existing pages to use new components
|
||||
- [ ] Add component documentation
|
||||
- [ ] Write component tests
|
||||
- [ ] Create Storybook examples
|
37
qwrk/docs/frontend/layouts/ROUTES.md
Normal file
37
qwrk/docs/frontend/layouts/ROUTES.md
Normal file
@ -0,0 +1,37 @@
|
||||
# Frontend Route Component Mapping
|
||||
|
||||
## Core Route Hierarchy
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[/:orgSlug/] --> B[projects/]
|
||||
B --> C[create/]
|
||||
C --> D[template/]
|
||||
D --> E[configure]
|
||||
D --> F[deploy]
|
||||
C --> G[success/:id]
|
||||
B --> H[:id/]
|
||||
H --> I[overview]
|
||||
H --> J[deployments]
|
||||
H --> K[settings/]
|
||||
K --> L[general]
|
||||
K --> M[git]
|
||||
K --> N[domains]
|
||||
K --> O[environment-variables]
|
||||
```
|
||||
|
||||
## Component Mapping Table
|
||||
|
||||
| Route Path | Component File | Entry Point |
|
||||
|------------|----------------|-------------|
|
||||
| `:orgSlug/projects/create` | `pages/org-slug/projects/create/index.tsx` | NewProject |
|
||||
| `:orgSlug/projects/create/template` | `pages/org-slug/projects/create/template/index.tsx` | CreateRepo |
|
||||
| `:orgSlug/projects/create/template/configure` | `pages/org-slug/projects/create/template/Configure.tsx` | Configure |
|
||||
| `:orgSlug/projects/create/template/deploy` | `pages/org-slug/projects/create/template/Deploy.tsx` | Deploy |
|
||||
| `:orgSlug/projects/create/success/:id` | `pages/org-slug/projects/create/success/Id.tsx` | Id |
|
||||
| `:orgSlug/projects/:id/overview` | `pages/org-slug/projects/id/Overview.tsx` | OverviewTabPanel |
|
||||
| `:orgSlug/projects/:id/deployments` | `pages/org-slug/projects/id/Deployments.tsx` | DeploymentsTabPanel |
|
||||
| `:orgSlug/projects/:id/settings/general` | `pages/org-slug/projects/id/settings/General.tsx` | GeneralTabPanel |
|
||||
| `:orgSlug/projects/:id/settings/git` | `pages/org-slug/projects/id/settings/Git.tsx` | GitTabPanel |
|
||||
| `:orgSlug/projects/:id/settings/domains` | `pages/org-slug/projects/id/settings/Domains.tsx` | Domains |
|
||||
| `:orgSlug/projects/:id/settings/environment-variables` | `pages/org-slug/projects/id/settings/EnvironmentVariables.tsx` | EnvironmentVariablesTabPanel |
|
7
standards/init-commit.md
Normal file
7
standards/init-commit.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Initial Commit for QWRK UX Changes
|
||||
|
||||
This is the first commit for QWRK UX changes to a fork of the `snowballtools-base` repository in Gitea. This commit sets the foundation for the upcoming user experience improvements and modifications.
|
||||
|
||||
- Repository: `snowballtools-base`
|
||||
- Platform: Gitea
|
||||
- Purpose: QWRK UX changes
|
Loading…
Reference in New Issue
Block a user