From c4ace6dae9a57dce2610aabf74f5ad59939c27a4 Mon Sep 17 00:00:00 2001 From: Jose Manuel Serrano Amaut <a20122128@pucp.pe> Date: Wed, 8 Mar 2023 01:07:30 -0500 Subject: [PATCH] [WIP]: Add FileCard component and FileCard demo page. Missing to add upload layer in component. Also missing to decide to delete rightlayer and set abosulte positions for delete button and others. Missing to refactopr some grids flexbox for displaying filecard properly since they are horizontal higher. --- .../DemoFileMosaicUploadStatus.tsx | 32 +++- .../DemoFileMosaicValidation.jsx | 15 +- .../components/file-card/FileCard.scss | 70 +++++++- .../components/file-card/FileCard.tsx | 24 +-- .../components/FileCardInfoLayer.tsx | 42 +++++ .../{ => components}/FileCardPaper.scss | 0 .../{ => components}/FileCardRightLayer.tsx | 4 +- .../FileMosaicRightLayer.scss | 0 .../FileMosaicInfoLayerProps.ts | 2 +- src/pages/demo/FileCardDemoPage.jsx | 162 ++++++++++++++---- 10 files changed, 292 insertions(+), 59 deletions(-) create mode 100644 src/files-ui/components/file-card/components/FileCardInfoLayer.tsx rename src/files-ui/components/file-card/{ => components}/FileCardPaper.scss (100%) rename src/files-ui/components/file-card/{ => components}/FileCardRightLayer.tsx (97%) rename src/files-ui/components/file-card/{ => components}/FileMosaicRightLayer.scss (100%) diff --git a/src/components/demo-components/filemosaic-demo/DemoFileMosaicUploadStatus.tsx b/src/components/demo-components/filemosaic-demo/DemoFileMosaicUploadStatus.tsx index ed044df..de2f6b1 100644 --- a/src/components/demo-components/filemosaic-demo/DemoFileMosaicUploadStatus.tsx +++ b/src/components/demo-components/filemosaic-demo/DemoFileMosaicUploadStatus.tsx @@ -4,9 +4,10 @@ import { useFakeProgress, ExtFile, UPLOADSTATUS, + FileCard, } from "../../../files-ui"; -const DemoFileMosaicUploadStatus = () => { +const DemoFileMosaicUploadStatus = (props:{card?:boolean}) => { const progress = useFakeProgress(); const [status1, setStatus1] = React.useState<UPLOADSTATUS>("uploading"); @@ -35,6 +36,32 @@ const DemoFileMosaicUploadStatus = () => { const handleAbort = (id: string | number | undefined) => { console.log("Upload aborted in file: " + id); }; + if(props.card) + return ( +<> + <FlexRowContainer card> + <FileCard {...preparingFile} /> + <FileCard {...preparingFile} onCancel={handleCancel} /> + </FlexRowContainer> + + <FlexRowContainer card> + <FileCard {...uploadingFile} /> + <FileCard {...uploadingFile} progress={progress} /> + <FileCard {...uploadingFile} onAbort={handleAbort} /> + <FileCard + {...uploadingFile} + onAbort={handleAbort} + progress={progress} + /> + </FlexRowContainer> + + <FlexRowContainer card> + <FileCard {...uploadResultFiles[0]} uploadStatus={status1} /> + <FileCard {...uploadResultFiles[1]} uploadStatus={status2} /> + <FileCard {...uploadResultFiles[2]} uploadStatus={status3} /> + </FlexRowContainer> + </> + ) return ( <> <FlexRowContainer> @@ -63,7 +90,7 @@ const DemoFileMosaicUploadStatus = () => { }; export default DemoFileMosaicUploadStatus; -const FlexRowContainer = (props: { children: React.ReactNode }) => { +const FlexRowContainer = (props: { children: React.ReactNode, card?:boolean }) => { return ( <div style={{ @@ -71,6 +98,7 @@ const FlexRowContainer = (props: { children: React.ReactNode }) => { flexWrap: "wrap", justifyContent: "space-evenly", width: "100%", + flexDirection:props.card?"column":"row" }} > {props.children} diff --git a/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx b/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx index 0c3d1a9..f02c995 100644 --- a/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx +++ b/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { FileMosaic } from "../../../files-ui"; +import { FileCard, FileMosaic } from "../../../files-ui"; const sampleFilesProps = [ { @@ -14,7 +14,7 @@ const sampleFilesProps = [ type: "image/png", name: "valid file created from props.png", valid: false, - errors: ["File is too big", "File type is not allowed"] + errors: ["File is too big", "File type is not allowed"], }, { id: "fileId-3", @@ -25,7 +25,16 @@ const sampleFilesProps = [ }, ]; -const DemoFileMosaicValidation = () => { +const DemoFileMosaicValidation = ({ card }) => { + if (card) + return ( + <> + {sampleFilesProps.map((extFile) => ( + <FileCard key={extFile.id} {...extFile} info /> + ))} + </> + ); + return ( <> {sampleFilesProps.map((extFile) => ( diff --git a/src/files-ui/components/file-card/FileCard.scss b/src/files-ui/components/file-card/FileCard.scss index 4c3c8d0..51b3b7d 100644 --- a/src/files-ui/components/file-card/FileCard.scss +++ b/src/files-ui/components/file-card/FileCard.scss @@ -12,7 +12,7 @@ position: relative; font-size: 15px; font-weight: 400; - width: 380px; + width: 350px; .files-ui-file-card-main-layer-container { width: 380px; box-sizing: border-box; @@ -35,7 +35,7 @@ display: flex; align-items: center; justify-content: flex-start; - gap:5px; + gap: 5px; .file-card-icon-container { //margin: 0 10px; width: 100px; @@ -120,16 +120,11 @@ justify-content: space-between; flex-direction: column; padding: 3px; - width: 60px; + width: 36px; //background-color: aquamarine; height: 100%; } .file-card-upload-layer { - position: absolute; - left: 0; - right: 0; - width: 100%; - height: 100%; display: flex; box-sizing: border-box; //background-color: rgba(0, 0, 0, 0.5); @@ -153,5 +148,64 @@ align-items: center; justify-content: flex-end; } + .file-card-info-layer-container { + display: flex; + box-sizing: border-box; + //background-color: rgba(0, 0, 0, 0.5); + background: linear-gradient( + to right, + + rgba(0, 0, 0, 0.3), + rgba(0, 0, 0, 0.5), + rgba(0, 0, 0, 0.75), + rgba(0, 0, 0, 0.9), + rgba(0, 0, 0, 0.9), + rgba(0, 0, 0, 0.9), + rgba(0, 0, 0, 0.9), + rgba(0, 0, 0, 0.9), + rgba(0, 0, 0, 0.9) + ); + color: rgba(255, 255, 255, 0.8); + font-weight: 500; + font-size: 1em; + overflow: hidden; + align-items: center; + justify-content: flex-end; + .file-card-file-info { + width: 250px; + height: 100px; + text-align: left; + scrollbar-width: thin; + overflow: auto; + scrollbar-color: #646c7fa9 transparent; + + &::-webkit-scrollbar { + width: 9px; + } + &::-webkit-scrollbar-track { + background: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #646c7fa9; + border-radius: 20px; + border: transparent; + } + .files-ui-file-card-info-layer-header { + display: flex; + width: 100%; + flex-direction: row; + align-items: center; + justify-content: flex-end; + } + .heading { + font-weight: 600; + padding: 0 5px; + } + .label { + padding: 0 5px; + font-weight: 399; + } + } + } } } diff --git a/src/files-ui/components/file-card/FileCard.tsx b/src/files-ui/components/file-card/FileCard.tsx index 2dabd5a..7e19259 100644 --- a/src/files-ui/components/file-card/FileCard.tsx +++ b/src/files-ui/components/file-card/FileCard.tsx @@ -1,23 +1,17 @@ import * as React from "react"; -import { FileCardProps, FileCardPropsDefault } from "./FileCardProps"; +import { FileCardProps } from "./FileCardProps"; import "./FileCard.scss"; -import "./FileCardPaper.scss"; -import FileItemImage from "../file-item/components/FileItemImage/FileItemImage"; -import useFileItemInitializer from "../file-item/hooks/useFileItemInitializer"; +import "./components/FileCardPaper.scss"; import { getLocalFileItemData } from "../file-item/utils/getLocalFileItemData"; -import { Clear } from "../icons"; import { fileSizeFormater, shrinkWord } from "../../core"; -import { mergeProps } from "../overridable"; -import { showFileItemComponent } from "../file-item/utils/showFileItemComponent"; -import useFileItemProgress from "../file-item/hooks/useFileItemProgress"; -import MainLayerBodyNeo from "../file-item/components/FileItemMainLayer/MainLayerBody/MainLayerBodyNeo"; import useProgress from "../file-mosaic/hooks/useProgress"; import useFileMosaicInitializer from "../file-mosaic/hooks/useFileMosaicInitializer"; import { useIsUploading } from "../file-mosaic/hooks/useIsUploading"; import LayerContainer from "../file-mosaic/components/file-mosaic-layer/LayerContainer"; import Layer from "../file-mosaic/components/file-mosaic-layer/Layer"; import FileMosaicImageLayer from "../file-mosaic/components/FIleMosaicImageLayer/FileMosaicImageLayer"; -import FileCardRightLayer from "./FileCardRightLayer"; +import FileCardRightLayer from "./components/FileCardRightLayer"; +import FileCardInfoLayer from "./components/FileCardInfoLayer"; const setFinalElevation = (elevation: string | number): number => { // let finalElevation: number = ""; @@ -319,6 +313,16 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { isActive={alwaysActive || hovering} /> </Layer> + <Layer className="file-card-info-layer-container" visible={showInfo}> + <FileCardInfoLayer + onCloseInfo={handleCloseInfo} + valid={valid} + localization={localization} + localName={localName} + sizeFormatted={sizeFormatted} + localType={localType} + /> + </Layer> <Layer className="file-card-upload-layer" visible={isUploading}> Upload Layer </Layer> diff --git a/src/files-ui/components/file-card/components/FileCardInfoLayer.tsx b/src/files-ui/components/file-card/components/FileCardInfoLayer.tsx new file mode 100644 index 0000000..bd548c3 --- /dev/null +++ b/src/files-ui/components/file-card/components/FileCardInfoLayer.tsx @@ -0,0 +1,42 @@ +import * as React from "react"; +import { FileMosaicInfoLayerProps } from "../../file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayerProps"; +import FileMosaicStatus from "../../file-mosaic/components/FileMosaicStatus/FileMosaicStatus"; +import { Cancel } from "../../icons"; +type FileCardInfoLayerProps = FileMosaicInfoLayerProps; +const FileCardInfoLayer: React.FC<FileCardInfoLayerProps> = ( + props: FileCardInfoLayerProps +) => { + const { + valid, + localization, + onCloseInfo, + uploadStatus, + localName, + sizeFormatted, + localType, + } = props; + return ( + <div className="file-card-file-info"> + <div className="files-ui-file-card-info-layer-header"> + <Cancel + style={{ margin: 0, right: 0, top: 0 }} + color="rgba(255,255,255,0.8)" + onClick={onCloseInfo} + colorFill="black" + /> + <FileMosaicStatus + valid={valid} + uploadStatus={uploadStatus} + localization={localization} + /> + </div> + <div className="heading">Name:</div> + <div className="label">{localName}</div> + <div className="heading">Size:</div> + <div className="label">{sizeFormatted}</div> + <div className="heading">Type:</div> + <div className="label">{localType}</div> + </div> + ); +}; +export default FileCardInfoLayer; diff --git a/src/files-ui/components/file-card/FileCardPaper.scss b/src/files-ui/components/file-card/components/FileCardPaper.scss similarity index 100% rename from src/files-ui/components/file-card/FileCardPaper.scss rename to src/files-ui/components/file-card/components/FileCardPaper.scss diff --git a/src/files-ui/components/file-card/FileCardRightLayer.tsx b/src/files-ui/components/file-card/components/FileCardRightLayer.tsx similarity index 97% rename from src/files-ui/components/file-card/FileCardRightLayer.tsx rename to src/files-ui/components/file-card/components/FileCardRightLayer.tsx index c2e766d..0ef7bc9 100644 --- a/src/files-ui/components/file-card/FileCardRightLayer.tsx +++ b/src/files-ui/components/file-card/components/FileCardRightLayer.tsx @@ -1,12 +1,12 @@ import * as React from "react"; -import { Localization, UPLOADSTATUS } from "../../core"; +import { Localization, UPLOADSTATUS } from "../../../core"; import { Clear, DownloadFile, InfoDisney, PlayIcon, Visibility, -} from "../icons"; +} from "../../icons"; import "./FileMosaicRightLayer.scss"; declare type FileCardRightLayerProps = { darkMode?: boolean; diff --git a/src/files-ui/components/file-card/FileMosaicRightLayer.scss b/src/files-ui/components/file-card/components/FileMosaicRightLayer.scss similarity index 100% rename from src/files-ui/components/file-card/FileMosaicRightLayer.scss rename to src/files-ui/components/file-card/components/FileMosaicRightLayer.scss diff --git a/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayerProps.ts b/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayerProps.ts index 7bb535a..6587467 100644 --- a/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayerProps.ts +++ b/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayerProps.ts @@ -1,6 +1,6 @@ import { Localization, UPLOADSTATUS } from "../../../../core"; -export interface FileMosaicInfoLayerProps{ +export type FileMosaicInfoLayerProps = { valid: boolean | null | undefined; uploadStatus?: UPLOADSTATUS; localization?: Localization; diff --git a/src/pages/demo/FileCardDemoPage.jsx b/src/pages/demo/FileCardDemoPage.jsx index 58f248a..ba70091 100644 --- a/src/pages/demo/FileCardDemoPage.jsx +++ b/src/pages/demo/FileCardDemoPage.jsx @@ -7,7 +7,6 @@ import Stack from "@mui/material/Stack"; import Alert from "@mui/material/Alert"; import CodeHighlight from "../../components/codeHighlight/CodeHighlight"; import DescParagraph from "../../components/demo-components/desc-paragraph/DescParagraph"; -import BasicFileMosaicDemo from "../../components/demo-components/filemosaic-demo/DemoFileMosaicBasic"; import SubTitle from "../../components/demo-components/sub-title/SubTitle"; import TypeHighlight from "../../components/typeHighlight/TypeHighlight"; import MainTitle from "../../components/main-title/MainTitle"; @@ -21,6 +20,10 @@ import DemoContainerFileMosaic from "../../components/demo-components/filemosaic import DemoFileMosaicDarkMode from "../../components/demo-components/filemosaic-demo/DemoFileMosaicDarkMode"; import CodeJSFileMosaicDarkMode from "../../components/demo-components/filemosaic-demo/CodeJSFileMosaicDarkMode"; import AnchorToTab from "../../components/util-components/AnchorToTab"; +import DemoFileMosaicValidation from "../../components/demo-components/filemosaic-demo/DemoFileMosaicValidation"; +import CodeJSFileMosaicValidation from "../../components/demo-components/filemosaic-demo/CodeJSFileMosaicValidation"; +import DemoFileMosaicUploadStatus from "../../components/demo-components/filemosaic-demo/DemoFileMosaicUploadStatus"; +import CodeJSFileMosaicUploadStatus from "../../components/demo-components/filemosaic-demo/CodeJSFileMosaicUploadStatus"; const FileCardDemoPage = (props) => { return ( @@ -28,42 +31,42 @@ const FileCardDemoPage = (props) => { <MainContentContainer> <MainTitle>FileCard</MainTitle> <MainParagraph> - File cards, as well as file mosaics, are compact elements that - represent a file in the UI. They can be used for just showing general - info of the file, or either allow the user to interact with them. + File cards are compact elements that represent a file in the UI. They + can be used for just showing general info of the file, or either to + allow the user to interact with them. </MainParagraph> <DescParagraph> - This widget allow users to see information of Files and / or trigger - actions. + This widget allow users to see information of{" "} + <TypeHighlight> Files</TypeHighlight> and / or trigger actions. </DescParagraph> <Alert severity="info"> While included here as a standalone component, the most common use - will be as a result of the "onChange" event of {"<Dropzone/>"} or{" "} - {"<InputButton/>"} components, so some of the behavior demonstrated - here is not shown in context.{" "} + will be to display the result of the "onChange" event of{" "} + <CodeHighlight>{"<Dropzone/>"}</CodeHighlight> or{" "} + <CodeHighlight>{"<InputButton/>"}</CodeHighlight> components, so some + of the behavior demonstrated here is not totally shown in context.{" "} </Alert> <section id="basic-filecard"> <SubTitle content="Basic FileCard" /> <DescParagraph> - The <CodeHighlight>FileCard</CodeHighlight> supports displaying - information from <TypeHighlight>File</TypeHighlight> object or - individual props. + The <CodeHighlight>FileCard</CodeHighlight> component supports + displaying information from a{" "} + <TypeHighlight> + <AnchorToTab href="https://developer.mozilla.org/en-US/docs/Web/API/File"> + File + </AnchorToTab> + </TypeHighlight>{" "} + object or from given props. + <br /> + Also, the <TypeHighlight>onDelete</TypeHighlight> prop is used to + remove the file selection. </DescParagraph> - <Paper - variant="outlined" - style={{ - padding: "25px", - display: "flex", - alignItems: "center", - justifyContent: "center", - }} - > - <Stack spacing={2} direction="row" alignItems={"center"}> - <DemoFileCardBasic /> - </Stack> - </Paper> + <DemoContainerFileMosaic> + <DemoFileCardBasic /> + </DemoContainerFileMosaic> <CodeJSFileCardBasic /> + <Alert severity="info"> <AlertTitle> FileInputButton </AlertTitle> For completeness, some of these examples include{" "} @@ -106,7 +109,7 @@ const FileCardDemoPage = (props) => { <DemoFileMosaicImagePreview card /> </DemoContainerFileMosaic> - <CodeJSFileMosaicImagePreview card/> + <CodeJSFileMosaicImagePreview card /> <Alert severity="info"> As you can notice, when <CodeHighlight>{`imageUrl`}</CodeHighlight> prop is present, the{" "} @@ -120,12 +123,107 @@ const FileCardDemoPage = (props) => { </Alert> </section> {/** VALIDATION UPLOAD AND MORE */} + + <section id="validation"> + <SubTitle content="Validation" /> + <DescParagraph> + The <CodeHighlight>valid</CodeHighlight> prop can be set to{" "} + <TypeHighlight>true</TypeHighlight>,{" "} + <TypeHighlight>false</TypeHighlight> or{" "} + <TypeHighlight>undefined</TypeHighlight>. + </DescParagraph> + + <DemoContainerFileMosaic> + <DemoFileMosaicValidation card /> + </DemoContainerFileMosaic> + + <CodeJSFileMosaicValidation /> + <Alert severity="info"> + Typically, <CodeHighlight>{"<Dropzone/>"}</CodeHighlight> or{" "} + <CodeHighlight>{"<FileInputButton/>"}</CodeHighlight> components set + this prop when validating the input from a given criteria. You can + see the behaviour mentioned in the following demos: + <ul> + <li> + <AnchorToTab href="/components/dropzone#validation"> + Dropzone validation + </AnchorToTab> + </li> + <li> + <AnchorToTab href="/components/fileinputbutton#validation"> + FileInputButton validation + </AnchorToTab> + </li> + </ul> + </Alert> + </section> + + <section id="uploading"> + <SubTitle content="Uploading status" /> + <DescParagraph> + The <CodeHighlight>uploadStatus</CodeHighlight> prop can be set to{" "} + <TypeHighlight>"preparing"</TypeHighlight>,{" "} + <TypeHighlight>"uploading"</TypeHighlight>,{" "} + <TypeHighlight>"aborted"</TypeHighlight>,{" "} + <TypeHighlight>"error"</TypeHighlight> or{" "} + <TypeHighlight>"success"</TypeHighlight>. Also the{" "} + <CodeHighlight>uploadMessage</CodeHighlight> prop is used for + displaying the error or success message. Finally, the{" "} + <CodeHighlight>progress</CodeHighlight> prop can be used to show the + current progress of the upload process. + <br /> + Each of the following examples demonstrates one state combination of + the FileMosaic component. + </DescParagraph> + + <Paper + variant="outlined" + style={{ + padding: "25px", + display: "flex", + alignItems: "center", + justifyContent: "center", + flexDirection: "row", + gap: "7px", + flexWrap: "wrap", + }} + > + <DemoFileMosaicUploadStatus card /> + </Paper> + + <CodeJSFileMosaicUploadStatus card /> + + <Alert severity="info"> + As you can see, you have full control of the FileCard upload + props. You can take advantage of them to ake your own upload + function and show the user the progress. + <br /> On the other hand, you can also leverage the capability of{" "} + <CodeHighlight>{"<Dropzone/>"}</CodeHighlight> and{" "} + <CodeHighlight>{"<FileInputButton/>"}</CodeHighlight> components + since they also manage the{" "} + <TypeHighlight>{"uploadStatus"}</TypeHighlight> + prop for you when upload is enabled. You can see the behaviour + mentioned in the following demos: + <ul> + <li> + <AnchorToTab href="/components/dropzone#uploading"> + Dropzone upload + </AnchorToTab> + </li> + <li> + <AnchorToTab href="/components/fileinputbutton#uploading"> + FileInputButton upload + </AnchorToTab> + </li> + </ul> + </Alert> + </section> + <section id="dark-mode"> <SubTitle content="Dark mode" /> <DescParagraph> - The <CodeHighlight>FileCard</CodeHighlight> component supports - dark mode by setting the prop{" "} - <TypeHighlight>darkMode</TypeHighlight> to{" "} + The <CodeHighlight>FileCard</CodeHighlight> component supports dark + mode by setting the prop <TypeHighlight>darkMode</TypeHighlight> to{" "} <TypeHighlight>true</TypeHighlight>. </DescParagraph> @@ -144,7 +242,7 @@ const FileCardDemoPage = (props) => { <CodeJSFileMosaicDarkMode card /> </section> - {/* <section id="localization"> + {/* <section id="localization"> <SubTitle content="Localization" /> <DescParagraph> The <CodeHighlight>FileMosaic</CodeHighlight> component has @@ -217,9 +315,7 @@ const FileCardDemoPage = (props) => { </DescParagraph> <ul> <li> - <AnchorToTab href="/api/filecard"> - {"<FileMosaic/>"} - </AnchorToTab> + <AnchorToTab href="/api/filecard">{"<FileMosaic/>"}</AnchorToTab> </li> <li> <AnchorToTab href="/api/fileinputbuttom"> -- GitLab