Skip to content

Commit

Permalink
feat(FileCard): Add Link and Image to FileCard (#957)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lisa18289 authored Nov 7, 2024
1 parent dc1a90c commit 0543759
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 39 deletions.
48 changes: 43 additions & 5 deletions packages/components/src/components/FileCard/FileCard.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
border-width: var(--file-card--border-width);
border-style: var(--file-card--border-style);
border-radius: var(--file-card--corner-radius);
padding-inline: var(--file-card--padding-x);
padding-block: var(--file-card--padding-y);
display: flex;
gap: var(--file-card--spacing);
align-items: center;
max-width: 100%;
overflow: hidden;
position: relative;

&:not(:has(.link)),
.link {
display: flex;
align-items: center;
padding-inline: var(--file-card--padding-x);
padding-block: var(--file-card--padding-y);
gap: var(--file-card--spacing);
}

.text {
display: flex;
Expand All @@ -29,4 +34,37 @@
font-size: var(--file-card--sub-title-font-size);
}
}

&:has(.link) {
display: grid;
grid-template-areas: "content";

.link {
flex-grow: 1;
grid-area: content;
overflow: hidden;

&:hover {
background-color: var(--file-card--background-color--hover);
}

&[data-pressed] {
background-color: var(--file-card--background-color--pressed);
}
}

.text {
--button-width: calc(
var(--icon--size--s) + var(--button--padding-s-icon-only) * 2
);
padding-right: calc(var(--file-card--spacing) + var(--button-width));
}

.deleteButton {
grid-area: content;
margin-right: var(--file-card--padding-x);
justify-self: end;
align-self: center;
}
}
}
62 changes: 30 additions & 32 deletions packages/components/src/components/FileCard/FileCard.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import React from "react";
import { Avatar } from "@/components/Avatar";
import { Avatar } from "./components/Avatar";
import { Text } from "@/components/Text";
import { IconClose, IconFile } from "@/components/Icon/components/icons";
import IconImage from "@/components/Icon/components/icons/IconImage";
import { Button } from "@/components/Button";
import type {
PropsWithClassName,
PropsWithElementType,
} from "@/lib/types/props";
import styles from "./FileCard.module.scss";
import clsx from "clsx";
import { flowComponent } from "@/lib/componentFactory/flowComponent";
import locales from "./locales/*.locale.json";
import { useLocalizedStringFormatter } from "react-aria";
import { FileSizeText } from "@/components/FileCard/components/FileSizeText";
import { Link, type LinkProps } from "@/components/Link";
import Wrap from "@/components/Wrap";
import { DeleteButton } from "@/components/FileCard/components/DeleteButton";

export interface FileCardProps
extends PropsWithClassName,
PropsWithElementType<"div" | "li"> {
PropsWithElementType<"div" | "li">,
Pick<LinkProps, "onPress" | "href" | "target" | "download"> {
name: string;
type?: string;
onDelete?: () => void;
sizeInBytes?: number;
imageSrc?: string;
}

export const FileCard = flowComponent("FileCard", (props) => {
Expand All @@ -32,40 +32,38 @@ export const FileCard = flowComponent("FileCard", (props) => {
name,
className,
elementType = "div",
onPress,
href,
target,
download,
imageSrc,
} = props;

const rootClassName = clsx(styles.fileCard, className);

const Element = elementType;

const stringFormatter = useLocalizedStringFormatter(locales);

const avatar = (
<Avatar color="blue">
{type?.includes("image") ? <IconImage /> : <IconFile />}
</Avatar>
);

return (
<Element className={rootClassName}>
{avatar}
<span className={styles.text}>
<Text className={styles.title}>
<b>{name}</b>
</Text>
{sizeInBytes && <FileSizeText sizeInBytes={sizeInBytes} />}
</span>
{onDelete && (
<Button
aria-label={stringFormatter.format(`fileCard.delete`)}
size="s"
variant="plain"
color="secondary"
onPress={onDelete}
<Wrap if={href || onPress}>
<Link
className={styles.link}
unstyled
href={href}
onPress={onPress}
target={target}
download={download}
>
<IconClose />
</Button>
)}
<Avatar type={type} imageSrc={imageSrc} />
<span className={styles.text}>
<Text className={styles.title}>
<b>{name}</b>
</Text>
{sizeInBytes && <FileSizeText sizeInBytes={sizeInBytes} />}
</span>
</Link>
</Wrap>
{onDelete && <DeleteButton onDelete={onDelete} />}
</Element>
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { FC } from "react";
import React from "react";
import IconImage from "../../../Icon/components/icons/IconImage";
import { IconFile } from "@/components/Icon/components/icons";
import { Avatar as AvatarComponent } from "@/components/Avatar";
import { Image } from "@/components/Image";

interface Props {
type?: string;
imageSrc?: string;
}

export const Avatar: FC<Props> = (props) => {
const { type, imageSrc } = props;

if (imageSrc) {
return (
<AvatarComponent>
<Image src={imageSrc} />
</AvatarComponent>
);
}

return (
<AvatarComponent color="blue">
{type?.startsWith("image") ? <IconImage /> : <IconFile />}
</AvatarComponent>
);
};
export default Avatar;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Avatar";
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { FC } from "react";
import React from "react";
import { Button } from "@/components/Button";
import styles from "@/components/FileCard/FileCard.module.scss";
import { IconClose } from "@/components/Icon/components/icons";
import locales from "../../locales/*.locale.json";
import { useLocalizedStringFormatter } from "react-aria";

interface Props {
onDelete: () => void;
}

export const DeleteButton: FC<Props> = (props) => {
const { onDelete } = props;
const stringFormatter = useLocalizedStringFormatter(locales);

return (
<Button
className={styles.deleteButton}
aria-label={stringFormatter.format(`fileCard.delete`)}
size="s"
variant="plain"
color="secondary"
onPress={onDelete}
>
<IconClose />
</Button>
);
};

export default DeleteButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./DeleteButton";
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { FileCard } from "@/components/FileCard";
import { dummyText } from "@/lib/dev/dummyText";
import { action } from "@storybook/addon-actions";

const meta: Meta<typeof FileCard> = {
title: "Upload/FileCard",
Expand All @@ -21,7 +23,28 @@ export const WithSize: Story = { args: { sizeInBytes: 47500 } };
export const WithOnDelete: Story = {
args: {
onDelete: () => {
console.log("deleted");
action("onDelete");
},
},
};

export const WithLink: Story = {
args: {
href: "#",
},
};

export const WithLinkAndOnDelete: Story = {
args: {
href: "#",
onDelete: () => {
action("onDelete");
},
},
};

export const WithImage: Story = {
args: {
imageSrc: dummyText.imageSrc,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react";
import defaultMeta from "./Default.stories";
import { FileCard } from "@/components/FileCard";
import { dummyText } from "@/lib/dev/dummyText";
import { action } from "@storybook/addon-actions";

const meta: Meta<typeof FileCard> = {
...defaultMeta,
Expand All @@ -13,5 +14,22 @@ export default meta;
type Story = StoryObj<typeof FileCard>;

export const LongName: Story = {
args: { name: dummyText.long, sizeInBytes: 47500 },
args: {
name: dummyText.long,
sizeInBytes: 47500,
onDelete: () => {
action("onDelete");
},
},
};

export const LongNameAndLink: Story = {
args: {
name: dummyText.long,
sizeInBytes: 47500,
onDelete: () => {
action("onDelete");
},
href: "#",
},
};
5 changes: 5 additions & 0 deletions packages/design-tokens/src/upload/file-card.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ file-card:
value: "{neutral-outline-border-color}"
sub-title-font-size:
value: "{font-size-text.s}"
background-color:
hover:
value: "{neutral-outline-background-color.hover}"
pressed:
value: "{neutral-outline-background-color.pressed}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import FileCard from "@mittwald/flow-react-components/FileCard";

<FileCard
type="image/jpg"
name="image.jpg"
sizeInBytes={47500}
imageSrc="https://mittwald.github.io/flow/assets/mittwald_logo_rgb.jpg"
/>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import FileCard from "@mittwald/flow-react-components/FileCard";

<FileCard
type="image/jpg"
name="image.jpg"
sizeInBytes={47500}
href="#"
/>;
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,15 @@
# Mit Delete Button

<LiveCodeEditor example="delete" editorCollapsed />

---

# Mit Link

<LiveCodeEditor example="link" editorCollapsed />

---

# Mit Bild

<LiveCodeEditor example="image" editorCollapsed />

0 comments on commit 0543759

Please sign in to comment.