Skip to content

Commit a9fccbd

Browse files
feat(S2): S2 ListView (adobe#8878)
* feat: s2 ListView * Explore highlight selection * fix docs type check * Add highlight selection option b to table * Add highlight selection option b to ListView * change selection behaviour of table for highlight mode * add option D as highlightMode * change font weight to bold for highlight selection * update background color * Start new highlight selection prototypes, ListView and part of TreeView * fix lint * update styles for listview and treeview * tableview * design updates * fix colors and add disabled items * fix lint * initialize docs * fix edgeToText import * update ListView (loadingMore, actionmenu, empty state, checkbox) * match selection styles to treeview/tableview * docs improvements * add jsdoc * support hasChildItems chevron * add stories * add hasChildItems example to docs * fix overflow in empty state * use objectFit: 'cover' for images * vertically align icons * add overflowMode * audit props * codemods * add chromatic stories * lint * add ListView testing docs * fix types * docs types * add description for search menu * docs types * fix selection checkbox visibility (always hide if disabled) * remove highlightMode prop * remove Tree/Table selection changes * remove unrelated Picker change * remove press scaling * keep bottom border width static to avoid 1px shift when highlight selection occurs. * add remaining states to chromatic * remove ListViewLoadMoreItem * fix prop types * update migration guide * remove bottom border radius for last item * prop types * remove style props from list item * remove seam mask element in favor of extending row background * make docs example wide * update docs content * add ActionBar support * fix gap for checkbox selection * docs update * style updates * remove renderer context * merge selection for checkbox selection * update docs * add LinkOut icon for links that open in new tab * fix storybook stories * add example to ActionBar docs * reserve space for trailing icon if at least one row has one * add padding to loading spinner * separate the icon and thumbnail slots examples in docs * docs types * move check image into chromatic folder * export ListViewContext from index.ts * cleanup story * use icons in all items in navigation docs * remove unused shorthands from macro theme * refactor to move isPrevSelected, isNextSelected, etc. logic out of GridList. * fix last item bottom border styles * pass id instead of item through render props (matches Table) * fix border styles * add explicit bottom border width --------- Co-authored-by: Reid Barber <reid@reidbarber.com>
1 parent 745de5b commit a9fccbd

File tree

22 files changed

+2269
-23
lines changed

22 files changed

+2269
-23
lines changed

.storybook-s2/docs/Migrating.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ export function Migrating() {
259259
<li className={style({font: 'body', marginY: 8})}>If within <Code>Picker</Code>: Update <Code>Item</Code> to be a <Code>PickerItem</Code></li>
260260
<li className={style({font: 'body', marginY: 8})}>If within <Code>ComboBox</Code>: Update <Code>Item</Code> to be a <Code>ComboBoxItem</Code></li>
261261
<li className={style({font: 'body', marginY: 8})}>If within <Code>ListBox</Code>: Update <Code>Item</Code> to be a <Code>ListBoxItem</Code></li>
262+
<li className={style({font: 'body', marginY: 8})}>If within <Code>ListView</Code>: Update <Code>Item</Code> to be a <Code>ListViewItem</Code></li>
262263
<li className={style({font: 'body', marginY: 8})}>If within <Code>TabList</Code>: Update <Code>Item</Code> to be a <Code>Tab</Code></li>
263264
<li className={style({font: 'body', marginY: 8})}>If within <Code>TabPanels</Code>: Update <Code>Item</Code> to be a <Code>TabPanel</Code> and remove surrounding <Code>TabPanels</Code></li>
264265
<li className={style({font: 'body', marginY: 8})}>Update <Code>key</Code> to be <Code>id</Code> (and keep <Code>key</Code> if rendered inside <Code>array.map</Code>)</li>
@@ -275,6 +276,12 @@ export function Migrating() {
275276
<li className={style({font: 'body', marginY: 8})}>Update <Code>Item</Code> to be a <Code>ListBoxItem</Code></li>
276277
</ul>
277278

279+
<H3>ListView</H3>
280+
<ul className="sb-unstyled">
281+
<li className={style({font: 'body', marginY: 8})}>[PENDING] Comment out <Code>density</Code> (it has not been implemented yet)</li>
282+
<li className={style({font: 'body', marginY: 8})}>[PENDING] Comment out <Code>dragAndDropHooks</Code> (it has not been implemented yet)</li>
283+
</ul>
284+
278285
<H3>Menu</H3>
279286
<ul className="sb-unstyled">
280287
<li className={style({font: 'body', marginY: 8})}>Update <Code>Item</Code> to be a <Code>MenuItem</Code></li>
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/*
2+
* Copyright 2026 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import {ActionButton, ActionButtonGroup, ActionMenu, Content, Heading, IllustratedMessage, Image, ListView, ListViewItem, MenuItem, Text} from '../src';
14+
import {checkers} from './check';
15+
import Delete from '../s2wf-icons/S2_Icon_Delete_20_N.svg';
16+
import Edit from '../s2wf-icons/S2_Icon_Edit_20_N.svg';
17+
import File from '../s2wf-icons/S2_Icon_File_20_N.svg';
18+
import Folder from '../s2wf-icons/S2_Icon_Folder_20_N.svg';
19+
import FolderOpen from '../spectrum-illustrations/linear/FolderOpen';
20+
import type {Meta, StoryObj} from '@storybook/react';
21+
import {style} from '../style/spectrum-theme' with {type: 'macro'};
22+
23+
const meta: Meta<typeof ListView> = {
24+
component: ListView,
25+
parameters: {
26+
chromaticProvider: {disableAnimations: true}
27+
},
28+
title: 'S2 Chromatic/ListView'
29+
};
30+
31+
export default meta;
32+
type Story = StoryObj<typeof ListView>;
33+
34+
let listViewStyles = style({width: 320, height: 320});
35+
36+
const items = [
37+
{id: 'utilities', name: 'Utilities', type: 'folder', description: '16 items'},
38+
{id: 'photoshop', name: 'Adobe Photoshop', type: 'file', description: 'Application'},
39+
{id: 'illustrator', name: 'Adobe Illustrator', type: 'file', description: 'Application'},
40+
{id: 'xd', name: 'Adobe XD', type: 'file', description: 'Application'}
41+
];
42+
43+
export const Example: Story = {
44+
render: (args) => (
45+
<ListView {...args} aria-label="Files" styles={listViewStyles}>
46+
<ListViewItem id="utilities" textValue="Utilities" hasChildItems>
47+
<Folder />
48+
<Text>Utilities</Text>
49+
<Text slot="description">16 items</Text>
50+
</ListViewItem>
51+
<ListViewItem id="photoshop">Adobe Photoshop</ListViewItem>
52+
<ListViewItem id="illustrator">Adobe Illustrator</ListViewItem>
53+
<ListViewItem id="xd">Adobe XD</ListViewItem>
54+
</ListView>
55+
),
56+
args: {
57+
selectionMode: 'multiple',
58+
onLoadMore: undefined
59+
}
60+
};
61+
62+
export const HighlightSelection: Story = {
63+
...Example,
64+
args: {
65+
...Example.args,
66+
selectionStyle: 'highlight',
67+
selectedKeys: ['photoshop', 'illustrator']
68+
}
69+
};
70+
71+
export const Quiet: Story = {
72+
...Example,
73+
args: {
74+
...Example.args,
75+
isQuiet: true
76+
}
77+
};
78+
79+
export const WithImages: Story = {
80+
render: (args) => (
81+
<ListView {...args} aria-label="Images" styles={listViewStyles} items={items}>
82+
{(item) => (
83+
<ListViewItem textValue={item.name}>
84+
<Text>{item.name}</Text>
85+
<Image src={checkers} alt={item.name} />
86+
</ListViewItem>
87+
)}
88+
</ListView>
89+
)
90+
};
91+
92+
export const OverflowTruncate: Story = {
93+
render: (args) => (
94+
<ListView {...args} aria-label="Long text examples" styles={listViewStyles}>
95+
<ListViewItem id="a">
96+
This is a very very very very very very very very long title.
97+
</ListViewItem>
98+
<ListViewItem id="b" textValue="Short title, long description">
99+
<Text>Short title</Text>
100+
<Text slot="description">This is a very very very very very very very very long description.</Text>
101+
</ListViewItem>
102+
<ListViewItem id="c" textValue="Long title, long description">
103+
<Text>This is a very very very very very very very very long title.</Text>
104+
<Text slot="description">This is a very very very very very very very very long description.</Text>
105+
</ListViewItem>
106+
</ListView>
107+
),
108+
args: {
109+
...Example.args,
110+
overflowMode: 'truncate'
111+
}
112+
};
113+
114+
export const OverflowWrap: Story = {
115+
render: (args) => (
116+
<ListView {...args} aria-label="Long text examples" styles={listViewStyles}>
117+
<ListViewItem id="a">
118+
This is a very very very very very very very very long title.
119+
</ListViewItem>
120+
<ListViewItem id="b" textValue="Short title, long description">
121+
<Text>Short title</Text>
122+
<Text slot="description">This is a very very very very very very very very long description.</Text>
123+
</ListViewItem>
124+
<ListViewItem id="c" textValue="Long title, long description">
125+
<Text>This is a very very very very very very very very long title.</Text>
126+
<Text slot="description">This is a very very very very very very very very long description.</Text>
127+
</ListViewItem>
128+
</ListView>
129+
),
130+
args: {
131+
...Example.args,
132+
overflowMode: 'wrap'
133+
}
134+
};
135+
136+
export const DisabledItems: Story = {
137+
render: (args) => (
138+
<ListView {...args} aria-label="Files" items={items} styles={listViewStyles} selectionMode="multiple" disabledKeys={['utilities', 'illustrator']}>
139+
{(item) => (
140+
<ListViewItem textValue={item.name} hasChildItems={item.type === 'folder'}>
141+
{item.type === 'folder' ? <Folder /> : <File />}
142+
<Text>{item.name}</Text>
143+
<Text slot="description">{item.description}</Text>
144+
</ListViewItem>
145+
)}
146+
</ListView>
147+
)
148+
};
149+
150+
export const DisabledBehaviorSelection: Story = {
151+
...DisabledItems,
152+
args: {
153+
disabledBehavior: 'selection'
154+
}
155+
};
156+
157+
export const CheckboxSelection: Story = {
158+
...Example,
159+
args: {
160+
...Example.args,
161+
selectionStyle: 'checkbox',
162+
selectedKeys: ['photoshop', 'illustrator']
163+
}
164+
};
165+
166+
export const Links: Story = {
167+
render: (args) => (
168+
<ListView {...args} aria-label="Bookmarks" styles={listViewStyles}>
169+
<ListViewItem id="https://adobe.com/" href="https://adobe.com/" target="_blank">Adobe</ListViewItem>
170+
<ListViewItem id="https://google.com/" href="https://google.com/" target="_blank">Google</ListViewItem>
171+
<ListViewItem id="https://apple.com/" href="https://apple.com/" target="_blank">Apple</ListViewItem>
172+
<ListViewItem id="https://nytimes.com/" href="https://nytimes.com/" target="_blank">New York Times</ListViewItem>
173+
</ListView>
174+
),
175+
args: {
176+
selectionMode: 'none'
177+
}
178+
};
179+
180+
export const WithActions: Story = {
181+
render: (args) => (
182+
<ListView {...args} aria-label="Files" styles={listViewStyles}>
183+
<ListViewItem id="utilities" textValue="Utilities" hasChildItems>
184+
<Folder />
185+
<Text>Utilities</Text>
186+
<Text slot="description">16 items</Text>
187+
<ActionButtonGroup>
188+
<ActionButton aria-label="Edit"><Edit /></ActionButton>
189+
</ActionButtonGroup>
190+
<ActionMenu>
191+
<MenuItem id="edit"><Edit /><Text>Edit</Text></MenuItem>
192+
<MenuItem id="delete"><Delete /><Text>Delete</Text></MenuItem>
193+
</ActionMenu>
194+
</ListViewItem>
195+
<ListViewItem id="photoshop" textValue="Adobe Photoshop">
196+
<Text>Adobe Photoshop</Text>
197+
<Text slot="description">Application</Text>
198+
<ActionButtonGroup>
199+
<ActionButton aria-label="Edit"><Edit /></ActionButton>
200+
</ActionButtonGroup>
201+
<ActionMenu>
202+
<MenuItem id="edit"><Edit /><Text>Edit</Text></MenuItem>
203+
<MenuItem id="delete"><Delete /><Text>Delete</Text></MenuItem>
204+
</ActionMenu>
205+
</ListViewItem>
206+
</ListView>
207+
),
208+
args: {
209+
selectionMode: 'single'
210+
}
211+
};
212+
213+
export const Loading: Story = {
214+
render: (args) => (
215+
<ListView {...args} aria-label="Loading list" styles={listViewStyles}>
216+
{[]}
217+
</ListView>
218+
),
219+
args: {
220+
loadingState: 'loading'
221+
}
222+
};
223+
224+
export const LoadingMore: Story = {
225+
render: (args) => (
226+
<ListView {...args} aria-label="Loading more list" styles={listViewStyles} items={items} onLoadMore={() => {}}>
227+
{(item) => (
228+
<ListViewItem textValue={item.name}>
229+
{item.name}
230+
</ListViewItem>
231+
)}
232+
</ListView>
233+
),
234+
args: {
235+
loadingState: 'loadingMore'
236+
}
237+
};
238+
239+
export const EmptyState: Story = {
240+
render: (args) => (
241+
<ListView
242+
{...args}
243+
aria-label="Empty list"
244+
styles={listViewStyles}
245+
renderEmptyState={() => (
246+
<IllustratedMessage>
247+
<FolderOpen />
248+
<Heading>No results</Heading>
249+
<Content>No results found.</Content>
250+
</IllustratedMessage>
251+
)}>
252+
{[]}
253+
</ListView>
254+
)
255+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
export let checkers = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAuMTAwMDk4IDBIMy4xMDAxVjNIMC4xMDAwOThWMFoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTAuMTAwMDk4IDE4SDMuMTAwMVYyMUgwLjEwMDA5OFYxOFoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTYuMTAwMSAwSDkuMTAwMVYzSDYuMTAwMVYwWiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNNi4xMDAxIDE4SDkuMTAwMVYyMUg2LjEwMDFWMThaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0xMi4xMDAxIDE4SDkuMTAwMVYxNUgxMi4xMDAxVjE4WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMTIuMTAwMSAyNEg5LjEwMDFWMjFIMTIuMTAwMVYyNFoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTE1LjEwMDEgMEgxMi4xMDAxVjNIMTUuMTAwMVYwWiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMTUuMTAwMSAxOEgxMi4xMDAxVjIxSDE1LjEwMDFWMThaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0xOC4xMDAxIDE4SDE1LjEwMDFWMTVIMTguMTAwMVYxOFoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTE4LjEwMDEgMjRIMTUuMTAwMVYyMUgxOC4xMDAxVjI0WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMjEuMTAwMSAwSDE4LjEwMDFWM0gyMS4xMDAxVjBaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0yMS4xMDAxIDE4SDE4LjEwMDFWMjFIMjEuMTAwMVYxOFoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTI0LjEwMDEgMThIMjEuMTAwMVYxNUgyNC4xMDAxVjE4WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMjEuMTAwMSAyMUgyNC4xMDAxVjI0SDIxLjEwMDFWMjFaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik02LjEwMDEgMThIMy4xMDAxVjE1SDYuMTAwMVYxOFoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTYuMTAwMSAyNEgzLjEwMDFWMjFINi4xMDAxVjI0WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMC4xMDAwOTggNkgzLjEwMDFWM0gwLjEwMDA5OFY2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYuMTAwMSA2SDkuMTAwMVYzSDYuMTAwMVY2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTEyLjEwMDEgMTJIOS4xMDAxVjE1SDEyLjEwMDFWMTJaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTUuMTAwMSA2SDEyLjEwMDFWM0gxNS4xMDAxVjZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTguMTAwMSAxMkgxNS4xMDAxVjE1SDE4LjEwMDFWMTJaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMjEuMTAwMSA2SDE4LjEwMDFWM0gyMS4xMDAxVjZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMjQuMTAwMSAxMkgyMS4xMDAxVjE1SDI0LjEwMDFWMTJaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNi4xMDAxIDEySDMuMTAwMVYxNUg2LjEwMDFWMTJaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMC4xMDAwOTggOUgzLjEwMDFWNkgwLjEwMDA5OFY5WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNNi4xMDAxIDlIOS4xMDAxVjZINi4xMDAxVjlaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0xMi4xMDAxIDlIOS4xMDAxVjEySDEyLjEwMDFWOVoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTE1LjEwMDEgOUgxMi4xMDAxVjZIMTUuMTAwMVY5WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMTguMTAwMSA5SDE1LjEwMDFWMTJIMTguMTAwMVY5WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMjEuMTAwMSA5SDE4LjEwMDFWNkgyMS4xMDAxVjlaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0yNC4xMDAxIDlIMjEuMTAwMVYxMkgyNC4xMDAxVjlaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik02LjEwMDEgOUgzLjEwMDFWMTJINi4xMDAxVjlaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0wLjEwMDA5OCAxMkgzLjEwMDFWOUgwLjEwMDA5OFYxMloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik02LjEwMDEgMTJIOS4xMDAxVjlINi4xMDAxVjEyWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTEyLjEwMDEgNkg5LjEwMDFWOUgxMi4xMDAxVjZaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTUuMTAwMSAxMkgxMi4xMDAxVjlIMTUuMTAwMVYxMloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xOC4xMDAxIDZIMTUuMTAwMVY5SDE4LjEwMDFWNloiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yMS4xMDAxIDEySDE4LjEwMDFWOUgyMS4xMDAxVjEyWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTI0LjEwMDEgNkgyMS4xMDAxVjlIMjQuMTAwMVY2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYuMTAwMSA2SDMuMTAwMVY5SDYuMTAwMVY2WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTAuMTAwMDk4IDE1SDMuMTAwMVYxMkgwLjEwMDA5OFYxNVoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTYuMTAwMSAxNUg5LjEwMDFWMTJINi4xMDAxVjE1WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMTIuMTAwMSAzSDkuMTAwMVY2SDEyLjEwMDFWM1oiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTE1LjEwMDEgMTVIMTIuMTAwMVYxMkgxNS4xMDAxVjE1WiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNMTguMTAwMSAzSDE1LjEwMDFWNkgxOC4xMDAxVjNaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0yMS4xMDAxIDE1SDE4LjEwMDFWMTJIMjEuMTAwMVYxNVoiIGZpbGw9IiNFMUUxRTEiLz4KPHBhdGggZD0iTTI0LjEwMDEgM0gyMS4xMDAxVjZIMjQuMTAwMVYzWiIgZmlsbD0iI0UxRTFFMSIvPgo8cGF0aCBkPSJNNi4xMDAxIDNIMy4xMDAxVjZINi4xMDAxVjNaIiBmaWxsPSIjRTFFMUUxIi8+CjxwYXRoIGQ9Ik0wLjEwMDA5OCAxOEgzLjEwMDFWMTVIMC4xMDAwOThWMThaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMC4xMDAwOTggMjRIMy4xMDAxVjIxSDAuMTAwMDk4VjI0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYuMTAwMSAxOEg5LjEwMDFWMTVINi4xMDAxVjE4WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTYuMTAwMSAyNEg5LjEwMDFWMjFINi4xMDAxVjI0WiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTEyLjEwMDEgMEg5LjEwMDFWM0gxMi4xMDAxVjBaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTIuMTAwMSAxOEg5LjEwMDFWMjFIMTIuMTAwMVYxOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xNS4xMDAxIDE4SDEyLjEwMDFWMTVIMTUuMTAwMVYxOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xNS4xMDAxIDI0SDEyLjEwMDFWMjFIMTUuMTAwMVYyNFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xOC4xMDAxIDBIMTUuMTAwMVYzSDE4LjEwMDFWMFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xOC4xMDAxIDE4SDE1LjEwMDFWMjFIMTguMTAwMVYxOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yMS4xMDAxIDE4SDE4LjEwMDFWMTVIMjEuMTAwMVYxOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yMS4xMDAxIDI0SDE4LjEwMDFWMjFIMjEuMTAwMVYyNFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yMS4xMDAxIDNIMjQuMTAwMVYwSDIxLjEwMDFWM1oiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0yNC4xMDAxIDE4SDIxLjEwMDFWMjFIMjQuMTAwMVYxOFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik02LjEwMDEgMEgzLjEwMDFWM0g2LjEwMDFWMFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik02LjEwMDEgMThIMy4xMDAxVjIxSDYuMTAwMVYxOFoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=';

0 commit comments

Comments
 (0)