From 4826ce8b113cda69baf95f338189f34ea5d51e63 Mon Sep 17 00:00:00 2001
From: Jose Manuel Serrano Amaut <a20122128@pucp.pe>
Date: Thu, 23 Mar 2023 01:35:11 -0500
Subject: [PATCH] [FEAT]: Add context provider for icons and darkmode

---
 .../FilesUiProvider/FilesUiContextType.ts     |  7 +-
 .../components/file-card/FileCard.tsx         |  5 +-
 .../components/file-mosaic/FileMosaic.tsx     |  7 +-
 .../hooks/useFileMosaicInitializer.ts         | 11 ++-
 src/files-ui/core/index.ts                    |  3 +-
 src/files-ui/core/mime/mime.ts                | 60 ++++++++-----
 src/files-ui/core/types/IconsMap.ts           | 84 +++++++++++++++++++
 src/files-ui/core/types/index.ts              |  5 +-
 8 files changed, 148 insertions(+), 34 deletions(-)
 create mode 100644 src/files-ui/core/types/IconsMap.ts

diff --git a/src/files-ui/FilesUiProvider/FilesUiContextType.ts b/src/files-ui/FilesUiProvider/FilesUiContextType.ts
index 948a295..4f848a9 100644
--- a/src/files-ui/FilesUiProvider/FilesUiContextType.ts
+++ b/src/files-ui/FilesUiProvider/FilesUiContextType.ts
@@ -1,3 +1,8 @@
+import { IconsMap } from "../core";
+
 export type FilesUiConfig = {
     darkMode?:boolean;
-}
\ No newline at end of file
+    icons?:IconsConfig;
+}
+
+export type IconsConfig=IconsMap;
\ No newline at end of file
diff --git a/src/files-ui/components/file-card/FileCard.tsx b/src/files-ui/components/file-card/FileCard.tsx
index c0cbd05..25a19eb 100644
--- a/src/files-ui/components/file-card/FileCard.tsx
+++ b/src/files-ui/components/file-card/FileCard.tsx
@@ -109,7 +109,7 @@ const FileCard: React.FC<FileCardProps> = (props: FileCardProps) => {
     //} = mergeProps(props, FileCardPropsDefault);
   } = props;
 //context
-const { darkMode: darkModeContext } = React.useContext(FilesUiContext);
+const { darkMode: darkModeContext , icons} = React.useContext(FilesUiContext);
 const darkMode: boolean | undefined =
   darkModeProp !== undefined ? darkModeProp : darkModeContext;
 
@@ -150,7 +150,8 @@ const darkMode: boolean | undefined =
     valid,
     preview as boolean,
     imageUrl,
-    videoUrl
+    videoUrl,
+    icons
   );
   //The size formatted and rounded in 2 decimals
   const sizeFormatted: string | undefined = fileSizeFormater(localSize);
diff --git a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx
index 2f4564f..8700e91 100644
--- a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx
+++ b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx
@@ -71,10 +71,10 @@ const FileMosaic: React.FC<FileMosaicProps> = (props: FileMosaicProps) => {
   } = props;
 
   //context
-  const { darkMode: darkModeContext } = React.useContext(FilesUiContext);
+  const { darkMode: darkModeContext, icons } = React.useContext(FilesUiContext);
   const darkMode: boolean | undefined =
     darkModeProp !== undefined ? darkModeProp : darkModeContext;
-  console.log("globalConfig", darkMode);
+  console.log("globalConfig", darkMode, icons);
 
   //localizers
 
@@ -120,7 +120,8 @@ const FileMosaic: React.FC<FileMosaicProps> = (props: FileMosaicProps) => {
     valid,
     preview as boolean,
     imageUrl,
-    videoUrl
+    videoUrl,
+    icons
   );
 
   //The size formatted and rounded in 2 decimals
diff --git a/src/files-ui/components/file-mosaic/hooks/useFileMosaicInitializer.ts b/src/files-ui/components/file-mosaic/hooks/useFileMosaicInitializer.ts
index b28c2ce..c2ed841 100644
--- a/src/files-ui/components/file-mosaic/hooks/useFileMosaicInitializer.ts
+++ b/src/files-ui/components/file-mosaic/hooks/useFileMosaicInitializer.ts
@@ -1,6 +1,7 @@
 import * as React from "react";
 import { getURLFileIco, readAsDataURL } from "../../../core";
 import { getURLFileIcoFromNameAndType } from "../../../core/mime/mime";
+import { IconsConfig } from "../../../FilesUiProvider/FilesUiContextType";
 
 /**
  * Initializer hook for FileItemNeo
@@ -20,6 +21,7 @@ const useFileMosaicInitializer = (
     preview: boolean,
     imageUrl: string | undefined,
     videoUrl: string | undefined,
+    customIcons?:IconsConfig,
     xhr?: XMLHttpRequest,
 
 ): [boolean, boolean, boolean, string, string | undefined, File | string | undefined] => {
@@ -40,6 +42,7 @@ const useFileMosaicInitializer = (
         preview: boolean,
         imageUrl: string | undefined,
         videoUrl: string | undefined,
+        customIcons?:IconsConfig,
         xhr?: XMLHttpRequest,
         progress?: number
     ) => {
@@ -48,8 +51,8 @@ const useFileMosaicInitializer = (
 
         if (!file && (!name && !type)) return;
 
-        const { url } = file ? getURLFileIco(file) :
-            getURLFileIcoFromNameAndType(name, type);
+        const { url } = file ? getURLFileIco(file,customIcons) :
+            getURLFileIcoFromNameAndType(name, type,customIcons);
 
         //console.log("init", url);
 
@@ -107,7 +110,7 @@ const useFileMosaicInitializer = (
 
     //////   CLEAN UP
     React.useEffect(() => {
-        init(file, name, type, valid, preview || false, imageUrl, videoUrl);
+        init(file, name, type, valid, preview || false, imageUrl, videoUrl,customIcons);
         return () => {
             setImageSource(undefined);
             setIsImage(false);
@@ -115,7 +118,7 @@ const useFileMosaicInitializer = (
             setIsReady(false);
         };
         // eslint-disable-next-line
-    }, [file, name, type, valid, preview, imageUrl, videoUrl]);
+    }, [file, name, type, valid, preview, imageUrl, videoUrl,customIcons]);
 
     return [isReady, isImage, isVideo, url, imageSource, videoSource];
 }
diff --git a/src/files-ui/core/index.ts b/src/files-ui/core/index.ts
index f59b949..260fef3 100644
--- a/src/files-ui/core/index.ts
+++ b/src/files-ui/core/index.ts
@@ -87,7 +87,8 @@ export type {
     UploadPromiseResponse,
     UploadResponse,
     UploadConfig,
-    UPLOADSTATUS
+    UPLOADSTATUS,
+    IconsMap
 } from "./types";
 
 export {
diff --git a/src/files-ui/core/mime/mime.ts b/src/files-ui/core/mime/mime.ts
index 73ac85f..cf8eccb 100644
--- a/src/files-ui/core/mime/mime.ts
+++ b/src/files-ui/core/mime/mime.ts
@@ -19,14 +19,15 @@ import {
     zip
 } from "./icons";
 import { getExt } from "../utils/getExt";
+import { IconsMap } from "../types";
 
-const DEF_GEN_MIME: string = "octet";
+const DEF_GEN_MIME: keyof IconsMap = "octet";
 /**
  * 
  * @param tailMime 
  * @returns 
  */
-export const audioSelector = (tailMime: string): string => {
+export const audioSelector = (tailMime: string): keyof IconsMap => {
     switch (tailMime) {
         case "aac": return "aac";
         case "midi": return "midi";
@@ -43,7 +44,7 @@ export const audioSelector = (tailMime: string): string => {
         default: return DEF_GEN_MIME;
     }
 }
-export const textSelector = (tailMime: string): string => {
+export const textSelector = (tailMime: string): keyof IconsMap => {
     switch (tailMime) {
         case "css": return "css";
         case "csv": return "csv";
@@ -57,12 +58,12 @@ export const textSelector = (tailMime: string): string => {
 
     }
 }
-export const imageSelector = (tailMime: string): string => {
+export const imageSelector = (tailMime: string): keyof IconsMap => {
     switch (tailMime) {
         case "bmp": return "bmp";
         case "gif": return "gif";
         // case "vnd.microsoft.icon": return "ico";
-        case "ico": return "ico";
+        //case "ico": return "ico";
         case "jpg": return "jpeg";
         case "jpeg": return "jpeg";
         case "png": return "png";
@@ -74,7 +75,7 @@ export const imageSelector = (tailMime: string): string => {
 
     }
 }
-export const fontSelector = (tailMime: string): string => {
+export const fontSelector = (tailMime: string): keyof IconsMap => {
     switch (tailMime) {
         case "otf": return "otf";
         case "ttf": return "ttf";
@@ -85,7 +86,7 @@ export const fontSelector = (tailMime: string): string => {
     }
 }
 
-export const videoSelector = (tailMime: string): string => {
+export const videoSelector = (tailMime: string): keyof IconsMap => {
     switch (tailMime) {
         case "x-msvideo": return "avi";
         case "msvideo": return "avi";
@@ -108,7 +109,7 @@ export const videoSelector = (tailMime: string): string => {
  * @param tailMime 
  * @returns 
  */
-export const applicationSelector = (tailMime: string): string => {
+export const applicationSelector = (tailMime: string): keyof IconsMap => {
     switch (tailMime) {
         case "x-abiword": return "abw";
         case "abiword": return "abw";
@@ -164,7 +165,7 @@ export const applicationSelector = (tailMime: string): string => {
  * @returns the generic type, 
 if not found it return "octet" that means generic binary file
  */
-export const mimeSelector = (mimeType?: string): string => {
+export const mimeSelector = (mimeType?: string): keyof IconsMap => {
     // let genericMime: string | undefined = undefined;
     if (!mimeType || !mimeType.includes("/")) {
         return DEF_GEN_MIME;
@@ -194,8 +195,8 @@ export const mimeSelector = (mimeType?: string): string => {
  * @param extension 
  * @returns 
  */
-export const extensionSelector = (extension?: string): string => {
-    let genericMime: string = "octet";
+export const extensionSelector = (extension?: string): keyof IconsMap => {
+    let genericMime: keyof IconsMap = "octet";
 
     if (extension && extension !== "") {
         if (extension.includes("zip") || extension.includes("rar")) {
@@ -219,7 +220,7 @@ export const extensionSelector = (extension?: string): string => {
         } else if (extension === "java") {
             genericMime = "java";
         } else if (extension === "ts") {
-            genericMime = "ts";
+            genericMime = "typescript";
         } else if (extension === "sass" || extension === "scss") {
             genericMime = "sass";
         }
@@ -232,8 +233,8 @@ export const extensionSelector = (extension?: string): string => {
  * @param extension 
  * @returns 
  */
-export const checkIsCode = (extension?: string): string => {
-    let genericMime = "text";
+export const checkIsCode = (extension?: string): keyof IconsMap => {
+    let genericMime: keyof IconsMap = "text";
     if (extension && extension !== "") {
         if (extension === "jsx") {
             genericMime = "react";
@@ -258,17 +259,22 @@ export const checkIsCode = (extension?: string): string => {
 
 /**
  * Looks for a suitable file icon
+ * If not found, returns octet-stream url
  * @param props mime and extension from file to search
- * @returns the result file ico, if not found, turns octet-stream url
+ * @returns the result file ico
  */
 export const getURLFileIco = (
-    file: File | undefined
+    file: File | undefined,
+    customIcons: IconsMap | undefined
 ): ResultFileIco => {
 
-    let result = "";
+    let result: keyof IconsMap = "fallBack";
     //if not file, return octet
     if (!file) {
         result = DEF_GEN_MIME;
+        if (customIcons?.fallBack)
+            return { url: customIcons?.fallBack, mimeResume: result };
+
         return { url: mimeUrlList[result], mimeResume: result };
     } else {
         result = mimeSelector(file.type);
@@ -285,6 +291,11 @@ export const getURLFileIco = (
         result = extensionSelector(extention);
     }
 
+    const customUrl = customIcons?.[result];
+    if (customUrl !== undefined)
+        return { url: customUrl, mimeResume: result };
+
+
     return { url: mimeUrlList[result], mimeResume: result };
 }
 /**
@@ -295,12 +306,15 @@ export const getURLFileIco = (
 export const getURLFileIcoFromNameAndType = (
     name: string | undefined,
     type: string | undefined,
+    customIcons: IconsMap | undefined
 ): ResultFileIco => {
 
-    let result = "";
+    let result: keyof IconsMap = "octet";
     //if not nam and type, return octet
     if (!name) {
         result = DEF_GEN_MIME;
+        if (customIcons?.fallBack)
+            return { url: customIcons?.fallBack, mimeResume: result };
         return { url: mimeUrlList[result], mimeResume: result };
     } else {
         result = mimeSelector(type);
@@ -316,12 +330,15 @@ export const getURLFileIcoFromNameAndType = (
     if (result === DEF_GEN_MIME) {
         result = extensionSelector(extention);
     }
+    const customUrl = customIcons?.[result];
+    if (customUrl !== undefined)
+        return { url: customUrl, mimeResume: result };
 
     return { url: mimeUrlList[result], mimeResume: result };
 }
 interface ResultFileIco {
     url: string;
-    mimeResume: string;
+    mimeResume: keyof IconsMap;
 }
 /**
  * set of registered mimes on MDN
@@ -333,9 +350,6 @@ interface MimeSelector {
 }
 
 const mimeUrlList: MimeSelector = {
-    img: "https://ssl.gstatic.com/docs/doclist/images/mediatype/icon_1_image_x16.png",
-    video: "https://ssl.gstatic.com/docs/doclist/images/mediatype/icon_1_video_x16.png",
-    audio: "https://ssl.gstatic.com/docs/doclist/images/mediatype/icon_1_audio_x16.png",
     aac: aac,
     accdb: accdb,
     abw: abw,
@@ -416,4 +430,6 @@ const mimeUrlList: MimeSelector = {
     react: react,
     vue: vue,
 
+
+    fallBack: octet,
 };
\ No newline at end of file
diff --git a/src/files-ui/core/types/IconsMap.ts b/src/files-ui/core/types/IconsMap.ts
new file mode 100644
index 0000000..1e258c3
--- /dev/null
+++ b/src/files-ui/core/types/IconsMap.ts
@@ -0,0 +1,84 @@
+
+export type IconsMap = {
+    aac?: string;
+    accdb?: string;
+    abw?: string;
+    arc?: string;
+    avi?: string;
+    azw?: string;
+    octet?: string;
+    bmp?: string;
+    bz?: string;
+    bz2?: string;
+    cda?: string;
+    csh?: string;
+    css?: string;
+    csv?: string;
+    docx?: string;
+    drawio?: string;
+    eot?: string;
+    epub?: string;
+    gzip?: string;
+    gif?: string;
+    html?: string;
+    //ico: ico,
+    icalendar?: string;
+    jar?: string;
+    jpeg?: string;
+    javascript?: string;
+    json?: string;
+    jsonld?: string;
+    midi?: string;
+    //  js: js,
+    mp3?: string;
+    mp4?: string;
+    mpeg?: string;
+    mpkg?: string;
+    mp2t?: string;
+    odp?: string;
+    ods?: string;
+    odt?: string;
+    oga?: string;
+    ogv?: string;
+    ogx?: string;
+    opus?: string;
+    otf?: string;
+    png?: string;
+    pdf?: string;
+    php?: string;
+    pptx?: string;
+    psd?: string;
+    rar?: string;
+    rtf?: string;
+    sass?: string;
+    sh?: string;
+    //svg: svg,
+    swf?: string;
+    tar?: string;
+    tiff?: string;
+    ttf?: string;
+    //ts: ts,
+    typescript?: string;
+    text?: string;
+    vsd?: string;
+    wav?: string;
+    weba?: string;
+    webm?: string;
+    webp?: string;
+    woff?: string;
+    wma?: string;
+    wmv?: string;
+    xhtml?: string;
+    xlsx?: string;
+    xml?: string;
+    xul?: string;
+    zip?: string;
+    // threegp: threegp,
+    sevenzip?: string;
+    python?: string;
+    java?: string;
+    react?: string;
+    vue?: string;
+
+    fallBack?: string;
+}
\ No newline at end of file
diff --git a/src/files-ui/core/types/index.ts b/src/files-ui/core/types/index.ts
index ede5878..98e17c5 100644
--- a/src/files-ui/core/types/index.ts
+++ b/src/files-ui/core/types/index.ts
@@ -21,4 +21,7 @@ export type { ServerResponse, UploadPromiseResponse, UploadResponse } from "./up
 export type { ValidateFileResponse, FileValidatorProps } from "./validation";
 
 export type { UploadConfig } from "./UploadConfig";
-export { createUploadConfig } from "./UploadConfig";
\ No newline at end of file
+
+export { createUploadConfig } from "./UploadConfig";
+
+export type { IconsMap } from "./IconsMap";
\ No newline at end of file
-- 
GitLab