diff --git a/packages/components/src/components/FileCard/FileCard.module.scss b/packages/components/src/components/FileCard/FileCard.module.scss index d7db5f757..9f993b0f2 100644 --- a/packages/components/src/components/FileCard/FileCard.module.scss +++ b/packages/components/src/components/FileCard/FileCard.module.scss @@ -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; @@ -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; + } + } } diff --git a/packages/components/src/components/FileCard/FileCard.tsx b/packages/components/src/components/FileCard/FileCard.tsx index 159a3a792..c04db33c9 100644 --- a/packages/components/src/components/FileCard/FileCard.tsx +++ b/packages/components/src/components/FileCard/FileCard.tsx @@ -1,9 +1,6 @@ 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, @@ -11,17 +8,20 @@ import type { 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 { name: string; type?: string; onDelete?: () => void; sizeInBytes?: number; + imageSrc?: string; } export const FileCard = flowComponent("FileCard", (props) => { @@ -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 = ( - - {type?.includes("image") ? : } - - ); - return ( - {avatar} - - - {name} - - {sizeInBytes && } - - {onDelete && ( - - )} + + + + {name} + + {sizeInBytes && } + + + + {onDelete && } ); }); diff --git a/packages/components/src/components/FileCard/components/Avatar/Avatar.tsx b/packages/components/src/components/FileCard/components/Avatar/Avatar.tsx new file mode 100644 index 000000000..457062f13 --- /dev/null +++ b/packages/components/src/components/FileCard/components/Avatar/Avatar.tsx @@ -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) => { + const { type, imageSrc } = props; + + if (imageSrc) { + return ( + + + + ); + } + + return ( + + {type?.startsWith("image") ? : } + + ); +}; +export default Avatar; diff --git a/packages/components/src/components/FileCard/components/Avatar/index.ts b/packages/components/src/components/FileCard/components/Avatar/index.ts new file mode 100644 index 000000000..8d3d546e7 --- /dev/null +++ b/packages/components/src/components/FileCard/components/Avatar/index.ts @@ -0,0 +1 @@ +export * from "./Avatar"; diff --git a/packages/components/src/components/FileCard/components/DeleteButton/DeleteButton.tsx b/packages/components/src/components/FileCard/components/DeleteButton/DeleteButton.tsx new file mode 100644 index 000000000..5990cb852 --- /dev/null +++ b/packages/components/src/components/FileCard/components/DeleteButton/DeleteButton.tsx @@ -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) => { + const { onDelete } = props; + const stringFormatter = useLocalizedStringFormatter(locales); + + return ( + + ); +}; + +export default DeleteButton; diff --git a/packages/components/src/components/FileCard/components/DeleteButton/index.ts b/packages/components/src/components/FileCard/components/DeleteButton/index.ts new file mode 100644 index 000000000..5ee6de22b --- /dev/null +++ b/packages/components/src/components/FileCard/components/DeleteButton/index.ts @@ -0,0 +1 @@ +export * from "./DeleteButton"; diff --git a/packages/components/src/components/FileCard/stories/Default.stories.tsx b/packages/components/src/components/FileCard/stories/Default.stories.tsx index a614ab24a..6a0a02dc3 100644 --- a/packages/components/src/components/FileCard/stories/Default.stories.tsx +++ b/packages/components/src/components/FileCard/stories/Default.stories.tsx @@ -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 = { title: "Upload/FileCard", @@ -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, + }, +}; diff --git a/packages/components/src/components/FileCard/stories/EdgeCases.stories.tsx b/packages/components/src/components/FileCard/stories/EdgeCases.stories.tsx index dcb86430f..5bdddeb8b 100644 --- a/packages/components/src/components/FileCard/stories/EdgeCases.stories.tsx +++ b/packages/components/src/components/FileCard/stories/EdgeCases.stories.tsx @@ -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 = { ...defaultMeta, @@ -13,5 +14,22 @@ export default meta; type Story = StoryObj; 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: "#", + }, }; diff --git a/packages/design-tokens/src/upload/file-card.yml b/packages/design-tokens/src/upload/file-card.yml index f86cce5c8..027cfdab1 100644 --- a/packages/design-tokens/src/upload/file-card.yml +++ b/packages/design-tokens/src/upload/file-card.yml @@ -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}" diff --git a/packages/docs/src/content/03-components/upload/file-card/examples/image.tsx b/packages/docs/src/content/03-components/upload/file-card/examples/image.tsx new file mode 100644 index 000000000..8af030dbf --- /dev/null +++ b/packages/docs/src/content/03-components/upload/file-card/examples/image.tsx @@ -0,0 +1,8 @@ +import FileCard from "@mittwald/flow-react-components/FileCard"; + +; diff --git a/packages/docs/src/content/03-components/upload/file-card/examples/link.tsx b/packages/docs/src/content/03-components/upload/file-card/examples/link.tsx new file mode 100644 index 000000000..9ee840de3 --- /dev/null +++ b/packages/docs/src/content/03-components/upload/file-card/examples/link.tsx @@ -0,0 +1,8 @@ +import FileCard from "@mittwald/flow-react-components/FileCard"; + +; diff --git a/packages/docs/src/content/03-components/upload/file-card/overview.mdx b/packages/docs/src/content/03-components/upload/file-card/overview.mdx index 5a9bb058f..b811de211 100644 --- a/packages/docs/src/content/03-components/upload/file-card/overview.mdx +++ b/packages/docs/src/content/03-components/upload/file-card/overview.mdx @@ -7,3 +7,15 @@ # Mit Delete Button + +--- + +# Mit Link + + + +--- + +# Mit Bild + +