diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md new file mode 100644 index 00000000..cd9978a1 --- /dev/null +++ b/DOCUMENTATION.md @@ -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/) \ No newline at end of file diff --git a/packages/frontend/src/components/layout/navigation/NavigationWrapper.tsx b/packages/frontend/src/components/layout/navigation/NavigationWrapper.tsx index 754dc755..5e86bbab 100644 --- a/packages/frontend/src/components/layout/navigation/NavigationWrapper.tsx +++ b/packages/frontend/src/components/layout/navigation/NavigationWrapper.tsx @@ -1,6 +1,5 @@ import { cn } from '@/lib/utils'; import { TopNavigation } from './TopNavigation'; -import { useGitHubAuth } from '@/hooks/useGitHubAuth'; /** * NavigationWrapperProps interface extends React.HTMLProps to include all standard HTML div attributes. @@ -23,7 +22,7 @@ export function NavigationWrapper({ className, ...props }: NavigationWrapperProps) { - const { isAuthenticated } = useGitHubAuth(); + // const { isAuthenticated } = useGitHubAuth(); return (
diff --git a/packages/frontend/src/components/projects/ProjectCard/ProjectCard.tsx b/packages/frontend/src/components/projects/ProjectCard/ProjectCard.tsx index eaa49ea6..e3eb99d0 100644 --- a/packages/frontend/src/components/projects/ProjectCard/ProjectCard.tsx +++ b/packages/frontend/src/components/projects/ProjectCard/ProjectCard.tsx @@ -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 - * * ``` */ @@ -98,16 +98,19 @@ export const ProjectCard = ({
-

{project.name}

+

+ {project.name} +

- {project.deployments[0]?.applicationDeploymentRecordData?.url ?? 'No domain'} + {project.deployments[0]?.applicationDeploymentRecordData?.url ?? + 'No domain'}

{hasError && } - diff --git a/packages/frontend/src/context/WalletContext.tsx b/packages/frontend/src/context/WalletContext.tsx new file mode 100644 index 00000000..5f33a59a --- /dev/null +++ b/packages/frontend/src/context/WalletContext.tsx @@ -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; + disconnect: () => void; +} + +/** + * @const WalletContext + * @description Creates a context for managing wallet connection state. + */ +const WalletContext = createContext(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(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 ( + + {children} + + ); +}; + +/** + * @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; +}; diff --git a/packages/frontend/src/layouts/ProjectSearch.tsx b/packages/frontend/src/layouts/ProjectSearch.tsx index 94795c1e..d010d527 100644 --- a/packages/frontend/src/layouts/ProjectSearch.tsx +++ b/packages/frontend/src/layouts/ProjectSearch.tsx @@ -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 ( - <> - - - // - //
- // {/* Header */} - //
- //
- //
- // { - // navigate( - // `/${project.organization.slug}/projects/${project.id}`, - // ); - // }} - // /> - //
- //
- // - // - // {user?.name && ( - //

- // {formatAddress(user.name)} - //

- // )} - //
- //
- //
+ +
+ {/* Header */} +
+
+
+ { + navigate( + `/${project.organization.slug}/projects/${project.id}`, + ); + }} + /> +
+
+ + + {user?.name && ( +

+ {formatAddress(user.name)} +

+ )} +
+
+
- // {/* Content */} - //
- // - //
- //
- //
+ {/* Content */} +
+ +
+
+
); }; diff --git a/qwrk/docs/frontend/SHADCN_MIGRATION.md b/qwrk/docs/frontend/SHADCN_MIGRATION.md new file mode 100644 index 00000000..fc253fce --- /dev/null +++ b/qwrk/docs/frontend/SHADCN_MIGRATION.md @@ -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 diff --git a/qwrk/docs/frontend/layouts/LAYOUT_STRATEGY.md b/qwrk/docs/frontend/layouts/LAYOUT_STRATEGY.md new file mode 100644 index 00000000..0dba4195 --- /dev/null +++ b/qwrk/docs/frontend/layouts/LAYOUT_STRATEGY.md @@ -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 ( + + +
Action]} + /> +
+ {/* Page content */} +
+ + + ); +} +``` + +### 2. Tabbed Page Structure + +```typescript +import { + NavigationWrapper, + ScreenWrapper, + Header, + TabWrapper, + TabsList, + TabsTrigger, + TabsContent +} from '@/components/layout'; + +function TabbedPage() { + return ( + + +
+ + + Tab 1 + Tab 2 + + + Content 1 + + + Content 2 + + + + + ); +} +``` + +## 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 diff --git a/qwrk/docs/frontend/layouts/ROUTES.md b/qwrk/docs/frontend/layouts/ROUTES.md new file mode 100644 index 00000000..f673770d --- /dev/null +++ b/qwrk/docs/frontend/layouts/ROUTES.md @@ -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 | diff --git a/standards/init-commit.md b/standards/init-commit.md new file mode 100644 index 00000000..cba91de8 --- /dev/null +++ b/standards/init-commit.md @@ -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