forked from Qortal/q-share
Copy button added to FileContent.tsx
Share button is bigger and Icon is primary app color Minor fixes to imports
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "qtube",
|
"name": "qshare",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,624 +0,0 @@
|
|||||||
import React, { useEffect, useMemo, useState } from "react";
|
|
||||||
import {
|
|
||||||
AddCoverImageButton,
|
|
||||||
AddLogoIcon,
|
|
||||||
CoverImagePreview,
|
|
||||||
CrowdfundActionButton,
|
|
||||||
CrowdfundActionButtonRow,
|
|
||||||
CustomInputField,
|
|
||||||
CustomSelect,
|
|
||||||
LogoPreviewRow,
|
|
||||||
ModalBody,
|
|
||||||
NewCrowdfundTitle,
|
|
||||||
StyledButton,
|
|
||||||
TimesIcon,
|
|
||||||
} from "./Upload-styles.tsx";
|
|
||||||
import {
|
|
||||||
Box,
|
|
||||||
FormControl,
|
|
||||||
InputLabel,
|
|
||||||
MenuItem,
|
|
||||||
Modal,
|
|
||||||
OutlinedInput,
|
|
||||||
Select,
|
|
||||||
SelectChangeEvent,
|
|
||||||
Typography,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import ShortUniqueId from "short-unique-id";
|
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
|
||||||
import AddBoxIcon from "@mui/icons-material/AddBox";
|
|
||||||
import { useDropzone } from "react-dropzone";
|
|
||||||
|
|
||||||
import { setNotification } from "../../state/features/notificationsSlice";
|
|
||||||
import { objectToBase64, uint8ArrayToBase64 } from "../../utils/toBase64";
|
|
||||||
import { RootState } from "../../state/store";
|
|
||||||
import {
|
|
||||||
upsertFilesBeginning,
|
|
||||||
addToHashMap,
|
|
||||||
upsertFiles,
|
|
||||||
setEditFile,
|
|
||||||
updateFile,
|
|
||||||
updateInHashMap,
|
|
||||||
setEditPlaylist,
|
|
||||||
} from "../../state/features/fileSlice.ts";
|
|
||||||
import ImageUploader from "../common/ImageUploader";
|
|
||||||
import {
|
|
||||||
QSHARE_PLAYLIST_BASE,
|
|
||||||
QSHARE_FILE_BASE,
|
|
||||||
} from "../../constants/Identifiers.ts";
|
|
||||||
import { Playlists } from "../Playlists/Playlists";
|
|
||||||
import { PlaylistListEdit } from "../PlaylistListEdit/PlaylistListEdit";
|
|
||||||
import { TextEditor } from "../common/TextEditor/TextEditor";
|
|
||||||
import { extractTextFromHTML } from "../common/TextEditor/utils";
|
|
||||||
import {
|
|
||||||
firstCategories,
|
|
||||||
secondCategories,
|
|
||||||
} from "../../constants/Categories/1stCategories.ts";
|
|
||||||
|
|
||||||
const uid = new ShortUniqueId();
|
|
||||||
const shortuid = new ShortUniqueId({ length: 5 });
|
|
||||||
|
|
||||||
interface NewCrowdfundProps {
|
|
||||||
editId?: string;
|
|
||||||
editContent?: null | {
|
|
||||||
title: string;
|
|
||||||
user: string;
|
|
||||||
coverImage: string | null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface VideoFile {
|
|
||||||
file: File;
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
coverImage?: string;
|
|
||||||
}
|
|
||||||
export const EditPlaylist = () => {
|
|
||||||
const theme = useTheme();
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const username = useSelector((state: RootState) => state.auth?.user?.name);
|
|
||||||
const userAddress = useSelector(
|
|
||||||
(state: RootState) => state.auth?.user?.address
|
|
||||||
);
|
|
||||||
const editVideoProperties = useSelector(
|
|
||||||
(state: RootState) => state.file.editPlaylistProperties
|
|
||||||
);
|
|
||||||
const [playlistData, setPlaylistData] = useState<any>(null);
|
|
||||||
const [title, setTitle] = useState<string>("");
|
|
||||||
const [description, setDescription] = useState<string>("");
|
|
||||||
const [coverImage, setCoverImage] = useState<string>("");
|
|
||||||
const [videos, setVideos] = useState([]);
|
|
||||||
const [selectedCategoryVideos, setSelectedCategoryVideos] =
|
|
||||||
useState<any>(null);
|
|
||||||
const [selectedSubCategoryVideos, setSelectedSubCategoryVideos] =
|
|
||||||
useState<any>(null);
|
|
||||||
|
|
||||||
const isNew = useMemo(() => {
|
|
||||||
return editVideoProperties?.mode === "new";
|
|
||||||
}, [editVideoProperties]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isNew) {
|
|
||||||
setPlaylistData({
|
|
||||||
videos: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, [isNew]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (editVideoProperties) {
|
|
||||||
// const descriptionString = editVideoProperties?.description || "";
|
|
||||||
// // Splitting the string at the asterisks
|
|
||||||
// const parts = descriptionString.split("**");
|
|
||||||
|
|
||||||
// // The part within the asterisks
|
|
||||||
// const extractedString = parts[1];
|
|
||||||
|
|
||||||
// // The part after the last asterisks
|
|
||||||
// const description = parts[2] || ""; // Using '|| '' to handle cases where there is no text after the last **
|
|
||||||
// setTitle(editVideoProperties?.title || "");
|
|
||||||
// setDescription(editVideoProperties?.fullDescription || "");
|
|
||||||
// setCoverImage(editVideoProperties?.videoImage || "");
|
|
||||||
|
|
||||||
// // Split the extracted string into key-value pairs
|
|
||||||
// const keyValuePairs = extractedString.split(";");
|
|
||||||
|
|
||||||
// // Initialize variables to hold the category and subcategory values
|
|
||||||
// let category, subcategory;
|
|
||||||
|
|
||||||
// // Loop through each key-value pair
|
|
||||||
// keyValuePairs.forEach((pair) => {
|
|
||||||
// const [key, value] = pair.split(":");
|
|
||||||
|
|
||||||
// // Check the key and assign the value to the appropriate variable
|
|
||||||
// if (key === "category") {
|
|
||||||
// category = value;
|
|
||||||
// } else if (key === "subcategory") {
|
|
||||||
// subcategory = value;
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if(category){
|
|
||||||
// const selectedOption = categories.find((option) => option.id === +category);
|
|
||||||
// setSelectedCategoryVideos(selectedOption || null);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if(subcategory){
|
|
||||||
// const selectedOption = categories.find((option) => option.id === +subcategory);
|
|
||||||
// setSelectedCategoryVideos(selectedOption || null);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }, [editVideoProperties]);
|
|
||||||
|
|
||||||
const checkforPlaylist = React.useCallback(async videoList => {
|
|
||||||
try {
|
|
||||||
const combinedData: any = {};
|
|
||||||
const videos = [];
|
|
||||||
if (videoList) {
|
|
||||||
for (const vid of videoList) {
|
|
||||||
const url = `/arbitrary/resources/search?mode=ALL&service=DOCUMENT&identifier=${vid.identifier}&limit=1&includemetadata=true&reverse=true&name=${vid.name}&exactmatchnames=true&offset=0`;
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const responseDataSearchVid = await response.json();
|
|
||||||
|
|
||||||
if (responseDataSearchVid?.length > 0) {
|
|
||||||
let resourceData2 = responseDataSearchVid[0];
|
|
||||||
videos.push(resourceData2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
combinedData.videos = videos;
|
|
||||||
setPlaylistData(combinedData);
|
|
||||||
} catch (error) {}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (editVideoProperties) {
|
|
||||||
setTitle(editVideoProperties?.title || "");
|
|
||||||
|
|
||||||
if (editVideoProperties?.htmlDescription) {
|
|
||||||
setDescription(editVideoProperties?.htmlDescription);
|
|
||||||
} else if (editVideoProperties?.description) {
|
|
||||||
const paragraph = `<p>${editVideoProperties?.description}</p>`;
|
|
||||||
setDescription(paragraph);
|
|
||||||
}
|
|
||||||
setCoverImage(editVideoProperties?.image || "");
|
|
||||||
setVideos(editVideoProperties?.videos || []);
|
|
||||||
|
|
||||||
if (editVideoProperties?.category) {
|
|
||||||
const selectedOption = firstCategories.find(
|
|
||||||
option => option.id === +editVideoProperties.category
|
|
||||||
);
|
|
||||||
setSelectedCategoryVideos(selectedOption || null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
editVideoProperties?.category &&
|
|
||||||
editVideoProperties?.subcategory &&
|
|
||||||
secondCategories[+editVideoProperties?.category]
|
|
||||||
) {
|
|
||||||
const selectedOption = secondCategories[
|
|
||||||
+editVideoProperties?.category
|
|
||||||
]?.find(option => option.id === +editVideoProperties.subcategory);
|
|
||||||
setSelectedSubCategoryVideos(selectedOption || null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editVideoProperties?.videos) {
|
|
||||||
checkforPlaylist(editVideoProperties?.videos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [editVideoProperties]);
|
|
||||||
|
|
||||||
const onClose = () => {
|
|
||||||
setTitle("");
|
|
||||||
setDescription("");
|
|
||||||
setVideos([]);
|
|
||||||
setPlaylistData(null);
|
|
||||||
setSelectedCategoryVideos(null);
|
|
||||||
setSelectedSubCategoryVideos(null);
|
|
||||||
setCoverImage("");
|
|
||||||
dispatch(setEditPlaylist(null));
|
|
||||||
};
|
|
||||||
|
|
||||||
async function publishQDNResource() {
|
|
||||||
try {
|
|
||||||
if (!title) throw new Error("Please enter a title");
|
|
||||||
if (!description) throw new Error("Please enter a description");
|
|
||||||
if (!coverImage) throw new Error("Please select cover image");
|
|
||||||
if (!selectedCategoryVideos) throw new Error("Please select a category");
|
|
||||||
|
|
||||||
if (!editVideoProperties) return;
|
|
||||||
if (!userAddress) throw new Error("Unable to locate user address");
|
|
||||||
let errorMsg = "";
|
|
||||||
let name = "";
|
|
||||||
if (username) {
|
|
||||||
name = username;
|
|
||||||
}
|
|
||||||
if (!name) {
|
|
||||||
errorMsg =
|
|
||||||
"Cannot publish without access to your name. Please authenticate.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isNew && editVideoProperties?.user !== username) {
|
|
||||||
errorMsg = "Cannot publish another user's resource";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorMsg) {
|
|
||||||
dispatch(
|
|
||||||
setNotification({
|
|
||||||
msg: errorMsg,
|
|
||||||
alertType: "error",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const category = selectedCategoryVideos.id;
|
|
||||||
const subcategory = selectedSubCategoryVideos?.id || "";
|
|
||||||
|
|
||||||
const videoStructured = playlistData.videos.map(item => {
|
|
||||||
const descriptionVid = item?.metadata?.description;
|
|
||||||
if (!descriptionVid) throw new Error("cannot find video code");
|
|
||||||
|
|
||||||
// Split the string by ';'
|
|
||||||
let parts = descriptionVid.split(";");
|
|
||||||
|
|
||||||
// Initialize a variable to hold the code value
|
|
||||||
let codeValue = "";
|
|
||||||
|
|
||||||
// Loop through the parts to find the one that starts with 'code:'
|
|
||||||
for (let part of parts) {
|
|
||||||
if (part.startsWith("code:")) {
|
|
||||||
codeValue = part.split(":")[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!codeValue) throw new Error("cannot find video code");
|
|
||||||
|
|
||||||
return {
|
|
||||||
identifier: item.identifier,
|
|
||||||
name: item.name,
|
|
||||||
service: item.service,
|
|
||||||
code: codeValue,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
const id = uid();
|
|
||||||
|
|
||||||
let commentsId = editVideoProperties?.id;
|
|
||||||
|
|
||||||
if (isNew) {
|
|
||||||
commentsId = `${QSHARE_PLAYLIST_BASE}_cm_${id}`;
|
|
||||||
}
|
|
||||||
const stringDescription = extractTextFromHTML(description);
|
|
||||||
|
|
||||||
const playlistObject: any = {
|
|
||||||
title,
|
|
||||||
version: 1,
|
|
||||||
description: stringDescription,
|
|
||||||
htmlDescription: description,
|
|
||||||
image: coverImage,
|
|
||||||
videos: videoStructured,
|
|
||||||
commentsId: commentsId,
|
|
||||||
category,
|
|
||||||
subcategory,
|
|
||||||
};
|
|
||||||
|
|
||||||
const codes = videoStructured.map(item => `c:${item.code};`).join("");
|
|
||||||
let metadescription =
|
|
||||||
`**category:${category};subcategory:${subcategory};${codes}**` +
|
|
||||||
stringDescription.slice(0, 120);
|
|
||||||
|
|
||||||
const crowdfundObjectToBase64 = await objectToBase64(playlistObject);
|
|
||||||
// Description is obtained from raw data
|
|
||||||
|
|
||||||
let identifier = editVideoProperties?.id;
|
|
||||||
const sanitizeTitle = title
|
|
||||||
.replace(/[^a-zA-Z0-9\s-]/g, "")
|
|
||||||
.replace(/\s+/g, "-")
|
|
||||||
.replace(/-+/g, "-")
|
|
||||||
.trim()
|
|
||||||
.toLowerCase();
|
|
||||||
if (isNew) {
|
|
||||||
identifier = `${QSHARE_PLAYLIST_BASE}${sanitizeTitle.slice(0, 30)}_${id}`;
|
|
||||||
}
|
|
||||||
const requestBodyJson: any = {
|
|
||||||
action: "PUBLISH_QDN_RESOURCE",
|
|
||||||
name: username,
|
|
||||||
service: "PLAYLIST",
|
|
||||||
data64: crowdfundObjectToBase64,
|
|
||||||
title: title.slice(0, 50),
|
|
||||||
description: metadescription,
|
|
||||||
identifier: identifier,
|
|
||||||
tag1: QSHARE_FILE_BASE,
|
|
||||||
};
|
|
||||||
|
|
||||||
await qortalRequest(requestBodyJson);
|
|
||||||
if (isNew) {
|
|
||||||
const objectToStore = {
|
|
||||||
title: title.slice(0, 50),
|
|
||||||
description: metadescription,
|
|
||||||
id: identifier,
|
|
||||||
service: "PLAYLIST",
|
|
||||||
name: username,
|
|
||||||
...playlistObject,
|
|
||||||
};
|
|
||||||
dispatch(updateFile(objectToStore));
|
|
||||||
dispatch(updateInHashMap(objectToStore));
|
|
||||||
} else {
|
|
||||||
dispatch(
|
|
||||||
updateFile({
|
|
||||||
...editVideoProperties,
|
|
||||||
...playlistObject,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
dispatch(
|
|
||||||
updateInHashMap({
|
|
||||||
...editVideoProperties,
|
|
||||||
...playlistObject,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
onClose();
|
|
||||||
} catch (error: any) {
|
|
||||||
let notificationObj: any = null;
|
|
||||||
if (typeof error === "string") {
|
|
||||||
notificationObj = {
|
|
||||||
msg: error || "Failed to publish update",
|
|
||||||
alertType: "error",
|
|
||||||
};
|
|
||||||
} else if (typeof error?.error === "string") {
|
|
||||||
notificationObj = {
|
|
||||||
msg: error?.error || "Failed to publish update",
|
|
||||||
alertType: "error",
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
notificationObj = {
|
|
||||||
msg: error?.message || "Failed to publish update",
|
|
||||||
alertType: "error",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (!notificationObj) return;
|
|
||||||
dispatch(setNotification(notificationObj));
|
|
||||||
|
|
||||||
throw new Error("Failed to publish update");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleOnchange = (index: number, type: string, value: string) => {
|
|
||||||
// setFiles((prev) => {
|
|
||||||
// let formattedValue = value
|
|
||||||
// console.log({type})
|
|
||||||
// if(type === 'title'){
|
|
||||||
// formattedValue = value.replace(/[^a-zA-Z0-9\s]/g, "")
|
|
||||||
// }
|
|
||||||
// const copyFiles = [...prev];
|
|
||||||
// copyFiles[index] = {
|
|
||||||
// ...copyFiles[index],
|
|
||||||
// [type]: formattedValue,
|
|
||||||
// };
|
|
||||||
// return copyFiles;
|
|
||||||
// });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOptionCategoryChangeVideos = (
|
|
||||||
event: SelectChangeEvent<string>
|
|
||||||
) => {
|
|
||||||
const optionId = event.target.value;
|
|
||||||
const selectedOption = firstCategories.find(
|
|
||||||
option => option.id === +optionId
|
|
||||||
);
|
|
||||||
setSelectedCategoryVideos(selectedOption || null);
|
|
||||||
};
|
|
||||||
const handleOptionSubCategoryChangeVideos = (
|
|
||||||
event: SelectChangeEvent<string>,
|
|
||||||
subcategories: any[]
|
|
||||||
) => {
|
|
||||||
const optionId = event.target.value;
|
|
||||||
const selectedOption = subcategories.find(
|
|
||||||
option => option.id === +optionId
|
|
||||||
);
|
|
||||||
setSelectedSubCategoryVideos(selectedOption || null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeVideo = index => {
|
|
||||||
const copyData = structuredClone(playlistData);
|
|
||||||
copyData.videos.splice(index, 1);
|
|
||||||
setPlaylistData(copyData);
|
|
||||||
};
|
|
||||||
|
|
||||||
const addVideo = data => {
|
|
||||||
if (playlistData?.videos?.length > 9) {
|
|
||||||
dispatch(
|
|
||||||
setNotification({
|
|
||||||
msg: "Max 10 videos per playlist",
|
|
||||||
alertType: "error",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const copyData = structuredClone(playlistData);
|
|
||||||
copyData.videos = [...copyData.videos, { ...data }];
|
|
||||||
setPlaylistData(copyData);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Modal
|
|
||||||
open={!!editVideoProperties}
|
|
||||||
aria-labelledby="modal-title"
|
|
||||||
aria-describedby="modal-description"
|
|
||||||
>
|
|
||||||
<ModalBody>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isNew ? (
|
|
||||||
<NewCrowdfundTitle>Create new playlist</NewCrowdfundTitle>
|
|
||||||
) : (
|
|
||||||
<NewCrowdfundTitle>Update Playlist properties</NewCrowdfundTitle>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
<>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
gap: "20px",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<FormControl fullWidth sx={{ marginBottom: 2 }}>
|
|
||||||
<InputLabel id="Category">Select a Category</InputLabel>
|
|
||||||
<Select
|
|
||||||
labelId="Category"
|
|
||||||
input={<OutlinedInput label="Select a Category" />}
|
|
||||||
value={selectedCategoryVideos?.id || ""}
|
|
||||||
onChange={handleOptionCategoryChangeVideos}
|
|
||||||
>
|
|
||||||
{firstCategories.map(option => (
|
|
||||||
<MenuItem key={option.id} value={option.id}>
|
|
||||||
{option.name}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
{selectedCategoryVideos &&
|
|
||||||
secondCategories[selectedCategoryVideos?.id] && (
|
|
||||||
<FormControl fullWidth sx={{ marginBottom: 2 }}>
|
|
||||||
<InputLabel id="Category">Select a Sub-Category</InputLabel>
|
|
||||||
<Select
|
|
||||||
labelId="Sub-Category"
|
|
||||||
input={<OutlinedInput label="Select a Sub-Category" />}
|
|
||||||
value={selectedSubCategoryVideos?.id || ""}
|
|
||||||
onChange={e =>
|
|
||||||
handleOptionSubCategoryChangeVideos(
|
|
||||||
e,
|
|
||||||
secondCategories[selectedCategoryVideos?.id]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{secondCategories[selectedCategoryVideos.id].map(
|
|
||||||
option => (
|
|
||||||
<MenuItem key={option.id} value={option.id}>
|
|
||||||
{option.name}
|
|
||||||
</MenuItem>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
<React.Fragment>
|
|
||||||
{!coverImage ? (
|
|
||||||
<ImageUploader onPick={(img: string) => setCoverImage(img)}>
|
|
||||||
<AddCoverImageButton variant="contained">
|
|
||||||
Add Cover Image
|
|
||||||
<AddLogoIcon
|
|
||||||
sx={{
|
|
||||||
height: "25px",
|
|
||||||
width: "auto",
|
|
||||||
}}
|
|
||||||
></AddLogoIcon>
|
|
||||||
</AddCoverImageButton>
|
|
||||||
</ImageUploader>
|
|
||||||
) : (
|
|
||||||
<LogoPreviewRow>
|
|
||||||
<CoverImagePreview src={coverImage} alt="logo" />
|
|
||||||
<TimesIcon
|
|
||||||
color={theme.palette.text.primary}
|
|
||||||
onClickFunc={() => setCoverImage("")}
|
|
||||||
height={"32"}
|
|
||||||
width={"32"}
|
|
||||||
></TimesIcon>
|
|
||||||
</LogoPreviewRow>
|
|
||||||
)}
|
|
||||||
<CustomInputField
|
|
||||||
name="title"
|
|
||||||
label="Title of playlist"
|
|
||||||
variant="filled"
|
|
||||||
value={title}
|
|
||||||
onChange={e => {
|
|
||||||
const value = e.target.value;
|
|
||||||
const formattedValue = value.replace(
|
|
||||||
/[^a-zA-Z0-9\s-_!?]/g,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
setTitle(formattedValue);
|
|
||||||
}}
|
|
||||||
inputProps={{ maxLength: 180 }}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
{/* <CustomInputField
|
|
||||||
name="description"
|
|
||||||
label="Describe your playlist in a few words"
|
|
||||||
variant="filled"
|
|
||||||
value={description}
|
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
|
||||||
inputProps={{ maxLength: 10000 }}
|
|
||||||
multiline
|
|
||||||
maxRows={3}
|
|
||||||
required
|
|
||||||
/> */}
|
|
||||||
<Typography
|
|
||||||
sx={{
|
|
||||||
fontSize: "18px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Description of playlist
|
|
||||||
</Typography>
|
|
||||||
<TextEditor
|
|
||||||
inlineContent={description}
|
|
||||||
setInlineContent={value => {
|
|
||||||
setDescription(value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</React.Fragment>
|
|
||||||
|
|
||||||
<PlaylistListEdit
|
|
||||||
playlistData={playlistData}
|
|
||||||
removeVideo={removeVideo}
|
|
||||||
addVideo={addVideo}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
|
|
||||||
<CrowdfundActionButtonRow>
|
|
||||||
<CrowdfundActionButton
|
|
||||||
onClick={() => {
|
|
||||||
onClose();
|
|
||||||
}}
|
|
||||||
variant="contained"
|
|
||||||
color="error"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</CrowdfundActionButton>
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
gap: "20px",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<CrowdfundActionButton
|
|
||||||
variant="contained"
|
|
||||||
onClick={() => {
|
|
||||||
publishQDNResource();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Publish
|
|
||||||
</CrowdfundActionButton>
|
|
||||||
</Box>
|
|
||||||
</CrowdfundActionButtonRow>
|
|
||||||
</ModalBody>
|
|
||||||
</Modal>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,586 +0,0 @@
|
|||||||
import { styled } from "@mui/system";
|
|
||||||
import {
|
|
||||||
Accordion,
|
|
||||||
AccordionDetails,
|
|
||||||
AccordionSummary,
|
|
||||||
Box,
|
|
||||||
Button,
|
|
||||||
Grid,
|
|
||||||
Rating,
|
|
||||||
TextField,
|
|
||||||
Typography,
|
|
||||||
Select
|
|
||||||
} from "@mui/material";
|
|
||||||
import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
|
|
||||||
import { TimesSVG } from "../../assets/svgs/TimesSVG";
|
|
||||||
|
|
||||||
export const DoubleLine = styled(Typography)`
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 3;
|
|
||||||
overflow: hidden;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const MainContainer = styled(Grid)({
|
|
||||||
width: "100%",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "flex-start",
|
|
||||||
justifyContent: "center",
|
|
||||||
margin: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const MainCol = styled(Grid)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
width: "100%",
|
|
||||||
padding: "20px",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CreateContainer = styled(Box)(({ theme }) => ({
|
|
||||||
position: "fixed",
|
|
||||||
bottom: "20px",
|
|
||||||
right: "20px",
|
|
||||||
cursor: "pointer",
|
|
||||||
background: theme.palette.background.default,
|
|
||||||
width: "50px",
|
|
||||||
height: "50px",
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
borderRadius: "50%",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ModalBody = styled(Box)(({ theme }) => ({
|
|
||||||
position: "absolute",
|
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
borderRadius: "4px",
|
|
||||||
top: "50%",
|
|
||||||
left: "50%",
|
|
||||||
transform: "translate(-50%, -50%)",
|
|
||||||
width: "75%",
|
|
||||||
maxWidth: "900px",
|
|
||||||
padding: "15px 35px",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "17px",
|
|
||||||
overflowY: "auto",
|
|
||||||
maxHeight: "95vh",
|
|
||||||
boxShadow:
|
|
||||||
theme.palette.mode === "dark"
|
|
||||||
? "0px 4px 5px 0px hsla(0,0%,0%,0.14), 0px 1px 10px 0px hsla(0,0%,0%,0.12), 0px 2px 4px -1px hsla(0,0%,0%,0.2)"
|
|
||||||
: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px",
|
|
||||||
"&::-webkit-scrollbar-track": {
|
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-track:hover": {
|
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar": {
|
|
||||||
width: "16px",
|
|
||||||
height: "10px",
|
|
||||||
backgroundColor: theme.palette.mode === "light" ? "#f6f8fa" : "#292d3e",
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-thumb": {
|
|
||||||
backgroundColor: theme.palette.mode === "light" ? "#d3d9e1" : "#575757",
|
|
||||||
borderRadius: "8px",
|
|
||||||
backgroundClip: "content-box",
|
|
||||||
border: "4px solid transparent",
|
|
||||||
},
|
|
||||||
"&::-webkit-scrollbar-thumb:hover": {
|
|
||||||
backgroundColor: theme.palette.mode === "light" ? "#b7bcc4" : "#474646",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const NewCrowdfundTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 400,
|
|
||||||
fontFamily: "Raleway",
|
|
||||||
fontSize: "25px",
|
|
||||||
userSelect: "none",
|
|
||||||
}));
|
|
||||||
export const NewCrowdFundFont = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 400,
|
|
||||||
fontFamily: "Raleway",
|
|
||||||
fontSize: "18px",
|
|
||||||
userSelect: "none",
|
|
||||||
}));
|
|
||||||
export const NewCrowdfundTimeDescription = styled(Typography)(({ theme }) => ({
|
|
||||||
fontWeight: 400,
|
|
||||||
fontFamily: "Raleway",
|
|
||||||
fontSize: "18px",
|
|
||||||
userSelect: "none",
|
|
||||||
fontStyle: "italic",
|
|
||||||
textDecoration: "underline",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CustomInputField = styled(TextField)(({ theme }) => ({
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "19px",
|
|
||||||
letterSpacing: "0px",
|
|
||||||
fontWeight: 400,
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
borderColor: theme.palette.background.paper,
|
|
||||||
"& label": {
|
|
||||||
color: theme.palette.mode === "light" ? "#808183" : "#edeef0",
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "19px",
|
|
||||||
letterSpacing: "0px",
|
|
||||||
fontWeight: 400,
|
|
||||||
},
|
|
||||||
"& label.Mui-focused": {
|
|
||||||
color: theme.palette.mode === "light" ? "#A0AAB4" : "#d7d8da",
|
|
||||||
},
|
|
||||||
"& .MuiInput-underline:after": {
|
|
||||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
|
||||||
},
|
|
||||||
"& .MuiOutlinedInput-root": {
|
|
||||||
"& fieldset": {
|
|
||||||
borderColor: "#E0E3E7",
|
|
||||||
},
|
|
||||||
"&:hover fieldset": {
|
|
||||||
borderColor: "#B2BAC2",
|
|
||||||
},
|
|
||||||
"&.Mui-focused fieldset": {
|
|
||||||
borderColor: "#6F7E8C",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"& .MuiInputBase-root": {
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "19px",
|
|
||||||
letterSpacing: "0px",
|
|
||||||
fontWeight: 400,
|
|
||||||
},
|
|
||||||
"& [class$='-MuiFilledInput-root']": {
|
|
||||||
padding: "30px 12px 8px",
|
|
||||||
},
|
|
||||||
"& .MuiFilledInput-root:after": {
|
|
||||||
borderBottomColor: theme.palette.secondary.main,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Copse",
|
|
||||||
letterSpacing: "1px",
|
|
||||||
fontWeight: 400,
|
|
||||||
fontSize: "20px",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
userSelect: "none",
|
|
||||||
wordBreak: "break-word",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundSubTitleRow = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
width: "100%",
|
|
||||||
flexDirection: "row",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CrowdfundSubTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Copse",
|
|
||||||
letterSpacing: "1px",
|
|
||||||
fontWeight: 400,
|
|
||||||
fontSize: "17px",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
userSelect: "none",
|
|
||||||
wordBreak: "break-word",
|
|
||||||
borderBottom: `1px solid ${theme.palette.text.primary}`,
|
|
||||||
paddingBottom: "1.5px",
|
|
||||||
width: "fit-content",
|
|
||||||
textDecoration: "none",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundDescription = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Raleway",
|
|
||||||
fontSize: "16px",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
userSelect: "none",
|
|
||||||
wordBreak: "break-word",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const Spacer = ({ height }: any) => {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
height: height,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const StyledCardHeaderComment = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
gap: "5px",
|
|
||||||
padding: "7px 0px",
|
|
||||||
});
|
|
||||||
export const StyledCardCol = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
overflow: "hidden",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "2px",
|
|
||||||
alignItems: "flex-start",
|
|
||||||
width: "100%",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const StyledCardColComment = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
overflow: "hidden",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "2px",
|
|
||||||
alignItems: "flex-start",
|
|
||||||
width: "100%",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AuthorTextComment = styled(Typography)({
|
|
||||||
fontFamily: "Raleway, sans-serif",
|
|
||||||
fontSize: "16px",
|
|
||||||
lineHeight: "1.2",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AddLogoIcon = styled(AddPhotoAlternateIcon)(({ theme }) => ({
|
|
||||||
color: "#fff",
|
|
||||||
height: "25px",
|
|
||||||
width: "auto",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CoverImagePreview = styled("img")(({ theme }) => ({
|
|
||||||
width: "100px",
|
|
||||||
height: "100px",
|
|
||||||
objectFit: "contain",
|
|
||||||
userSelect: "none",
|
|
||||||
borderRadius: "3px",
|
|
||||||
marginBottom: "10px",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const LogoPreviewRow = styled(Box)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
gap: "10px",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const TimesIcon = styled(TimesSVG)(({ theme }) => ({
|
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
borderRadius: "50%",
|
|
||||||
padding: "5px",
|
|
||||||
transition: "all 0.2s ease-in-out",
|
|
||||||
"&:hover": {
|
|
||||||
cursor: "pointer",
|
|
||||||
scale: "1.1",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundCardTitle = styled(DoubleLine)(({ theme }) => ({
|
|
||||||
fontFamily: "Montserrat",
|
|
||||||
fontSize: "24px",
|
|
||||||
letterSpacing: "-0.3px",
|
|
||||||
userSelect: "none",
|
|
||||||
marginBottom: "auto",
|
|
||||||
textAlign: "center",
|
|
||||||
"@media (max-width: 650px)": {
|
|
||||||
fontSize: "18px",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundUploadDate = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Montserrat",
|
|
||||||
fontSize: "12px",
|
|
||||||
letterSpacing: "0.2px",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
userSelect: "none",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CATContainer = styled(Box)(({ theme }) => ({
|
|
||||||
position: "relative",
|
|
||||||
display: "flex",
|
|
||||||
padding: "15px",
|
|
||||||
flexDirection: "column",
|
|
||||||
gap: "20px",
|
|
||||||
justifyContent: "center",
|
|
||||||
width: "100%",
|
|
||||||
alignItems: "center",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const AddCrowdFundButton = styled(Button)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
textTransform: "none",
|
|
||||||
padding: "10px 25px",
|
|
||||||
fontSize: "15px",
|
|
||||||
gap: "8px",
|
|
||||||
color: "#ffffff",
|
|
||||||
backgroundColor:
|
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.main : "#2a9a86",
|
|
||||||
border: "none",
|
|
||||||
borderRadius: "5px",
|
|
||||||
transition: "all 0.3s ease-in-out",
|
|
||||||
"&:hover": {
|
|
||||||
cursor: "pointer",
|
|
||||||
backgroundColor:
|
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.dark : "#217e6d",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const EditCrowdFundButton = styled(Button)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
textTransform: "none",
|
|
||||||
padding: "5px 12px",
|
|
||||||
gap: "8px",
|
|
||||||
color: "#ffffff",
|
|
||||||
backgroundColor:
|
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.main : "#2a9a86",
|
|
||||||
border: "none",
|
|
||||||
borderRadius: "5px",
|
|
||||||
transition: "all 0.3s ease-in-out",
|
|
||||||
"&:hover": {
|
|
||||||
cursor: "pointer",
|
|
||||||
backgroundColor:
|
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.dark : "#217e6d",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundListWrapper = styled(Box)(({ theme }) => ({
|
|
||||||
width: "100%",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
marginTop: "0px",
|
|
||||||
background: theme.palette.background.default,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundTitleRow = styled(Box)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
width: "100%",
|
|
||||||
gap: "10px",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundPageTitle = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Copse",
|
|
||||||
fontSize: "35px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: "1px",
|
|
||||||
userSelect: "none",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundStatusRow = styled(Box)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "21px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: 0,
|
|
||||||
border: `1px solid ${theme.palette.text.primary}`,
|
|
||||||
borderRadius: "8px",
|
|
||||||
padding: "15px 25px",
|
|
||||||
userSelect: "none",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundDescriptionRow = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
width: "100%",
|
|
||||||
fontFamily: "Montserrat",
|
|
||||||
fontSize: "18px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AboutMyCrowdfund = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Copse",
|
|
||||||
fontSize: "23px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: "1px",
|
|
||||||
userSelect: "none",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundInlineContentRow = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
width: "100%",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CrowdfundInlineContent = styled(Box)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "19px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: 0,
|
|
||||||
userSelect: "none",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundAccordion = styled(Accordion)(({ theme }) => ({
|
|
||||||
backgroundColor: theme.palette.primary.light,
|
|
||||||
"& .Mui-expanded": {
|
|
||||||
minHeight: "auto !important",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundAccordionSummary = styled(AccordionSummary)({
|
|
||||||
height: "50px",
|
|
||||||
"& .Mui-expanded": {
|
|
||||||
margin: "0px !important",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CrowdfundAccordionFont = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: "0px",
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
userSelect: "none",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundAccordionDetails = styled(AccordionDetails)({
|
|
||||||
padding: "0px 16px 16px 16px",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AddCoverImageButton = styled(Button)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
fontFamily: "Montserrat",
|
|
||||||
fontSize: "16px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: "0.2px",
|
|
||||||
color: "white",
|
|
||||||
gap: "5px",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CoverImage = styled("img")({
|
|
||||||
width: "100%",
|
|
||||||
height: "250px",
|
|
||||||
objectFit: "cover",
|
|
||||||
objectPosition: "center",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CrowdfundActionButtonRow = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
width: "100%",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const CrowdfundActionButton = styled(Button)(({ theme }) => ({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
fontFamily: "Montserrat",
|
|
||||||
fontSize: "16px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: "0.2px",
|
|
||||||
color: "white",
|
|
||||||
gap: "5px",
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const BackToHomeButton = styled(Button)(({ theme }) => ({
|
|
||||||
position: "absolute",
|
|
||||||
top: "20px",
|
|
||||||
left: "20px",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
fontFamily: "Montserrat",
|
|
||||||
fontSize: "13px",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: "0.2px",
|
|
||||||
color: "white",
|
|
||||||
gap: "5px",
|
|
||||||
padding: "5px 10px",
|
|
||||||
backgroundColor: theme.palette.secondary.main,
|
|
||||||
transition: "all 0.3s ease-in-out",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundColor: theme.palette.secondary.dark,
|
|
||||||
cursor: "pointer",
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const CrowdfundLoaderRow = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
gap: "10px",
|
|
||||||
padding: "10px",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const RatingContainer = styled(Box)({
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
padding: "1px 5px",
|
|
||||||
borderRadius: "5px",
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
transition: "all 0.3s ease-in-out",
|
|
||||||
"&:hover": {
|
|
||||||
cursor: "pointer",
|
|
||||||
backgroundColor: "#e4ddddac",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const StyledRating = styled(Rating)({
|
|
||||||
fontSize: "28px",
|
|
||||||
});
|
|
||||||
|
|
||||||
export const NoReviewsFont = styled(Typography)(({ theme }) => ({
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontWeight: 400,
|
|
||||||
letterSpacing: 0,
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const StyledButton = styled(Button)(({ theme }) => ({
|
|
||||||
fontWeight: 600,
|
|
||||||
color: theme.palette.text.primary
|
|
||||||
}))
|
|
||||||
|
|
||||||
export const CustomSelect = styled(Select)(({ theme }) => ({
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "19px",
|
|
||||||
letterSpacing: "0px",
|
|
||||||
fontWeight: 400,
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
'& .MuiSelect-select': {
|
|
||||||
padding: '12px',
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "19px",
|
|
||||||
letterSpacing: "0px",
|
|
||||||
fontWeight: 400,
|
|
||||||
borderRadius: theme.shape.borderRadius, // Match border radius
|
|
||||||
},
|
|
||||||
'&:before': {
|
|
||||||
// Underline style
|
|
||||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
|
||||||
},
|
|
||||||
'&:after': {
|
|
||||||
// Underline style when focused
|
|
||||||
borderBottomColor: theme.palette.secondary.main,
|
|
||||||
},
|
|
||||||
'& .MuiOutlinedInput-root': {
|
|
||||||
'& fieldset': {
|
|
||||||
borderColor: "#E0E3E7",
|
|
||||||
},
|
|
||||||
'&:hover fieldset': {
|
|
||||||
borderColor: "#B2BAC2",
|
|
||||||
},
|
|
||||||
'&.Mui-focused fieldset': {
|
|
||||||
borderColor: "#6F7E8C",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'& .MuiInputBase-root': {
|
|
||||||
fontFamily: "Mulish",
|
|
||||||
fontSize: "19px",
|
|
||||||
letterSpacing: "0px",
|
|
||||||
fontWeight: 400,
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
@@ -290,7 +290,15 @@ export const PublishFile = ({ editId, editContent }: NewCrowdfundProps) => {
|
|||||||
{editId ? null : (
|
{editId ? null : (
|
||||||
<StyledButton
|
<StyledButton
|
||||||
color="primary"
|
color="primary"
|
||||||
startIcon={<AddBoxIcon />}
|
startIcon={
|
||||||
|
<AddBoxIcon
|
||||||
|
sx={{
|
||||||
|
color: "#66C3FE",
|
||||||
|
width: "40px",
|
||||||
|
height: "40px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ import {
|
|||||||
Rating,
|
Rating,
|
||||||
TextField,
|
TextField,
|
||||||
Typography,
|
Typography,
|
||||||
Select
|
Select,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
|
import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
|
||||||
import { TimesSVG } from "../../assets/svgs/TimesSVG";
|
import { TimesSVG } from "../../assets/svgs/TimesSVG";
|
||||||
|
import { fontSizeSmall } from "../../constants/Misc.ts";
|
||||||
|
|
||||||
export const DoubleLine = styled(Typography)`
|
export const DoubleLine = styled(Typography)`
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
@@ -67,9 +68,9 @@ export const ModalBody = styled(Box)(({ theme }) => ({
|
|||||||
overflowY: "auto",
|
overflowY: "auto",
|
||||||
maxHeight: "95vh",
|
maxHeight: "95vh",
|
||||||
boxShadow:
|
boxShadow:
|
||||||
theme.palette.mode === "dark"
|
theme.palette.mode === "dark"
|
||||||
? "0px 4px 5px 0px hsla(0,0%,0%,0.14), 0px 1px 10px 0px hsla(0,0%,0%,0.12), 0px 2px 4px -1px hsla(0,0%,0%,0.2)"
|
? "0px 4px 5px 0px hsla(0,0%,0%,0.14), 0px 1px 10px 0px hsla(0,0%,0%,0.12), 0px 2px 4px -1px hsla(0,0%,0%,0.2)"
|
||||||
: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px",
|
: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px",
|
||||||
"&::-webkit-scrollbar-track": {
|
"&::-webkit-scrollbar-track": {
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
},
|
},
|
||||||
@@ -159,8 +160,6 @@ export const CustomInputField = styled(TextField)(({ theme }) => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
|
export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
|
||||||
fontFamily: "Copse",
|
fontFamily: "Copse",
|
||||||
letterSpacing: "1px",
|
letterSpacing: "1px",
|
||||||
@@ -203,11 +202,11 @@ export const CrowdfundDescription = styled(Typography)(({ theme }) => ({
|
|||||||
|
|
||||||
export const Spacer = ({ height }: any) => {
|
export const Spacer = ({ height }: any) => {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
height: height,
|
height: height,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -314,14 +313,14 @@ export const AddCrowdFundButton = styled(Button)(({ theme }) => ({
|
|||||||
gap: "8px",
|
gap: "8px",
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.main : "#2a9a86",
|
theme.palette.mode === "dark" ? theme.palette.primary.main : "#2a9a86",
|
||||||
border: "none",
|
border: "none",
|
||||||
borderRadius: "5px",
|
borderRadius: "5px",
|
||||||
transition: "all 0.3s ease-in-out",
|
transition: "all 0.3s ease-in-out",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.dark : "#217e6d",
|
theme.palette.mode === "dark" ? theme.palette.primary.dark : "#217e6d",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -333,14 +332,14 @@ export const EditCrowdFundButton = styled(Button)(({ theme }) => ({
|
|||||||
gap: "8px",
|
gap: "8px",
|
||||||
color: "#ffffff",
|
color: "#ffffff",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.main : "#2a9a86",
|
theme.palette.mode === "dark" ? theme.palette.primary.main : "#2a9a86",
|
||||||
border: "none",
|
border: "none",
|
||||||
borderRadius: "5px",
|
borderRadius: "5px",
|
||||||
transition: "all 0.3s ease-in-out",
|
transition: "all 0.3s ease-in-out",
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
theme.palette.mode === "dark" ? theme.palette.primary.dark : "#217e6d",
|
theme.palette.mode === "dark" ? theme.palette.primary.dark : "#217e6d",
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -540,8 +539,9 @@ export const NoReviewsFont = styled(Typography)(({ theme }) => ({
|
|||||||
export const StyledButton = styled(Button)(({ theme }) => ({
|
export const StyledButton = styled(Button)(({ theme }) => ({
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
fontFamily: "Cairo"
|
fontFamily: "Cairo",
|
||||||
}))
|
fontSize: fontSizeSmall,
|
||||||
|
}));
|
||||||
|
|
||||||
export const CustomSelect = styled(Select)(({ theme }) => ({
|
export const CustomSelect = styled(Select)(({ theme }) => ({
|
||||||
fontFamily: "Mulish",
|
fontFamily: "Mulish",
|
||||||
@@ -550,38 +550,38 @@ export const CustomSelect = styled(Select)(({ theme }) => ({
|
|||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
backgroundColor: theme.palette.background.default,
|
backgroundColor: theme.palette.background.default,
|
||||||
'& .MuiSelect-select': {
|
"& .MuiSelect-select": {
|
||||||
padding: '12px',
|
padding: "12px",
|
||||||
fontFamily: "Mulish",
|
fontFamily: "Mulish",
|
||||||
fontSize: "19px",
|
fontSize: "19px",
|
||||||
letterSpacing: "0px",
|
letterSpacing: "0px",
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
borderRadius: theme.shape.borderRadius, // Match border radius
|
borderRadius: theme.shape.borderRadius, // Match border radius
|
||||||
},
|
},
|
||||||
'&:before': {
|
"&:before": {
|
||||||
// Underline style
|
// Underline style
|
||||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
||||||
},
|
},
|
||||||
'&:after': {
|
"&:after": {
|
||||||
// Underline style when focused
|
// Underline style when focused
|
||||||
borderBottomColor: theme.palette.secondary.main,
|
borderBottomColor: theme.palette.secondary.main,
|
||||||
},
|
},
|
||||||
'& .MuiOutlinedInput-root': {
|
"& .MuiOutlinedInput-root": {
|
||||||
'& fieldset': {
|
"& fieldset": {
|
||||||
borderColor: "#E0E3E7",
|
borderColor: "#E0E3E7",
|
||||||
},
|
},
|
||||||
'&:hover fieldset': {
|
"&:hover fieldset": {
|
||||||
borderColor: "#B2BAC2",
|
borderColor: "#B2BAC2",
|
||||||
},
|
},
|
||||||
'&.Mui-focused fieldset': {
|
"&.Mui-focused fieldset": {
|
||||||
borderColor: "#6F7E8C",
|
borderColor: "#6F7E8C",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'& .MuiInputBase-root': {
|
"& .MuiInputBase-root": {
|
||||||
fontFamily: "Mulish",
|
fontFamily: "Mulish",
|
||||||
fontSize: "19px",
|
fontSize: "19px",
|
||||||
letterSpacing: "0px",
|
letterSpacing: "0px",
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
65
src/components/common/CopyLinkButton.tsx
Normal file
65
src/components/common/CopyLinkButton.tsx
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import ShareIcon from "@mui/icons-material/Share";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
ButtonBase,
|
||||||
|
Tooltip,
|
||||||
|
tooltipClasses,
|
||||||
|
TooltipProps,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { styled } from "@mui/system";
|
||||||
|
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { setNotification } from "../../state/features/notificationsSlice.ts";
|
||||||
|
|
||||||
|
export interface CopyLinkButtonProps {
|
||||||
|
link: string;
|
||||||
|
tooltipTitle: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TooltipLine = styled("div")(({ theme }) => ({
|
||||||
|
fontSize: "18px",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const CustomWidthTooltipStyles = styled(
|
||||||
|
({ className, ...props }: TooltipProps) => (
|
||||||
|
<Tooltip {...props} classes={{ popper: className }} />
|
||||||
|
)
|
||||||
|
)({
|
||||||
|
[`& .${tooltipClasses.tooltip}`]: {
|
||||||
|
maxWidth: 600,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const CustomTooltip = ({ title, ...props }: TooltipProps) => {
|
||||||
|
if (typeof title === "string") title = <TooltipLine>{title}</TooltipLine>;
|
||||||
|
|
||||||
|
return <CustomWidthTooltipStyles title={title} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CopyLinkButton = ({ link, tooltipTitle }: CopyLinkButtonProps) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
return (
|
||||||
|
<CustomTooltip title={tooltipTitle} placement={"top"} arrow>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(link).then(() => {
|
||||||
|
dispatch(
|
||||||
|
setNotification({
|
||||||
|
msg: "Copied to clipboard!",
|
||||||
|
alertType: "success",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ShareIcon />
|
||||||
|
</ButtonBase>
|
||||||
|
</Box>
|
||||||
|
</CustomTooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
export const minPriceSuperlike = 10;
|
export const minPriceSuperlike = 10;
|
||||||
export const titleFormatter = /[^a-zA-Z0-9\s-_!?()&'",.;:|—~@#$%^*+=<>]/g;
|
export const titleFormatter = /[^a-zA-Z0-9\s-_!?()&'",.;:|—~@#$%^*+=<>]/g;
|
||||||
export const titleFormatterOnSave = /[^a-zA-Z0-9\s-_!()&',.;—~@#$%^+=]/g;
|
export const titleFormatterOnSave = /[^a-zA-Z0-9\s-_!()&',.;—~@#$%^+=]/g;
|
||||||
|
|
||||||
|
export const fileMaxSize = 2147; // Size in Megabytes (decimal)
|
||||||
|
export const maxSize = fileMaxSize * 1024 * 1024;
|
||||||
|
|
||||||
|
export const fontSizeExSmall = "70%";
|
||||||
|
export const fontSizeSmall = "80%";
|
||||||
|
export const fontSizeMedium = "100%";
|
||||||
|
export const fontSizeLarge = "120%";
|
||||||
|
export const fontSizeExLarge = "150%";
|
||||||
|
export const maxCommentLength = 10_000;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
import { CopyLinkButton } from "../../components/common/CopyLinkButton.tsx";
|
||||||
|
import { fontSizeMedium } from "../../constants/Misc.ts";
|
||||||
import { setIsLoadingGlobal } from "../../state/features/globalSlice";
|
import { setIsLoadingGlobal } from "../../state/features/globalSlice";
|
||||||
import { Avatar, Box, Typography, useTheme } from "@mui/material";
|
import { Avatar, Box, Typography, useTheme } from "@mui/material";
|
||||||
import { RootState } from "../../state/store";
|
import { RootState } from "../../state/store";
|
||||||
@@ -309,7 +311,7 @@ export const FileContent = () => {
|
|||||||
});
|
});
|
||||||
return categoryDisplay;
|
return categoryDisplay;
|
||||||
}
|
}
|
||||||
return "no videodata";
|
return "No file data";
|
||||||
}, [fileData]);
|
}, [fileData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -404,16 +406,21 @@ export const FileContent = () => {
|
|||||||
</StyledCardHeaderComment>
|
</StyledCardHeaderComment>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<Box>
|
<Box
|
||||||
<Typography
|
sx={{
|
||||||
sx={{
|
display: "flex",
|
||||||
fontWeight: "bold",
|
alignItems: "center",
|
||||||
fontSize: "16px",
|
gap: "10px",
|
||||||
userSelect: "none",
|
fontWeight: "bold",
|
||||||
}}
|
fontSize: fontSizeMedium,
|
||||||
>
|
userSelect: "none",
|
||||||
{categoriesDisplay}
|
}}
|
||||||
</Typography>
|
>
|
||||||
|
{categoriesDisplay}
|
||||||
|
<CopyLinkButton
|
||||||
|
link={`qortal://APP/Q-Share/share/${encodeURIComponent(fileData?.user)}/${encodeURIComponent(fileData?.id)}`}
|
||||||
|
tooltipTitle={`Copy page link`}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="15px" />
|
<Spacer height="15px" />
|
||||||
<Box
|
<Box
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import { VideoPlayerGlobal } from "../components/common/VideoPlayerGlobal";
|
|||||||
import { Rnd } from "react-rnd";
|
import { Rnd } from "react-rnd";
|
||||||
import { RequestQueue } from "../utils/queue";
|
import { RequestQueue } from "../utils/queue";
|
||||||
import { EditFile } from "../components/EditFile/EditFile.tsx";
|
import { EditFile } from "../components/EditFile/EditFile.tsx";
|
||||||
import { EditPlaylist } from "../components/EditPlaylist/EditPlaylist";
|
|
||||||
import ConsentModal from "../components/common/ConsentModal";
|
import ConsentModal from "../components/common/ConsentModal";
|
||||||
import { useIframe } from "../hooks/useIframe.tsx";
|
import { useIframe } from "../hooks/useIframe.tsx";
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ let timer: number | null = null;
|
|||||||
export const queue = new RequestQueue();
|
export const queue = new RequestQueue();
|
||||||
|
|
||||||
const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||||
useIframe()
|
useIframe();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const isDragging = useRef(false);
|
const isDragging = useRef(false);
|
||||||
const [userAvatar, setUserAvatar] = useState<string>("");
|
const [userAvatar, setUserAvatar] = useState<string>("");
|
||||||
@@ -141,7 +140,7 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
|||||||
authenticate={askForAccountInformation}
|
authenticate={askForAccountInformation}
|
||||||
/>
|
/>
|
||||||
<EditFile />
|
<EditFile />
|
||||||
<EditPlaylist />
|
|
||||||
<Rnd
|
<Rnd
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
onDragStop={onDragStop}
|
onDragStop={onDragStop}
|
||||||
|
|||||||
Reference in New Issue
Block a user