const useNetwork = (mainnet, testnet) => { return context.networkId === "mainnet" ? mainnet : testnet; }; State.init({ contracts: props.contracts, theme: props.theme || "light", ownerId: useNetwork("sourcescan.near", "sourcescan.testnet"), }); if (props.contracts) State.update({ contracts: props.contracts, }); const dark = { bg: "#28282b", color: "#e6eaee", border: "#748094", button: { bg: "#39393c", hoverBg: "#5e5e60", }, }; const light = { bg: "#e3e8ef", color: "#4c5566", border: "#748094", button: { bg: "#eef2f6", hoverBg: "#e3e8ef", }, }; const useTheme = (light, dark) => { return state.theme === "light" ? light : dark; }; const Center = styled.div` display: flex; justify-content: center; align-items: center; text-align: center; `; const Table = styled.table` border: 1px solid ${useTheme(light.border, dark.border)}; background-color: ${useTheme(light.bg, dark.bg)}; color: ${useTheme(light.color, dark.color)}; border-collapse: separate; border-spacing: 0; border-radius: 10px; text-align: start; width: 50%; thead { text-transform: uppercase; font-size: 12px; font-weight: 100; color: ${useTheme(light.border, dark.border)}; } th { padding: 15px; } td { border-top: 0.5px dashed ${useTheme(light.border, dark.border)}; padding: 15px; } @media only screen and (max-width: 600px) { border: none; thead { display: none; } th { display: block; width: 100%; } tr { border-radius: 10px; display: block; width: full; border: 1px solid ${useTheme(light.border, dark.border)}; margin-bottom: 40px; } td { position: relative; display: flex; align-items: end; justify-content: end; text-align: end; border: none; } td:before { width: 100%; content: attr(data-label); text-transform: uppercase; padding-right: 20px; font-size: 12px; font-weight: 100; color: ${useTheme(light.border, dark.border)}; font-weight: bold; text-align: start; } } `; const HStack = styled.div` display: flex; flex-direction: row; justify-content: start; align-items: start; gap: 8px; `; const Desktop = styled.div` display: flex; @media only screen and (max-width: 600px) { display: none; } `; const Mobile = styled.div` display: none; @media only screen and (max-width: 600px) { display: flex; width: 230%; } `; const A = styled.a` text-decoration: none; color: ${useTheme(light.color, dark.color)}; :hover { text-decoration: none; color: ${useTheme(light.color, dark.color)}; } `; const Button = styled.a` height: 36px; width: 96px; text-align: center; font-weight: 600; border-radius: 6px; padding-top: 5px; padding-bottom: 5px; border: 1px solid transparent; color: ${useTheme(light.color, dark.color)}; background-color: ${useTheme(light.button.bg, dark.button.bg)}; transition: background-color 0.1s ease-in-out; &:hover, &:focus { background: #ecedee; text-decoration: none; outline: none; color: ${useTheme(light.color, dark.color)}; } :hover { background-color: ${useTheme(light.button.hoverBg, dark.button.hoverBg)}; } `; const truncateStringInMiddle = (str, maxLength) => { if (str.length <= maxLength) { return str; } const halfMaxLength = Math.floor(maxLength / 2); const firstHalf = str.slice(0, halfMaxLength); const secondHalf = str.slice(-halfMaxLength); return firstHalf + "..." + secondHalf; }; function customEncodeURIComponent(str) { const specialChars = { "!": "%21", "#": "%23", $: "%24", "&": "%26", "'": "%27", "(": "%28", ")": "%29", "*": "%2A", "+": "%2B", ",": "%2C", "/": "%2F", ":": "%3A", ";": "%3B", "=": "%3D", "?": "%3F", "@": "%40", "[": "%5B", "]": "%5D", }; let encodedStr = ""; for (let i = 0; i < str.length; i++) { const char = str[i]; if (specialChars[char]) { encodedStr += specialChars[char]; } else { encodedStr += char; } } return encodedStr; } const infoHref = (contractId) => `/${ state.ownerId }/widget/SourceScan.Contracts.Info?contractId=${contractId}&theme=${customEncodeURIComponent( JSON.stringify( useTheme( { bg: light.bg, color: light.color, border: `1px dashed ${light.border}`, text: { fontSize: "18px", }, heading: { fontSize: "20px", fontWeight: "600", underline: true, }, }, { bg: dark.bg, color: dark.color, border: `1px dashed ${dark.border}`, text: { fontSize: "18px", }, heading: { fontSize: "20px", fontWeight: "600", underline: true, }, } ) ) )}`; return ( <> {state.contracts.length === 0 ? ( <>Nothing here...</> ) : ( <Table> <thead> <tr> <th>Contract</th> <th>Lang</th> <th>IPFS</th> <th>Github</th> <th>Approved</th> <Desktop> <th></th> </Desktop> </tr> </thead> <tbody> {state.contracts ? state.contracts.map((contract, i) => { const contractId = contract[0]; const lang = contract[1].lang; const cid = contract[1].cid; const deploy_tx = contract[1].deploy_tx; const github = contract[1].github; return ( <tr key={i}> <td data-label={"Contract"}>{contractId}</td> <td data-label={"Lang"}>{lang}</td> <td data-label={"IPFS"}> <HStack> {truncateStringInMiddle(cid, 8)} <A href={`${props.apiHost}/ipfs/${cid}`} target={"_blank"} > <Widget src={`${state.ownerId}/widget/SourceScan.Common.Icons.LinkIcon`} props={{ width: "20px", height: "20px" }} /> </A> </HStack> </td> <td data-label={"Github"}> {github ? ( <HStack> {github.owner}/{github.repo} <A href={`https://github.com/${github.owner}/${github.repo}/tree/${github.sha}`} target={"_blank"} > <Widget src={`${state.ownerId}/widget/SourceScan.Common.Icons.LinkIcon`} props={{ width: "20px", height: "20px" }} /> </A> </HStack> ) : ( "None" )} </td> <td data-label={"Approved"}> <Center> <Widget src={`${state.ownerId}/widget/SourceScan.Contracts.Approved`} props={{ rpcUrl: props.rpcUrl, apiHost: props.apiHost, accountId: contractId, cid: cid, ownerId: state.ownerId, deploy_tx: deploy_tx, }} /> </Center> </td> <td> <Desktop> <OverlayTrigger key={state.placement} placement={state.placement} overlay={ <Tooltip id={`tooltip-${placement}`}> Show More </Tooltip> } > <A href={infoHref(contractId)} target={"_blank"}> <Widget src={`${state.ownerId}/widget/SourceScan.Common.Icons.InfoIcon`} props={{ width: "20px", height: "20px" }} /> </A> </OverlayTrigger> </Desktop> <Mobile> <Button href={infoHref(contractId)} target={"_blank"}> More </Button> </Mobile> </td> </tr> ); }) : null} </tbody> </Table> )} </> );