Skip to content

Commit 467bf25

Browse files
committed
feat(Deck): add modalDeck and demo
1 parent c489fdf commit 467bf25

File tree

13 files changed

+708
-47
lines changed

13 files changed

+708
-47
lines changed

packages/module/patternfly-docs/content/extensions/component-groups/examples/Deck/Deck.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ id: Deck
1010
source: react
1111
# If you use typescript, the name of the interface to display props for
1212
# These are found through the sourceProps function provided in patternfly-docs.source.js
13-
propComponents: ['Deck', 'DeckPage', 'DeckButton']
13+
propComponents: ['Deck', 'DeckPage', 'DeckButton', 'ModalDeck']
1414
sourceLink: https://github.com/patternfly/react-component-groups/blob/main/packages/module/patternfly-docs/content/extensions/component-groups/examples/Deck/Deck.md
1515
---
1616

1717
import Deck from '@patternfly/react-component-groups/dist/dynamic/Deck';
18+
import { ModalDeck } from '@patternfly/react-component-groups/dist/dynamic/ModalDeck';
1819
import { FunctionComponent, useState } from 'react';
1920

2021
The **deck** component is a compact, sequential container for presenting a suite of static announcements or an informational walkthrough. It is not intended for task completion or form-filling workflows.
@@ -34,3 +35,11 @@ You can also add custom `onClick` handlers for analytics, validation, or other l
3435

3536
```
3637

38+
### Modal deck
39+
40+
Display the deck in a modal dialog. The `ModalDeck` component wraps the Deck in a PatternFly Modal without a close button or extra padding, ideal for guided walkthroughs that require user interaction.
41+
42+
```ts file="./ModalDeckExample.tsx"
43+
44+
```
45+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
# Sidenav top-level section
3+
# should be the same for all markdown files
4+
section: Component groups
5+
subsection: Content containers
6+
# Sidenav secondary level section
7+
# should be the same for all markdown files
8+
id: Deck
9+
# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility)
10+
source: react-demos
11+
sourceLink: https://github.com/patternfly/react-component-groups/blob/main/packages/module/patternfly-docs/content/extensions/component-groups/examples/Deck/DeckDemos.md
12+
---
13+
import { FunctionComponent, useState } from 'react';
14+
15+
import Deck from '@patternfly/react-component-groups/dist/dynamic/Deck';
16+
import { ModalDeck } from '@patternfly/react-component-groups/dist/dynamic/ModalDeck';
17+
18+
## Demos
19+
20+
### Onboarding modal deck
21+
22+
A complete onboarding experience using ModalDeck to guide users through key product features. This demo demonstrates a multi-step walkthrough with custom styling, labels, and content.
23+
24+
```ts file="./OnboardingModalDeckDemo.tsx"
25+
26+
```

packages/module/patternfly-docs/content/extensions/component-groups/examples/Deck/DeckExample.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export const BasicExample: FunctionComponent = () => {
2020
{
2121
content: (
2222
<div>
23-
<h2>Welcome to the Deck</h2>
2423
<p>This is the first page of your informational walkthrough.</p>
2524
</div>
2625
),
@@ -37,7 +36,6 @@ export const BasicExample: FunctionComponent = () => {
3736
{
3837
content: (
3938
<div>
40-
<h2>Page 2</h2>
4139
<p>Continue through your walkthrough.</p>
4240
</div>
4341
),
@@ -53,7 +51,6 @@ export const BasicExample: FunctionComponent = () => {
5351
{
5452
content: (
5553
<div>
56-
<h2>Final Page</h2>
5754
<p>You've reached the end of the deck.</p>
5855
</div>
5956
),
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/* eslint-disable no-console */
2+
import React, { FunctionComponent, useState } from 'react';
3+
import Deck, { DeckButton } from '@patternfly/react-component-groups/dist/dynamic/Deck';
4+
import { ModalDeck } from '@patternfly/react-component-groups/dist/dynamic/ModalDeck';
5+
import { Button, ButtonVariant } from '@patternfly/react-core';
6+
7+
export const ModalDeckExample: FunctionComponent = () => {
8+
const [isModalOpen, setIsModalOpen] = useState(false);
9+
10+
const handleClose = () => {
11+
setIsModalOpen(false);
12+
console.log('Modal deck closed');
13+
};
14+
15+
const pages = [
16+
{
17+
content: (
18+
<div>
19+
<h2>Welcome to the Modal Deck</h2>
20+
<p>This deck is displayed in a modal dialog.</p>
21+
</div>
22+
),
23+
buttons: [
24+
{
25+
children: 'Next',
26+
variant: ButtonVariant.primary,
27+
navigation: 'next'
28+
}
29+
] as DeckButton[]
30+
},
31+
{
32+
content: (
33+
<div>
34+
<h2>Page 2</h2>
35+
<p>Navigate through the walkthrough.</p>
36+
</div>
37+
),
38+
buttons: [
39+
{
40+
children: 'Next',
41+
variant: ButtonVariant.primary,
42+
navigation: 'next'
43+
}
44+
] as DeckButton[]
45+
},
46+
{
47+
content: (
48+
<div>
49+
<h2>Final Page</h2>
50+
<p>Click Close to finish.</p>
51+
</div>
52+
),
53+
buttons: [
54+
{
55+
children: 'Close',
56+
variant: ButtonVariant.primary,
57+
navigation: 'close'
58+
}
59+
] as DeckButton[]
60+
}
61+
];
62+
63+
return (
64+
<>
65+
<Button onClick={() => setIsModalOpen(true)}>
66+
Launch modal deck
67+
</Button>
68+
<ModalDeck isOpen={isModalOpen} onClose={handleClose}>
69+
<Deck
70+
pages={pages}
71+
onClose={handleClose}
72+
onPageChange={(index) => console.log('Page changed to:', index + 1)}
73+
/>
74+
</ModalDeck>
75+
</>
76+
);
77+
};
78+
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/* eslint-disable no-console */
2+
import React, { FunctionComponent, useState } from 'react';
3+
import Deck, { DeckButton } from '@patternfly/react-component-groups/dist/dynamic/Deck';
4+
import { ModalDeck } from '@patternfly/react-component-groups/dist/dynamic/ModalDeck';
5+
import { Button, ButtonVariant, Label, Title, Stack, StackItem, Content } from '@patternfly/react-core';
6+
7+
export const OnboardingModalDeckDemo: FunctionComponent = () => {
8+
const [isModalOpen, setIsModalOpen] = useState(false);
9+
10+
const handleClose = () => {
11+
setIsModalOpen(false);
12+
console.log('Onboarding completed or skipped');
13+
};
14+
15+
// Placeholder for illustration - in a real app, replace with actual images
16+
const placeholderImage = (
17+
<div
18+
style={{
19+
width: '256px',
20+
height: '256px',
21+
borderRadius: '8px',
22+
background: 'repeating-linear-gradient(45deg, #f3f4f6, #f3f4f6 10px, #e5e7eb 10px, #e5e7eb 20px)',
23+
opacity: 0.25,
24+
margin: 'auto'
25+
}}
26+
/>
27+
);
28+
29+
const pages = [
30+
{
31+
content: (
32+
<Stack hasGutter>
33+
<StackItem>{placeholderImage}</StackItem>
34+
<StackItem>
35+
<Title headingLevel="h2" size="2xl">Welcome to [Product Name]</Title>
36+
</StackItem>
37+
<StackItem>
38+
<Content component="p">
39+
Harness the full potential of the hybrid cloud, simply by asking.
40+
</Content>
41+
</StackItem>
42+
</Stack>
43+
),
44+
buttons: [
45+
{
46+
children: 'Continue',
47+
variant: ButtonVariant.primary,
48+
navigation: 'next'
49+
}
50+
] as DeckButton[]
51+
},
52+
{
53+
content: (
54+
<Stack hasGutter>
55+
<StackItem>{placeholderImage}</StackItem>
56+
<StackItem><Label color="grey">AI Command Center</Label></StackItem>
57+
<StackItem><Title headingLevel="h2" size="2xl">Intelligence at your command</Title></StackItem>
58+
<StackItem><Content component="p">Ask anything. Get answers. Troubleshoot, analyze, and understand your entire fleet just by asking. It's the power of your data, in plain language.</Content></StackItem>
59+
</Stack>
60+
),
61+
buttons: [
62+
{
63+
children: 'Continue',
64+
variant: ButtonVariant.primary,
65+
navigation: 'next'
66+
}
67+
] as DeckButton[]
68+
},
69+
{
70+
content: (
71+
<Stack hasGutter>
72+
<StackItem>{placeholderImage}</StackItem>
73+
<StackItem><Label color="grey">Canvas Mode</Label></StackItem>
74+
<StackItem><Title headingLevel="h2" size="2xl">Go from conversation to clarity.</Title></StackItem>
75+
<StackItem><Content component="p">Transform answers into custom dashboards. In Canvas Mode, you can effortlessly arrange, customize, and build the precise view you need to monitor what matters most.</Content></StackItem>
76+
</Stack>
77+
),
78+
buttons: [
79+
{
80+
children: 'Continue',
81+
variant: ButtonVariant.primary,
82+
navigation: 'next'
83+
}
84+
] as DeckButton[]
85+
},
86+
{
87+
content: (
88+
<Stack hasGutter>
89+
<StackItem>{placeholderImage}</StackItem>
90+
<StackItem><Label color="grey">Sharing</Label></StackItem>
91+
<StackItem><Title headingLevel="h2" size="2xl">Share your vision. Instantly.</Title></StackItem>
92+
<StackItem><Content component="p">An insight is only powerful when it’s shared. Save any view to your library and share it with your team in a single click. Drive decisions, together.</Content></StackItem>
93+
</Stack>
94+
),
95+
buttons: [
96+
{
97+
children: 'Get started',
98+
variant: ButtonVariant.primary,
99+
navigation: 'close'
100+
}
101+
] as DeckButton[]
102+
}
103+
];
104+
105+
return (
106+
<>
107+
<Button onClick={() => setIsModalOpen(true)}>
108+
Launch onboarding
109+
</Button>
110+
<ModalDeck
111+
isOpen={isModalOpen}
112+
modalProps={{
113+
'aria-label': 'Product onboarding walkthrough'
114+
}}
115+
>
116+
<Deck
117+
pages={pages}
118+
onClose={handleClose}
119+
onPageChange={(index) => console.log('Onboarding page:', index + 1)}
120+
ariaLabel="Product onboarding"
121+
ariaRoleDescription="onboarding walkthrough"
122+
contentFlexProps={{
123+
spaceItems: { default: 'spaceItemsXl' }
124+
}}
125+
/>
126+
</ModalDeck>
127+
</>
128+
);
129+
};
130+

0 commit comments

Comments
 (0)