Skip to content

Commit f2b1482

Browse files
committed
version 3
1 parent dda9a97 commit f2b1482

2 files changed

Lines changed: 202 additions & 0 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { useState } from "react";
5+
import clsx from "clsx";
6+
7+
import Box from "@cloudscape-design/components/box";
8+
import Button from "@cloudscape-design/components/button";
9+
import Container from "@cloudscape-design/components/container";
10+
import Header from "@cloudscape-design/components/header";
11+
import Icon, { IconProps } from "@cloudscape-design/components/icon";
12+
import SpaceBetween from "@cloudscape-design/components/space-between";
13+
14+
import { ChatBubble } from "../../lib/components";
15+
import { Page } from "../app/templates";
16+
import { ChatBubbleAvatarGenAI, ChatBubbleAvatarUser } from "./util-components";
17+
18+
import styles from "./styles.module.scss";
19+
20+
export default function ChatBubbleSelectableCustomPage() {
21+
const [selectedCardId, setSelectedCardId] = useState<null | string>(null);
22+
return (
23+
<Page title="Chat bubble: selectable custom card">
24+
<SpaceBetween direction="horizontal" size="l">
25+
<Container header={<Header variant="h3">Chat container</Header>}>
26+
<SpaceBetween size="m">
27+
<ChatBubble avatar={<ChatBubbleAvatarUser />} type="outgoing" ariaLabel="User at 4:24:12pm">
28+
<Box color="text-body-secondary">User request example</Box>
29+
</ChatBubble>
30+
31+
<ChatBubble avatar={<ChatBubbleAvatarGenAI />} type="incoming" ariaLabel="Gen AI at 4:24:24pm">
32+
<Box color="text-body-secondary">Normal response example</Box>
33+
</ChatBubble>
34+
35+
<ChatBubble
36+
avatar={<ChatBubbleAvatarGenAI />}
37+
hideAvatar={true}
38+
type="incoming"
39+
ariaLabel="Gen AI at 4:24:25pm"
40+
additionalContent={
41+
<SpaceBetween size="s" direction="horizontal">
42+
<CustomSelectableCard
43+
header="Selectable card 1"
44+
pressed={selectedCardId === "1"}
45+
iconName="expand"
46+
iconNamePressed="shrink"
47+
onClick={() => setSelectedCardId(selectedCardId === "1" ? null : "1")}
48+
>
49+
Selectable card 1 content
50+
</CustomSelectableCard>
51+
<CustomSelectableCard
52+
header="Selectable card 2"
53+
pressed={selectedCardId === "2"}
54+
iconName="expand"
55+
iconNamePressed="shrink"
56+
onClick={() => setSelectedCardId(selectedCardId === "2" ? null : "2")}
57+
>
58+
Selectable card 2 content
59+
</CustomSelectableCard>
60+
</SpaceBetween>
61+
}
62+
>
63+
Selectable response example
64+
</ChatBubble>
65+
</SpaceBetween>
66+
</Container>
67+
68+
<Container header={<Header variant="h3">Presentation container</Header>}>
69+
{selectedCardId ? (
70+
<SpaceBetween size="m">
71+
<Box>{selectedCardId === "1" ? "First" : "Second"} card is selected</Box>
72+
<Button onClick={() => setSelectedCardId(null)}>Clear selection</Button>
73+
</SpaceBetween>
74+
) : null}
75+
</Container>
76+
</SpaceBetween>
77+
</Page>
78+
);
79+
}
80+
81+
function CustomSelectableCard({
82+
header,
83+
children,
84+
iconName,
85+
iconNamePressed,
86+
pressed,
87+
onClick,
88+
}: {
89+
header: React.ReactNode;
90+
children: React.ReactNode;
91+
iconName: IconProps.Name;
92+
iconNamePressed: IconProps.Name;
93+
pressed: boolean;
94+
onClick: () => void;
95+
}) {
96+
return (
97+
<button
98+
aria-pressed={pressed}
99+
className={clsx(styles["selectable-card"], pressed && styles["selectable-card-pressed"])}
100+
onClick={onClick}
101+
>
102+
<SpaceBetween size="s">
103+
<div className={styles["selectable-card-header"]}>
104+
<Box fontWeight="bold">{header}</Box>
105+
<Icon name={pressed ? iconNamePressed : iconName} />
106+
</div>
107+
<Box>{children}</Box>
108+
</SpaceBetween>
109+
</button>
110+
);
111+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
@use "../../node_modules/@cloudscape-design/design-tokens/index.scss" as cs;
7+
8+
@mixin styles-reset {
9+
border-collapse: separate;
10+
border-spacing: 0;
11+
box-sizing: border-box;
12+
caption-side: top;
13+
cursor: auto;
14+
direction: inherit;
15+
empty-cells: show;
16+
font-family: serif;
17+
font-size: medium;
18+
font-style: normal;
19+
font-variant: normal;
20+
font-weight: 400;
21+
font-stretch: normal;
22+
line-height: normal;
23+
hyphens: none;
24+
letter-spacing: normal;
25+
list-style: disc outside none;
26+
tab-size: 8;
27+
text-align: start;
28+
text-indent: 0;
29+
text-shadow: none;
30+
text-transform: none;
31+
visibility: visible;
32+
white-space: normal;
33+
word-spacing: normal;
34+
}
35+
36+
@mixin focus-highlight(
37+
$gutter: 4px,
38+
$border-radius: cs.$border-radius-control-default-focus-ring,
39+
$border-color: cs.$color-border-item-focused,
40+
$border-width: 2px
41+
) {
42+
position: relative;
43+
box-sizing: border-box;
44+
outline: 2px dotted transparent;
45+
outline-offset: calc($gutter - 1px);
46+
47+
&::before {
48+
content: " ";
49+
display: block;
50+
position: absolute;
51+
box-sizing: border-box;
52+
inset-inline-start: calc(-1 * #{$gutter});
53+
inset-block-start: calc(-1 * #{$gutter});
54+
inline-size: calc(100% + 2 * #{$gutter});
55+
block-size: calc(100% + 2 * #{$gutter});
56+
border-radius: $border-radius;
57+
border: $border-width solid $border-color;
58+
}
59+
}
60+
61+
.selectable-card {
62+
@include styles-reset;
63+
background: cs.$color-background-layout-main;
64+
border-radius: 8px;
65+
border: 2px solid cs.$color-border-divider-default;
66+
padding: cs.$space-scaled-s cs.$space-scaled-s;
67+
cursor: pointer;
68+
69+
&:hover {
70+
background: cs.$color-background-dropdown-item-hover;
71+
}
72+
73+
&-pressed {
74+
border-color: cs.$color-border-item-selected;
75+
background: cs.$color-background-item-selected;
76+
77+
&:hover {
78+
background: cs.$color-background-item-selected;
79+
}
80+
}
81+
82+
&:focus-visible {
83+
@include focus-highlight(8px, 8px);
84+
}
85+
}
86+
87+
.selectable-card-header {
88+
display: flex;
89+
justify-content: space-between;
90+
gap: cs.$space-static-s;
91+
}

0 commit comments

Comments
 (0)