From 7fbfdaf85e25df3931dcf57afb51cf130898ca6b Mon Sep 17 00:00:00 2001 From: icld Date: Wed, 26 Feb 2025 11:43:21 -0800 Subject: [PATCH] Onboarding documented, begin consume existing components --- .gitignore | 1 + README.md | 24 +- packages/frontend/.gitignore | 4 +- packages/frontend/package.json | 4 +- packages/frontend/src/App.tsx | 4 +- packages/frontend/src/app/layout.tsx | 17 + packages/frontend/src/app/page.tsx | 74 +++ packages/frontend/src/components/Dropdown.tsx | 24 + .../src/components/FormatMilliSecond.tsx | 17 + .../src/components/HorizontalLine.tsx | 11 + packages/frontend/src/components/Logo.tsx | 17 + .../frontend/src/components/SearchBar.tsx | 12 + packages/frontend/src/components/Stepper.tsx | 25 + .../frontend/src/components/StopWatch.tsx | 20 +- .../src/components/VerticalStepper.tsx | 25 + .../src/components/examples/ExamplePage.tsx | 19 + .../layout/navigation/NavigationWrapper.tsx | 3 + .../layout/navigation/TopNavigation.tsx | 4 + .../onboarding-flow/OPTIMIZATION.md | 117 ++++ .../components/onboarding-flow/Onboarding.tsx | 81 +++ .../src/components/onboarding-flow/README.md | 109 ++++ .../onboarding-flow/common/background-svg.tsx | 13 + .../onboarding-flow/common/index.ts | 13 + .../common/laconic-icon-lettering.tsx | 42 ++ .../common/onboarding-container.tsx | 34 ++ .../onboarding-flow/common/step-header.tsx | 46 ++ .../common/step-navigation.tsx | 80 +++ .../configure-step/configure-step.tsx | 64 +++ .../onboarding-flow/configure-step/index.ts | 9 + .../connect-step/connect-button.tsx | 52 ++ .../connect-step/connect-deploy-first-app.tsx | 39 ++ .../connect-step/connect-initial.tsx | 33 ++ .../connect-step/connect-step.tsx | 61 ++ .../onboarding-flow/connect-step/index.ts | 14 + .../connect-step/repository-list.tsx | 44 ++ .../connect-step/template-list.tsx | 51 ++ .../deploy-step/deploy-step.tsx | 49 ++ .../onboarding-flow/deploy-step/index.ts | 9 + .../src/components/onboarding-flow/index.ts | 29 + .../onboarding-flow/sidebar/index.ts | 9 + .../onboarding-flow/sidebar/sidebar-nav.tsx | 138 +++++ .../src/components/onboarding-flow/store.ts | 61 ++ .../src/components/onboarding-flow/types.ts | 83 +++ .../onboarding-flow/useOnboarding.ts | 41 ++ .../onboarding/NavigationSidebar.tsx | 14 +- .../onboarding/OnboardingDialog.tsx | 9 +- .../projects/ProjectCard/ProjectCard.theme.ts | 18 +- .../projects/ProjectCard/ProjectCard.tsx | 228 +++----- .../ProjectCard/ProjectCardActions.tsx | 69 +++ .../ProjectCard/ProjectDeploymentInfo.tsx | 61 ++ .../projects/ProjectCard/ProjectStatusDot.tsx | 52 ++ .../frontend/src/context/OctokitContext.tsx | 10 +- .../frontend/src/layouts/DashboardLayout.tsx | 1 + standards/COMPONENT_DOCUMENTATION.md | 525 ++++++++++++++++++ standards/FEATURE_BUILDING.md | 232 ++++++++ standards/FEATURE_BUILDING_TEMPLATE.md | 239 ++++++++ standards/README.md | 41 ++ yarn.lock | 10 + 58 files changed, 2961 insertions(+), 174 deletions(-) create mode 100644 packages/frontend/src/app/layout.tsx create mode 100644 packages/frontend/src/app/page.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/OPTIMIZATION.md create mode 100644 packages/frontend/src/components/onboarding-flow/Onboarding.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/README.md create mode 100644 packages/frontend/src/components/onboarding-flow/common/background-svg.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/common/index.ts create mode 100644 packages/frontend/src/components/onboarding-flow/common/laconic-icon-lettering.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/common/onboarding-container.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/common/step-header.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/common/step-navigation.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/configure-step/configure-step.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/configure-step/index.ts create mode 100644 packages/frontend/src/components/onboarding-flow/connect-step/connect-button.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/connect-step/connect-deploy-first-app.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/connect-step/connect-initial.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/connect-step/connect-step.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/connect-step/index.ts create mode 100644 packages/frontend/src/components/onboarding-flow/connect-step/repository-list.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/connect-step/template-list.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/deploy-step/deploy-step.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/deploy-step/index.ts create mode 100644 packages/frontend/src/components/onboarding-flow/index.ts create mode 100644 packages/frontend/src/components/onboarding-flow/sidebar/index.ts create mode 100644 packages/frontend/src/components/onboarding-flow/sidebar/sidebar-nav.tsx create mode 100644 packages/frontend/src/components/onboarding-flow/store.ts create mode 100644 packages/frontend/src/components/onboarding-flow/types.ts create mode 100644 packages/frontend/src/components/onboarding-flow/useOnboarding.ts create mode 100644 packages/frontend/src/components/projects/ProjectCard/ProjectCardActions.tsx create mode 100644 packages/frontend/src/components/projects/ProjectCard/ProjectDeploymentInfo.tsx create mode 100644 packages/frontend/src/components/projects/ProjectCard/ProjectStatusDot.tsx create mode 100644 standards/COMPONENT_DOCUMENTATION.md create mode 100644 standards/FEATURE_BUILDING.md create mode 100644 standards/FEATURE_BUILDING_TEMPLATE.md create mode 100644 standards/README.md diff --git a/.gitignore b/.gitignore index 027d0170..2749f420 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ packages/frontend/dist/ # TypeDoc generated documentation docs/ +.cursor/ diff --git a/README.md b/README.md index fda8b5e8..61ac548c 100644 --- a/README.md +++ b/README.md @@ -20,20 +20,20 @@ yarn build --ignore frontend ### Environment variables, running the development server, and deployment -Follow the instructions in the README.md files of the [backend](packages/backend/README.md) and [frontend](packages/frontend/README.md) packages. +Follow the instructions in the README.md files of the [backend](packages/backend/README.md) and +[frontend](packages/frontend/README.md) packages. -## Documentation +## Development Guidelines -This project uses TSDoc for code documentation and TypeDoc for generating API documentation. +### Project Standards -### Generating Documentation +We maintain a set of project-wide standards and conventions in the [standards](./standards) +directory. These standards help ensure consistency across the codebase and make it easier for +developers to collaborate. -To generate the API documentation, run: +Current standards: -```zsh -yarn docs -``` - -This will create a `docs` directory with the generated documentation. - -For more information about writing documentation, see [DOCUMENTATION.md](DOCUMENTATION.md). +- [Component Documentation Standards](./standards/COMPONENT_DOCUMENTATION.md) - Guidelines for + documenting components, hooks, and utilities +- [Feature Building Process](./standards/FEATURE_BUILDING.md) - Standardized approach to building + new features from design to implementation diff --git a/packages/frontend/.gitignore b/packages/frontend/.gitignore index 6904e0c5..4461d15e 100644 --- a/packages/frontend/.gitignore +++ b/packages/frontend/.gitignore @@ -24,4 +24,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -*storybook.log \ No newline at end of file +*storybook.log + +.cursor/ \ No newline at end of file diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 471a75d6..c48ed173 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -32,6 +32,7 @@ "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-dropdown-menu": "^2.1.6", "@radix-ui/react-hover-card": "^1.1.6", + "@radix-ui/react-icons": "^1.3.2", "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-menubar": "^1.1.6", "@radix-ui/react-navigation-menu": "^1.2.5", @@ -100,7 +101,8 @@ "vaul": "^1.1.2", "viem": "^2.7.11", "web-vitals": "^2.1.4", - "zod": "^3.24.2" + "zod": "^3.24.2", + "zustand": "^5.0.3" }, "devDependencies": { "@chromatic-com/storybook": "^1.3.3", diff --git a/packages/frontend/src/App.tsx b/packages/frontend/src/App.tsx index 33ec9cb0..68118da8 100644 --- a/packages/frontend/src/App.tsx +++ b/packages/frontend/src/App.tsx @@ -18,10 +18,10 @@ const router = createBrowserRouter([ children: [ // { // element: , - // children: [ + // children: [` // { // path: '', - // element: , + // element: ,` // }, // { // path: 'projects', diff --git a/packages/frontend/src/app/layout.tsx b/packages/frontend/src/app/layout.tsx new file mode 100644 index 00000000..dbeabcf1 --- /dev/null +++ b/packages/frontend/src/app/layout.tsx @@ -0,0 +1,17 @@ +import type React from "react" +import "@/styles/globals.css" + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + +
{children}
+ + + ) +} + diff --git a/packages/frontend/src/app/page.tsx b/packages/frontend/src/app/page.tsx new file mode 100644 index 00000000..9496910c --- /dev/null +++ b/packages/frontend/src/app/page.tsx @@ -0,0 +1,74 @@ +import { + OnboardingContainer, + SidebarNav, + StepHeader, + StepNavigation, +} from '@/components/onboarding-flow'; +import { ConfigureStep } from '@/components/onboarding-flow/configure-step/configure-step'; +import { ConnectStep } from '@/components/onboarding-flow/connect-step/connect-step'; +import { DeployStep } from '@/components/onboarding-flow/deploy-step/deploy-step'; +import { useOnboarding } from '@/components/onboarding-flow/store'; +import { FileCog, GitPullRequest, SquareArrowOutDownRight } from 'lucide-react'; + +/** Icons for each step in the onboarding flow */ +const stepIcons = { + connect: , + configure: , + deploy: , +}; + +/** Titles for each step in the onboarding flow */ +const stepTitles = { + connect: 'Connect', + configure: 'Configure', + deploy: 'Deploy', +}; + +/** Descriptions for each step in the onboarding flow */ +const stepDescriptions = { + connect: 'Connect and import a GitHub repository to start deploying.', + configure: 'Set up your deployment configuration and environment variables.', + deploy: 'Review your settings and deploy your project.', +}; + +/** + * Main onboarding page component + * Orchestrates the entire onboarding flow and manages step transitions + * + * Component Hierarchy: + * - OnboardingContainer + * - SidebarNav (step progress) + * - Main content + * - StepHeader (current step info) + * - Step content (ConnectStep | ConfigureStep | DeployStep) + * - StepNavigation (previous/next controls) + * + * @returns {JSX.Element} Complete onboarding interface + */ +export default function Page() { + const { currentStep, nextStep, previousStep } = useOnboarding(); + + return ( + + +
+ +
+ {currentStep === 'connect' && } + {currentStep === 'configure' && } + {currentStep === 'deploy' && } +
+ +
+
+ ); +} diff --git a/packages/frontend/src/components/Dropdown.tsx b/packages/frontend/src/components/Dropdown.tsx index 5660bea3..964bb384 100644 --- a/packages/frontend/src/components/Dropdown.tsx +++ b/packages/frontend/src/components/Dropdown.tsx @@ -9,6 +9,14 @@ export interface Option { label: string; } +/** + * Props for the Dropdown component. + * @interface DropdownProps + * @property {Option[]} options - The list of options to display in the dropdown. + * @property {(arg: ReactDropdownOption) => void} onChange - Callback fired when an option is selected. + * @property {string} [placeholder] - Placeholder text for the dropdown. + * @property {Option} [value] - The currently selected option. + */ interface DropdownProps { options: Option[]; onChange: (arg: ReactDropdownOption) => void; @@ -16,6 +24,22 @@ interface DropdownProps { value?: Option; } +/** + * A dropdown component that wraps the ReactDropdown library. + * + * @component + * @param {DropdownProps} props - The props for the Dropdown component. + * @returns {React.ReactElement} A dropdown element. + * + * @example + * ```tsx + * console.log(option)} + * placeholder="Select an option" + * /> + * ``` + */ const Dropdown = ({ placeholder, options, onChange, value }: DropdownProps) => { return ( { time: number; } +/** + * A component that formats a given time in milliseconds into a human-readable format. + * + * @component + * @param {FormatMilliSecondProps} props - The props for the FormatMillisecond component. + * @returns {React.ReactElement} A formatted time element. + * + * @example + * ```tsx + * + * ``` + */ const FormatMillisecond = ({ time, ...props }: FormatMilliSecondProps) => { const formatTime = Duration.fromMillis(time) .shiftTo('days', 'hours', 'minutes', 'seconds') diff --git a/packages/frontend/src/components/HorizontalLine.tsx b/packages/frontend/src/components/HorizontalLine.tsx index 62c6242f..0f917193 100644 --- a/packages/frontend/src/components/HorizontalLine.tsx +++ b/packages/frontend/src/components/HorizontalLine.tsx @@ -1,3 +1,14 @@ +/** + * A simple horizontal line component. + * + * @component + * @returns {React.ReactElement} A horizontal line element. + * + * @example + * ```tsx + * + * ``` + */ const HorizontalLine = () => { return
; }; diff --git a/packages/frontend/src/components/Logo.tsx b/packages/frontend/src/components/Logo.tsx index f4957f14..9c7f7808 100644 --- a/packages/frontend/src/components/Logo.tsx +++ b/packages/frontend/src/components/Logo.tsx @@ -1,9 +1,26 @@ import { Link } from 'react-router-dom'; +/** + * Props for the Logo component. + * @interface LogoProps + * @property {string} [orgSlug] - The organization slug used for the link. + */ interface LogoProps { orgSlug?: string; } +/** + * A component that renders the Snowball logo with a link to the organization's page. + * + * @component + * @param {LogoProps} props - The props for the Logo component. + * @returns {React.ReactElement} A logo element. + * + * @example + * ```tsx + * + * ``` + */ export const Logo = ({ orgSlug }: LogoProps) => { return ( diff --git a/packages/frontend/src/components/SearchBar.tsx b/packages/frontend/src/components/SearchBar.tsx index a334ad3a..64329f3d 100644 --- a/packages/frontend/src/components/SearchBar.tsx +++ b/packages/frontend/src/components/SearchBar.tsx @@ -3,6 +3,18 @@ import React, { forwardRef, RefAttributes } from 'react'; import { IconInput, type IconInputProps } from '@/components/ui/extended/input-w-icons'; import { Search } from 'lucide-react'; +/** + * A search bar component with an icon input. + * + * @component + * @param {InputProps & RefAttributes} props - The props for the SearchBar component. + * @returns {React.ReactElement} A search bar element. + * + * @example + * ```tsx + * console.log(e.target.value)} /> + * ``` + */ const SearchBar: React.ForwardRefRenderFunction< HTMLInputElement, IconInputProps & RefAttributes diff --git a/packages/frontend/src/components/Stepper.tsx b/packages/frontend/src/components/Stepper.tsx index 31e7e717..f462bdf5 100644 --- a/packages/frontend/src/components/Stepper.tsx +++ b/packages/frontend/src/components/Stepper.tsx @@ -4,17 +4,42 @@ const COLOR_COMPLETED = '#059669'; const COLOR_ACTIVE = '#CFE6FC'; const COLOR_NOT_STARTED = '#F1F5F9'; +/** + * Represents a step in the stepper. + * @interface StepperValue + * @property {number} step - The step number. + * @property {string} route - The route associated with the step. + * @property {string} label - The label for the step. + */ interface StepperValue { step: number; route: string; label: string; } +/** + * Props for the Stepper component. + * @interface StepperProps + * @property {number} activeStep - The currently active step. + * @property {StepperValue[]} stepperValues - The values for each step. + */ interface StepperProps { activeStep: number; stepperValues: StepperValue[]; } +/** + * A stepper component that displays a series of steps with different states. + * + * @component + * @param {StepperProps} props - The props for the Stepper component. + * @returns {React.ReactElement} A stepper element. + * + * @example + * ```tsx + * + * ``` + */ const Stepper = ({ activeStep, stepperValues }: StepperProps) => { return ( { return currentTime; }; +/** + * Props for the Stopwatch component. + * @interface StopwatchProps + * @property {Date} offsetTimestamp - The initial timestamp for the stopwatch. + * @property {boolean} isPaused - Whether the stopwatch is paused. + */ interface StopwatchProps extends Omit { offsetTimestamp: Date; isPaused: boolean; } +/** + * A stopwatch component that tracks elapsed time. + * + * @component + * @param {StopwatchProps} props - The props for the Stopwatch component. + * @returns {React.ReactElement} A stopwatch element. + * + * @example + * ```tsx + * + * ``` + */ const Stopwatch = ({ offsetTimestamp, isPaused, ...props }: StopwatchProps) => { const { totalSeconds, pause, start } = useStopwatch({ autoStart: true, @@ -29,4 +47,4 @@ const Stopwatch = ({ offsetTimestamp, isPaused, ...props }: StopwatchProps) => { return ; }; -export { Stopwatch, setStopWatchOffset }; +export { setStopWatchOffset, Stopwatch }; diff --git a/packages/frontend/src/components/VerticalStepper.tsx b/packages/frontend/src/components/VerticalStepper.tsx index 43ff80a4..73aff806 100644 --- a/packages/frontend/src/components/VerticalStepper.tsx +++ b/packages/frontend/src/components/VerticalStepper.tsx @@ -3,6 +3,14 @@ import * as CSS from 'csstype'; // // Nav // +/** + * Describes a step in the stepper navigation. + * @interface IStepDescription + * @property {() => JSX.Element} stepContent - The content of the step. + * @property {string} [stepStateColor] - The color representing the step's state. + * @property {number} [stepStatusCircleSize] - The size of the status circle. + * @property {() => void} [onClickHandler] - Handler for click events on the step. + */ export interface IStepDescription { stepContent: () => JSX.Element; stepStateColor?: string; @@ -10,10 +18,27 @@ export interface IStepDescription { onClickHandler?: () => void | undefined; } +/** + * Props for the StepperNav component. + * @interface IStepperNavProps + * @property {IStepDescription[]} steps - The steps to display in the navigation. + */ export interface IStepperNavProps { steps: IStepDescription[]; } +/** + * A navigation component for displaying steps in a vertical layout. + * + * @component + * @param {IStepperNavProps} props - The props for the StepperNav component. + * @returns {React.ReactElement} A stepper navigation element. + * + * @example + * ```tsx + *
Step 1
}]} /> + * ``` + */ export const StepperNav = (props: IStepperNavProps): JSX.Element => { return (