diff --git a/src/components/DownloadDetailsPopup.tsx b/src/components/DownloadDetailsPopup.tsx new file mode 100644 index 0000000..20f320f --- /dev/null +++ b/src/components/DownloadDetailsPopup.tsx @@ -0,0 +1,113 @@ +import { createPortal } from 'react-dom' +import { DownloadUrl } from '../types' + +export const DownloadDetailsPopup = ({ + title, + url, + hash, + signatureKey, + malwareScanLink, + modVersion, + customNote, + mediaUrl, + handleClose +}: DownloadUrl & { + handleClose: () => void +}) => { + return createPortal( +
+
+
+
+
+
+

{title || 'Authentication Details'}

+
+
+ + + +
+
+
+
+
+
+
+

Download URL

+
+
+

{url}

+
+
+
+
+

SHA-256 hash

+
+
+

{hash}

+
+
+
+
+

Signature from

+
+
+

{signatureKey}

+
+
+
+
+

Scan

+
+
+

{malwareScanLink}

+
+
+
+
+

Mod Version

+
+
+

{modVersion}

+
+
+
+
+

Note

+
+
+

{customNote}

+
+
+ {typeof mediaUrl !== 'undefined' && mediaUrl !== '' && ( +
+
+

Media

+
+
+ +
+
+ )} +
+
+
+
+
+
+
, + document.body + ) +} diff --git a/src/components/ModForm.tsx b/src/components/ModForm.tsx index b9a476f..45c3985 100644 --- a/src/components/ModForm.tsx +++ b/src/components/ModForm.tsx @@ -457,12 +457,14 @@ export const ModForm = () => { @@ -524,11 +526,13 @@ export const ModForm = () => { type DownloadUrlFieldsProps = { index: number url: string + title?: string hash: string signatureKey: string malwareScanLink: string modVersion: string customNote: string + mediaUrl?: string onUrlChange: (index: number, field: keyof DownloadUrl, value: string) => void onRemove: (index: number) => void } @@ -537,11 +541,13 @@ const DownloadUrlFields = React.memo( ({ index, url, + title, hash, signatureKey, malwareScanLink, modVersion, customNote, + mediaUrl, onUrlChange, onRemove }: DownloadUrlFieldsProps) => { @@ -579,6 +585,28 @@ const DownloadUrlFields = React.memo( +
+
+ + + +
+ +
+
+
+
+ + + +
+
+ { + onUrlChange(index, 'mediaUrl', values[0]) + }} + /> + + +
+
+
) } diff --git a/src/pages/mod/index.tsx b/src/pages/mod/index.tsx index 5b97147..f5c4a14 100644 --- a/src/pages/mod/index.tsx +++ b/src/pages/mod/index.tsx @@ -41,6 +41,7 @@ import { RouterLoadingSpinner } from 'components/LoadingSpinner' import { OriginalAuthor } from 'components/OriginalAuthor' import { Viewer } from 'components/Markdown/Viewer' import { PostWarnings } from 'components/PostWarning' +import { DownloadDetailsPopup } from 'components/DownloadDetailsPopup' const MOD_REPORT_REASONS = [ { label: 'Actually CP', key: 'actuallyCP' }, @@ -70,25 +71,6 @@ export const ModPage = () => { const [commentCount, setCommentCount] = useState(0) - const oldDownloadListRef = useRef(null) - - const handleViewOldLinks = () => { - if (oldDownloadListRef.current) { - // Toggle styles - if (oldDownloadListRef.current.style.height === '0px') { - // Enable styles - oldDownloadListRef.current.style.padding = '' - oldDownloadListRef.current.style.height = '' - oldDownloadListRef.current.style.border = '' - } else { - // Disable styles - oldDownloadListRef.current.style.padding = '0' - oldDownloadListRef.current.style.height = '0' - oldDownloadListRef.current.style.border = 'unset' - } - } - } - return ( <> @@ -136,37 +118,16 @@ export const ModPage = () => { )} {mod.downloadUrls.length > 1 && ( - <> -
- -
-
- {mod.downloadUrls - .slice(1) - .map((download, index) => ( - - ))} -
- +
+ {mod.downloadUrls + .slice(1) + .map((download, index) => ( + + ))} +
)} @@ -606,14 +567,8 @@ const Body = ({ ) } -const Download = ({ - url, - hash, - signatureKey, - malwareScanLink, - modVersion, - customNote -}: DownloadUrl) => { +const Download = (props: DownloadUrl) => { + const { url, title, malwareScanLink } = props const [showAuthDetails, setShowAuthDetails] = useState(false) const [showNotice, setShowNotice] = useState(false) const [showScanNotice, setShowCanNotice] = useState(false) @@ -645,6 +600,9 @@ const Download = ({ return (
+ {typeof title !== 'undefined' && title !== '' && ( + {title} + )}
diff --git a/src/pages/submitMod/action.ts b/src/pages/submitMod/action.ts index 5e51df4..51c16ef 100644 --- a/src/pages/submitMod/action.ts +++ b/src/pages/submitMod/action.ts @@ -256,6 +256,19 @@ const validateState = async ( errors.downloadUrls![i] = 'Download url must be valid and reachable' } + + if ( + downloadUrl.mediaUrl && + downloadUrl.mediaUrl.trim() !== '' && + (!isValidUrl(downloadUrl.mediaUrl) || + !isValidImageUrl(downloadUrl.mediaUrl) || + !(await isReachable(downloadUrl.mediaUrl))) + ) { + if (!errors.downloadUrls) + errors.downloadUrls = Array(formState.downloadUrls.length) + + errors.downloadUrls![i] = 'Media URLs must be valid and reachable image' + } } } diff --git a/src/styles/downloads.css b/src/styles/downloads.css index 0ff3847..66c7db4 100644 --- a/src/styles/downloads.css +++ b/src/styles/downloads.css @@ -11,7 +11,7 @@ display: grid; grid-template-columns: 1fr; grid-gap: 15px; - border: solid 1px rgba(255,255,255,0.05); + border: solid 1px rgba(255, 255, 255, 0.05); overflow: auto; max-height: 550px; padding: 15px; @@ -27,7 +27,7 @@ } .IBMSMSMBSSDownloadsTitle { - color: rgba(255,255,255,0.5); + color: rgba(255, 255, 255, 0.5); } .IBMSMSMBSSDownloadsElement { @@ -36,11 +36,11 @@ display: grid; grid-template-columns: 1fr; grid-gap: 10px; - border: solid 1px rgba(255,255,255,0); - background: rgba(255,255,255,0.05); + border: solid 1px rgba(255, 255, 255, 0); + background: rgba(255, 255, 255, 0.05); padding: 10px; border-radius: 10px; - box-shadow: 0 0 8px 0 rgb(0,0,0,0.1); + box-shadow: 0 0 8px 0 rgb(0, 0, 0, 0.1); } @media (max-width: 768px) { @@ -50,7 +50,7 @@ } .btnMain.IBMSMSMBSSDownloadsElementBtn { - background: rgba(255,255,255,0.05); + background: rgba(255, 255, 255, 0.05); border-radius: 10px; width: 100%; } @@ -62,8 +62,8 @@ } .btnMain.IBMSMSMBSSDownloadsElementBtn:hover { - background: rgba(255,255,255,0.1); - box-shadow: 0 0 8px 0 rgb(0,0,0,0.1); + background: rgba(255, 255, 255, 0.1); + box-shadow: 0 0 8px 0 rgb(0, 0, 0, 0.1); } .IBMSMSMBSSDownloadsElementInside { @@ -71,7 +71,7 @@ flex-direction: column; justify-content: start; align-items: start; - color: rgba(255,255,255,0.5); + color: rgba(255, 255, 255, 0.5); grid-gap: 10px; } @@ -97,27 +97,30 @@ justify-content: center; align-items: center; width: 100%; - background: rgba(255,255,255,0); + background: rgba(255, 255, 255, 0); overflow: hidden; border-radius: 10px; - border: solid 1px rgba(255,255,255,0.05); + border: solid 1px rgba(255, 255, 255, 0.05); cursor: pointer; } .IBMSMSMBSSDEIReactionsElement:hover { transition: ease 0.4s; - background: rgba(255,255,255,0.05); - color: rgba(255,255,255,0.75); - border: solid 1px rgba(255,255,255,0); + background: rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.75); + border: solid 1px rgba(255, 255, 255, 0); } -.IBMSMSMBSSDEIReactionsElement:hover > .IBMSMSMBSSDEIReactionsElementIconWrapper { +.IBMSMSMBSSDEIReactionsElement:hover + > .IBMSMSMBSSDEIReactionsElementIconWrapper { transition: ease 0.4s; - background: rgba(255,255,255,0.05); - border-right: solid 1px rgba(255,255,255,0); + background: rgba(255, 255, 255, 0.05); + border-right: solid 1px rgba(255, 255, 255, 0); } -.IBMSMSMBSSDEIReactionsElement:hover > .IBMSMSMBSSDEIReactionsElementIconWrapper > .IBMSMSMBSSDEIReactionsElementIcon { +.IBMSMSMBSSDEIReactionsElement:hover + > .IBMSMSMBSSDEIReactionsElementIconWrapper + > .IBMSMSMBSSDEIReactionsElementIcon { transform: scale(1.1); } @@ -147,9 +150,9 @@ justify-content: center; align-items: center; height: 100%; - background: rgba(255,255,255,0); + background: rgba(255, 255, 255, 0); padding: 10px 5px; - border-right: solid 1px rgba(255,255,255,0.05); + border-right: solid 1px rgba(255, 255, 255, 0.05); } .IBMSMSMBSSDownloadsElementInsideDetails { @@ -160,17 +163,20 @@ } .IBMSMSMBSSDEIReactionsElement.IBMSMSMBSSDEIReactionsElementActive { - background: rgba(255,255,255,0.05); - border: solid 1px rgba(255,255,255,0); + background: rgba(255, 255, 255, 0.05); + border: solid 1px rgba(255, 255, 255, 0); } -.IBMSMSMBSSDEIReactionsElement.IBMSMSMBSSDEIReactionsElementActive > .IBMSMSMBSSDEIReactionsElementIconWrapper { - background: rgba(255,255,255,0.05); - border-right: solid 1px rgba(255,255,255,0); +.IBMSMSMBSSDEIReactionsElement.IBMSMSMBSSDEIReactionsElementActive + > .IBMSMSMBSSDEIReactionsElementIconWrapper { + background: rgba(255, 255, 255, 0.05); + border-right: solid 1px rgba(255, 255, 255, 0); } -.IBMSMSMBSSDEIReactionsElement.IBMSMSMBSSDEIReactionsElementActive > .IBMSMSMBSSDEIReactionsElementIconWrapper > .IBMSMSMBSSDEIReactionsElementIcon { - color: rgba(255,255,255,0.75); +.IBMSMSMBSSDEIReactionsElement.IBMSMSMBSSDEIReactionsElementActive + > .IBMSMSMBSSDEIReactionsElementIconWrapper + > .IBMSMSMBSSDEIReactionsElementIcon { + color: rgba(255, 255, 255, 0.75); } .IBMSMSMBSSDownloadsActions { @@ -188,7 +194,7 @@ display: flex; flex-direction: column; border-radius: 10px; - border: solid 1px rgba(255,255,255,0.1); + border: solid 1px rgba(255, 255, 255, 0.1); overflow: auto; grid-gap: 1px; } @@ -202,7 +208,7 @@ .IBMSMSMBSSDownloadsElementInsideAltTableRow:hover { transition: ease 0.4s; - background: rgba(255,255,255,0.05); + background: rgba(255, 255, 255, 0.05); } @media (max-width: 576px) { @@ -216,12 +222,17 @@ text-align: start; padding: 10px 15px; } +.IBMSMSMBSSDownloadsElementInsideAltTableRowCol_Img { + width: 100%; + max-width: 300px; + border-radius: 6px; +} .IBMSMSMBSSDownloadsElementInsideAltTableRowCol.IBMSMSMBSSDownloadsElementInsideAltTableRowColFirst { text-align: center; font-weight: bold; max-width: 200px; - background: rgba(255,255,255,0.05); + background: rgba(255, 255, 255, 0.05); display: flex; justify-content: center; align-items: center; @@ -237,13 +248,12 @@ transition: ease 0.4s; cursor: pointer; font-weight: 400; - color: rgba(255,255,255,0.25); + color: rgba(255, 255, 255, 0.25); } .IBMSMSMBSSDownloadsElementInsideAltText:hover { transition: ease 0.4s; cursor: pointer; font-weight: 600; - color: rgba(255,255,255,0.75); + color: rgba(255, 255, 255, 0.75); } - diff --git a/src/types/mod.ts b/src/types/mod.ts index a62fe5b..fdd9036 100644 --- a/src/types/mod.ts +++ b/src/types/mod.ts @@ -41,11 +41,13 @@ export interface ModFormState { export interface DownloadUrl { url: string + title?: string hash: string signatureKey: string malwareScanLink: string modVersion: string customNote: string + mediaUrl?: string } export interface ModDetails extends Omit {