Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions packages/react/src/Spinner/Spinner.examples.stories.module.css
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot This file should be called Spinner.example.stories.module.css

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to Spinner.examples.stories.module.css in commit 0749f4f.

Screenshot showing the story still works correctly

Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.LoadingExample {
display: flex;
align-items: flex-start;
flex-direction: column;
gap: var(--base-size-8);
}

.LoadingIndicator {
align-items: center;
display: flex;
gap: var(--base-size-4);
}

.LoadButton {
margin-bottom: var(--base-size-16);
}

.ChecksList {
border: var(--borderWidth-thin) solid var(--borderColor-default);
border-radius: var(--borderRadius-medium);
padding: var(--base-size-8);
background-color: var(--bgColor-default);
}

.CheckItem {
display: flex;
align-items: flex-start;
gap: var(--base-size-8);
padding: var(--base-size-8);
}

.CheckIcon {
display: flex;
align-items: center;
justify-content: center;
min-width: 16px;
height: 16px;
}

.CheckContent {
display: flex;
flex-direction: column;
gap: var(--base-size-4);
flex: 1;
}

.CheckDescription {
color: var(--fgColor-muted);
}
78 changes: 76 additions & 2 deletions packages/react/src/Spinner/Spinner.examples.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react'
import type {Meta} from '@storybook/react-vite'
import Spinner from './Spinner'
import {Button} from '..'
import {Button, Text, Stack} from '..'
import {VisuallyHidden} from '../VisuallyHidden'
import {AriaStatus} from '../live-region'
import classes from './SpinnerStories.module.css'
import {CheckCircleFillIcon, XCircleFillIcon} from '@primer/octicons-react'
import classes from './Spinner.examples.stories.module.css'

export default {
title: 'Components/Spinner/Examples',
Expand Down Expand Up @@ -95,3 +96,76 @@ export const FullLifecycleVisibleLoadingText = () => {
</div>
)
}

// Example showing a list of PR checks similar to GitHub's UI
export const PullRequestChecks = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot No need to complete the checks. I just need pending state. What's important is to make the checks start at slightly different delay so that the spinners can be out of sync with each other

type CheckStatus = 'pending' | 'success' | 'failure'

interface Check {
id: string
name: string
description: string
status: CheckStatus
}

const [checks, setChecks] = React.useState<Check[]>([
{id: '1', name: 'Build', description: 'Building and testing the application', status: 'pending'},
{id: '2', name: 'Lint', description: 'Running ESLint checks', status: 'pending'},
{id: '3', name: 'Type Check', description: 'Running TypeScript type checks', status: 'pending'},
{id: '4', name: 'Tests', description: 'Running unit tests', status: 'pending'},
])

const runChecks = async () => {
// Simulate checks running one by one
for (let i = 0; i < checks.length; i++) {
await wait(1500)
setChecks(prevChecks => {
const newChecks = [...prevChecks]
// Randomly pass or fail each check (mostly pass)
newChecks[i] = {...newChecks[i], status: Math.random() > 0.2 ? 'success' : 'failure'}
return newChecks
})
}
}

const allComplete = checks.every(check => check.status !== 'pending')
const hasFailures = checks.some(check => check.status === 'failure')

return (
<Stack direction="vertical" gap="normal" padding="normal">
<div>
<Button onClick={runChecks} disabled={!allComplete && checks.some(check => check.status !== 'pending')}>
Run checks
</Button>
</div>

<Stack direction="vertical" gap="condensed" className={classes.ChecksList}>
{checks.map(check => (
<div key={check.id} className={classes.CheckItem}>
<div className={classes.CheckIcon}>
{check.status === 'pending' && <Spinner size="small" srText={null} />}
{check.status === 'success' && (
<CheckCircleFillIcon size={16} fill="var(--fgColor-success)" aria-label="Success" />
)}
{check.status === 'failure' && (
<XCircleFillIcon size={16} fill="var(--fgColor-danger)" aria-label="Failed" />
)}
</div>
<div className={classes.CheckContent}>
<Text weight="semibold">{check.name}</Text>
<Text size="small" className={classes.CheckDescription}>
{check.description}
</Text>
</div>
</div>
))}
</Stack>

{allComplete && (
<VisuallyHidden>
<AriaStatus>{hasFailures ? 'Some checks failed' : 'All checks passed successfully'}</AriaStatus>
</VisuallyHidden>
)}
</Stack>
)
}
16 changes: 0 additions & 16 deletions packages/react/src/Spinner/SpinnerStories.module.css

This file was deleted.

Loading