diff --git a/src/components/demo-components/filemosaic-demo/DemoFileMosaicDarkMode.tsx b/src/components/demo-components/filemosaic-demo/DemoFileMosaicDarkMode.tsx index a65af2237e54eab3e71943cb5e8797a62c04b1ee..e1cbbecc3b806680ba356d02d32d69448c271132 100644 --- a/src/components/demo-components/filemosaic-demo/DemoFileMosaicDarkMode.tsx +++ b/src/components/demo-components/filemosaic-demo/DemoFileMosaicDarkMode.tsx @@ -6,6 +6,7 @@ const sampleFileProps: ExtFile = { size: 28 * 1024 * 1024, type: "text/plain", name: "file created from props.jsx", + valid: true, }; const DemoFileMosaicDarkMode = (props: { card?: boolean }) => { const removeFile = (id: string | number | undefined) => { @@ -18,9 +19,10 @@ const DemoFileMosaicDarkMode = (props: { card?: boolean }) => { style={{ display: "flex", justifyContent: "center", - width: "50%", + minWidth: "50%", backgroundColor: "white", padding: "15px 0", + flexGrow:1 }} > <FileCard {...sampleFileProps} info onDelete={removeFile} /> @@ -29,9 +31,10 @@ const DemoFileMosaicDarkMode = (props: { card?: boolean }) => { style={{ display: "flex", justifyContent: "center", - width: "50%", + minWidth: "50%", backgroundColor: "#121212", padding: "15px 0", + flexGrow: 1, }} > <FileCard {...sampleFileProps} info darkMode onDelete={removeFile} /> @@ -44,9 +47,10 @@ const DemoFileMosaicDarkMode = (props: { card?: boolean }) => { style={{ display: "flex", justifyContent: "center", - width: "50%", + minWidth: "50%", backgroundColor: "white", padding: "15px 0", + flexGrow: 1, }} > <FileMosaic {...sampleFileProps} info onDelete={removeFile} /> @@ -55,9 +59,11 @@ const DemoFileMosaicDarkMode = (props: { card?: boolean }) => { style={{ display: "flex", justifyContent: "center", - width: "50%", + minWidth: "50%", backgroundColor: "#121212", padding: "15px 0", + flexGrow: 1, + }} > <FileMosaic {...sampleFileProps} info darkMode onDelete={removeFile} /> diff --git a/src/files-ui/components/file-card/FileCard.scss b/src/files-ui/components/file-card/FileCard.scss index 51b3b7dbe02a0d71a9aad3f4cc6a75e52f27411d..0475dcaae8b8f7dbd5fff102bee689487f1525e8 100644 --- a/src/files-ui/components/file-card/FileCard.scss +++ b/src/files-ui/components/file-card/FileCard.scss @@ -1,7 +1,7 @@ @import url(https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700,900); .files-ui-file-card-main-container { border-radius: 8px; - overflow: hidden; + //overflow: hidden; color: rgba(0, 0, 0, 0.858); display: flex; flex-direction: row; @@ -14,6 +14,8 @@ font-weight: 400; width: 350px; .files-ui-file-card-main-layer-container { + border-radius: 8px; + overflow: hidden; width: 380px; box-sizing: border-box; height: 100px; @@ -74,6 +76,13 @@ } } } + .file-card-status-layer { + display: flex; + align-items: flex-end; + justify-content: flex-start; + padding: 5px; + box-sizing: border-box; + } } .file-card-data { line-height: 18px; @@ -124,7 +133,7 @@ //background-color: aquamarine; height: 100%; } - .file-card-upload-layer { + .file-card-upload-layer-container { display: flex; box-sizing: border-box; //background-color: rgba(0, 0, 0, 0.5); @@ -147,6 +156,7 @@ overflow: hidden; align-items: center; justify-content: flex-end; + height: 100%; } .file-card-info-layer-container { display: flex; @@ -178,6 +188,7 @@ scrollbar-width: thin; overflow: auto; scrollbar-color: #646c7fa9 transparent; + // position: relative; &::-webkit-scrollbar { width: 9px; @@ -196,6 +207,9 @@ flex-direction: row; align-items: center; justify-content: flex-end; + /* position: absolute; + top: 5; + right: 5; */ } .heading { font-weight: 600; diff --git a/src/files-ui/components/file-card/FileCard.tsx b/src/files-ui/components/file-card/FileCard.tsx index 7e192590fbba1b419a88bed7069e9fa14e94a7da..bb64438b4c95389b42f69b478459fca583a42224 100644 --- a/src/files-ui/components/file-card/FileCard.tsx +++ b/src/files-ui/components/file-card/FileCard.tsx @@ -12,6 +12,9 @@ import Layer from "../file-mosaic/components/file-mosaic-layer/Layer"; import FileMosaicImageLayer from "../file-mosaic/components/FIleMosaicImageLayer/FileMosaicImageLayer"; import FileCardRightLayer from "./components/FileCardRightLayer"; import FileCardInfoLayer from "./components/FileCardInfoLayer"; +import FileMosaicStatus from "../file-mosaic/components/FileMosaicStatus/FileMosaicStatus"; +import FileCardUploadLayer from "./components/FileCardUploadLayer"; +import { Tooltip } from "../tooltip"; const setFinalElevation = (elevation: string | number): number => { // let finalElevation: number = ""; @@ -35,7 +38,8 @@ const makeFileCardClassName = ( className: string | undefined ): string => { console.log("FileCard makeFileCardClassName", elevation, darkMode, className); - let finalClassName: string = "files-ui-file-card-main-container"; + let finalClassName: string = "files-ui-file-card-main-container files-ui-tooltip card"; + if (elevation) { finalClassName += " elevation-" + setFinalElevation(elevation); } @@ -247,6 +251,7 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { > <Layer className="file-card-main-layer" visible={true}> <div className="file-card-icon-plus-data"> + {/** ICON + STATUS */} <div className="file-card-icon-container"> <LayerContainer className="file-card-icon-layer"> {/** IMAGE LAYER BLUR */} @@ -270,19 +275,22 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { isBlur={false} /> </Layer> + <Layer className="file-card-status-layer" visible={true}> + <FileMosaicStatus + valid={valid} + uploadStatus={uploadStatus} + localization={localization} + /> + </Layer> </LayerContainer> </div> - + {/** DATA */} <div className={ darkMode ? "file-card-data dark-mode" : "file-card-data" } > - <div className={"file-card-name"}> - {/* {shrinkWord(localName, true)} */} - {localName} - </div> - + <div className={"file-card-name"}>{localName}</div> <div className={"file-card-size"}>{sizeFormatted}</div> <div className={"file-card-size"}>{shrinkWord(localType)}</div> </div> @@ -313,6 +321,7 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { isActive={alwaysActive || hovering} /> </Layer> + <Layer className="file-card-info-layer-container" visible={showInfo}> <FileCardInfoLayer onCloseInfo={handleCloseInfo} @@ -323,47 +332,43 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => { localType={localType} /> </Layer> - <Layer className="file-card-upload-layer" visible={isUploading}> - Upload Layer + + {/** UPLOAD LAYER */} + <Layer + className="file-card-upload-layer-container" + visible={isUploading} + > + <div className="files-ui-file-card-upload-layer"> + <FileCardUploadLayer + uploadStatus={uploadStatus} + progress={localProgress} + onCancel={onCancel ? () => onCancel?.(id) : undefined} + onAbort={ + onAbort + ? () => { + xhr?.abort(); + onAbort?.(id); + } + : undefined + } + localization={localization} + /> + </div> </Layer> </LayerContainer> - {/* <FileItemImage - imageSource={imageSource} - url={url} - fileName={localName} - backgroundBlurImage={backgroundBlurImage as boolean} - card={true} + + <Tooltip + open={resultOnTooltip} + uploadStatus={uploadStatus} + valid={valid} + errors={errors} + uploadMessage={uploadMessage} /> - - <div - className={darkMode ? "file-card-data dark-mode" : "file-card-data"} - > - <div className={"file-card-name"}>{shrinkWord(localName, true)}</div> - - <div className={"file-card-size"}>{sizeFormatted}</div> - <div className={"file-card-size"}>{shrinkWord(localType)}</div> - </div> - - <div className="files-ui-file-card-right"> - <Clear - style={{ position: "absolute", right: 0, top: 0 }} - className="dui-file-item-icon" - color="rgba(255,255,255,0.851)" - onClick={handleDelete} - size="small" - colorFill="transparent" - /> - <MainLayerBodyNeo - hide={false} - uploadStatus={uploadStatus} - localization={localization} - progress={progress} - onAbort={onAbort} - valid={valid} - hovering={true} - onCancel={onCancel} - /> - </div> */} + {downloadUrl && ( + <a ref={downloadRef} href={downloadUrl} download={localName} hidden> + download_file + </a> + )} </div> ); } diff --git a/src/files-ui/components/file-card/components/FileCardInfoLayer.tsx b/src/files-ui/components/file-card/components/FileCardInfoLayer.tsx index bd548c3644ed55ef55aaa8bf8ffc76269a3d39ee..823437c92e429479beb2ec5598ac138bcac3dd7e 100644 --- a/src/files-ui/components/file-card/components/FileCardInfoLayer.tsx +++ b/src/files-ui/components/file-card/components/FileCardInfoLayer.tsx @@ -17,19 +17,18 @@ const FileCardInfoLayer: React.FC<FileCardInfoLayerProps> = ( } = props; return ( <div className="file-card-file-info"> - <div className="files-ui-file-card-info-layer-header"> + {/* <FileMosaicStatus + style={{ margin: 0, right: 5, bottom: 0, position:"absolute" }} + valid={valid} + uploadStatus={uploadStatus} + localization={localization} + /> */} <Cancel - style={{ margin: 0, right: 0, top: 0 }} + style={{ margin: 0, right: 5, top: 0, position:"absolute" }} 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> diff --git a/src/files-ui/components/file-card/components/FileCardUploadLayer.scss b/src/files-ui/components/file-card/components/FileCardUploadLayer.scss new file mode 100644 index 0000000000000000000000000000000000000000..c84a6ef13847fd3462bcaba82ddfe0875996c59e --- /dev/null +++ b/src/files-ui/components/file-card/components/FileCardUploadLayer.scss @@ -0,0 +1,44 @@ +.files-ui-file-card-upload-layer { + width: 100px; + height: 100%; + //background-color: rgba(0, 0, 0, 0.5); + color: rgba(255, 255, 255, 0.8); + font-weight: 500; + font-size: 1em; + position: relative; + overflow: hidden; + + .elevation-list-card { + transition: all 1.5s ease; + position: absolute; + top: 0; + left: 0; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + .elevation-item-card { + width: 100%; + height: 100px; + + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 0 10px; + box-sizing: border-box; + + span { + text-align: center; + word-break: break-word; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; /* number of lines to show */ + line-clamp: 2; + -webkit-box-orient: vertical; + } + } + } +} diff --git a/src/files-ui/components/file-card/components/FileCardUploadLayer.tsx b/src/files-ui/components/file-card/components/FileCardUploadLayer.tsx new file mode 100644 index 0000000000000000000000000000000000000000..57f0c68a5423573f862d2b47de36838c056ee3bb --- /dev/null +++ b/src/files-ui/components/file-card/components/FileCardUploadLayer.tsx @@ -0,0 +1,119 @@ +import * as React from "react"; +import { Localization, UPLOADSTATUS } from "../../../core"; +import { + AbortedStatus, + EmptyStatus, + ErrorStatus, + PreparingStatus, + SuccessStatus, + UploadingStatus, +} from "../../file-status"; +import "./FileCardUploadLayer.scss"; +export interface FileCardUploadLayerPropsMap { + visible?: boolean; + uploadStatus?: UPLOADSTATUS; + onCancel?: Function; + onAbort?: Function; + progress?: number; + localization?: Localization; +} + +export type FileCardUploadLayerProps = { + [T in keyof FileCardUploadLayerPropsMap]: FileCardUploadLayerPropsMap[T]; +}; + +const FileCardUploadLayer: React.FC<FileCardUploadLayerProps> = ( + props: FileCardUploadLayerProps +) => { + const { uploadStatus, onCancel, onAbort, progress, localization } = props; + const elevationContainerRef = React.useRef<HTMLDivElement | null>(null); + const listContainerStoryRef = React.useRef<HTMLDivElement | null>(null); + + const [statusHistory, setStatusHistory] = React.useState< + Array<UPLOADSTATUS | undefined> + >([undefined]); + + React.useEffect(() => { + setStatusHistory((statusHistory: Array<UPLOADSTATUS | undefined>) => { + if ( + statusHistory[statusHistory.length - 1] === "preparing" && + uploadStatus === "uploading" + ) { + const tempStatusHistory = [...statusHistory]; + tempStatusHistory[statusHistory.length - 1] = uploadStatus; + //replace + return [...tempStatusHistory]; + } + return [...statusHistory, uploadStatus]; + }); + }, [uploadStatus]); + + const elevate = () => { + const currentElevationContainer = elevationContainerRef.current; + const currentElevationList = listContainerStoryRef.current; + if (currentElevationContainer === null || currentElevationList === null) + return; + + currentElevationList.style.top = + 0 - (statusHistory.length - 1) * 100 + "px"; + }; + React.useEffect(() => { + if (statusHistory.length > 1) elevate(); + // eslint-disable-next-line + }, [statusHistory.length]); + + return ( + <div className={"elevation-layer-container"} ref={elevationContainerRef}> + <div className="elevation-list-card" ref={listContainerStoryRef}> + {statusHistory.map((status, index) => { + switch (status) { + case "preparing": + return ( + <div className="elevation-item-card" key={index + 1}> + <PreparingStatus + onCancel={onCancel} + localization={localization} + /> + </div> + ); + case "uploading": + return ( + <div className="elevation-item-card" key={index + 1}> + <UploadingStatus + onAbort={onAbort} + progress={progress} + localization={localization} + /> + </div> + ); + case "error": + return ( + <div className="elevation-item-card" key={index + 1}> + <ErrorStatus size={60} localization={localization} /> + </div> + ); + case "success": + return ( + <div className="elevation-item-card" key={index + 1}> + <SuccessStatus localization={localization} /> + </div> + ); + case "aborted": + return ( + <div className="elevation-item-card" key={index + 1}> + <AbortedStatus localization={localization} /> + </div> + ); + default: + return ( + <div className="elevation-item-card" key={index + 1}> + <EmptyStatus /> + </div> + ); + } + })} + </div> + </div> + ); +}; +export default FileCardUploadLayer; diff --git a/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayer.tsx b/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayer.tsx index 3e5156647fb6c43287acf9eb17ed28c90bb0f5c3..21a2e6a43af382f3c94f0312e33e16247c379e6e 100644 --- a/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayer.tsx +++ b/src/files-ui/components/file-mosaic/components/FileMosaicInfoLayer/FileMosaicInfoLayer.tsx @@ -19,7 +19,7 @@ const FileMosaicInfoLayer: React.FC<FileMosaicInfoLayerProps> = ( <React.Fragment> <div className="files-ui-file-mosaic-info-layer-header"> <Cancel - style={{ margin: 0, right: 0, top: 0 }} + //style={{ margin: 0, right: 0, top: 0 }} color="rgba(255,255,255,0.8)" onClick={onCloseInfo} colorFill="black" diff --git a/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatus.tsx b/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatus.tsx index 8501bfb4d9d11cf462076b0a79b320ae4301eb4e..66dd014627d2163f8ce4678a104e01ef2cf2fa4d 100644 --- a/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatus.tsx +++ b/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatus.tsx @@ -8,7 +8,7 @@ import { FileItemLocalizerSelector, LocalLabels } from "../../../../core"; const FileMosaicStatus: React.FC<FileMosaicStatusProps> = ( props: FileMosaicStatusProps ) => { - const { valid, uploadStatus, localization } = props; + const { valid, uploadStatus, localization, style } = props; const FileItemStatusLocalizer: LocalLabels = FileItemLocalizerSelector( localization @@ -16,7 +16,7 @@ const FileMosaicStatus: React.FC<FileMosaicStatusProps> = ( if (uploadStatus === "success") { return ( - <div className="files-ui-file-item-status-container file-status-ok"> + <div className="files-ui-file-item-status-container file-status-ok" style={style}> <CloudDone color="#4caf50" size="small" className="status-icon" /> {FileItemStatusLocalizer.success as string} </div> @@ -24,7 +24,7 @@ const FileMosaicStatus: React.FC<FileMosaicStatusProps> = ( } if (uploadStatus === "error" || uploadStatus === "aborted") { return ( - <div className="files-ui-file-item-status-container file-status-error"> + <div className="files-ui-file-item-status-container file-status-error" style={style}> <UploadError color="#f44336" size="semi-medium" @@ -37,14 +37,14 @@ const FileMosaicStatus: React.FC<FileMosaicStatusProps> = ( if (valid !== undefined && valid !== null) { if (valid) { return ( - <div className="files-ui-file-item-status-container file-status-ok"> + <div className="files-ui-file-item-status-container file-status-ok" style={style}> <CheckCircle color="#4caf50" size="small" className="status-icon" /> {FileItemStatusLocalizer.valid as string} </div> ); } else { return ( - <div className="files-ui-file-item-status-container file-status-error"> + <div className="files-ui-file-item-status-container file-status-error" style={style}> <DoDisturb color="#f44336" size="small" className="status-icon" /> {FileItemStatusLocalizer.denied as string} </div> diff --git a/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatusProps.ts b/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatusProps.ts index 577c58a09659bca32ad33e996eebe2faaa7811ec..e449be638a27d7a09ddf7628d8a8d2c9c23e7743 100644 --- a/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatusProps.ts +++ b/src/files-ui/components/file-mosaic/components/FileMosaicStatus/FileMosaicStatusProps.ts @@ -22,4 +22,7 @@ export interface FileMosaicStatusProps { */ localization?: Localization; + + style?:React.CSSProperties; + } \ No newline at end of file diff --git a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.scss b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.scss index 78bf294dc99cda25b94a6523d27c7010dc2517ed..23e29424be4489b2ddfc784c7907393c639a47b2 100644 --- a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.scss +++ b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.scss @@ -163,73 +163,7 @@ } } -/* &.files-ui-tooltip { - cursor: default; - position: relative; - display: inline-block; - box-sizing: border-box; - // border-bottom: 1px dotted black; - &:hover { - z-index: 2; - - .files-ui-tooltip-tooltiptext { - visibility: visible; - opacity: 1; - z-index: 2; - } - } - - .files-ui-tooltip-tooltiptext { - box-sizing: border-box; - font-family: "Poppins", sans-serif; - font-size: 0.8rem; - visibility: hidden; - width: 132px; - // background-color: green; - color: #fff; - text-align: center; - border-radius: 6px; - padding: 2px 2px; - position: absolute; - //z-index: 2; - //top: 190px; - top: 180px; - left: 66px; - margin-left: -60px; - - // Fade in tooltip - takes 1 second to go from 0% to 100% opac: - opacity: 0; - transition: opacity 1s; - &.not-valid-error { - background: linear-gradient(to top, #c62828, #d32f2f); - - &::after { - border-color: transparent transparent #d32f2f transparent; - } - } - - &.success { - //background-color: green; - background: linear-gradient(to top, #1b5e20, #2e7d32); - - &::after { - border-color: transparent transparent #2e7d32 transparent; - } - } - - &::after { - content: ""; - position: absolute; - bottom: 100%; - left: 50%; - margin-left: -5px; - border-width: 5px; - border-style: solid; - //border-color: transparent transparent green transparent; - } - } - } */ } //// ICONS diff --git a/src/files-ui/components/file-status/ErrorStatus.tsx b/src/files-ui/components/file-status/ErrorStatus.tsx index b17f6bde8f44446dc232bfe0196a371a921ccf09..e930203c62556e7baa55443ad821c3a981300e80 100644 --- a/src/files-ui/components/file-status/ErrorStatus.tsx +++ b/src/files-ui/components/file-status/ErrorStatus.tsx @@ -17,7 +17,7 @@ const ErrorStatus: React.FC<ErrorStatusProps> = (props: ErrorStatusProps) => { backgroundColor: "rgba(244, 67, 54, 0.8)", borderRadius: "50%", }} - size={size || 65} + size={size || 65} /> <span> {FileItemStatusLocalizer.error as string}</span> </React.Fragment> diff --git a/src/files-ui/components/tooltip/components/Tooltip.scss b/src/files-ui/components/tooltip/components/Tooltip.scss index 0b35afd6fde8c572c9f6a74493273959aae08cbe..1e186717ea9d0deda76f77c35888b7b849707443 100644 --- a/src/files-ui/components/tooltip/components/Tooltip.scss +++ b/src/files-ui/components/tooltip/components/Tooltip.scss @@ -12,6 +12,66 @@ z-index: 2; } } + &.card { + &:hover { + z-index: 2; + .files-ui-tooltiptext { + visibility: visible; + opacity: 1; + z-index: 2; + } + } + .files-ui-tooltiptext { + box-sizing: border-box; + font-family: "Poppins", sans-serif; + + font-size: 0.8rem; + font-weight: 400; + visibility: hidden; + width: 200px; + // background-color: green; + color: #fff; + text-align: center; + border-radius: 6px; + padding: 2px 2px; + position: absolute; + z-index: 2; + left: calc(50% - 100px); + left: 0; + margin-top: 5px; + //top: calc(100% + 5px); + top: 100%; + // Fade in tooltip - takes 1 second to go from 0% to 100% opac: + opacity: 0; + transition: opacity 1s; + + &.not-valid-error { + background: linear-gradient(to top, #c62828, #d32f2f); + &::after { + border-color: transparent transparent #d32f2f transparent; + } + } + &.success { + //background-color: green; + background: linear-gradient(to top, #1b5e20, #2e7d32); + &::after { + border-color: transparent transparent #2e7d32 transparent; + } + } + + &::after { + content: ""; + position: absolute; + bottom: 100%; + left: 50%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + //border-color: transparent transparent green transparent; + } + } + } + .files-ui-tooltiptext { box-sizing: border-box; font-family: "Poppins", sans-serif; @@ -46,6 +106,7 @@ border-color: transparent transparent #2e7d32 transparent; } } + &::after { content: ""; position: absolute; diff --git a/src/pages/demo/FileCardDemoPage.jsx b/src/pages/demo/FileCardDemoPage.jsx index ba70091ed5de0e6d7c3cc1502a61237b90416d1a..ad715dcbc0a959f4fe4da3bd1f4d096177d420e7 100644 --- a/src/pages/demo/FileCardDemoPage.jsx +++ b/src/pages/demo/FileCardDemoPage.jsx @@ -235,6 +235,7 @@ const FileCardDemoPage = (props) => { alignItems: "center", justifyContent: "center", width: "100%", + flexWrap:"wrap" }} > <DemoFileMosaicDarkMode card />