Add new TableCellProfile

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2025-04-14 22:03:46 +02:00
parent 5e89ce52f1
commit ec5ebd167b
15 changed files with 306 additions and 5 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/canon': patch
---
Add new TableCellProfile component for Table and DataTable in Canon.
+42
View File
@@ -246,6 +246,48 @@
display: flex;
}
.canon-TableCellProfile {
gap: var(--canon-space-2);
flex-direction: row;
align-items: center;
display: flex;
}
.canon-TableCellProfileAvatar {
vertical-align: middle;
user-select: none;
color: var(--canon-fg-primary);
background-color: var(--canon-bg-surface-2);
border-radius: 100%;
justify-content: center;
align-items: center;
width: 1.25rem;
height: 1.25rem;
font-size: 1rem;
font-weight: 500;
line-height: 1;
display: inline-flex;
overflow: hidden;
}
.canon-TableCellProfileAvatarImage {
object-fit: cover;
width: 100%;
height: 100%;
}
.canon-TableCellProfileAvatarFallback {
width: 100%;
height: 100%;
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
box-shadow: inset 0 0 0 1px var(--canon-border);
border-radius: var(--canon-radius-full);
justify-content: center;
align-items: center;
display: flex;
}
.canon-Text {
font-family: var(--canon-font-regular);
margin: 0;
+42
View File
@@ -9470,6 +9470,48 @@
display: flex;
}
.canon-TableCellProfile {
gap: var(--canon-space-2);
flex-direction: row;
align-items: center;
display: flex;
}
.canon-TableCellProfileAvatar {
vertical-align: middle;
user-select: none;
color: var(--canon-fg-primary);
background-color: var(--canon-bg-surface-2);
border-radius: 100%;
justify-content: center;
align-items: center;
width: 1.25rem;
height: 1.25rem;
font-size: 1rem;
font-weight: 500;
line-height: 1;
display: inline-flex;
overflow: hidden;
}
.canon-TableCellProfileAvatarImage {
object-fit: cover;
width: 100%;
height: 100%;
}
.canon-TableCellProfileAvatarFallback {
width: 100%;
height: 100%;
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
box-shadow: inset 0 0 0 1px var(--canon-border);
border-radius: var(--canon-radius-full);
justify-content: center;
align-items: center;
display: flex;
}
.canon-Text {
font-family: var(--canon-font-regular);
margin: 0;
+21 -2
View File
@@ -260,6 +260,9 @@ export const DataTable: {
TableCellLink: ForwardRefExoticComponent<
TableCellLinkProps & RefAttributes<HTMLDivElement>
>;
TableCellProfile: ForwardRefExoticComponent<
TableCellProfileProps & RefAttributes<HTMLDivElement>
>;
TableHead: ForwardRefExoticComponent<
ThHTMLAttributes<HTMLTableCellElement> & RefAttributes<HTMLTableCellElement>
>;
@@ -1116,6 +1119,9 @@ export const Table: {
CellLink: ForwardRefExoticComponent<
TableCellLinkProps & RefAttributes<HTMLDivElement>
>;
CellProfile: ForwardRefExoticComponent<
TableCellProfileProps & RefAttributes<HTMLDivElement>
>;
Caption: ForwardRefExoticComponent<
HTMLAttributes<HTMLTableCaptionElement> &
RefAttributes<HTMLTableCaptionElement>
@@ -1124,7 +1130,7 @@ export const Table: {
// @public (undocumented)
export interface TableCellLinkProps
extends React.TdHTMLAttributes<HTMLTableCellElement> {
extends React.HTMLAttributes<HTMLDivElement> {
// (undocumented)
description?: string;
// (undocumented)
@@ -1135,9 +1141,22 @@ export interface TableCellLinkProps
title: string;
}
// @public (undocumented)
export interface TableCellProfileProps
extends React.HTMLAttributes<HTMLDivElement> {
// (undocumented)
name?: string;
// (undocumented)
src?: string;
// (undocumented)
to?: string;
// (undocumented)
withImage?: boolean;
}
// @public (undocumented)
export interface TableCellTextProps
extends React.TdHTMLAttributes<HTMLTableCellElement> {
extends React.HTMLAttributes<HTMLDivElement> {
// (undocumented)
description?: string;
// (undocumented)
@@ -46,5 +46,6 @@ export const DataTable = {
TableCell: Table.Cell,
TableCellText: Table.CellText,
TableCellLink: Table.CellLink,
TableCellProfile: Table.CellProfile,
TableHead: Table.Head,
};
@@ -58,7 +58,7 @@ export const columns: ColumnDef<DataProps>[] = [
accessorKey: 'owner',
header: 'Owner',
cell: ({ row }) => (
<DataTable.TableCellText title={row.getValue('owner')} />
<DataTable.TableCellProfile name={row.getValue('owner')} />
),
},
{
@@ -19,6 +19,7 @@ import clsx from 'clsx';
import { TableCell } from './TableCell/TableCell';
import { TableCellText } from './TableCellText/TableCellText';
import { TableCellLink } from './TableCellLink/TableCellLink';
import { TableCellProfile } from './TableCellProfile/TableCellProfile';
const TableRoot = forwardRef<
HTMLTableElement,
@@ -91,5 +92,6 @@ export const Table = {
Cell: TableCell,
CellText: TableCellText,
CellLink: TableCellLink,
CellProfile: TableCellProfile,
Caption: TableCaption,
};
@@ -18,7 +18,7 @@ import type { useRender } from '@base-ui-components/react/use-render';
/** @public */
export interface TableCellLinkProps
extends React.TdHTMLAttributes<HTMLTableCellElement> {
extends React.HTMLAttributes<HTMLDivElement> {
title: string;
description?: string;
href: string;
@@ -0,0 +1,47 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Meta, StoryObj } from '@storybook/react';
import { TableCellProfile } from './TableCellProfile';
const meta = {
title: 'Components/Table/TableCellProfile',
component: TableCellProfile,
} satisfies Meta<typeof TableCellProfile>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
src: 'https://avatars.githubusercontent.com/u/1540635?v=4',
name: 'Charles de Dreuille',
},
};
export const Fallback: Story = {
args: {
...Default.args,
src: 'https://avatars.githubusercontent.com/u/15406AAAAAAAAA',
},
};
export const WithLink: Story = {
args: {
...Default.args,
to: 'https://www.google.com',
},
};
@@ -0,0 +1,57 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.canon-TableCellProfile {
display: flex;
flex-direction: row;
gap: var(--canon-space-2);
align-items: center;
}
.canon-TableCellProfileAvatar {
display: inline-flex;
justify-content: center;
align-items: center;
vertical-align: middle;
border-radius: 100%;
user-select: none;
font-weight: 500;
color: var(--canon-fg-primary);
background-color: var(--canon-bg-surface-2);
font-size: 1rem;
line-height: 1;
overflow: hidden;
height: 1.25rem;
width: 1.25rem;
}
.canon-TableCellProfileAvatarImage {
object-fit: cover;
height: 100%;
width: 100%;
}
.canon-TableCellProfileAvatarFallback {
align-items: center;
display: flex;
justify-content: center;
height: 100%;
width: 100%;
font-size: var(--canon-font-size-2);
font-weight: var(--canon-font-weight-regular);
box-shadow: inset 0 0 0 1px var(--canon-border);
border-radius: var(--canon-radius-full);
}
@@ -0,0 +1,60 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { forwardRef } from 'react';
import clsx from 'clsx';
import { TableCellProfileProps } from './types';
import { Text } from '../../Text/Text';
import { Link } from '../../Link/Link';
import { Avatar } from '@base-ui-components/react/avatar';
/** @public */
const TableCellProfile = forwardRef<HTMLDivElement, TableCellProfileProps>(
({ className, src, name, to, withImage = true, ...rest }, ref) => (
<div
ref={ref}
className={clsx('canon-TableCellProfile', className)}
{...rest}
>
{withImage && (
<Avatar.Root className="canon-TableCellProfileAvatar">
<Avatar.Image
src={src}
width="20"
height="20"
className="canon-TableCellProfileAvatarImage"
/>
<Avatar.Fallback className="canon-TableCellProfileAvatarFallback">
{(name || '')
.split(' ')
.map(word => word[0])
.join('')
.toLocaleUpperCase('en-US')
.slice(0, 1)}
</Avatar.Fallback>
</Avatar.Root>
)}
{name && to ? (
<Link to={to}>{name}</Link>
) : (
<Text variant="body">{name}</Text>
)}
</div>
),
);
TableCellProfile.displayName = 'TableCellProfile';
export { TableCellProfile };
@@ -0,0 +1,24 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @public */
export interface TableCellProfileProps
extends React.HTMLAttributes<HTMLDivElement> {
src?: string;
name?: string;
to?: string;
withImage?: boolean;
}
@@ -16,7 +16,7 @@
/** @public */
export interface TableCellTextProps
extends React.TdHTMLAttributes<HTMLTableCellElement> {
extends React.HTMLAttributes<HTMLDivElement> {
title: string;
description?: string;
}
@@ -17,3 +17,4 @@
export * from './Table';
export * from './TableCellText/types';
export * from './TableCellLink/types';
export * from './TableCellProfile/types';
+1
View File
@@ -27,6 +27,7 @@
@import '../components/Table/TableCell/TableCell.styles.css';
@import '../components/Table/TableCellText/TableCellText.styles.css';
@import '../components/Table/TableCellLink/TableCellLink.styles.css';
@import '../components/Table/TableCellProfile/TableCellProfile.styles.css';
@import '../components/Text/styles.css';
@import '../components/Heading/styles.css';
@import '../components/IconButton/styles.css';