mirror of
https://github.com/Qortal/q-tube.git
synced 2026-04-22 08:03:59 +00:00
Merge pull request #91 from Qortal/feature/framework-implementation
Feature/framework implementation
This commit is contained in:
@@ -1,18 +0,0 @@
|
||||
module.exports = {
|
||||
env: { browser: true, amd: true, node: true, es2020: true },
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended",
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: { ecmaVersion: "latest", sourceType: "module" },
|
||||
plugins: ["react-refresh"],
|
||||
rules: {
|
||||
"react-refresh/only-export-components": "warn",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
"@typescript-eslint/no-unused-expressions": "off",
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
},
|
||||
};
|
||||
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
build
|
||||
dist
|
||||
23
.prettierrc
23
.prettierrc
@@ -1,10 +1,23 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"arrowParens": "always",
|
||||
"bracketSameLine": false,
|
||||
"bracketSpacing": true,
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"endOfLine": "lf",
|
||||
"experimentalTernaries": false,
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"insertPragma": false,
|
||||
"jsxBracketSameLine": false,
|
||||
"arrowParens": "avoid",
|
||||
"jsxSingleQuote": false,
|
||||
"printWidth": 80,
|
||||
"proseWrap": "preserve",
|
||||
"quoteProps": "as-needed",
|
||||
"requirePragma": false,
|
||||
"semi": true,
|
||||
"singleAttributePerLine": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"semi": true
|
||||
"trailingComma": "es5",
|
||||
"useTabs": false,
|
||||
"vueIndentScriptAndStyle": false
|
||||
}
|
||||
|
||||
37
eslint.config.js
Normal file
37
eslint.config.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import js from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import prettierPlugin from 'eslint-plugin-prettier';
|
||||
import prettierConfig from 'eslint-config-prettier';
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['dist'] },
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
files: ['**/*.{ts,tsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
prettier: prettierPlugin,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
'prettier/prettier': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
// This disables ESLint rules that would conflict with Prettier
|
||||
name: 'prettier-config',
|
||||
rules: prettierConfig.rules,
|
||||
}
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
@@ -8,6 +8,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="dropdown-portal-root"></div>
|
||||
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
3197
package-lock.json
generated
3197
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
25
package.json
25
package.json
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"build": "vite build",
|
||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
@@ -15,31 +15,32 @@
|
||||
"@mui/icons-material": "^7.1.0",
|
||||
"@mui/lab": "^7.0.0-beta.12",
|
||||
"@mui/material": "^7.1.0",
|
||||
"@preact/signals-react": "^2.3.0",
|
||||
"@reduxjs/toolkit": "^2.5.0",
|
||||
"compressorjs": "^1.2.1",
|
||||
"dompurify": "^3.2.3",
|
||||
"framer-motion": "^12.23.6",
|
||||
"i18n": "^0.15.1",
|
||||
"idb-keyval": "^6.2.2",
|
||||
"jotai": "^2.12.4",
|
||||
"localforage": "^1.10.0",
|
||||
"mediainfo.js": "^0.3.5",
|
||||
"moment": "^2.30.1",
|
||||
"qapp-core": "^1.0.29",
|
||||
"qapp-core": "^1.0.52",
|
||||
"quill": "^2.0.2",
|
||||
"quill-image-resize-module-react": "^3.0.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-dropzone": "^14.3.5",
|
||||
"react-i18next": "^15.5.3",
|
||||
"react-idle-timer": "^5.7.2",
|
||||
"react-intersection-observer": "^9.14.0",
|
||||
"react-quill-new": "^3.3.3",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-rnd": "^10.4.14",
|
||||
"react-router-dom": "^7.1.1",
|
||||
"react-router-dom": "^7.6.2",
|
||||
"react-toastify": "^11.0.2",
|
||||
"redux-persist": "^6.0.0",
|
||||
"short-unique-id": "^5.2.0",
|
||||
"ts-key-enum": "^2.0.13"
|
||||
"short-unique-id": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.0.0",
|
||||
"@types/react": "^19.0.2",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
||||
@@ -48,8 +49,10 @@
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-plugin-react-hooks": "^5.1.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.16",
|
||||
"globals": "^15.15.0",
|
||||
"prettier": "^3.4.2",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^6.3.5"
|
||||
"vite": "^6.3.5",
|
||||
"vite-plugin-static-copy": "^3.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/MediaInfoModule.wasm
Normal file
BIN
public/MediaInfoModule.wasm
Normal file
Binary file not shown.
@@ -1,42 +1,23 @@
|
||||
import { SubscriptionData } from "./components/common/ContentButtons/SubscribeButton.tsx";
|
||||
import { store } from "./state/store.ts";
|
||||
import { SubscriptionData } from './components/common/ContentButtons/SubscribeButton.tsx';
|
||||
|
||||
export const getUserName = async () => {
|
||||
const account = await qortalRequest({
|
||||
action: "GET_USER_ACCOUNT",
|
||||
action: 'GET_USER_ACCOUNT',
|
||||
});
|
||||
const nameData = await qortalRequest({
|
||||
action: "GET_ACCOUNT_NAMES",
|
||||
action: 'GET_ACCOUNT_NAMES',
|
||||
address: account.address,
|
||||
});
|
||||
|
||||
if (nameData?.length > 0) return nameData[0].name;
|
||||
else return "";
|
||||
else return '';
|
||||
};
|
||||
|
||||
export const filterVideosByName = (
|
||||
subscriptionList: SubscriptionData[],
|
||||
userName: string
|
||||
) => {
|
||||
return subscriptionList.filter(item => {
|
||||
return subscriptionList.filter((item) => {
|
||||
return item.userName === userName;
|
||||
});
|
||||
};
|
||||
export const subscriptionListFilter = async (reset = true) => {
|
||||
const filteredSubscriptionList =
|
||||
store.getState().video.filteredSubscriptionList;
|
||||
const isFilteredSubscriptionListEmpty = filteredSubscriptionList.length === 0;
|
||||
|
||||
if (!reset && !isFilteredSubscriptionListEmpty) {
|
||||
return filteredSubscriptionList;
|
||||
}
|
||||
|
||||
const subscriptionList = store.getState().persist.subscriptionList;
|
||||
const filterByUserName =
|
||||
store.getState().persist.subscriptionListFilter === "currentNameOnly";
|
||||
const userName = await getUserName();
|
||||
|
||||
if (filterByUserName && userName) {
|
||||
return filterVideosByName(subscriptionList, userName);
|
||||
} else return subscriptionList;
|
||||
};
|
||||
|
||||
68
src/App.tsx
68
src/App.tsx
@@ -1,66 +1,14 @@
|
||||
import { CssBaseline } from "@mui/material";
|
||||
import { ThemeProvider } from "@mui/material/styles";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Provider, useSelector } from "react-redux";
|
||||
import { Route, Routes } from "react-router-dom";
|
||||
import { PersistGate } from "redux-persist/integration/react";
|
||||
import { subscriptionListFilter } from "./App-Functions.ts";
|
||||
import Notification from "./components/common/Notification/Notification";
|
||||
import { useIframe } from "./hooks/useIframe.tsx";
|
||||
import { IndividualProfile } from "./pages/ContentPages/IndividualProfile/IndividualProfile";
|
||||
import { PlaylistContent } from "./pages/ContentPages/PlaylistContent/PlaylistContent";
|
||||
import { VideoContent } from "./pages/ContentPages/VideoContent/VideoContent";
|
||||
import { Home } from "./pages/Home/Home";
|
||||
import { setFilteredSubscriptions } from "./state/features/videoSlice.ts";
|
||||
import { store, persistor, RootState } from "./state/store";
|
||||
import { darkTheme, lightTheme } from "./styles/theme";
|
||||
import DownloadWrapper from "./wrappers/DownloadWrapper";
|
||||
import GlobalWrapper from "./wrappers/GlobalWrapper";
|
||||
import { ScrollWrapper } from "./wrappers/ScrollWrapper.tsx";
|
||||
import { QappCoreWrapper } from "./QappCoreWrapper.tsx";
|
||||
import Notification from './components/common/Notification/Notification';
|
||||
|
||||
import { Routes } from './Routes.tsx';
|
||||
import ThemeProviderWrapper from './styles/theme-provider.tsx';
|
||||
|
||||
function App() {
|
||||
// const themeColor = window._qdnTheme
|
||||
|
||||
const [theme, setTheme] = useState("dark");
|
||||
|
||||
useIframe();
|
||||
|
||||
useEffect(() => {
|
||||
subscriptionListFilter(false).then(filteredList => {
|
||||
store.dispatch(setFilteredSubscriptions(filteredList));
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<PersistGate loading={null} persistor={persistor}>
|
||||
<ThemeProvider theme={theme === "light" ? lightTheme : darkTheme}>
|
||||
<QappCoreWrapper>
|
||||
<Notification />
|
||||
<DownloadWrapper>
|
||||
<GlobalWrapper setTheme={(val: string) => setTheme(val)}>
|
||||
<ScrollWrapper>
|
||||
<CssBaseline />
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/video/:name/:id" element={<VideoContent />} />
|
||||
<Route
|
||||
path="/playlist/:name/:id"
|
||||
element={<PlaylistContent />}
|
||||
/>
|
||||
<Route
|
||||
path="/channel/:name"
|
||||
element={<IndividualProfile />}
|
||||
/>
|
||||
</Routes>
|
||||
</ScrollWrapper>
|
||||
</GlobalWrapper>
|
||||
</DownloadWrapper>
|
||||
</QappCoreWrapper>
|
||||
</ThemeProvider>
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
<ThemeProviderWrapper>
|
||||
<Notification />
|
||||
<Routes />
|
||||
</ThemeProviderWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
28
src/AppWrapper.tsx
Normal file
28
src/AppWrapper.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { GlobalProvider } from 'qapp-core';
|
||||
import Layout from './Layout';
|
||||
import { ScrollWrapper } from './wrappers/ScrollWrapper';
|
||||
import GlobalWrapper from './wrappers/GlobalWrapper';
|
||||
|
||||
export const AppWrapper = () => {
|
||||
return (
|
||||
<GlobalProvider
|
||||
config={{
|
||||
auth: {
|
||||
authenticateOnMount: true,
|
||||
balanceSetting: {
|
||||
interval: 120000,
|
||||
},
|
||||
},
|
||||
publicSalt: 'usVbeM9YpjGCbLrTcc78YJS0ap1AxDkHAOMZrp3+wDY=',
|
||||
appName: 'Q-Tube',
|
||||
enableGlobalVideoFeature: true,
|
||||
}}
|
||||
>
|
||||
<GlobalWrapper>
|
||||
<ScrollWrapper>
|
||||
<Layout />
|
||||
</ScrollWrapper>
|
||||
</GlobalWrapper>
|
||||
</GlobalProvider>
|
||||
);
|
||||
};
|
||||
136
src/Layout.tsx
Normal file
136
src/Layout.tsx
Normal file
@@ -0,0 +1,136 @@
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { useIframe } from './hooks/useIframe';
|
||||
import { Box, useTheme } from '@mui/material';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import { isSideBarExpandedAtom, scrollRefAtom } from './state/global/navbar';
|
||||
|
||||
import NavBar from './components/layout/Navbar/Navbar';
|
||||
import { Sidenav } from './components/layout/Sidenav/Sidenav';
|
||||
import { namesAtom } from './state/global/names';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { PageTransition } from './components/common/PageTransition';
|
||||
import { useIsSmall } from './hooks/useIsSmall';
|
||||
import { useIsMobile } from './hooks/useIsMobile';
|
||||
|
||||
const Layout = () => {
|
||||
const isSmall = useIsSmall();
|
||||
const isMobile = useIsMobile();
|
||||
const scrollRef = useRef<any>(null);
|
||||
const setScrollRef = useSetAtom(scrollRefAtom);
|
||||
const theme = useTheme();
|
||||
useEffect(() => {
|
||||
setScrollRef(scrollRef);
|
||||
}, [setScrollRef]);
|
||||
|
||||
const [names] = useAtom(namesAtom);
|
||||
const [showNavbar, setShowNavbar] = useState(true);
|
||||
const lastScrollY = useRef(0);
|
||||
useIframe();
|
||||
|
||||
useEffect(() => {
|
||||
const scrollElement = scrollRef.current;
|
||||
if (!scrollElement) return;
|
||||
|
||||
let lastY = 0;
|
||||
let ticking = false;
|
||||
|
||||
const handleScroll = () => {
|
||||
const currentY = scrollElement.scrollTop;
|
||||
const deltaY = currentY - lastY;
|
||||
|
||||
if (Math.abs(deltaY) < 70) {
|
||||
ticking = false;
|
||||
return; // skip tiny scrolls
|
||||
}
|
||||
|
||||
if (deltaY > 0 && currentY > 50) {
|
||||
setShowNavbar(false); // scroll down
|
||||
} else {
|
||||
setShowNavbar(true); // scroll up
|
||||
}
|
||||
|
||||
lastY = currentY;
|
||||
ticking = false;
|
||||
};
|
||||
|
||||
const onScroll = () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(handleScroll);
|
||||
ticking = true;
|
||||
}
|
||||
};
|
||||
|
||||
scrollElement.addEventListener('scroll', onScroll);
|
||||
return () => scrollElement.removeEventListener('scroll', onScroll);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box display="flex" flexDirection="column" height="100vh" overflow="hidden">
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
animate={
|
||||
showNavbar
|
||||
? { height: '64px', opacity: 1, y: 0 }
|
||||
: { height: '0px', opacity: 0, y: -20 }
|
||||
}
|
||||
transition={{ duration: 0.3, ease: 'easeInOut' }}
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<NavBar allNames={names} />
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
height: '100%',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
<Sidenav allNames={names} />
|
||||
|
||||
{/* Main Content */}
|
||||
|
||||
<Box
|
||||
ref={scrollRef}
|
||||
id="main-box"
|
||||
component="main"
|
||||
flex={1}
|
||||
p={isMobile ? 0 : 2}
|
||||
sx={{
|
||||
overflowY: 'scroll',
|
||||
'::-webkit-scrollbar-track': {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
|
||||
'::-webkit-scrollbar': {
|
||||
width: isMobile ? '0px' : '16px',
|
||||
height: '10px',
|
||||
display: isMobile ? 'none' : 'initial',
|
||||
},
|
||||
|
||||
'::-webkit-scrollbar-thumb': {
|
||||
backgroundColor: 'rgba(63, 67, 80, 0.24)',
|
||||
borderRadius: '8px',
|
||||
backgroundClip: 'content-box',
|
||||
border: '4px solid transparent',
|
||||
transition: '0.3s background-color',
|
||||
},
|
||||
'::-webkit-scrollbar-thumb:hover': {
|
||||
backgroundColor: 'rgba(63, 67, 80, 0.50)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Outlet />
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Layout;
|
||||
@@ -1,24 +0,0 @@
|
||||
import { GlobalProvider } from 'qapp-core'
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState } from './state/store';
|
||||
|
||||
export const QappCoreWrapper = ({children}) => {
|
||||
const { user } = useSelector((state: RootState) => state.auth);
|
||||
return (
|
||||
<GlobalProvider
|
||||
config={{
|
||||
auth: {
|
||||
authenticateOnMount: false,
|
||||
userAccountInfo: {
|
||||
address: user?.address,
|
||||
publicKey: user?.publicKey
|
||||
}
|
||||
},
|
||||
publicSalt: "usVbeM9YpjGCbLrTcc78YJS0ap1AxDkHAOMZrp3+wDY=",
|
||||
appName: "Q-Tube",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</GlobalProvider>
|
||||
)
|
||||
}
|
||||
79
src/Routes.tsx
Normal file
79
src/Routes.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
|
||||
import App from './App';
|
||||
import { AppWrapper } from './AppWrapper';
|
||||
import { Home } from './pages/Home/Home';
|
||||
import { VideoContent } from './pages/ContentPages/VideoContent/VideoContent';
|
||||
import { PlaylistContent } from './pages/ContentPages/PlaylistContent/PlaylistContent';
|
||||
import { IndividualProfile } from './pages/ContentPages/IndividualProfile/IndividualProfile';
|
||||
import { Search } from './pages/Search/Search';
|
||||
import { Subscriptions } from './pages/Subscriptions/Subscriptions';
|
||||
import { Bookmarks } from './pages/Bookmarks/Bookmarks';
|
||||
import { History } from './pages/History/History';
|
||||
|
||||
interface CustomWindow extends Window {
|
||||
_qdnBase: string;
|
||||
}
|
||||
const customWindow = window as unknown as CustomWindow;
|
||||
const baseUrl = customWindow?._qdnBase || '';
|
||||
|
||||
export function Routes() {
|
||||
const router = createBrowserRouter(
|
||||
[
|
||||
{
|
||||
path: '/',
|
||||
element: <AppWrapper />, // GlobalProvider wrapper
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
element: <Home />,
|
||||
},
|
||||
{
|
||||
path: 'subscriptions',
|
||||
element: <Subscriptions />,
|
||||
},
|
||||
{
|
||||
path: 'bookmarks',
|
||||
element: <Bookmarks />,
|
||||
},
|
||||
{
|
||||
path: 'history',
|
||||
element: <History />,
|
||||
},
|
||||
{
|
||||
path: 'search',
|
||||
element: <Search />,
|
||||
},
|
||||
{
|
||||
path: 'video/:name/:id',
|
||||
element: <VideoContent />,
|
||||
},
|
||||
{
|
||||
path: 'playlist/:name/:id',
|
||||
element: <PlaylistContent />,
|
||||
},
|
||||
{
|
||||
path: 'playlist/:name/:id/:s/:n/:i',
|
||||
element: <PlaylistContent />,
|
||||
},
|
||||
{
|
||||
path: 'channel/:name',
|
||||
element: <IndividualProfile />,
|
||||
},
|
||||
{
|
||||
path: 'channel/:name/:section',
|
||||
element: <IndividualProfile />,
|
||||
},
|
||||
{
|
||||
path: 'channel/:name/:section',
|
||||
element: <IndividualProfile />,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
{
|
||||
basename: baseUrl,
|
||||
}
|
||||
);
|
||||
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import {
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import { CardContentContainerComment } from "../common/Comments/Comments-styles";
|
||||
} from '@mui/material';
|
||||
import React from 'react';
|
||||
import { CardContentContainerComment } from '../common/Comments/Comments-styles';
|
||||
import { useIsSmall } from '../../hooks/useIsSmall';
|
||||
import { AddToBookmarks } from '../common/ContentButtons/AddToBookmarks';
|
||||
|
||||
interface PlaylistsProps {
|
||||
playlistData;
|
||||
@@ -21,25 +23,34 @@ export const Playlists = ({
|
||||
onClick,
|
||||
sx,
|
||||
}: PlaylistsProps) => {
|
||||
const isSmall = useIsSmall();
|
||||
const theme = useTheme();
|
||||
const isScreenSmall = !useMediaQuery(`(min-width:700px)`);
|
||||
const PlaylistsHeight = "36vw"; // This is videoplayer width * 9/16 (inverse of aspect ratio)
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: isScreenSmall ? "200px" : PlaylistsHeight,
|
||||
// width: "100%",
|
||||
...sx,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<AddToBookmarks
|
||||
metadataReference={{
|
||||
identifier: playlistData?.identifier,
|
||||
service: 'PLAYLIST',
|
||||
name: playlistData?.name,
|
||||
}}
|
||||
type="playlist"
|
||||
/>
|
||||
<CardContentContainerComment
|
||||
sx={{
|
||||
marginTop: "0px",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
marginTop: '0px',
|
||||
height: '100%',
|
||||
gap: '3px',
|
||||
padding: '3px',
|
||||
}}
|
||||
>
|
||||
{playlistData?.videos?.map((vid, index) => {
|
||||
@@ -50,15 +61,20 @@ export const Playlists = ({
|
||||
<Box
|
||||
key={vid?.identifier}
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
width: "100%",
|
||||
background: isCurrentVidPlaying && theme.palette.primary.main,
|
||||
alignItems: "center",
|
||||
padding: "10px",
|
||||
borderRadius: "5px",
|
||||
cursor: isCurrentVidPlaying ? "default" : "pointer",
|
||||
userSelect: "none",
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
width: '100%',
|
||||
|
||||
alignItems: 'center',
|
||||
padding: '10px',
|
||||
borderRadius: '5px',
|
||||
cursor: isCurrentVidPlaying ? 'default' : 'pointer',
|
||||
userSelect: 'none',
|
||||
border: '1px solid rgba(255, 255, 255, 0.23)',
|
||||
...(isCurrentVidPlaying && {
|
||||
background: theme.palette.primary.main,
|
||||
color: theme.palette.primary.contrastText,
|
||||
}),
|
||||
}}
|
||||
onClick={() => {
|
||||
if (isCurrentVidPlaying) return;
|
||||
@@ -68,16 +84,16 @@ export const Playlists = ({
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
fontWeight: "bold",
|
||||
fontSize: isSmall ? '16px' : '18px',
|
||||
fontWeight: 'bold',
|
||||
}}
|
||||
>
|
||||
{index + 1}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
wordBreak: "break-word",
|
||||
fontSize: isSmall ? '16px' : '18px',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{vid?.metadata?.title}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
AddCoverImageButton,
|
||||
AddLogoIcon,
|
||||
@@ -6,13 +6,11 @@ import {
|
||||
CrowdfundActionButton,
|
||||
CrowdfundActionButtonRow,
|
||||
CustomInputField,
|
||||
CustomSelect,
|
||||
LogoPreviewRow,
|
||||
ModalBody,
|
||||
LogoPreviewRow,
|
||||
NewCrowdfundTitle,
|
||||
StyledButton,
|
||||
TimesIcon,
|
||||
} from "./Upload-styles.tsx";
|
||||
} from './Upload-styles.tsx';
|
||||
import {
|
||||
Box,
|
||||
FormControl,
|
||||
@@ -24,71 +22,46 @@ import {
|
||||
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";
|
||||
} from '@mui/material';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
|
||||
import { setNotification } from "../../../state/features/notificationsSlice.ts";
|
||||
import {
|
||||
objectToBase64,
|
||||
objectToFile,
|
||||
uint8ArrayToBase64,
|
||||
} from "../../../utils/PublishFormatter.ts";
|
||||
import { RootState } from "../../../state/store.ts";
|
||||
import {
|
||||
upsertVideosBeginning,
|
||||
addToHashMap,
|
||||
upsertVideos,
|
||||
setEditVideo,
|
||||
updateVideo,
|
||||
updateInHashMap,
|
||||
setEditPlaylist,
|
||||
} from "../../../state/features/videoSlice.ts";
|
||||
import ImageUploader from "../../common/ImageUploader.tsx";
|
||||
import { categories, subCategories } from "../../../constants/Categories.ts";
|
||||
import { Playlists } from "../../Playlists/Playlists.tsx";
|
||||
import { PlaylistListEdit } from "../PlaylistListEdit/PlaylistListEdit.tsx";
|
||||
import { TextEditor } from "../../common/TextEditor/TextEditor.tsx";
|
||||
import { extractTextFromHTML } from "../../common/TextEditor/utils.ts";
|
||||
import { objectToBase64 } from '../../../utils/PublishFormatter.ts';
|
||||
import ImageUploader from '../../common/ImageUploader.tsx';
|
||||
import { categories, subCategories } from '../../../constants/Categories.ts';
|
||||
import { Playlists } from '../../Playlists/Playlists.tsx';
|
||||
import { PlaylistListEdit } from '../PlaylistListEdit/PlaylistListEdit.tsx';
|
||||
import { TextEditor } from '../../common/TextEditor/TextEditor.tsx';
|
||||
import { extractTextFromHTML } from '../../common/TextEditor/utils.ts';
|
||||
import {
|
||||
QTUBE_PLAYLIST_BASE,
|
||||
QTUBE_VIDEO_BASE,
|
||||
} from "../../../constants/Identifiers.ts";
|
||||
} from '../../../constants/Identifiers.ts';
|
||||
import { useAuth, useGlobal } from 'qapp-core';
|
||||
import {
|
||||
AltertObject,
|
||||
setNotificationAtom,
|
||||
} from '../../../state/global/notifications.ts';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import { editPlaylistAtom } from '../../../state/publish/playlist.ts';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
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 { t } = useTranslation(['core', 'category']);
|
||||
|
||||
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.video.editPlaylistProperties
|
||||
);
|
||||
const { name: username, address: userAddress } = useAuth();
|
||||
const setNotification = useSetAtom(setNotificationAtom);
|
||||
const { lists } = useGlobal();
|
||||
const [editVideoProperties] = useAtom(editPlaylistAtom);
|
||||
const setEditPlaylist = useSetAtom(editPlaylistAtom);
|
||||
|
||||
const [playlistData, setPlaylistData] = useState<any>(null);
|
||||
const [title, setTitle] = useState<string>("");
|
||||
const [description, setDescription] = useState<string>("");
|
||||
const [coverImage, setCoverImage] = useState<string>("");
|
||||
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);
|
||||
@@ -96,7 +69,7 @@ export const EditPlaylist = () => {
|
||||
useState<any>(null);
|
||||
|
||||
const isNew = useMemo(() => {
|
||||
return editVideoProperties?.mode === "new";
|
||||
return editVideoProperties?.mode === 'new';
|
||||
}, [editVideoProperties]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -107,83 +80,39 @@ export const EditPlaylist = () => {
|
||||
}
|
||||
}, [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 => {
|
||||
const checkforPlaylist = React.useCallback(async (videoList) => {
|
||||
try {
|
||||
const combinedData: any = {};
|
||||
const videos = [];
|
||||
const videos: any[] = [];
|
||||
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",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseDataSearchVid = await response.json();
|
||||
|
||||
if (responseDataSearchVid?.length > 0) {
|
||||
const resourceData2 = responseDataSearchVid[0];
|
||||
videos.push(resourceData2);
|
||||
if (resourceData2) {
|
||||
videos.push(resourceData2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
combinedData.videos = videos;
|
||||
setPlaylistData(combinedData);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.error(error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (editVideoProperties) {
|
||||
setTitle(editVideoProperties?.title || "");
|
||||
setTitle(editVideoProperties?.title || '');
|
||||
|
||||
if (editVideoProperties?.htmlDescription) {
|
||||
setDescription(editVideoProperties?.htmlDescription);
|
||||
@@ -191,12 +120,12 @@ export const EditPlaylist = () => {
|
||||
const paragraph = `<p>${editVideoProperties?.description}</p>`;
|
||||
setDescription(paragraph);
|
||||
}
|
||||
setCoverImage(editVideoProperties?.image || "");
|
||||
setCoverImage(editVideoProperties?.image || '');
|
||||
setVideos(editVideoProperties?.videos || []);
|
||||
|
||||
if (editVideoProperties?.category) {
|
||||
const selectedOption = categories.find(
|
||||
option => option.id === +editVideoProperties.category
|
||||
(option) => option.id === +editVideoProperties.category
|
||||
);
|
||||
setSelectedCategoryVideos(selectedOption || null);
|
||||
}
|
||||
@@ -208,7 +137,7 @@ export const EditPlaylist = () => {
|
||||
) {
|
||||
const selectedOption = subCategories[
|
||||
+editVideoProperties?.category
|
||||
]?.find(option => option.id === +editVideoProperties.subcategory);
|
||||
]?.find((option) => option.id === +editVideoProperties.subcategory);
|
||||
setSelectedSubCategoryVideos(selectedOption || null);
|
||||
}
|
||||
|
||||
@@ -219,69 +148,68 @@ export const EditPlaylist = () => {
|
||||
}, [editVideoProperties]);
|
||||
|
||||
const onClose = () => {
|
||||
setTitle("");
|
||||
setDescription("");
|
||||
setTitle('');
|
||||
setDescription('');
|
||||
setVideos([]);
|
||||
setPlaylistData(null);
|
||||
setSelectedCategoryVideos(null);
|
||||
setSelectedSubCategoryVideos(null);
|
||||
setCoverImage("");
|
||||
dispatch(setEditPlaylist(null));
|
||||
setCoverImage('');
|
||||
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 (!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 (!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.";
|
||||
'Cannot publish without access to your name. Please authenticate.';
|
||||
}
|
||||
|
||||
if (!isNew && editVideoProperties?.user !== username) {
|
||||
if (!isNew && editVideoProperties?.name !== username) {
|
||||
errorMsg = "Cannot publish another user's resource";
|
||||
}
|
||||
|
||||
if (errorMsg) {
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: errorMsg,
|
||||
alertType: "error",
|
||||
})
|
||||
);
|
||||
const notificationObj: AltertObject = {
|
||||
msg: errorMsg,
|
||||
alertType: 'error',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
return;
|
||||
}
|
||||
const category = selectedCategoryVideos.id;
|
||||
const subcategory = selectedSubCategoryVideos?.id || "";
|
||||
const subcategory = selectedSubCategoryVideos?.id || '';
|
||||
|
||||
const videoStructured = playlistData.videos.map(item => {
|
||||
const videoStructured = playlistData.videos.map((item) => {
|
||||
const descriptionVid = item?.metadata?.description;
|
||||
if (!descriptionVid) throw new Error("cannot find video code");
|
||||
if (!descriptionVid) throw new Error('cannot find video code');
|
||||
|
||||
// Split the string by ';'
|
||||
const parts = descriptionVid.split(";");
|
||||
const parts = descriptionVid.split(';');
|
||||
|
||||
// Initialize a variable to hold the code value
|
||||
let codeValue = "";
|
||||
let codeValue = '';
|
||||
|
||||
// Loop through the parts to find the one that starts with 'code:'
|
||||
for (const part of parts) {
|
||||
if (part.startsWith("code:")) {
|
||||
codeValue = part.split(":")[1];
|
||||
if (part.startsWith('code:')) {
|
||||
codeValue = part.split(':')[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!codeValue) throw new Error("cannot find video code");
|
||||
if (!codeValue) throw new Error('cannot find video code');
|
||||
|
||||
return {
|
||||
identifier: item.identifier,
|
||||
@@ -292,8 +220,7 @@ export const EditPlaylist = () => {
|
||||
});
|
||||
const id = uid.rnd();
|
||||
|
||||
let commentsId = editVideoProperties?.id;
|
||||
|
||||
let commentsId = editVideoProperties?.identifier;
|
||||
if (isNew) {
|
||||
commentsId = `${QTUBE_PLAYLIST_BASE}_cm_${id}`;
|
||||
}
|
||||
@@ -312,20 +239,20 @@ export const EditPlaylist = () => {
|
||||
};
|
||||
|
||||
const codes = videoStructured
|
||||
.map(item => `c:${item.code};`)
|
||||
.map((item) => `c:${item.code};`)
|
||||
.slice(0, 10)
|
||||
.join("");
|
||||
.join('');
|
||||
const metadescription =
|
||||
`**category:${category};subcategory:${subcategory};${codes}**` +
|
||||
stringDescription.slice(0, 120);
|
||||
|
||||
// Description is obtained from raw data
|
||||
|
||||
let identifier = editVideoProperties?.id;
|
||||
let identifier = editVideoProperties?.identifier;
|
||||
const sanitizeTitle = title
|
||||
.replace(/[^a-zA-Z0-9\s-]/g, "")
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/[^a-zA-Z0-9\s-]/g, '')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (isNew) {
|
||||
@@ -335,9 +262,9 @@ export const EditPlaylist = () => {
|
||||
)}_${id}`;
|
||||
}
|
||||
const requestBodyJson: any = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
action: 'PUBLISH_QDN_RESOURCE',
|
||||
name: username,
|
||||
service: "PLAYLIST",
|
||||
service: 'PLAYLIST',
|
||||
data64: await objectToBase64(playlistObject),
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
@@ -351,57 +278,47 @@ export const EditPlaylist = () => {
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
id: identifier,
|
||||
service: "PLAYLIST",
|
||||
service: 'PLAYLIST',
|
||||
user: username,
|
||||
...playlistObject,
|
||||
};
|
||||
dispatch(updateVideo(objectToStore));
|
||||
dispatch(updateInHashMap(objectToStore));
|
||||
} else {
|
||||
dispatch(
|
||||
updateVideo({
|
||||
...editVideoProperties,
|
||||
...playlistObject,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
updateInHashMap({
|
||||
...editVideoProperties,
|
||||
...playlistObject,
|
||||
})
|
||||
);
|
||||
lists.updateNewResources([
|
||||
{
|
||||
data: playlistObject,
|
||||
qortalMetadata: {
|
||||
identifier: identifier,
|
||||
service: 'PLAYLIST',
|
||||
name: username || '',
|
||||
size: 100,
|
||||
updated: Date.now(),
|
||||
metadata: {
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
tags: [QTUBE_VIDEO_BASE],
|
||||
},
|
||||
created: editVideoProperties?.created,
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "Playlist published",
|
||||
alertType: "success",
|
||||
})
|
||||
);
|
||||
const notificationObj: AltertObject = {
|
||||
msg: 'Playlist published',
|
||||
alertType: 'success',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
|
||||
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));
|
||||
const isError = error instanceof Error;
|
||||
const message = isError ? error?.message : 'Failed to publish update';
|
||||
const notificationObj: AltertObject = {
|
||||
msg: message,
|
||||
alertType: 'error',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
|
||||
throw new Error("Failed to publish update");
|
||||
throw new Error('Failed to publish update');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +326,7 @@ export const EditPlaylist = () => {
|
||||
event: SelectChangeEvent<string>
|
||||
) => {
|
||||
const optionId = event.target.value;
|
||||
const selectedOption = categories.find(option => option.id === +optionId);
|
||||
const selectedOption = categories.find((option) => option.id === +optionId);
|
||||
setSelectedCategoryVideos(selectedOption || null);
|
||||
};
|
||||
const handleOptionSubCategoryChangeVideos = (
|
||||
@@ -418,28 +335,28 @@ export const EditPlaylist = () => {
|
||||
) => {
|
||||
const optionId = event.target.value;
|
||||
const selectedOption = subcategories.find(
|
||||
option => option.id === +optionId
|
||||
(option) => option.id === +optionId
|
||||
);
|
||||
setSelectedSubCategoryVideos(selectedOption || null);
|
||||
};
|
||||
|
||||
const removeVideo = index => {
|
||||
const removeVideo = (index) => {
|
||||
const copyData = structuredClone(playlistData);
|
||||
copyData.videos.splice(index, 1);
|
||||
setPlaylistData(copyData);
|
||||
};
|
||||
|
||||
const addVideo = data => {
|
||||
const addVideo = (data) => {
|
||||
const copyData = structuredClone(playlistData);
|
||||
copyData.videos = [...copyData.videos, { ...data }];
|
||||
setPlaylistData(copyData);
|
||||
};
|
||||
|
||||
const updateVideoList = list => {
|
||||
const updateVideoList = (list) => {
|
||||
const copyData = structuredClone(playlistData);
|
||||
copyData.videos = [...list];
|
||||
setPlaylistData(copyData);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -448,39 +365,61 @@ export const EditPlaylist = () => {
|
||||
aria-labelledby="modal-title"
|
||||
aria-describedby="modal-description"
|
||||
>
|
||||
<ModalBody>
|
||||
<ModalBody
|
||||
sx={{
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
{isNew ? (
|
||||
<NewCrowdfundTitle>Create new playlist</NewCrowdfundTitle>
|
||||
<NewCrowdfundTitle>
|
||||
{t('core:publish.create_new_playlist', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</NewCrowdfundTitle>
|
||||
) : (
|
||||
<NewCrowdfundTitle>Update Playlist properties</NewCrowdfundTitle>
|
||||
<NewCrowdfundTitle>
|
||||
{t('core:publish.update_playlist_properties', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</NewCrowdfundTitle>
|
||||
)}
|
||||
</Box>
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<FormControl fullWidth sx={{ marginBottom: 2 }}>
|
||||
<InputLabel id="Category">Select a Category</InputLabel>
|
||||
<InputLabel id="Category">
|
||||
{t('core:publish.select_category', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="Category"
|
||||
input={<OutlinedInput label="Select a Category" />}
|
||||
value={selectedCategoryVideos?.id || ""}
|
||||
input={
|
||||
<OutlinedInput
|
||||
label={t('core:publish.select_category', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
/>
|
||||
}
|
||||
value={selectedCategoryVideos?.id || ''}
|
||||
onChange={handleOptionCategoryChangeVideos}
|
||||
>
|
||||
{categories.map(option => (
|
||||
{categories.map((option) => (
|
||||
<MenuItem key={option.id} value={option.id}>
|
||||
{option.name}
|
||||
{t(`category:categories.${option.id}`)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
@@ -488,23 +427,35 @@ export const EditPlaylist = () => {
|
||||
{selectedCategoryVideos &&
|
||||
subCategories[selectedCategoryVideos?.id] && (
|
||||
<FormControl fullWidth sx={{ marginBottom: 2 }}>
|
||||
<InputLabel id="Category">Select a Sub-Category</InputLabel>
|
||||
<InputLabel id="Category">
|
||||
{t('core:publish.select_subcategory', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</InputLabel>
|
||||
<Select
|
||||
labelId="Sub-Category"
|
||||
input={<OutlinedInput label="Select a Sub-Category" />}
|
||||
value={selectedSubCategoryVideos?.id || ""}
|
||||
onChange={e =>
|
||||
input={
|
||||
<OutlinedInput
|
||||
label={t('core:publish.select_subcategory', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
/>
|
||||
}
|
||||
value={selectedSubCategoryVideos?.id || ''}
|
||||
onChange={(e) =>
|
||||
handleOptionSubCategoryChangeVideos(
|
||||
e,
|
||||
subCategories[selectedCategoryVideos?.id]
|
||||
)
|
||||
}
|
||||
>
|
||||
{subCategories[selectedCategoryVideos.id].map(option => (
|
||||
<MenuItem key={option.id} value={option.id}>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
{subCategories[selectedCategoryVideos.id].map(
|
||||
(option) => (
|
||||
<MenuItem key={option.id} value={option.id}>
|
||||
{t(`category:subcategories.${option.id}`)}
|
||||
</MenuItem>
|
||||
)
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
@@ -513,11 +464,13 @@ export const EditPlaylist = () => {
|
||||
{!coverImage ? (
|
||||
<ImageUploader onPick={(img: string) => setCoverImage(img)}>
|
||||
<AddCoverImageButton variant="contained">
|
||||
Add Cover Image
|
||||
{t('core:publish.add_cover_image', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
<AddLogoIcon
|
||||
sx={{
|
||||
height: "25px",
|
||||
width: "auto",
|
||||
height: '25px',
|
||||
width: 'auto',
|
||||
}}
|
||||
></AddLogoIcon>
|
||||
</AddCoverImageButton>
|
||||
@@ -527,22 +480,24 @@ export const EditPlaylist = () => {
|
||||
<CoverImagePreview src={coverImage} alt="logo" />
|
||||
<TimesIcon
|
||||
color={theme.palette.text.primary}
|
||||
onClickFunc={() => setCoverImage("")}
|
||||
height={"32"}
|
||||
width={"32"}
|
||||
onClickFunc={() => setCoverImage('')}
|
||||
height={'32'}
|
||||
width={'32'}
|
||||
></TimesIcon>
|
||||
</LogoPreviewRow>
|
||||
)}
|
||||
<CustomInputField
|
||||
name="title"
|
||||
label="Title of playlist"
|
||||
label={t('core:publish.title_playlist', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
variant="filled"
|
||||
value={title}
|
||||
onChange={e => {
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
const formattedValue = value.replace(
|
||||
/[^a-zA-Z0-9\s-_!?]/g,
|
||||
""
|
||||
''
|
||||
);
|
||||
setTitle(formattedValue);
|
||||
}}
|
||||
@@ -562,14 +517,16 @@ export const EditPlaylist = () => {
|
||||
/> */}
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
fontSize: '18px',
|
||||
}}
|
||||
>
|
||||
Description of playlist
|
||||
{t('core:publish.description_playlist', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
<TextEditor
|
||||
inlineContent={description}
|
||||
setInlineContent={value => {
|
||||
setInlineContent={(value) => {
|
||||
setDescription(value);
|
||||
}}
|
||||
/>
|
||||
@@ -591,13 +548,15 @@ export const EditPlaylist = () => {
|
||||
variant="contained"
|
||||
color="error"
|
||||
>
|
||||
Cancel
|
||||
{t('core:action.cancel', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</CrowdfundActionButton>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<CrowdfundActionButton
|
||||
@@ -606,7 +565,9 @@ export const EditPlaylist = () => {
|
||||
publishQDNResource();
|
||||
}}
|
||||
>
|
||||
Publish
|
||||
{t('core:publish.publish_action', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</CrowdfundActionButton>
|
||||
</Box>
|
||||
</CrowdfundActionButtonRow>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { styled } from "@mui/system";
|
||||
import { styled } from '@mui/system';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
TextField,
|
||||
Typography,
|
||||
Select,
|
||||
} from "@mui/material";
|
||||
import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
|
||||
import { TimesSVG } from "../../../assets/svgs/TimesSVG.tsx";
|
||||
} from '@mui/material';
|
||||
import AddPhotoAlternateIcon from '@mui/icons-material/AddPhotoAlternate';
|
||||
import { TimesSVG } from '../../../assets/svgs/TimesSVG.tsx';
|
||||
|
||||
export const DoubleLine = styled(Typography)`
|
||||
display: -webkit-box;
|
||||
@@ -22,181 +22,172 @@ export const DoubleLine = styled(Typography)`
|
||||
`;
|
||||
|
||||
export const MainContainer = styled(Grid)({
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "center",
|
||||
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",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
padding: '20px',
|
||||
}));
|
||||
|
||||
export const CreateContainer = styled(Box)(({ theme }) => ({
|
||||
position: "fixed",
|
||||
bottom: "20px",
|
||||
right: "20px",
|
||||
cursor: "pointer",
|
||||
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%",
|
||||
width: '50px',
|
||||
height: '50px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: '50%',
|
||||
}));
|
||||
|
||||
export const ModalBody = styled(Box)(({ theme }) => ({
|
||||
position: "absolute",
|
||||
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",
|
||||
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": {
|
||||
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": {
|
||||
'&::-webkit-scrollbar-track:hover': {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "16px",
|
||||
height: "10px",
|
||||
backgroundColor: theme.palette.mode === "light" ? "#f6f8fa" : "#292d3e",
|
||||
'&::-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': {
|
||||
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",
|
||||
'&::-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",
|
||||
fontSize: '25px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
export const NewCrowdFundFont = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 400,
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "18px",
|
||||
userSelect: "none",
|
||||
fontSize: '18px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
export const NewCrowdfundTimeDescription = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 400,
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "18px",
|
||||
userSelect: "none",
|
||||
fontStyle: "italic",
|
||||
textDecoration: "underline",
|
||||
fontSize: '18px',
|
||||
userSelect: 'none',
|
||||
fontStyle: 'italic',
|
||||
textDecoration: 'underline',
|
||||
}));
|
||||
|
||||
export const CustomInputField = styled(TextField)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
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",
|
||||
'& label': {
|
||||
color: theme.palette.mode === 'light' ? '#808183' : '#edeef0',
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
},
|
||||
"& label.Mui-focused": {
|
||||
color: theme.palette.mode === "light" ? "#A0AAB4" : "#d7d8da",
|
||||
'& label.Mui-focused': {
|
||||
color: theme.palette.mode === 'light' ? '#A0AAB4' : '#d7d8da',
|
||||
},
|
||||
"& .MuiInput-underline:after": {
|
||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
||||
'& .MuiInput-underline:after': {
|
||||
borderBottomColor: theme.palette.mode === 'light' ? '#B2BAC2' : '#c9cccf',
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
borderColor: "#E0E3E7",
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: '#E0E3E7',
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
borderColor: "#B2BAC2",
|
||||
'&:hover fieldset': {
|
||||
borderColor: '#B2BAC2',
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
borderColor: "#6F7E8C",
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: '#6F7E8C',
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-root": {
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
'& .MuiInputBase-root': {
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
},
|
||||
"& [class$='-MuiFilledInput-root']": {
|
||||
padding: "30px 12px 8px",
|
||||
padding: '30px 12px 8px',
|
||||
},
|
||||
"& .MuiFilledInput-root:after": {
|
||||
'& .MuiFilledInput-root:after': {
|
||||
borderBottomColor: theme.palette.secondary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
letterSpacing: "1px",
|
||||
letterSpacing: '1px',
|
||||
fontWeight: 400,
|
||||
fontSize: "20px",
|
||||
fontSize: '20px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
}));
|
||||
|
||||
export const CrowdfundSubTitleRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
flexDirection: "row",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
});
|
||||
|
||||
export const CrowdfundSubTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
letterSpacing: "1px",
|
||||
letterSpacing: '1px',
|
||||
fontWeight: 400,
|
||||
fontSize: "17px",
|
||||
fontSize: '17px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
borderBottom: `1px solid ${theme.palette.text.primary}`,
|
||||
paddingBottom: "1.5px",
|
||||
width: "fit-content",
|
||||
textDecoration: "none",
|
||||
paddingBottom: '1.5px',
|
||||
width: 'fit-content',
|
||||
textDecoration: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundDescription = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "16px",
|
||||
fontSize: '16px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
}));
|
||||
|
||||
export const Spacer = ({ height }: any) => {
|
||||
@@ -210,326 +201,313 @@ export const Spacer = ({ height }: any) => {
|
||||
};
|
||||
|
||||
export const StyledCardHeaderComment = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: "5px",
|
||||
padding: "7px 0px",
|
||||
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%",
|
||||
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%",
|
||||
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",
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.2',
|
||||
});
|
||||
|
||||
export const AddLogoIcon = styled(AddPhotoAlternateIcon)(({ theme }) => ({
|
||||
color: "#fff",
|
||||
height: "25px",
|
||||
width: "auto",
|
||||
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 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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
fontSize: '12px',
|
||||
letterSpacing: '0.2px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CATContainer = styled(Box)(({ theme }) => ({
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
padding: "15px",
|
||||
flexDirection: "column",
|
||||
gap: "20px",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
gap: '10px',
|
||||
}));
|
||||
|
||||
export const CrowdfundPageTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
fontSize: "35px",
|
||||
fontSize: '35px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "1px",
|
||||
userSelect: "none",
|
||||
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",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: '21px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
border: `1px solid ${theme.palette.text.primary}`,
|
||||
borderRadius: "8px",
|
||||
padding: "15px 25px",
|
||||
userSelect: "none",
|
||||
borderRadius: '8px',
|
||||
padding: '15px 25px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundDescriptionRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "18px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
fontSize: '18px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
});
|
||||
|
||||
export const AboutMyCrowdfund = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
fontSize: "23px",
|
||||
fontSize: '23px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "1px",
|
||||
userSelect: "none",
|
||||
letterSpacing: '1px',
|
||||
userSelect: 'none',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const CrowdfundInlineContentRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const CrowdfundInlineContent = styled(Box)(({ theme }) => ({
|
||||
display: "flex",
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
display: 'flex',
|
||||
fontSize: '19px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordion = styled(Accordion)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
"& .Mui-expanded": {
|
||||
minHeight: "auto !important",
|
||||
'& .Mui-expanded': {
|
||||
minHeight: 'auto !important',
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordionSummary = styled(AccordionSummary)({
|
||||
height: "50px",
|
||||
"& .Mui-expanded": {
|
||||
margin: "0px !important",
|
||||
height: '50px',
|
||||
'& .Mui-expanded': {
|
||||
margin: '0px !important',
|
||||
},
|
||||
});
|
||||
|
||||
export const CrowdfundAccordionFont = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "20px",
|
||||
fontSize: '20px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0px",
|
||||
letterSpacing: '0px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordionDetails = styled(AccordionDetails)({
|
||||
padding: "0px 16px 16px 16px",
|
||||
padding: '0px 16px 16px 16px',
|
||||
});
|
||||
|
||||
export const AddCoverImageButton = styled(Button)(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "16px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
letterSpacing: '0.2px',
|
||||
color: 'white',
|
||||
gap: '5px',
|
||||
}));
|
||||
|
||||
export const CoverImage = styled("img")({
|
||||
width: "100%",
|
||||
height: "250px",
|
||||
objectFit: "cover",
|
||||
objectPosition: "center",
|
||||
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%",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const CrowdfundActionButton = styled(Button)(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "16px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
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",
|
||||
position: 'absolute',
|
||||
top: '20px',
|
||||
left: '20px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '13px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
padding: "5px 10px",
|
||||
letterSpacing: '0.2px',
|
||||
color: 'white',
|
||||
gap: '5px',
|
||||
padding: '5px 10px',
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
transition: "all 0.3s ease-in-out",
|
||||
"&:hover": {
|
||||
transition: 'all 0.3s ease-in-out',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.secondary.dark,
|
||||
cursor: "pointer",
|
||||
cursor: 'pointer',
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundLoaderRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: "10px",
|
||||
padding: "10px",
|
||||
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",
|
||||
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",
|
||||
fontSize: '28px',
|
||||
});
|
||||
|
||||
export const NoReviewsFont = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
color: theme.palette.text.primary,
|
||||
@@ -541,43 +519,40 @@ export const StyledButton = styled(Button)(({ theme }) => ({
|
||||
}));
|
||||
|
||||
export const CustomSelect = styled(Select)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
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",
|
||||
'& .MuiSelect-select': {
|
||||
padding: '12px',
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
borderRadius: theme.shape.borderRadius, // Match border radius
|
||||
},
|
||||
"&:before": {
|
||||
'&:before': {
|
||||
// Underline style
|
||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
||||
borderBottomColor: theme.palette.mode === 'light' ? '#B2BAC2' : '#c9cccf',
|
||||
},
|
||||
"&:after": {
|
||||
'&:after': {
|
||||
// Underline style when focused
|
||||
borderBottomColor: theme.palette.secondary.main,
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
borderColor: "#E0E3E7",
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: '#E0E3E7',
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
borderColor: "#B2BAC2",
|
||||
'&:hover fieldset': {
|
||||
borderColor: '#B2BAC2',
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
borderColor: "#6F7E8C",
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: '#6F7E8C',
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-root": {
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
'& .MuiInputBase-root': {
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { styled } from "@mui/system";
|
||||
import { styled } from '@mui/system';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
TextField,
|
||||
Typography,
|
||||
Select,
|
||||
} from "@mui/material";
|
||||
import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
|
||||
import { TimesSVG } from "../../../assets/svgs/TimesSVG.tsx";
|
||||
} from '@mui/material';
|
||||
import AddPhotoAlternateIcon from '@mui/icons-material/AddPhotoAlternate';
|
||||
import { TimesSVG } from '../../../assets/svgs/TimesSVG.tsx';
|
||||
|
||||
export const DoubleLine = styled(Typography)`
|
||||
display: -webkit-box;
|
||||
@@ -22,181 +22,172 @@ export const DoubleLine = styled(Typography)`
|
||||
`;
|
||||
|
||||
export const MainContainer = styled(Grid)({
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "center",
|
||||
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",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
padding: '20px',
|
||||
}));
|
||||
|
||||
export const CreateContainer = styled(Box)(({ theme }) => ({
|
||||
position: "fixed",
|
||||
bottom: "20px",
|
||||
right: "20px",
|
||||
cursor: "pointer",
|
||||
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%",
|
||||
width: '50px',
|
||||
height: '50px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: '50%',
|
||||
}));
|
||||
|
||||
export const ModalBody = styled(Box)(({ theme }) => ({
|
||||
position: "absolute",
|
||||
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",
|
||||
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": {
|
||||
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": {
|
||||
'&::-webkit-scrollbar-track:hover': {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "16px",
|
||||
height: "10px",
|
||||
backgroundColor: theme.palette.mode === "light" ? "#f6f8fa" : "#292d3e",
|
||||
'&::-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': {
|
||||
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",
|
||||
'&::-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",
|
||||
fontSize: '25px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
export const NewCrowdFundFont = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 400,
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "18px",
|
||||
userSelect: "none",
|
||||
fontSize: '18px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
export const NewCrowdfundTimeDescription = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 400,
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "18px",
|
||||
userSelect: "none",
|
||||
fontStyle: "italic",
|
||||
textDecoration: "underline",
|
||||
fontSize: '18px',
|
||||
userSelect: 'none',
|
||||
fontStyle: 'italic',
|
||||
textDecoration: 'underline',
|
||||
}));
|
||||
|
||||
export const CustomInputField = styled(TextField)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
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",
|
||||
'& label': {
|
||||
color: theme.palette.mode === 'light' ? '#808183' : '#edeef0',
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
},
|
||||
"& label.Mui-focused": {
|
||||
color: theme.palette.mode === "light" ? "#A0AAB4" : "#d7d8da",
|
||||
'& label.Mui-focused': {
|
||||
color: theme.palette.mode === 'light' ? '#A0AAB4' : '#d7d8da',
|
||||
},
|
||||
"& .MuiInput-underline:after": {
|
||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
||||
'& .MuiInput-underline:after': {
|
||||
borderBottomColor: theme.palette.mode === 'light' ? '#B2BAC2' : '#c9cccf',
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
borderColor: "#E0E3E7",
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: '#E0E3E7',
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
borderColor: "#B2BAC2",
|
||||
'&:hover fieldset': {
|
||||
borderColor: '#B2BAC2',
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
borderColor: "#6F7E8C",
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: '#6F7E8C',
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-root": {
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
'& .MuiInputBase-root': {
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
},
|
||||
"& [class$='-MuiFilledInput-root']": {
|
||||
padding: "30px 12px 8px",
|
||||
padding: '30px 12px 8px',
|
||||
},
|
||||
"& .MuiFilledInput-root:after": {
|
||||
'& .MuiFilledInput-root:after': {
|
||||
borderBottomColor: theme.palette.secondary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
letterSpacing: "1px",
|
||||
letterSpacing: '1px',
|
||||
fontWeight: 400,
|
||||
fontSize: "20px",
|
||||
fontSize: '20px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
}));
|
||||
|
||||
export const CrowdfundSubTitleRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
flexDirection: "row",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
});
|
||||
|
||||
export const CrowdfundSubTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
letterSpacing: "1px",
|
||||
letterSpacing: '1px',
|
||||
fontWeight: 400,
|
||||
fontSize: "17px",
|
||||
fontSize: '17px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
borderBottom: `1px solid ${theme.palette.text.primary}`,
|
||||
paddingBottom: "1.5px",
|
||||
width: "fit-content",
|
||||
textDecoration: "none",
|
||||
paddingBottom: '1.5px',
|
||||
width: 'fit-content',
|
||||
textDecoration: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundDescription = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "16px",
|
||||
fontSize: '16px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
}));
|
||||
|
||||
export const Spacer = ({ height }: any) => {
|
||||
@@ -210,326 +201,313 @@ export const Spacer = ({ height }: any) => {
|
||||
};
|
||||
|
||||
export const StyledCardHeaderComment = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: "5px",
|
||||
padding: "7px 0px",
|
||||
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%",
|
||||
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%",
|
||||
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",
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.2',
|
||||
});
|
||||
|
||||
export const AddLogoIcon = styled(AddPhotoAlternateIcon)(({ theme }) => ({
|
||||
color: "#fff",
|
||||
height: "25px",
|
||||
width: "auto",
|
||||
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 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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
fontSize: '12px',
|
||||
letterSpacing: '0.2px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CATContainer = styled(Box)(({ theme }) => ({
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
padding: "15px",
|
||||
flexDirection: "column",
|
||||
gap: "20px",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
gap: '10px',
|
||||
}));
|
||||
|
||||
export const CrowdfundPageTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
fontSize: "35px",
|
||||
fontSize: '35px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "1px",
|
||||
userSelect: "none",
|
||||
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",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: '21px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
border: `1px solid ${theme.palette.text.primary}`,
|
||||
borderRadius: "8px",
|
||||
padding: "15px 25px",
|
||||
userSelect: "none",
|
||||
borderRadius: '8px',
|
||||
padding: '15px 25px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundDescriptionRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "18px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
fontSize: '18px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
});
|
||||
|
||||
export const AboutMyCrowdfund = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
fontSize: "23px",
|
||||
fontSize: '23px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "1px",
|
||||
userSelect: "none",
|
||||
letterSpacing: '1px',
|
||||
userSelect: 'none',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const CrowdfundInlineContentRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const CrowdfundInlineContent = styled(Box)(({ theme }) => ({
|
||||
display: "flex",
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
display: 'flex',
|
||||
fontSize: '19px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordion = styled(Accordion)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
"& .Mui-expanded": {
|
||||
minHeight: "auto !important",
|
||||
'& .Mui-expanded': {
|
||||
minHeight: 'auto !important',
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordionSummary = styled(AccordionSummary)({
|
||||
height: "50px",
|
||||
"& .Mui-expanded": {
|
||||
margin: "0px !important",
|
||||
height: '50px',
|
||||
'& .Mui-expanded': {
|
||||
margin: '0px !important',
|
||||
},
|
||||
});
|
||||
|
||||
export const CrowdfundAccordionFont = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "20px",
|
||||
fontSize: '20px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0px",
|
||||
letterSpacing: '0px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordionDetails = styled(AccordionDetails)({
|
||||
padding: "0px 16px 16px 16px",
|
||||
padding: '0px 16px 16px 16px',
|
||||
});
|
||||
|
||||
export const AddCoverImageButton = styled(Button)(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "16px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
letterSpacing: '0.2px',
|
||||
color: 'white',
|
||||
gap: '5px',
|
||||
}));
|
||||
|
||||
export const CoverImage = styled("img")({
|
||||
width: "100%",
|
||||
height: "250px",
|
||||
objectFit: "cover",
|
||||
objectPosition: "center",
|
||||
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%",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const CrowdfundActionButton = styled(Button)(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "16px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
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",
|
||||
position: 'absolute',
|
||||
top: '20px',
|
||||
left: '20px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '13px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
padding: "5px 10px",
|
||||
letterSpacing: '0.2px',
|
||||
color: 'white',
|
||||
gap: '5px',
|
||||
padding: '5px 10px',
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
transition: "all 0.3s ease-in-out",
|
||||
"&:hover": {
|
||||
transition: 'all 0.3s ease-in-out',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.secondary.dark,
|
||||
cursor: "pointer",
|
||||
cursor: 'pointer',
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundLoaderRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: "10px",
|
||||
padding: "10px",
|
||||
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",
|
||||
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",
|
||||
fontSize: '28px',
|
||||
});
|
||||
|
||||
export const NoReviewsFont = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
color: theme.palette.text.primary,
|
||||
@@ -541,43 +519,40 @@ export const StyledButton = styled(Button)(({ theme }) => ({
|
||||
}));
|
||||
|
||||
export const CustomSelect = styled(Select)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
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",
|
||||
'& .MuiSelect-select': {
|
||||
padding: '12px',
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
borderRadius: theme.shape.borderRadius, // Match border radius
|
||||
},
|
||||
"&:before": {
|
||||
'&:before': {
|
||||
// Underline style
|
||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
||||
borderBottomColor: theme.palette.mode === 'light' ? '#B2BAC2' : '#c9cccf',
|
||||
},
|
||||
"&:after": {
|
||||
'&:after': {
|
||||
// Underline style when focused
|
||||
borderBottomColor: theme.palette.secondary.main,
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
borderColor: "#E0E3E7",
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: '#E0E3E7',
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
borderColor: "#B2BAC2",
|
||||
'&:hover fieldset': {
|
||||
borderColor: '#B2BAC2',
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
borderColor: "#6F7E8C",
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: '#6F7E8C',
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-root": {
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
'& .MuiInputBase-root': {
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
|
||||
@@ -10,36 +10,29 @@ import {
|
||||
SelectChangeEvent,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { Signal, useSignal, useSignalEffect } from "@preact/signals-react";
|
||||
import Compressor from "compressorjs";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { categories, subCategories } from "../../../constants/Categories.ts";
|
||||
import { QTUBE_VIDEO_BASE } from "../../../constants/Identifiers.ts";
|
||||
} from '@mui/material';
|
||||
import Compressor from 'compressorjs';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useDropzone } from 'react-dropzone';
|
||||
import { categories, subCategories } from '../../../constants/Categories.ts';
|
||||
import { QTUBE_VIDEO_BASE } from '../../../constants/Identifiers.ts';
|
||||
import {
|
||||
maxSize,
|
||||
titleFormatter,
|
||||
videoMaxSize,
|
||||
} from "../../../constants/Misc.ts";
|
||||
} from '../../../constants/Misc.ts';
|
||||
|
||||
import { setNotification } from "../../../state/features/notificationsSlice.ts";
|
||||
import BoundedNumericTextField from '../../../utils/BoundedNumericTextField.tsx';
|
||||
import { objectToBase64 } from '../../../utils/PublishFormatter.ts';
|
||||
import {
|
||||
setEditVideo,
|
||||
updateInHashMap,
|
||||
updateVideo,
|
||||
} from "../../../state/features/videoSlice.ts";
|
||||
import { RootState } from "../../../state/store.ts";
|
||||
import BoundedNumericTextField from "../../../utils/BoundedNumericTextField.tsx";
|
||||
import { objectToBase64 } from "../../../utils/PublishFormatter.ts";
|
||||
import { FrameExtractor } from "../../common/FrameExtractor/FrameExtractor.tsx";
|
||||
import ImageUploader from "../../common/ImageUploader.tsx";
|
||||
import { TextEditor } from "../../common/TextEditor/TextEditor.tsx";
|
||||
import { extractTextFromHTML } from "../../common/TextEditor/utils.ts";
|
||||
import { MultiplePublish } from "../MultiplePublish/MultiplePublishAll.tsx";
|
||||
import { toBase64 } from "../PublishVideo/PublishVideo.tsx";
|
||||
getFileExtension,
|
||||
getFileExtensionIndex,
|
||||
} from '../../../utils/stringFunctions.ts';
|
||||
import { FrameExtractor } from '../../common/FrameExtractor/FrameExtractor.tsx';
|
||||
import ImageUploader from '../../common/ImageUploader.tsx';
|
||||
import { TextEditor } from '../../common/TextEditor/TextEditor.tsx';
|
||||
import { extractTextFromHTML } from '../../common/TextEditor/utils.ts';
|
||||
import { toBase64 } from '../PublishVideo/PublishVideo.tsx';
|
||||
|
||||
import {
|
||||
AddCoverImageButton,
|
||||
@@ -52,136 +45,102 @@ import {
|
||||
ModalBody,
|
||||
NewCrowdfundTitle,
|
||||
TimesIcon,
|
||||
} from "./EditVideo-styles.tsx";
|
||||
|
||||
const uid = new ShortUniqueId();
|
||||
const shortuid = new ShortUniqueId({ length: 5 });
|
||||
|
||||
} from './EditVideo-styles.tsx';
|
||||
import { showError, useAuth, useGlobal, usePublish } from 'qapp-core';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import {
|
||||
AltertObject,
|
||||
setNotificationAtom,
|
||||
} from '../../../state/global/notifications.ts';
|
||||
import { editVideoAtom } from '../../../state/publish/video.ts';
|
||||
import { useMediaInfo } from '../../../hooks/useMediaInfo.tsx';
|
||||
export const EditVideo = () => {
|
||||
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.video.editVideoProperties
|
||||
);
|
||||
const [publishes, setPublishes] = useState<any>(null);
|
||||
const [isOpenMultiplePublish, setIsOpenMultiplePublish] = useState(false);
|
||||
const [videoPropertiesToSetToRedux, setVideoPropertiesToSetToRedux] =
|
||||
useState(null);
|
||||
const setNotification = useSetAtom(setNotificationAtom);
|
||||
const setEditVideo = useSetAtom(editVideoAtom);
|
||||
const { name: username, address: userAddress } = useAuth();
|
||||
const { lists } = useGlobal();
|
||||
const [editVideoProperties] = useAtom(editVideoAtom);
|
||||
|
||||
const [title, setTitle] = useState<string>("");
|
||||
const [description, setDescription] = useState<string>("");
|
||||
const [coverImage, setCoverImage] = useState<string>("");
|
||||
const [file, setFile] = useState(null);
|
||||
const publishFromLibrary = usePublish();
|
||||
|
||||
const [title, setTitle] = useState<string>('');
|
||||
const [description, setDescription] = useState<string>('');
|
||||
const [coverImage, setCoverImage] = useState<string>('');
|
||||
const [file, setFile] = useState<null | File>(null);
|
||||
const [selectedCategoryVideos, setSelectedCategoryVideos] =
|
||||
useState<any>(null);
|
||||
const [selectedSubCategoryVideos, setSelectedSubCategoryVideos] =
|
||||
useState<any>(null);
|
||||
const [imageExtracts, setImageExtracts] = useState<any>([]);
|
||||
|
||||
const videoDuration: Signal<number[]> = useSignal([
|
||||
const [videoDurations, setVideoDurations] = useState<number[]>([
|
||||
editVideoProperties?.duration || 0,
|
||||
]);
|
||||
const { isHEVC } = useMediaInfo();
|
||||
|
||||
useEffect(() => {
|
||||
videoDuration.value[0] = Math.floor(editVideoProperties?.duration);
|
||||
}, [editVideoProperties]);
|
||||
if (editVideoProperties?.duration) {
|
||||
setVideoDurations([Math.floor(editVideoProperties?.duration || 0)]);
|
||||
}
|
||||
}, [editVideoProperties?.duration]);
|
||||
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
accept: {
|
||||
"video/*": [],
|
||||
'video/*': [],
|
||||
},
|
||||
maxFiles: 1,
|
||||
maxSize,
|
||||
onDrop: (acceptedFiles, rejectedFiles) => {
|
||||
onDrop: async (acceptedFiles, rejectedFiles) => {
|
||||
const firstFile = acceptedFiles[0];
|
||||
|
||||
setFile(firstFile);
|
||||
const notSupportedCodec = await isHEVC(firstFile);
|
||||
|
||||
let errorString = null;
|
||||
const isMKV = getFileExtension(firstFile) === 'mkv';
|
||||
const isUnsupportedFile = notSupportedCodec || isMKV;
|
||||
|
||||
if (isUnsupportedFile) {
|
||||
if (notSupportedCodec)
|
||||
showError(`${firstFile.name} uses the unsupported encoding: HEVC`);
|
||||
if (isMKV)
|
||||
showError(
|
||||
`${firstFile.name} uses the unsupported file container: MKV`
|
||||
);
|
||||
} else setFile(firstFile);
|
||||
|
||||
let errorString: null | string = null;
|
||||
|
||||
rejectedFiles.forEach(({ file, errors }) => {
|
||||
errors.forEach(error => {
|
||||
if (error.code === "file-too-large") {
|
||||
errors.forEach((error) => {
|
||||
if (error.code === 'file-too-large') {
|
||||
errorString = `File must be under ${videoMaxSize}MB`;
|
||||
}
|
||||
console.log(`Error with file ${file.name}: ${error.message}`);
|
||||
console.error(`Error with file ${file.name}: ${error.message}`);
|
||||
});
|
||||
});
|
||||
if (errorString) {
|
||||
const notificationObj = {
|
||||
const notificationObj: AltertObject = {
|
||||
msg: errorString,
|
||||
alertType: "error",
|
||||
alertType: 'error',
|
||||
};
|
||||
|
||||
dispatch(setNotification(notificationObj));
|
||||
setNotification(notificationObj);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// 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]);
|
||||
|
||||
useEffect(() => {
|
||||
if (editVideoProperties) {
|
||||
setTitle(editVideoProperties?.title || "");
|
||||
setTitle(editVideoProperties?.title || '');
|
||||
if (editVideoProperties?.htmlDescription) {
|
||||
setDescription(editVideoProperties?.htmlDescription);
|
||||
} else if (editVideoProperties?.fullDescription) {
|
||||
const paragraph = `<p>${editVideoProperties?.fullDescription}</p>`;
|
||||
setDescription(paragraph);
|
||||
}
|
||||
setCoverImage(editVideoProperties?.videoImage || "");
|
||||
setCoverImage(editVideoProperties?.videoImage || '');
|
||||
|
||||
if (editVideoProperties?.category) {
|
||||
const selectedOption = categories.find(
|
||||
option => option.id === +editVideoProperties.category
|
||||
(option) => option.id === +editVideoProperties.category
|
||||
);
|
||||
setSelectedCategoryVideos(selectedOption || null);
|
||||
}
|
||||
@@ -193,38 +152,38 @@ export const EditVideo = () => {
|
||||
) {
|
||||
const selectedOption = subCategories[
|
||||
+editVideoProperties?.category
|
||||
]?.find(option => option.id === +editVideoProperties.subcategory);
|
||||
]?.find((option) => option.id === +editVideoProperties.subcategory);
|
||||
setSelectedSubCategoryVideos(selectedOption || null);
|
||||
}
|
||||
}
|
||||
}, [editVideoProperties]);
|
||||
|
||||
const onClose = () => {
|
||||
dispatch(setEditVideo(null));
|
||||
setVideoPropertiesToSetToRedux(null);
|
||||
setEditVideo(null);
|
||||
setFile(null);
|
||||
setTitle("");
|
||||
setTitle('');
|
||||
setImageExtracts([]);
|
||||
setDescription("");
|
||||
setCoverImage("");
|
||||
setDescription('');
|
||||
setCoverImage('');
|
||||
};
|
||||
|
||||
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 (!username) throw new Error('A name is required to publish');
|
||||
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 (!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.";
|
||||
'Cannot publish without access to your name. Please authenticate.';
|
||||
}
|
||||
|
||||
if (editVideoProperties?.user !== username) {
|
||||
@@ -232,35 +191,34 @@ export const EditVideo = () => {
|
||||
}
|
||||
|
||||
if (errorMsg) {
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: errorMsg,
|
||||
alertType: "error",
|
||||
})
|
||||
);
|
||||
const notificationObj: AltertObject = {
|
||||
msg: errorMsg,
|
||||
alertType: 'error',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
return;
|
||||
}
|
||||
const listOfPublishes = [];
|
||||
const listOfPublishes: any[] = [];
|
||||
const category = selectedCategoryVideos.id;
|
||||
const subcategory = selectedSubCategoryVideos?.id || "";
|
||||
const subcategory = selectedSubCategoryVideos?.id || '';
|
||||
|
||||
const fullDescription = extractTextFromHTML(description);
|
||||
let fileExtension = "mp4";
|
||||
const fileExtensionSplit = file?.name?.split(".");
|
||||
if (fileExtensionSplit?.length > 1) {
|
||||
fileExtension = fileExtensionSplit?.pop() || "mp4";
|
||||
let fileExtension = 'mp4';
|
||||
const fileExtensionSplit = file?.name?.split('.');
|
||||
if (fileExtensionSplit && fileExtensionSplit?.length > 1) {
|
||||
fileExtension = fileExtensionSplit?.pop() || 'mp4';
|
||||
}
|
||||
|
||||
const filename = title.slice(0, 15);
|
||||
// Step 1: Replace all white spaces with underscores
|
||||
|
||||
// Replace all forms of whitespace (including non-standard ones) with underscores
|
||||
const stringWithUnderscores = filename.replace(/[\s\uFEFF\xA0]+/g, "_");
|
||||
const stringWithUnderscores = filename.replace(/[\s\uFEFF\xA0]+/g, '_');
|
||||
|
||||
// Remove all non-alphanumeric characters (except underscores)
|
||||
const alphanumericString = stringWithUnderscores.replace(
|
||||
/[^a-zA-Z0-9_]/g,
|
||||
""
|
||||
''
|
||||
);
|
||||
|
||||
const videoObject: any = {
|
||||
@@ -275,21 +233,20 @@ export const EditVideo = () => {
|
||||
category,
|
||||
subcategory,
|
||||
code: editVideoProperties.code,
|
||||
videoType: file?.type || "video/mp4",
|
||||
videoType: file?.type || editVideoProperties?.videoType || 'video/mp4',
|
||||
filename: `${alphanumericString.trim()}.${fileExtension}`,
|
||||
fileSize: file?.size || 0,
|
||||
duration: videoDuration.value[0] || editVideoProperties?.duration || 0,
|
||||
fileSize: file?.size || editVideoProperties?.fileSize || 0,
|
||||
duration: videoDurations[0] || editVideoProperties?.duration || 0,
|
||||
};
|
||||
console.log("edit publish duration: ", videoObject?.duration);
|
||||
const metadescription =
|
||||
`**category:${category};subcategory:${subcategory};code:${editVideoProperties.code}**` +
|
||||
description.slice(0, 150);
|
||||
|
||||
// Description is obtained from raw data
|
||||
const requestBodyJson: any = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
action: 'PUBLISH_QDN_RESOURCE',
|
||||
name: username,
|
||||
service: "DOCUMENT",
|
||||
service: 'DOCUMENT',
|
||||
data64: await objectToBase64(videoObject),
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
@@ -301,51 +258,55 @@ export const EditVideo = () => {
|
||||
|
||||
if (file && editVideoProperties.videoReference?.identifier) {
|
||||
const requestBodyVideo: any = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
action: 'PUBLISH_QDN_RESOURCE',
|
||||
name: username,
|
||||
service: "VIDEO",
|
||||
service: 'VIDEO',
|
||||
file,
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
identifier: editVideoProperties.videoReference?.identifier,
|
||||
tag1: QTUBE_VIDEO_BASE,
|
||||
filename: `${alphanumericString.trim()}.${fileExtension}`,
|
||||
filename: file.name,
|
||||
};
|
||||
listOfPublishes.push(requestBodyVideo);
|
||||
}
|
||||
|
||||
const multiplePublish = {
|
||||
action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
|
||||
resources: [...listOfPublishes],
|
||||
};
|
||||
setPublishes(multiplePublish);
|
||||
setIsOpenMultiplePublish(true);
|
||||
setVideoPropertiesToSetToRedux({
|
||||
...editVideoProperties,
|
||||
...videoObject,
|
||||
});
|
||||
} 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));
|
||||
await publishFromLibrary.publishMultipleResources(listOfPublishes);
|
||||
|
||||
throw new Error("Failed to publish update");
|
||||
lists.updateNewResources([
|
||||
{
|
||||
data: videoObject,
|
||||
qortalMetadata: {
|
||||
identifier: editVideoProperties.id,
|
||||
service: 'DOCUMENT',
|
||||
name: username,
|
||||
size: 100,
|
||||
updated: Date.now(),
|
||||
metadata: {
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
tags: [QTUBE_VIDEO_BASE],
|
||||
},
|
||||
created: editVideoProperties?.created,
|
||||
},
|
||||
},
|
||||
]);
|
||||
const notificationObj: AltertObject = {
|
||||
msg: 'Video updated',
|
||||
alertType: 'success',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
|
||||
onClose();
|
||||
} catch (error: any) {
|
||||
const isError = error instanceof Error;
|
||||
const message = isError ? error?.message : 'Failed to publish update';
|
||||
const notificationObj: AltertObject = {
|
||||
msg: message,
|
||||
alertType: 'error',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
throw new Error('Failed to publish update');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +314,7 @@ export const EditVideo = () => {
|
||||
event: SelectChangeEvent<string>
|
||||
) => {
|
||||
const optionId = event.target.value;
|
||||
const selectedOption = categories.find(option => option.id === +optionId);
|
||||
const selectedOption = categories.find((option) => option.id === +optionId);
|
||||
setSelectedCategoryVideos(selectedOption || null);
|
||||
};
|
||||
const handleOptionSubCategoryChangeVideos = (
|
||||
@@ -362,39 +323,42 @@ export const EditVideo = () => {
|
||||
) => {
|
||||
const optionId = event.target.value;
|
||||
const selectedOption = subcategories.find(
|
||||
option => option.id === +optionId
|
||||
(option) => option.id === +optionId
|
||||
);
|
||||
setSelectedSubCategoryVideos(selectedOption || null);
|
||||
};
|
||||
|
||||
const onFramesExtracted = async imgs => {
|
||||
const onFramesExtracted = async (imgs) => {
|
||||
try {
|
||||
const imagesExtracts = [];
|
||||
const imagesExtracts: string[] = [];
|
||||
|
||||
for (const img of imgs) {
|
||||
try {
|
||||
let compressedFile;
|
||||
const image = img;
|
||||
await new Promise<void>(resolve => {
|
||||
await new Promise<void>((resolve) => {
|
||||
new Compressor(image, {
|
||||
quality: 0.8,
|
||||
maxWidth: 750,
|
||||
mimeType: "image/webp",
|
||||
mimeType: 'image/webp',
|
||||
success(result) {
|
||||
const file = new File([result], "name", {
|
||||
type: "image/webp",
|
||||
const file = new File([result], 'name', {
|
||||
type: 'image/webp',
|
||||
});
|
||||
compressedFile = file;
|
||||
resolve();
|
||||
},
|
||||
error(error) {
|
||||
console.log(error);
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
});
|
||||
if (!compressedFile) continue;
|
||||
const base64Img = await toBase64(compressedFile);
|
||||
imagesExtracts.push(base64Img);
|
||||
const result = await toBase64(compressedFile);
|
||||
|
||||
if (result && typeof result === 'string') {
|
||||
imagesExtracts.push(result);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
@@ -402,7 +366,7 @@ export const EditVideo = () => {
|
||||
|
||||
setImageExtracts(imagesExtracts);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -413,12 +377,12 @@ export const EditVideo = () => {
|
||||
aria-labelledby="modal-title"
|
||||
aria-describedby="modal-description"
|
||||
>
|
||||
<ModalBody sx={{ maxHeight: "98vh" }}>
|
||||
<ModalBody sx={{ maxHeight: '98vh' }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<NewCrowdfundTitle>Update Video properties</NewCrowdfundTitle>
|
||||
@@ -427,11 +391,11 @@ export const EditVideo = () => {
|
||||
<Box
|
||||
{...getRootProps()}
|
||||
sx={{
|
||||
border: "1px dashed gray",
|
||||
border: '1px dashed gray',
|
||||
padding: 2,
|
||||
textAlign: "center",
|
||||
textAlign: 'center',
|
||||
marginBottom: 2,
|
||||
cursor: "pointer",
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
<input {...getInputProps()} />
|
||||
@@ -439,16 +403,16 @@ export const EditVideo = () => {
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
marginBottom: "10px",
|
||||
marginBottom: '10px',
|
||||
}}
|
||||
>
|
||||
{file?.name}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<FormControl fullWidth sx={{ marginBottom: 2 }}>
|
||||
@@ -456,10 +420,10 @@ export const EditVideo = () => {
|
||||
<Select
|
||||
labelId="Category"
|
||||
input={<OutlinedInput label="Select a Category" />}
|
||||
value={selectedCategoryVideos?.id || ""}
|
||||
value={selectedCategoryVideos?.id || ''}
|
||||
onChange={handleOptionCategoryChangeVideos}
|
||||
>
|
||||
{categories.map(option => (
|
||||
{categories.map((option) => (
|
||||
<MenuItem key={option.id} value={option.id}>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
@@ -473,19 +437,21 @@ export const EditVideo = () => {
|
||||
<Select
|
||||
labelId="Sub-Category"
|
||||
input={<OutlinedInput label="Select a Sub-Category" />}
|
||||
value={selectedSubCategoryVideos?.id || ""}
|
||||
onChange={e =>
|
||||
value={selectedSubCategoryVideos?.id || ''}
|
||||
onChange={(e) =>
|
||||
handleOptionSubCategoryChangeVideos(
|
||||
e,
|
||||
subCategories[selectedCategoryVideos?.id]
|
||||
)
|
||||
}
|
||||
>
|
||||
{subCategories[selectedCategoryVideos.id].map(option => (
|
||||
<MenuItem key={option.id} value={option.id}>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
{subCategories[selectedCategoryVideos.id].map(
|
||||
(option) => (
|
||||
<MenuItem key={option.id} value={option.id}>
|
||||
{option.name}
|
||||
</MenuItem>
|
||||
)
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
@@ -493,8 +459,9 @@ export const EditVideo = () => {
|
||||
{file && (
|
||||
<FrameExtractor
|
||||
videoFile={file}
|
||||
onFramesExtracted={imgs => onFramesExtracted(imgs)}
|
||||
videoDurations={videoDuration}
|
||||
onFramesExtracted={(imgs) => onFramesExtracted(imgs)}
|
||||
videoDurations={videoDurations}
|
||||
setVideoDurations={setVideoDurations}
|
||||
index={0}
|
||||
/>
|
||||
)}
|
||||
@@ -505,8 +472,8 @@ export const EditVideo = () => {
|
||||
Add Cover Image
|
||||
<AddLogoIcon
|
||||
sx={{
|
||||
height: "25px",
|
||||
width: "auto",
|
||||
height: '25px',
|
||||
width: 'auto',
|
||||
}}
|
||||
></AddLogoIcon>
|
||||
</AddCoverImageButton>
|
||||
@@ -516,9 +483,9 @@ export const EditVideo = () => {
|
||||
<CoverImagePreview src={coverImage} alt="logo" />
|
||||
<TimesIcon
|
||||
color={theme.palette.text.primary}
|
||||
onClickFunc={() => setCoverImage("")}
|
||||
height={"32"}
|
||||
width={"32"}
|
||||
onClickFunc={() => setCoverImage('')}
|
||||
height={'32'}
|
||||
width={'32'}
|
||||
></TimesIcon>
|
||||
</LogoPreviewRow>
|
||||
)}
|
||||
@@ -528,9 +495,10 @@ export const EditVideo = () => {
|
||||
label="Video Duration in Seconds"
|
||||
addIconButtons={false}
|
||||
allowDecimals={false}
|
||||
initialValue={videoDuration.value[0].toString()}
|
||||
afterChange={s => {
|
||||
videoDuration.value[0] = +s;
|
||||
initialValue={videoDurations[0].toString()}
|
||||
afterChange={(s) => {
|
||||
const newS = +s;
|
||||
setVideoDurations([newS]);
|
||||
}}
|
||||
/>
|
||||
<CustomInputField
|
||||
@@ -538,9 +506,9 @@ export const EditVideo = () => {
|
||||
label="Title of video"
|
||||
variant="filled"
|
||||
value={title}
|
||||
onChange={e => {
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
const formattedValue = value.replace(titleFormatter, "");
|
||||
const formattedValue = value.replace(titleFormatter, '');
|
||||
setTitle(formattedValue);
|
||||
}}
|
||||
inputProps={{ maxLength: 180 }}
|
||||
@@ -548,28 +516,17 @@ export const EditVideo = () => {
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
fontSize: '18px',
|
||||
}}
|
||||
>
|
||||
Description of video
|
||||
</Typography>
|
||||
<TextEditor
|
||||
inlineContent={description}
|
||||
setInlineContent={value => {
|
||||
setInlineContent={(value) => {
|
||||
setDescription(value);
|
||||
}}
|
||||
/>
|
||||
{/* <CustomInputField
|
||||
name="description"
|
||||
label="Describe your video in a few words"
|
||||
variant="filled"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
inputProps={{ maxLength: 10000 }}
|
||||
multiline
|
||||
maxRows={3}
|
||||
required
|
||||
/> */}
|
||||
</React.Fragment>
|
||||
</>
|
||||
|
||||
@@ -585,9 +542,9 @@ export const EditVideo = () => {
|
||||
</CrowdfundActionButton>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
alignItems: "center",
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<CrowdfundActionButton
|
||||
@@ -595,7 +552,7 @@ export const EditVideo = () => {
|
||||
onClick={() => {
|
||||
publishQDNResource();
|
||||
}}
|
||||
disabled={file && imageExtracts.length === 0}
|
||||
disabled={!!file && imageExtracts?.length === 0}
|
||||
>
|
||||
{file && imageExtracts.length === 0 && (
|
||||
<CircularProgress color="secondary" size={14} />
|
||||
@@ -606,37 +563,6 @@ export const EditVideo = () => {
|
||||
</CrowdfundActionButtonRow>
|
||||
</ModalBody>
|
||||
</Modal>
|
||||
{isOpenMultiplePublish && (
|
||||
<MultiplePublish
|
||||
isOpen={isOpenMultiplePublish}
|
||||
onError={messageNotification => {
|
||||
setIsOpenMultiplePublish(false);
|
||||
setPublishes(null);
|
||||
if (messageNotification) {
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: messageNotification,
|
||||
alertType: "error",
|
||||
})
|
||||
);
|
||||
}
|
||||
}}
|
||||
onSubmit={() => {
|
||||
setIsOpenMultiplePublish(false);
|
||||
const clonedCopy = structuredClone(videoPropertiesToSetToRedux);
|
||||
dispatch(updateVideo(clonedCopy));
|
||||
dispatch(updateInHashMap(clonedCopy));
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "Video updated",
|
||||
alertType: "success",
|
||||
})
|
||||
);
|
||||
onClose();
|
||||
}}
|
||||
publishes={publishes}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -11,6 +11,8 @@ import React, { useCallback, useEffect, useState, useRef } from "react";
|
||||
import { CircleSVG } from "../../../assets/svgs/CircleSVG.tsx";
|
||||
import { EmptyCircleSVG } from "../../../assets/svgs/EmptyCircleSVG.tsx";
|
||||
import { styled } from "@mui/system";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { usePublish } from "qapp-core";
|
||||
|
||||
interface Publish {
|
||||
resources: any[];
|
||||
@@ -30,6 +32,7 @@ export const MultiplePublish = ({
|
||||
onError,
|
||||
}: MultiplePublishProps) => {
|
||||
const theme = useTheme();
|
||||
const publishFromLibrary = usePublish()
|
||||
const listOfSuccessfulPublishesRef = useRef([]);
|
||||
const [listOfSuccessfulPublishes, setListOfSuccessfulPublishes] = useState<
|
||||
any[]
|
||||
@@ -41,7 +44,7 @@ export const MultiplePublish = ({
|
||||
const publish = useCallback(async (pub: any) => {
|
||||
const lengthOfResources = pub?.resources?.length;
|
||||
const lengthOfTimeout = lengthOfResources * 1200000; // Time out in QR, Seconds = 20 Minutes
|
||||
return await qortalRequestWithTimeout(pub, lengthOfTimeout);
|
||||
return await publishFromLibrary.publishMultipleResources(pub.resources)
|
||||
}, []);
|
||||
const [isPublishing, setIsPublishing] = useState(true);
|
||||
|
||||
@@ -123,9 +126,12 @@ export const MultiplePublish = ({
|
||||
const unpublished = listOfUnsuccessfulPublishes.map(
|
||||
item => item?.identifier
|
||||
);
|
||||
const key = `${publish?.service}-${publish?.name}-${publish?.identifier}`
|
||||
|
||||
return (
|
||||
<Box key={key}>
|
||||
<Box
|
||||
key={publish?.identifier}
|
||||
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
@@ -154,6 +160,8 @@ export const MultiplePublish = ({
|
||||
<CircularProgress size={16} color="secondary" />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
{!isPublishing && listOfUnsuccessfulPublishes.length > 0 && (
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { useState } from "react";
|
||||
import { CardContentContainerComment } from "../../common/Comments/Comments-styles.tsx";
|
||||
import { useState } from 'react';
|
||||
import { CardContentContainerComment } from '../../common/Comments/Comments-styles.tsx';
|
||||
import {
|
||||
CrowdfundSubTitle,
|
||||
CrowdfundSubTitleRow,
|
||||
} from "../PublishVideo/PublishVideo-styles.tsx";
|
||||
} from '../PublishVideo/PublishVideo-styles.tsx';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -14,28 +14,29 @@ import {
|
||||
Typography,
|
||||
useTheme,
|
||||
FormControlLabel,
|
||||
} from "@mui/material";
|
||||
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
|
||||
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
||||
import { removeVideo } from "../../../state/features/videoSlice.ts";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../../../state/store.ts";
|
||||
import { QTUBE_VIDEO_BASE } from "../../../constants/Identifiers.ts";
|
||||
} from '@mui/material';
|
||||
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
|
||||
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
|
||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import { QTUBE_VIDEO_BASE } from '../../../constants/Identifiers.ts';
|
||||
import { QortalMetadata, Spacer, useAuth } from 'qapp-core';
|
||||
import { useIsSmall } from '../../../hooks/useIsSmall.tsx';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
export const PlaylistListEdit = ({
|
||||
playlistData,
|
||||
updateVideoList,
|
||||
removeVideo,
|
||||
addVideo,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
const username = useSelector((state: RootState) => state.auth?.user?.name);
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const [searchResults, setSearchResults] = useState([]);
|
||||
const [filterSearch, setFilterSearch] = useState("");
|
||||
const theme = useTheme();
|
||||
const isSmall = useIsSmall();
|
||||
const { name: username } = useAuth();
|
||||
|
||||
const [searchResults, setSearchResults] = useState<QortalMetadata[]>([]);
|
||||
const [filterSearch, setFilterSearch] = useState('');
|
||||
const [userSearch, setUserSearch] = useState(
|
||||
`name=${username}&exactmatchnames=true&`
|
||||
);
|
||||
@@ -43,12 +44,12 @@ export const PlaylistListEdit = ({
|
||||
const videos = playlistData?.videos || [];
|
||||
//const [hoveredIndex, setHoveredIndex] = useState(null); // Mayb in the future
|
||||
|
||||
const handleRadioChange = event => {
|
||||
const handleRadioChange = (event) => {
|
||||
const value = event.target.value;
|
||||
if (value === "myVideos") {
|
||||
if (value === 'myVideos') {
|
||||
setUserSearch(`name=${username}&exactmatchnames=true&`);
|
||||
} else {
|
||||
setUserSearch(""); // All videos
|
||||
setUserSearch(''); // All videos
|
||||
}
|
||||
};
|
||||
|
||||
@@ -56,9 +57,9 @@ export const PlaylistListEdit = ({
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=DOCUMENT&mode=ALL&identifier=${QTUBE_VIDEO_BASE}&title=${filterSearch}&limit=20&includemetadata=true&reverse=true&${userSearch}offset=0`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseDataSearchVid = await response.json();
|
||||
@@ -81,27 +82,35 @@ export const PlaylistListEdit = ({
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
display: 'flex',
|
||||
flexDirection: isSmall ? 'column' : 'row',
|
||||
gap: '10px',
|
||||
width: '100%',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flex: '1 1 50%',
|
||||
outline: `1px ${theme.palette.action.active} solid`,
|
||||
padding: '5px',
|
||||
borderRadius: '5px',
|
||||
}}
|
||||
>
|
||||
<CrowdfundSubTitleRow>
|
||||
<CrowdfundSubTitle>Playlist</CrowdfundSubTitle>
|
||||
<CrowdfundSubTitle>
|
||||
{t('core:publish.playlist', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</CrowdfundSubTitle>
|
||||
</CrowdfundSubTitleRow>
|
||||
<CardContentContainerComment
|
||||
sx={{
|
||||
marginTop: "25px",
|
||||
height: "450px",
|
||||
overflow: "auto",
|
||||
marginTop: '25px',
|
||||
maxHeight: '450px',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
{videos.map((vid, index) => {
|
||||
@@ -109,30 +118,30 @@ export const PlaylistListEdit = ({
|
||||
<Box
|
||||
key={vid?.identifier}
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
padding: "10px",
|
||||
borderRadius: "5px",
|
||||
userSelect: "none",
|
||||
"&:hover .action-icons": { display: "flex" },
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
padding: '10px',
|
||||
borderRadius: '5px',
|
||||
userSelect: 'none',
|
||||
'&:hover .action-icons': { display: 'flex' },
|
||||
}}
|
||||
// onMouseEnter={() => setHoveredIndex(index)}
|
||||
// onMouseLeave={() => setHoveredIndex(null)}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "2px",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '2px',
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => moveItem(index, -1)}
|
||||
disabled={index === 0}
|
||||
sx={{ padding: "2px" }}
|
||||
sx={{ padding: '2px' }}
|
||||
>
|
||||
<ArrowUpwardIcon fontSize="small" />
|
||||
</IconButton>
|
||||
@@ -140,22 +149,22 @@ export const PlaylistListEdit = ({
|
||||
size="small"
|
||||
onClick={() => moveItem(index, 1)}
|
||||
disabled={index === playlistData?.videos?.length - 1}
|
||||
sx={{ padding: "2px" }}
|
||||
sx={{ padding: '2px' }}
|
||||
>
|
||||
<ArrowDownwardIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
{index + 1}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
wordBreak: "break-word",
|
||||
fontSize: '18px',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{vid?.metadata?.title}
|
||||
@@ -165,7 +174,7 @@ export const PlaylistListEdit = ({
|
||||
removeVideo(index);
|
||||
}}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
@@ -175,19 +184,26 @@ export const PlaylistListEdit = ({
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flex: '1 1 50%',
|
||||
outline: `1px ${theme.palette.action.active} solid`,
|
||||
padding: '5px',
|
||||
borderRadius: '5px',
|
||||
}}
|
||||
>
|
||||
<CrowdfundSubTitleRow>
|
||||
<CrowdfundSubTitle>Add videos to playlist</CrowdfundSubTitle>
|
||||
<CrowdfundSubTitle>
|
||||
{t('core:publish.add_videos_playlist', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</CrowdfundSubTitle>
|
||||
</CrowdfundSubTitleRow>
|
||||
<CardContentContainerComment
|
||||
sx={{
|
||||
marginTop: "25px",
|
||||
height: "450px",
|
||||
overflow: "auto",
|
||||
marginTop: '25px',
|
||||
maxHeight: '450px',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
@@ -200,63 +216,72 @@ export const PlaylistListEdit = ({
|
||||
<FormControlLabel
|
||||
value="myVideos"
|
||||
control={<Radio />}
|
||||
label="My Videos"
|
||||
label={t('core:publish.my_videos', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
componentsProps={{
|
||||
typography: { sx: { fontSize: "14px" } },
|
||||
typography: { sx: { fontSize: '14px' } },
|
||||
}}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value="allVideos"
|
||||
control={<Radio />}
|
||||
label="All Videos"
|
||||
label={t('core:publish.all_videos', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
componentsProps={{
|
||||
typography: { sx: { fontSize: "14px" } },
|
||||
typography: { sx: { fontSize: '14px' } },
|
||||
}}
|
||||
/>
|
||||
</RadioGroup>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
id="standard-adornment-name"
|
||||
onChange={e => {
|
||||
onChange={(e) => {
|
||||
setFilterSearch(e.target.value);
|
||||
}}
|
||||
value={filterSearch}
|
||||
placeholder="Search by title"
|
||||
placeholder={t('core:publish.search_by_title', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
sx={{
|
||||
borderBottom: "1px solid white",
|
||||
"&&:before": {
|
||||
borderBottom: "none",
|
||||
borderBottom: '1px solid white',
|
||||
'&&:before': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
"&&:after": {
|
||||
borderBottom: "none",
|
||||
'&&:after': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
"&&:hover:before": {
|
||||
borderBottom: "none",
|
||||
'&&:hover:before': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
"&&.Mui-focused:before": {
|
||||
borderBottom: "none",
|
||||
'&&.Mui-focused:before': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
"&&.Mui-focused": {
|
||||
outline: "none",
|
||||
'&&.Mui-focused': {
|
||||
outline: 'none',
|
||||
},
|
||||
fontSize: "18px",
|
||||
fontSize: '18px',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Spacer height="20px" />
|
||||
<Button
|
||||
onClick={() => {
|
||||
search();
|
||||
}}
|
||||
variant="contained"
|
||||
>
|
||||
Search
|
||||
{t('core:navbar.search', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
@@ -265,26 +290,26 @@ export const PlaylistListEdit = ({
|
||||
<Box
|
||||
key={vid?.identifier}
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
padding: "10px",
|
||||
borderRadius: "5px",
|
||||
userSelect: "none",
|
||||
display: 'flex',
|
||||
gap: '10px',
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
padding: '10px',
|
||||
borderRadius: '5px',
|
||||
userSelect: 'none',
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontSize: '14px',
|
||||
}}
|
||||
>
|
||||
{index + 1}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
wordBreak: "break-word",
|
||||
fontSize: '18px',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{vid?.metadata?.title}
|
||||
@@ -294,7 +319,7 @@ export const PlaylistListEdit = ({
|
||||
addVideo(vid);
|
||||
}}
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { styled } from "@mui/system";
|
||||
import { styled } from '@mui/system';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
TextField,
|
||||
Typography,
|
||||
Select,
|
||||
} from "@mui/material";
|
||||
import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
|
||||
import { TimesSVG } from "../../../assets/svgs/TimesSVG.tsx";
|
||||
} from '@mui/material';
|
||||
import AddPhotoAlternateIcon from '@mui/icons-material/AddPhotoAlternate';
|
||||
import { TimesSVG } from '../../../assets/svgs/TimesSVG.tsx';
|
||||
|
||||
export const DoubleLine = styled(Typography)`
|
||||
display: -webkit-box;
|
||||
@@ -22,183 +22,174 @@ export const DoubleLine = styled(Typography)`
|
||||
`;
|
||||
|
||||
export const MainContainer = styled(Grid)({
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "center",
|
||||
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",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
padding: '20px',
|
||||
}));
|
||||
|
||||
export const CreateContainer = styled(Box)(({ theme }) => ({
|
||||
position: "fixed",
|
||||
bottom: "20px",
|
||||
right: "20px",
|
||||
cursor: "pointer",
|
||||
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%",
|
||||
width: '50px',
|
||||
height: '50px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: '50%',
|
||||
}));
|
||||
|
||||
export const CodecTypography = styled(Typography)(({ theme }) => ({
|
||||
fontSize: "18px",
|
||||
fontSize: '18px',
|
||||
}));
|
||||
export const ModalBody = styled(Box)(({ theme }) => ({
|
||||
position: "absolute",
|
||||
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",
|
||||
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": {
|
||||
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": {
|
||||
'&::-webkit-scrollbar-track:hover': {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "16px",
|
||||
height: "10px",
|
||||
backgroundColor: theme.palette.mode === "light" ? "#f6f8fa" : "#292d3e",
|
||||
'&::-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': {
|
||||
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",
|
||||
'&::-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",
|
||||
fontSize: '25px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
export const NewCrowdFundFont = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 400,
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "18px",
|
||||
userSelect: "none",
|
||||
fontSize: '18px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
export const NewCrowdfundTimeDescription = styled(Typography)(({ theme }) => ({
|
||||
fontWeight: 400,
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "18px",
|
||||
userSelect: "none",
|
||||
fontStyle: "italic",
|
||||
textDecoration: "underline",
|
||||
fontSize: '18px',
|
||||
userSelect: 'none',
|
||||
fontStyle: 'italic',
|
||||
textDecoration: 'underline',
|
||||
}));
|
||||
|
||||
export const CustomInputField = styled(TextField)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
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",
|
||||
'& label': {
|
||||
color: theme.palette.mode === 'light' ? '#808183' : '#edeef0',
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
},
|
||||
"& label.Mui-focused": {
|
||||
color: theme.palette.mode === "light" ? "#A0AAB4" : "#d7d8da",
|
||||
'& label.Mui-focused': {
|
||||
color: theme.palette.mode === 'light' ? '#A0AAB4' : '#d7d8da',
|
||||
},
|
||||
"& .MuiInput-underline:after": {
|
||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
||||
'& .MuiInput-underline:after': {
|
||||
borderBottomColor: theme.palette.mode === 'light' ? '#B2BAC2' : '#c9cccf',
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
borderColor: "#E0E3E7",
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: '#E0E3E7',
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
borderColor: "#B2BAC2",
|
||||
'&:hover fieldset': {
|
||||
borderColor: '#B2BAC2',
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
borderColor: "#6F7E8C",
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: '#6F7E8C',
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-root": {
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
'& .MuiInputBase-root': {
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
},
|
||||
"& [class$='-MuiFilledInput-root']": {
|
||||
padding: "30px 12px 8px",
|
||||
padding: '30px 12px 8px',
|
||||
},
|
||||
"& .MuiFilledInput-root:after": {
|
||||
'& .MuiFilledInput-root:after': {
|
||||
borderBottomColor: theme.palette.secondary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
letterSpacing: "1px",
|
||||
letterSpacing: '1px',
|
||||
fontWeight: 400,
|
||||
fontSize: "20px",
|
||||
fontSize: '20px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
}));
|
||||
|
||||
export const CrowdfundSubTitleRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "start",
|
||||
flexDirection: "row",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'start',
|
||||
flexDirection: 'row',
|
||||
});
|
||||
|
||||
export const CrowdfundSubTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
letterSpacing: "1px",
|
||||
letterSpacing: '1px',
|
||||
fontWeight: 400,
|
||||
fontSize: "17px",
|
||||
fontSize: '17px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
borderBottom: `1px solid ${theme.palette.text.primary}`,
|
||||
paddingBottom: "1.5px",
|
||||
width: "fit-content",
|
||||
textDecoration: "none",
|
||||
paddingBottom: '1.5px',
|
||||
width: 'fit-content',
|
||||
textDecoration: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundDescription = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "16px",
|
||||
fontSize: '16px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
wordBreak: "break-word",
|
||||
userSelect: 'none',
|
||||
wordBreak: 'break-word',
|
||||
}));
|
||||
|
||||
export const Spacer = ({ height }: any) => {
|
||||
@@ -212,326 +203,313 @@ export const Spacer = ({ height }: any) => {
|
||||
};
|
||||
|
||||
export const StyledCardHeaderComment = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: "5px",
|
||||
padding: "7px 0px",
|
||||
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%",
|
||||
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%",
|
||||
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",
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.2',
|
||||
});
|
||||
|
||||
export const AddLogoIcon = styled(AddPhotoAlternateIcon)(({ theme }) => ({
|
||||
color: "#fff",
|
||||
height: "25px",
|
||||
width: "auto",
|
||||
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 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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
fontSize: '12px',
|
||||
letterSpacing: '0.2px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CATContainer = styled(Box)(({ theme }) => ({
|
||||
position: "relative",
|
||||
display: "flex",
|
||||
padding: "15px",
|
||||
flexDirection: "column",
|
||||
gap: "20px",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
alignItems: "center",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
gap: '10px',
|
||||
}));
|
||||
|
||||
export const CrowdfundPageTitle = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
fontSize: "35px",
|
||||
fontSize: '35px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "1px",
|
||||
userSelect: "none",
|
||||
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",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: '21px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
border: `1px solid ${theme.palette.text.primary}`,
|
||||
borderRadius: "8px",
|
||||
padding: "15px 25px",
|
||||
userSelect: "none",
|
||||
borderRadius: '8px',
|
||||
padding: '15px 25px',
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundDescriptionRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "18px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
fontSize: '18px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
});
|
||||
|
||||
export const AboutMyCrowdfund = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Copse",
|
||||
fontSize: "23px",
|
||||
fontSize: '23px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "1px",
|
||||
userSelect: "none",
|
||||
letterSpacing: '1px',
|
||||
userSelect: 'none',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const CrowdfundInlineContentRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const CrowdfundInlineContent = styled(Box)(({ theme }) => ({
|
||||
display: "flex",
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
display: 'flex',
|
||||
fontSize: '19px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordion = styled(Accordion)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
"& .Mui-expanded": {
|
||||
minHeight: "auto !important",
|
||||
'& .Mui-expanded': {
|
||||
minHeight: 'auto !important',
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordionSummary = styled(AccordionSummary)({
|
||||
height: "50px",
|
||||
"& .Mui-expanded": {
|
||||
margin: "0px !important",
|
||||
height: '50px',
|
||||
'& .Mui-expanded': {
|
||||
margin: '0px !important',
|
||||
},
|
||||
});
|
||||
|
||||
export const CrowdfundAccordionFont = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "20px",
|
||||
fontSize: '20px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0px",
|
||||
letterSpacing: '0px',
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const CrowdfundAccordionDetails = styled(AccordionDetails)({
|
||||
padding: "0px 16px 16px 16px",
|
||||
padding: '0px 16px 16px 16px',
|
||||
});
|
||||
|
||||
export const AddCoverImageButton = styled(Button)(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "16px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
letterSpacing: '0.2px',
|
||||
color: 'white',
|
||||
gap: '5px',
|
||||
}));
|
||||
|
||||
export const CoverImage = styled("img")({
|
||||
width: "100%",
|
||||
height: "250px",
|
||||
objectFit: "cover",
|
||||
objectPosition: "center",
|
||||
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%",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const CrowdfundActionButton = styled(Button)(({ theme }) => ({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
fontFamily: "Montserrat",
|
||||
fontSize: "16px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '16px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
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",
|
||||
position: 'absolute',
|
||||
top: '20px',
|
||||
left: '20px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
fontSize: '13px',
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
color: "white",
|
||||
gap: "5px",
|
||||
padding: "5px 10px",
|
||||
letterSpacing: '0.2px',
|
||||
color: 'white',
|
||||
gap: '5px',
|
||||
padding: '5px 10px',
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
transition: "all 0.3s ease-in-out",
|
||||
"&:hover": {
|
||||
transition: 'all 0.3s ease-in-out',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.secondary.dark,
|
||||
cursor: "pointer",
|
||||
cursor: 'pointer',
|
||||
},
|
||||
}));
|
||||
|
||||
export const CrowdfundLoaderRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: "10px",
|
||||
padding: "10px",
|
||||
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",
|
||||
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",
|
||||
fontSize: '28px',
|
||||
});
|
||||
|
||||
export const NoReviewsFont = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontWeight: 400,
|
||||
letterSpacing: 0,
|
||||
color: theme.palette.text.primary,
|
||||
@@ -543,43 +521,40 @@ export const StyledButton = styled(Button)(({ theme }) => ({
|
||||
}));
|
||||
|
||||
export const CustomSelect = styled(Select)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
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",
|
||||
'& .MuiSelect-select': {
|
||||
padding: '12px',
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
borderRadius: theme.shape.borderRadius, // Match border radius
|
||||
},
|
||||
"&:before": {
|
||||
'&:before': {
|
||||
// Underline style
|
||||
borderBottomColor: theme.palette.mode === "light" ? "#B2BAC2" : "#c9cccf",
|
||||
borderBottomColor: theme.palette.mode === 'light' ? '#B2BAC2' : '#c9cccf',
|
||||
},
|
||||
"&:after": {
|
||||
'&:after': {
|
||||
// Underline style when focused
|
||||
borderBottomColor: theme.palette.secondary.main,
|
||||
},
|
||||
"& .MuiOutlinedInput-root": {
|
||||
"& fieldset": {
|
||||
borderColor: "#E0E3E7",
|
||||
'& .MuiOutlinedInput-root': {
|
||||
'& fieldset': {
|
||||
borderColor: '#E0E3E7',
|
||||
},
|
||||
"&:hover fieldset": {
|
||||
borderColor: "#B2BAC2",
|
||||
'&:hover fieldset': {
|
||||
borderColor: '#B2BAC2',
|
||||
},
|
||||
"&.Mui-focused fieldset": {
|
||||
borderColor: "#6F7E8C",
|
||||
'&.Mui-focused fieldset': {
|
||||
borderColor: '#6F7E8C',
|
||||
},
|
||||
},
|
||||
"& .MuiInputBase-root": {
|
||||
fontFamily: "Mulish",
|
||||
fontSize: "19px",
|
||||
letterSpacing: "0px",
|
||||
'& .MuiInputBase-root': {
|
||||
fontSize: '19px',
|
||||
letterSpacing: '0px',
|
||||
fontWeight: 400,
|
||||
color: theme.palette.text.primary,
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,8 @@
|
||||
import React, { useState, useEffect, CSSProperties } from "react";
|
||||
import Skeleton from "@mui/material/Skeleton";
|
||||
import { Box } from "@mui/material";
|
||||
import DeletedVideo from "../assets/img/DeletedVideo.jpg";
|
||||
import React, { useState, useEffect, CSSProperties } from 'react';
|
||||
import Skeleton from '@mui/material/Skeleton';
|
||||
import { Box } from '@mui/material';
|
||||
import DeletedVideo from '../assets/img/DeletedVideo.jpg';
|
||||
import { useIsMobile } from '../hooks/useIsMobile';
|
||||
interface ResponsiveImageProps {
|
||||
src: string;
|
||||
width: number;
|
||||
@@ -9,6 +10,7 @@ interface ResponsiveImageProps {
|
||||
alt?: string;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
fill?: boolean;
|
||||
}
|
||||
|
||||
const ResponsiveImage: React.FC<ResponsiveImageProps> = ({
|
||||
@@ -18,7 +20,10 @@ const ResponsiveImage: React.FC<ResponsiveImageProps> = ({
|
||||
alt,
|
||||
className,
|
||||
style,
|
||||
fill,
|
||||
}) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const endLoading = (endTimeSeconds: number) => {
|
||||
@@ -33,34 +38,38 @@ const ResponsiveImage: React.FC<ResponsiveImageProps> = ({
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
padding: "2px",
|
||||
height: "100%",
|
||||
padding: isMobile ? '0px' : '5px',
|
||||
height: '100%',
|
||||
backgroundColor: '#050507',
|
||||
|
||||
...style,
|
||||
}}
|
||||
boxShadow={2}
|
||||
>
|
||||
{loading && (
|
||||
<Skeleton
|
||||
variant="rectangular"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 0,
|
||||
paddingBottom: `${(height / width) * 100}%`,
|
||||
objectFit: "contain",
|
||||
visibility: loading ? "visible" : "hidden",
|
||||
borderRadius: "8px",
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'contain',
|
||||
visibility: loading ? 'visible' : 'hidden',
|
||||
borderRadius: '8px',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<img
|
||||
onLoad={() => setLoading(false)}
|
||||
src={!src && !loading ? DeletedVideo : src || null}
|
||||
src={!src && !loading ? DeletedVideo : src || undefined}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
borderRadius: "8px",
|
||||
display: loading ? "none" : "unset",
|
||||
objectFit: "contain",
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: isMobile ? '0px' : '8px',
|
||||
display: loading ? 'none' : 'unset',
|
||||
objectFit: fill ? 'fill' : 'contain',
|
||||
maskImage: 'radial-gradient(circle, black 95%, transparent 100%)',
|
||||
maskMode: 'alpha',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -1,62 +1,65 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { styled } from "@mui/system";
|
||||
import { Grid } from "@mui/material";
|
||||
import { useFetchVideos } from "../hooks/useFetchVideos.tsx";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../state/store.ts";
|
||||
import { signal } from "@preact/signals-react";
|
||||
import { useEffect } from 'react';
|
||||
import { styled } from '@mui/system';
|
||||
import { Grid } from '@mui/material';
|
||||
import { useFetchVideos } from '../hooks/useFetchVideos.tsx';
|
||||
import { useAtom } from 'jotai';
|
||||
import {
|
||||
totalNamesPublishedAtom,
|
||||
totalVideosPublishedAtom,
|
||||
videosPerNamePublishedAtom,
|
||||
} from '../state/global/stats.ts';
|
||||
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
export const totalVideosPublished = signal(0);
|
||||
export const totalNamesPublished = signal(0);
|
||||
export const videosPerNamePublished = signal(0);
|
||||
|
||||
export const StatsData = () => {
|
||||
const [totalVideosPublished] = useAtom(totalVideosPublishedAtom);
|
||||
const [totalNamesPublished] = useAtom(totalNamesPublishedAtom);
|
||||
const [videosPerNamePublished] = useAtom(videosPerNamePublishedAtom);
|
||||
|
||||
const StatsCol = styled(Grid)(({ theme }) => ({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
padding: "20px 0px",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
padding: '20px 0px',
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}));
|
||||
|
||||
const { getVideosCount } = useFetchVideos();
|
||||
|
||||
const showValueIfExists = (value: number) => {
|
||||
return value > 0 ? "inline" : "none";
|
||||
return value > 0 ? 'inline' : 'none';
|
||||
};
|
||||
|
||||
const showStats = useSelector((state: RootState) => state.persist.showStats);
|
||||
const showVideoCount = showValueIfExists(totalVideosPublished.value);
|
||||
const showPublisherCount = showValueIfExists(totalNamesPublished.value);
|
||||
const showAverage = showValueIfExists(videosPerNamePublished.value);
|
||||
const showVideoCount = showValueIfExists(totalVideosPublished);
|
||||
const showPublisherCount = showValueIfExists(totalNamesPublished);
|
||||
const showAverage = showValueIfExists(videosPerNamePublished);
|
||||
useEffect(() => {
|
||||
getVideosCount();
|
||||
}, [getVideosCount]);
|
||||
|
||||
return (
|
||||
<StatsCol sx={{ display: showStats ? "block" : "none" }}>
|
||||
<StatsCol sx={{ display: 'block' }}>
|
||||
<div>
|
||||
Videos:{" "}
|
||||
<span style={{ fontWeight: "bold", display: showVideoCount }}>
|
||||
{totalVideosPublished.value}
|
||||
Videos:{' '}
|
||||
<span style={{ fontWeight: 'bold', display: showVideoCount }}>
|
||||
{totalVideosPublished}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
Publishers:{" "}
|
||||
<span style={{ fontWeight: "bold", display: showPublisherCount }}>
|
||||
{totalNamesPublished.value}
|
||||
Publishers:{' '}
|
||||
<span style={{ fontWeight: 'bold', display: showPublisherCount }}>
|
||||
{totalNamesPublished}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
Average:{" "}
|
||||
Average:{' '}
|
||||
<span
|
||||
style={{
|
||||
fontWeight: "bold",
|
||||
fontWeight: 'bold',
|
||||
display: showAverage,
|
||||
}}
|
||||
>
|
||||
{Number(videosPerNamePublished.value).toFixed(0)}
|
||||
{Number(videosPerNamePublished).toFixed(0)}
|
||||
</span>
|
||||
</div>
|
||||
</StatsCol>
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { styled } from '@mui/system';
|
||||
import {
|
||||
Box,
|
||||
Modal,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
import { Box, Modal, Typography } from '@mui/material';
|
||||
|
||||
export const StyledModal = styled(Modal)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}))
|
||||
justifyContent: 'center',
|
||||
}));
|
||||
|
||||
export const ModalContent = styled(Box)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
@@ -17,12 +13,11 @@ export const ModalContent = styled(Box)(({ theme }) => ({
|
||||
borderRadius: theme.spacing(1),
|
||||
width: '40%',
|
||||
'&:focus': {
|
||||
outline: 'none'
|
||||
}
|
||||
}))
|
||||
outline: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
export const ModalText = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Raleway",
|
||||
fontSize: "25px",
|
||||
fontSize: '25px',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
}));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -7,13 +7,14 @@ import {
|
||||
SelectChangeEvent,
|
||||
ListItem,
|
||||
List,
|
||||
useTheme
|
||||
} from "@mui/material";
|
||||
useTheme,
|
||||
} from '@mui/material';
|
||||
import {
|
||||
StyledModal,
|
||||
ModalContent,
|
||||
ModalText
|
||||
} from "./BlockedNamesModal-styles";
|
||||
ModalText,
|
||||
} from './BlockedNamesModal-styles';
|
||||
import { useBlockedNames } from 'qapp-core';
|
||||
|
||||
interface PostModalProps {
|
||||
open: boolean;
|
||||
@@ -22,16 +23,17 @@ interface PostModalProps {
|
||||
|
||||
export const BlockedNamesModal: React.FC<PostModalProps> = ({
|
||||
open,
|
||||
onClose
|
||||
onClose,
|
||||
}) => {
|
||||
const { removeFromBlockedList } = useBlockedNames();
|
||||
const [blockedNames, setBlockedNames] = useState<string[]>([]);
|
||||
const theme = useTheme();
|
||||
const getBlockedNames = React.useCallback(async () => {
|
||||
try {
|
||||
const listName = `blockedNames`;
|
||||
const response = await qortalRequest({
|
||||
action: "GET_LIST_ITEMS",
|
||||
list_name: listName
|
||||
action: 'GET_LIST_ITEMS',
|
||||
list_name: listName,
|
||||
});
|
||||
setBlockedNames(response);
|
||||
} catch (error) {
|
||||
@@ -45,11 +47,7 @@ export const BlockedNamesModal: React.FC<PostModalProps> = ({
|
||||
|
||||
const removeFromBlockList = async (name: string) => {
|
||||
try {
|
||||
const response = await qortalRequest({
|
||||
action: "DELETE_LIST_ITEM",
|
||||
list_name: "blockedNames",
|
||||
item: name
|
||||
});
|
||||
const response = await removeFromBlockedList([name]);
|
||||
|
||||
if (response === true) {
|
||||
setBlockedNames((prev) => prev.filter((n) => n !== name));
|
||||
@@ -63,18 +61,18 @@ export const BlockedNamesModal: React.FC<PostModalProps> = ({
|
||||
<ModalText>Manage blocked names</ModalText>
|
||||
<List
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: "1",
|
||||
overflow: "auto"
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flex: '1',
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
{blockedNames.map((name, index) => (
|
||||
<ListItem
|
||||
key={name + index}
|
||||
sx={{
|
||||
display: "flex"
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
<Typography>{name}</Typography>
|
||||
@@ -82,7 +80,6 @@ export const BlockedNamesModal: React.FC<PostModalProps> = ({
|
||||
sx={{
|
||||
backgroundColor: theme.palette.primary.light,
|
||||
color: theme.palette.text.primary,
|
||||
fontFamily: "Raleway"
|
||||
}}
|
||||
onClick={() => removeFromBlockList(name)}
|
||||
>
|
||||
|
||||
@@ -2,33 +2,41 @@ import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Collapse,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import React, { useCallback, useState, useEffect } from "react";
|
||||
import { CommentEditor } from "./CommentEditor";
|
||||
} from '@mui/material';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { CommentEditor } from './CommentEditor';
|
||||
import {
|
||||
CardContentContainerComment,
|
||||
CommentActionButtonRow,
|
||||
CommentDateText,
|
||||
CreatedTextComment,
|
||||
EditReplyButton,
|
||||
StyledCardComment,
|
||||
} from "./Comments-styles";
|
||||
import { StyledCardHeaderComment } from "./Comments-styles";
|
||||
import { StyledCardColComment } from "./Comments-styles";
|
||||
import { AuthorTextComment } from "./Comments-styles";
|
||||
} from './Comments-styles';
|
||||
import { StyledCardHeaderComment } from './Comments-styles';
|
||||
import { StyledCardColComment } from './Comments-styles';
|
||||
import { AuthorTextComment } from './Comments-styles';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
||||
import {
|
||||
StyledCardContentComment,
|
||||
LoadMoreCommentsButton as CommentActionButton,
|
||||
} from "./Comments-styles";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../../../state/store";
|
||||
import Portal from "../Portal";
|
||||
import { formatDate } from "../../../utils/time";
|
||||
} from './Comments-styles';
|
||||
|
||||
import Portal from '../Portal';
|
||||
import { formatDate } from '../../../utils/time';
|
||||
import { createAvatarLink, Spacer, useAuth } from 'qapp-core';
|
||||
import { useIsSmall } from '../../../hooks/useIsSmall';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import i18n from '../../../i18n/i18n';
|
||||
interface CommentProps {
|
||||
comment: any;
|
||||
postId: string;
|
||||
@@ -41,12 +49,15 @@ export const Comment = ({
|
||||
postName,
|
||||
onSubmit,
|
||||
}: CommentProps) => {
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const isSmall = useIsSmall();
|
||||
const [isReplying, setIsReplying] = useState<boolean>(false);
|
||||
const [isEditing, setIsEditing] = useState<boolean>(false);
|
||||
const { user } = useSelector((state: RootState) => state.auth);
|
||||
const { name } = useAuth();
|
||||
const [currentEdit, setCurrentEdit] = useState<any>(null);
|
||||
const theme = useTheme();
|
||||
|
||||
const [isOpenReplies, setIsOpenReplies] = useState(false);
|
||||
const handleSubmit = useCallback((comment: any, isEdit?: boolean) => {
|
||||
onSubmit(comment, isEdit);
|
||||
setCurrentEdit(null);
|
||||
@@ -57,9 +68,9 @@ export const Comment = ({
|
||||
<Box
|
||||
id={comment?.identifier}
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
flexDirection: "column",
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
}}
|
||||
>
|
||||
{currentEdit && (
|
||||
@@ -74,13 +85,13 @@ export const Comment = ({
|
||||
<DialogContent>
|
||||
<Box
|
||||
sx={{
|
||||
width: "300px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
width: '300px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<CommentEditor
|
||||
onSubmit={obj => handleSubmit(obj, true)}
|
||||
onSubmit={(obj) => handleSubmit(obj, true)}
|
||||
postId={postId}
|
||||
postName={postName}
|
||||
isEdit
|
||||
@@ -91,57 +102,76 @@ export const Comment = ({
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" onClick={() => setCurrentEdit(null)}>
|
||||
Close
|
||||
{t('core:action.close', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</Portal>
|
||||
)}
|
||||
|
||||
<CommentCard
|
||||
name={comment?.name}
|
||||
message={comment?.message}
|
||||
replies={comment?.replies || []}
|
||||
setCurrentEdit={setCurrentEdit}
|
||||
created={comment?.created}
|
||||
isOpenReplies={isOpenReplies}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
marginTop: "20px",
|
||||
justifyContent: "space-between",
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
{comment?.created && (
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
fontSize: "12px",
|
||||
marginLeft: "5px",
|
||||
{isReplying && (
|
||||
<CommentEditor
|
||||
onSubmit={handleSubmit}
|
||||
postId={postId}
|
||||
postName={postName}
|
||||
isReply
|
||||
commentId={comment.identifier}
|
||||
onCloseReply={() => {
|
||||
setIsReplying(false);
|
||||
setIsEditing(false);
|
||||
}}
|
||||
color={theme.palette.text.primary}
|
||||
>
|
||||
{formatDate(+comment?.created)}
|
||||
</Typography>
|
||||
/>
|
||||
)}
|
||||
<CommentActionButtonRow>
|
||||
<CommentActionButton
|
||||
size="small"
|
||||
variant="contained"
|
||||
onClick={() => setIsReplying(true)}
|
||||
>
|
||||
reply
|
||||
</CommentActionButton>
|
||||
{user?.name === comment?.name && (
|
||||
<CommentActionButton
|
||||
size="small"
|
||||
variant="contained"
|
||||
onClick={() => setCurrentEdit(comment)}
|
||||
>
|
||||
edit
|
||||
</CommentActionButton>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
marginTop: '20px',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
<CommentActionButtonRow
|
||||
sx={{
|
||||
gap: '20px',
|
||||
}}
|
||||
>
|
||||
{!isReplying && (
|
||||
<ButtonBase onClick={() => setIsReplying(true)}>
|
||||
<Typography>
|
||||
{' '}
|
||||
{t('core:action.reply', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
)}
|
||||
{isReplying && (
|
||||
|
||||
{/* {name === comment?.name && (
|
||||
<ButtonBase onClick={() => setCurrentEdit(comment)}>
|
||||
<Typography>Edit</Typography>
|
||||
</ButtonBase>
|
||||
)} */}
|
||||
{/* {isReplying && (
|
||||
<CommentActionButton
|
||||
size="small"
|
||||
variant="contained"
|
||||
@@ -152,29 +182,42 @@ export const Comment = ({
|
||||
>
|
||||
close
|
||||
</CommentActionButton>
|
||||
)} */}
|
||||
{comment?.replies && comment?.replies?.length > 0 && (
|
||||
<ButtonBase onClick={() => setIsOpenReplies((prev) => !prev)}>
|
||||
{isOpenReplies ? (
|
||||
<ExpandLessIcon
|
||||
sx={{
|
||||
color: 'primary.dark',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ExpandMoreIcon
|
||||
sx={{
|
||||
color: 'primary.dark',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Typography
|
||||
color="primary.dark"
|
||||
sx={{
|
||||
fontSize: isSmall ? '14px' : 'unset',
|
||||
}}
|
||||
>
|
||||
{isOpenReplies
|
||||
? ` ${t('core:comments.hide_replies', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})} (${comment?.replies?.length})`
|
||||
: ` ${t('core:comments.view_replies', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})} (${comment?.replies?.length})`}
|
||||
</Typography>
|
||||
</ButtonBase>
|
||||
)}
|
||||
</CommentActionButtonRow>
|
||||
</Box>
|
||||
</CommentCard>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
{isReplying && (
|
||||
<CommentEditor
|
||||
onSubmit={handleSubmit}
|
||||
postId={postId}
|
||||
postName={postName}
|
||||
isReply
|
||||
commentId={comment.identifier}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -186,37 +229,21 @@ export const CommentCard = ({
|
||||
replies,
|
||||
children,
|
||||
setCurrentEdit,
|
||||
isOpenReplies,
|
||||
isReply,
|
||||
}: any) => {
|
||||
const [avatarUrl, setAvatarUrl] = React.useState<string>("");
|
||||
const { user } = useSelector((state: RootState) => state.auth);
|
||||
const { i18n } = useTranslation(['core']);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const getAvatar = React.useCallback(async (author: string) => {
|
||||
try {
|
||||
const url = await qortalRequest({
|
||||
action: "GET_QDN_RESOURCE_URL",
|
||||
name: author,
|
||||
service: "THUMBNAIL",
|
||||
identifier: "qortal_avatar",
|
||||
});
|
||||
|
||||
setAvatarUrl(url);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
getAvatar(name);
|
||||
}, [name]);
|
||||
const isSmall = useIsSmall();
|
||||
const { name: username } = useAuth();
|
||||
const avatarUrl = createAvatarLink(name);
|
||||
|
||||
return (
|
||||
<CardContentContainerComment>
|
||||
<StyledCardHeaderComment
|
||||
sx={{
|
||||
"& .MuiCardHeader-content": {
|
||||
overflow: "hidden",
|
||||
'& .MuiCardHeader-content': {
|
||||
overflow: 'hidden',
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -224,72 +251,81 @@ export const CommentCard = ({
|
||||
<Avatar
|
||||
src={avatarUrl}
|
||||
alt={`${name}'s avatar`}
|
||||
sx={{ width: "35px", height: "35px" }}
|
||||
sx={{
|
||||
width: isReply && !isSmall ? '30px' : '40px',
|
||||
height: isReply && !isSmall ? '30px' : '40px',
|
||||
marginRight: '5px',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
<StyledCardColComment>
|
||||
<AuthorTextComment>{name}</AuthorTextComment>
|
||||
</StyledCardColComment>
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<StyledCardColComment
|
||||
sx={{
|
||||
flexDirection: 'row',
|
||||
gap: '10px',
|
||||
}}
|
||||
>
|
||||
<AuthorTextComment>{name}</AuthorTextComment>
|
||||
<CreatedTextComment>
|
||||
{formatDate(+created, i18n.language)}
|
||||
</CreatedTextComment>
|
||||
</StyledCardColComment>
|
||||
<Spacer height="10px" />
|
||||
<StyledCardContentComment>
|
||||
<StyledCardComment>{message}</StyledCardComment>
|
||||
</StyledCardContentComment>
|
||||
{children}
|
||||
</Box>
|
||||
</StyledCardHeaderComment>
|
||||
<StyledCardContentComment>
|
||||
<StyledCardComment>{message}</StyledCardComment>
|
||||
</StyledCardContentComment>
|
||||
<Box
|
||||
sx={{
|
||||
paddingLeft: "15px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{replies?.map((reply: any) => {
|
||||
return (
|
||||
<Box
|
||||
key={reply?.identifier}
|
||||
id={reply?.identifier}
|
||||
sx={{
|
||||
display: "flex",
|
||||
border: "1px solid grey",
|
||||
borderRadius: "10px",
|
||||
marginTop: "8px",
|
||||
}}
|
||||
>
|
||||
<CommentCard
|
||||
name={reply?.name}
|
||||
message={reply?.message}
|
||||
setCurrentEdit={setCurrentEdit}
|
||||
<Collapse in={isOpenReplies} timeout="auto" unmountOnExit>
|
||||
<Box
|
||||
sx={{
|
||||
paddingLeft: isSmall ? '2px' : '50px',
|
||||
paddingTop: '10px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
border: isSmall ? '1px solid grey' : 'unset',
|
||||
paddingRight: isSmall ? '2px' : 'unset',
|
||||
}}
|
||||
>
|
||||
{replies?.map((reply: any) => {
|
||||
return (
|
||||
<Box
|
||||
key={reply?.identifier}
|
||||
id={reply?.identifier}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
borderRadius: '10px',
|
||||
marginTop: '8px',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
justifyContent: "space-between",
|
||||
}}
|
||||
<CommentCard
|
||||
name={reply?.name}
|
||||
message={reply?.message}
|
||||
setCurrentEdit={setCurrentEdit}
|
||||
created={reply?.created}
|
||||
isReply
|
||||
>
|
||||
{reply?.created && (
|
||||
<CommentDateText>
|
||||
{formatDate(+reply?.created)}
|
||||
</CommentDateText>
|
||||
)}
|
||||
{user?.name === reply?.name ? (
|
||||
<EditReplyButton
|
||||
size="small"
|
||||
variant="contained"
|
||||
onClick={() => setCurrentEdit(reply)}
|
||||
sx={{}}
|
||||
>
|
||||
edit
|
||||
</EditReplyButton>
|
||||
) : (
|
||||
<Box />
|
||||
)}
|
||||
</Box>
|
||||
</CommentCard>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
{children}
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
></Box>
|
||||
</CommentCard>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</Collapse>
|
||||
</CardContentContainerComment>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
import { Box, Button, TextField } from "@mui/material";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "../../../state/store";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { setNotification } from "../../../state/features/notificationsSlice";
|
||||
import {hashWordWithoutPublicSalt} from 'qapp-core'
|
||||
import {
|
||||
publishFormatter,
|
||||
stringToFile,
|
||||
} from "../../../utils/PublishFormatter.ts";
|
||||
import localforage from "localforage";
|
||||
import { useEffect, useState } from 'react';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { hashWordWithoutPublicSalt, useAuth } from 'qapp-core';
|
||||
|
||||
import localforage from 'localforage';
|
||||
import {
|
||||
CommentInput,
|
||||
CommentInputContainer,
|
||||
SubmitCommentButton,
|
||||
} from "./Comments-styles";
|
||||
} from './Comments-styles';
|
||||
|
||||
import { COMMENT_BASE } from "../../../constants/Identifiers.ts";
|
||||
import { COMMENT_BASE } from '../../../constants/Identifiers.ts';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import {
|
||||
AltertObject,
|
||||
setNotificationAtom,
|
||||
} from '../../../state/global/notifications.ts';
|
||||
import { Box, Button } from '@mui/material';
|
||||
import { useIsSmall } from '../../../hooks/useIsSmall.tsx';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const uid = new ShortUniqueId({ length: 7 });
|
||||
|
||||
const notification = localforage.createInstance({
|
||||
name: "notification",
|
||||
name: 'notification',
|
||||
});
|
||||
|
||||
const MAX_ITEMS = 10;
|
||||
@@ -35,11 +36,11 @@ export interface Item {
|
||||
export async function addItem(item: Item): Promise<void> {
|
||||
// Get all items
|
||||
const notificationComments: Item[] =
|
||||
(await notification.getItem("comments")) || [];
|
||||
(await notification.getItem('comments')) || [];
|
||||
|
||||
// Find the item with the same id, if it exists
|
||||
const existingItemIndex = notificationComments.findIndex(
|
||||
i => i.id === item.id
|
||||
(i) => i.id === item.id
|
||||
);
|
||||
|
||||
if (existingItemIndex !== -1) {
|
||||
@@ -57,15 +58,15 @@ export async function addItem(item: Item): Promise<void> {
|
||||
}
|
||||
|
||||
// Store the items back into localForage
|
||||
await notification.setItem("comments", notificationComments);
|
||||
await notification.setItem('comments', notificationComments);
|
||||
}
|
||||
export async function updateItemDate(item: any): Promise<void> {
|
||||
// Get all items
|
||||
const notificationComments: Item[] =
|
||||
(await notification.getItem("comments")) || [];
|
||||
(await notification.getItem('comments')) || [];
|
||||
|
||||
const notificationCreatorComment: any =
|
||||
(await notification.getItem("post-comments")) || {};
|
||||
(await notification.getItem('post-comments')) || {};
|
||||
const findPostId = notificationCreatorComment[item.postId];
|
||||
if (findPostId) {
|
||||
notificationCreatorComment[item.postId].lastSeen = item.lastSeen;
|
||||
@@ -79,8 +80,8 @@ export async function updateItemDate(item: any): Promise<void> {
|
||||
});
|
||||
|
||||
// Store the items back into localForage
|
||||
await notification.setItem("comments", notificationComments);
|
||||
await notification.setItem("post-comments", notificationCreatorComment);
|
||||
await notification.setItem('comments', notificationComments);
|
||||
await notification.setItem('post-comments', notificationCreatorComment);
|
||||
}
|
||||
interface CommentEditorProps {
|
||||
postId: string;
|
||||
@@ -90,13 +91,14 @@ interface CommentEditorProps {
|
||||
commentId?: string;
|
||||
isEdit?: boolean;
|
||||
commentMessage?: string;
|
||||
onCloseReply?: () => void;
|
||||
}
|
||||
|
||||
function utf8ToBase64(inputString: string): string {
|
||||
// Encode the string as UTF-8
|
||||
const utf8String = encodeURIComponent(inputString).replace(
|
||||
/%([0-9A-F]{2})/g,
|
||||
(match, p1) => String.fromCharCode(Number("0x" + p1))
|
||||
(match, p1) => String.fromCharCode(Number('0x' + p1))
|
||||
);
|
||||
|
||||
// Convert the UTF-8 encoded string to base64
|
||||
@@ -112,11 +114,15 @@ export const CommentEditor = ({
|
||||
commentId,
|
||||
isEdit,
|
||||
commentMessage,
|
||||
onCloseReply,
|
||||
}: CommentEditorProps) => {
|
||||
const [value, setValue] = useState<string>("");
|
||||
const dispatch = useDispatch();
|
||||
const { user } = useSelector((state: RootState) => state.auth);
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const isSmall = useIsSmall();
|
||||
const [value, setValue] = useState<string>('');
|
||||
const { name, address } = useAuth();
|
||||
const setNotification = useSetAtom(setNotificationAtom);
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
useEffect(() => {
|
||||
if (isEdit && commentMessage) {
|
||||
setValue(commentMessage);
|
||||
@@ -127,45 +133,43 @@ export const CommentEditor = ({
|
||||
identifier: string,
|
||||
idForNotification?: string
|
||||
) => {
|
||||
const address = user?.address;
|
||||
const name = user?.name || "";
|
||||
let errorMsg = "";
|
||||
let errorMsg = '';
|
||||
|
||||
if (!address) {
|
||||
errorMsg = "Cannot post: your address isn't available";
|
||||
}
|
||||
if (!name) {
|
||||
errorMsg = "Cannot post without a name";
|
||||
errorMsg = 'Cannot post without a name';
|
||||
}
|
||||
|
||||
if (value.length > 200) {
|
||||
errorMsg = "Comment needs to be under 200 characters";
|
||||
errorMsg = 'Comment needs to be under 200 characters';
|
||||
}
|
||||
|
||||
if (errorMsg) {
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: errorMsg,
|
||||
alertType: "error",
|
||||
})
|
||||
);
|
||||
const notificationObj: AltertObject = {
|
||||
msg: errorMsg,
|
||||
alertType: 'error',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
try {
|
||||
const resourceResponse = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "BLOG_COMMENT",
|
||||
action: 'PUBLISH_QDN_RESOURCE',
|
||||
name: name!,
|
||||
service: 'BLOG_COMMENT',
|
||||
data64: utf8ToBase64(value),
|
||||
identifier: identifier,
|
||||
});
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "Comment successfully published",
|
||||
alertType: "success",
|
||||
})
|
||||
);
|
||||
const notificationObj: AltertObject = {
|
||||
msg: 'Comment successfully published',
|
||||
alertType: 'success',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
|
||||
if (idForNotification) {
|
||||
addItem({
|
||||
id: idForNotification,
|
||||
@@ -176,40 +180,27 @@ export const CommentEditor = ({
|
||||
}
|
||||
|
||||
return resourceResponse;
|
||||
} catch (error: any) {
|
||||
let notificationObj: any = null;
|
||||
if (typeof error === "string") {
|
||||
notificationObj = {
|
||||
msg: error || "Failed to publish comment",
|
||||
alertType: "error",
|
||||
};
|
||||
} else if (typeof error?.error === "string") {
|
||||
notificationObj = {
|
||||
msg: error?.error || "Failed to publish comment",
|
||||
alertType: "error",
|
||||
};
|
||||
} else {
|
||||
notificationObj = {
|
||||
msg: error?.message || "Failed to publish comment",
|
||||
alertType: "error",
|
||||
};
|
||||
}
|
||||
if (!notificationObj) throw new Error("Failed to publish comment");
|
||||
|
||||
dispatch(setNotification(notificationObj));
|
||||
throw new Error("Failed to publish comment");
|
||||
} catch (error) {
|
||||
const isError = error instanceof Error;
|
||||
const message = isError ? error?.message : 'Failed to publish comment';
|
||||
const notificationObj: AltertObject = {
|
||||
msg: message,
|
||||
alertType: 'error',
|
||||
};
|
||||
setNotification(notificationObj);
|
||||
throw new Error('Failed to publish comment');
|
||||
}
|
||||
};
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
const id = uid.rnd();
|
||||
const hashPostId = await hashWordWithoutPublicSalt(postId, 20)
|
||||
const hashPostId = await hashWordWithoutPublicSalt(postId, 20);
|
||||
let identifier = `${COMMENT_BASE}${hashPostId}_base_${id}`;
|
||||
let idForNotification = identifier;
|
||||
|
||||
if (isReply && commentId) {
|
||||
const removeBaseCommentId = commentId;
|
||||
removeBaseCommentId.replace("_base_", "");
|
||||
removeBaseCommentId.replace('_base_', '');
|
||||
identifier = `${COMMENT_BASE}${hashPostId}_reply_${removeBaseCommentId.slice(-6)}_${id}`;
|
||||
idForNotification = commentId;
|
||||
}
|
||||
@@ -222,20 +213,28 @@ export const CommentEditor = ({
|
||||
created: Date.now(),
|
||||
identifier,
|
||||
message: value,
|
||||
service: "BLOG_COMMENT",
|
||||
name: user?.name,
|
||||
service: 'BLOG_COMMENT',
|
||||
name: name,
|
||||
});
|
||||
setValue("");
|
||||
setValue('');
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<CommentInputContainer>
|
||||
<CommentInputContainer
|
||||
sx={{
|
||||
width: isSmall ? '100%' : '90%',
|
||||
}}
|
||||
>
|
||||
<CommentInput
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
id="standard-multiline-flexible"
|
||||
label="Your comment"
|
||||
label={t('core:comments.your_comment', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
multiline
|
||||
maxRows={4}
|
||||
variant="filled"
|
||||
@@ -243,13 +242,53 @@ export const CommentEditor = ({
|
||||
inputProps={{
|
||||
maxLength: 200,
|
||||
}}
|
||||
InputLabelProps={{ style: { fontSize: "18px" } }}
|
||||
onChange={e => setValue(e.target.value)}
|
||||
InputLabelProps={{ style: { fontSize: '18px' } }}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
|
||||
<SubmitCommentButton variant="contained" onClick={handleSubmit}>
|
||||
{isReply ? "Submit reply" : isEdit ? "Edit" : "Submit comment"}
|
||||
</SubmitCommentButton>
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
justifyContent: 'flex-end',
|
||||
display: 'flex',
|
||||
gap: '20px',
|
||||
visibility: isReply
|
||||
? 'visible'
|
||||
: value || isFocused
|
||||
? 'visible'
|
||||
: 'hidden',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
setValue('');
|
||||
if (!onCloseReply) return;
|
||||
onCloseReply();
|
||||
}}
|
||||
variant="text"
|
||||
>
|
||||
{t('core:action.cancel', {
|
||||
postProcess: 'capitalizeEachFirstChar',
|
||||
})}
|
||||
</Button>
|
||||
<SubmitCommentButton
|
||||
variant="contained"
|
||||
color="info"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
{isReply
|
||||
? t('core:comments.submit_reply', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
: isEdit
|
||||
? t('core:action.edit', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})
|
||||
: t('core:action.comment', {
|
||||
postProcess: 'capitalizeFirstChar',
|
||||
})}
|
||||
</SubmitCommentButton>
|
||||
</Box>
|
||||
</CommentInputContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { CommentEditor } from "./CommentEditor";
|
||||
import { Comment } from "./Comment";
|
||||
import { Box, Button, CircularProgress, useTheme } from "@mui/material";
|
||||
import { styled } from "@mui/system";
|
||||
import { useSelector } from "react-redux";
|
||||
import { RootState } from "../../../state/store";
|
||||
import { useNavigate, useLocation } from "react-router-dom";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { CommentEditor } from './CommentEditor';
|
||||
import { Comment } from './Comment';
|
||||
import { Box, Button, CircularProgress, useTheme } from '@mui/material';
|
||||
import { styled } from '@mui/system';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
CommentContainer,
|
||||
CommentEditorContainer,
|
||||
@@ -13,20 +11,21 @@ import {
|
||||
LoadMoreCommentsButton,
|
||||
LoadMoreCommentsButtonRow,
|
||||
NoCommentsRow,
|
||||
} from "./Comments-styles";
|
||||
} from './Comments-styles';
|
||||
import {
|
||||
CrowdfundSubTitle,
|
||||
CrowdfundSubTitleRow,
|
||||
} from "../../Publish/PublishVideo/PublishVideo-styles.tsx";
|
||||
import { COMMENT_BASE } from "../../../constants/Identifiers.ts";
|
||||
import { hashWordWithoutPublicSalt } from "qapp-core";
|
||||
} from '../../Publish/PublishVideo/PublishVideo-styles.tsx';
|
||||
import { COMMENT_BASE } from '../../../constants/Identifiers.ts';
|
||||
import { hashWordWithoutPublicSalt } from 'qapp-core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface CommentSectionProps {
|
||||
postId: string;
|
||||
postName: string;
|
||||
}
|
||||
|
||||
const Panel = styled("div")`
|
||||
const Panel = styled('div')`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: start;
|
||||
@@ -51,19 +50,19 @@ const Panel = styled("div")`
|
||||
}
|
||||
`;
|
||||
export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
const { t } = useTranslation(['core']);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [listComments, setListComments] = useState<any[]>([]);
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
const { user } = useSelector((state: RootState) => state.auth);
|
||||
const [newMessages, setNewMessages] = useState(0);
|
||||
const [loadingComments, setLoadingComments] = useState<boolean>(false);
|
||||
// console.log("postId is: ", postId, " postName is: ", postName);
|
||||
const onSubmit = (obj?: any, isEdit?: boolean) => {
|
||||
if (isEdit) {
|
||||
setListComments((prev: any[]) => {
|
||||
const findCommentIndex = prev.findIndex(
|
||||
item => item?.identifier === obj?.identifier
|
||||
(item) => item?.identifier === obj?.identifier
|
||||
);
|
||||
if (findCommentIndex === -1) return prev;
|
||||
|
||||
@@ -74,7 +73,7 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
|
||||
return;
|
||||
}
|
||||
setListComments(prev => [
|
||||
setListComments((prev) => [
|
||||
...prev,
|
||||
{
|
||||
...obj,
|
||||
@@ -84,9 +83,9 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
|
||||
useEffect(() => {
|
||||
const query = new URLSearchParams(location.search);
|
||||
let commentVar = query?.get("comment");
|
||||
let commentVar = query?.get('comment');
|
||||
if (commentVar) {
|
||||
if (commentVar && commentVar.endsWith("/")) {
|
||||
if (commentVar && commentVar.endsWith('/')) {
|
||||
commentVar = commentVar.slice(0, -1);
|
||||
}
|
||||
setIsOpen(true);
|
||||
@@ -94,9 +93,9 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
const el = document.getElementById(commentVar);
|
||||
if (el) {
|
||||
el.scrollIntoView();
|
||||
el.classList.add("glow");
|
||||
el.classList.add('glow');
|
||||
setTimeout(() => {
|
||||
el.classList.remove("glow");
|
||||
el.classList.remove('glow');
|
||||
}, 2000);
|
||||
}
|
||||
navigate(location.pathname, { replace: true });
|
||||
@@ -107,16 +106,16 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
const getReplies = useCallback(
|
||||
async (commentId, postId) => {
|
||||
const offset = 0;
|
||||
const hashPostId = await hashWordWithoutPublicSalt(postId, 20)
|
||||
const removeBaseCommentId = commentId.replace("_base_", "");
|
||||
const hashPostId = await hashWordWithoutPublicSalt(postId, 20);
|
||||
const removeBaseCommentId = commentId.replace('_base_', '');
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=BLOG_COMMENT&query=${COMMENT_BASE}${hashPostId}_reply_${removeBaseCommentId.slice(
|
||||
-6
|
||||
)}&limit=0&includemetadata=false&offset=${offset}&reverse=false&excludeblocked=true`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
@@ -126,9 +125,9 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
if (comment.identifier && comment.name) {
|
||||
const url = `/arbitrary/BLOG_COMMENT/${comment.name}/${comment.identifier}`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -154,26 +153,24 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
if (isNewMessages && numberOfComments) {
|
||||
offset = numberOfComments;
|
||||
}
|
||||
const hashPostId = await hashWordWithoutPublicSalt(postId, 20)
|
||||
const hashPostId = await hashWordWithoutPublicSalt(postId, 20);
|
||||
const url = `/arbitrary/resources/search?mode=ALL&service=BLOG_COMMENT&query=${COMMENT_BASE}${hashPostId}_base_&limit=20&includemetadata=false&offset=${offset}&reverse=false&excludeblocked=true`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
// console.log("url is: ", url);
|
||||
// console.log("response is: ", responseData);
|
||||
|
||||
let comments: any[] = [];
|
||||
for (const comment of responseData) {
|
||||
if (comment.identifier && comment.name) {
|
||||
const url = `/arbitrary/BLOG_COMMENT/${comment.name}/${comment.identifier}`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -189,7 +186,7 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
}
|
||||
}
|
||||
if (isNewMessages) {
|
||||
setListComments(prev => [...prev, ...comments]);
|
||||
setListComments((prev) => [...prev, ...comments]);
|
||||
setNewMessages(0);
|
||||
} else {
|
||||
setListComments(comments);
|
||||
@@ -209,12 +206,12 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
|
||||
const structuredCommentList = useMemo(() => {
|
||||
return listComments.reduce((acc, curr, index, array) => {
|
||||
if (curr?.identifier?.includes("_reply_")) {
|
||||
if (curr?.identifier?.includes('_reply_')) {
|
||||
return acc;
|
||||
}
|
||||
acc.push({
|
||||
...curr,
|
||||
replies: array.filter(comment =>
|
||||
replies: array.filter((comment) =>
|
||||
comment.identifier.includes(`_reply_${curr.identifier.slice(-6)}`)
|
||||
),
|
||||
});
|
||||
@@ -225,6 +222,13 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
return (
|
||||
<>
|
||||
<Panel>
|
||||
<CommentEditorContainer>
|
||||
<CommentEditor
|
||||
onSubmit={onSubmit}
|
||||
postId={postId}
|
||||
postName={postName}
|
||||
/>
|
||||
</CommentEditorContainer>
|
||||
<CommentsContainer>
|
||||
{loadingComments ? (
|
||||
<NoCommentsRow>
|
||||
@@ -254,25 +258,20 @@ export const CommentSection = ({ postId, postName }: CommentSectionProps) => {
|
||||
getComments(
|
||||
true,
|
||||
listComments.filter(
|
||||
item => !item.identifier.includes("_reply_")
|
||||
(item) => !item.identifier.includes('_reply_')
|
||||
).length
|
||||
);
|
||||
}}
|
||||
variant="contained"
|
||||
size="small"
|
||||
>
|
||||
Load More Comments
|
||||
{t('core:comments.load_more_comments', {
|
||||
postProcess: 'capitalizeEachFirstChar',
|
||||
})}
|
||||
</LoadMoreCommentsButton>
|
||||
</LoadMoreCommentsButtonRow>
|
||||
)}
|
||||
</CommentsContainer>
|
||||
<CommentEditorContainer>
|
||||
<CommentEditor
|
||||
onSubmit={onSubmit}
|
||||
postId={postId}
|
||||
postName={postName}
|
||||
/>
|
||||
</CommentEditorContainer>
|
||||
</Panel>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,281 +1,277 @@
|
||||
import { styled } from "@mui/system";
|
||||
import { Card, Box, Typography, Button, TextField } from "@mui/material";
|
||||
import { styled } from '@mui/system';
|
||||
import { Card, Box, Typography, Button, TextField } from '@mui/material';
|
||||
|
||||
export const StyledCard = styled(Card)(({ theme }) => ({
|
||||
backgroundColor:
|
||||
theme.palette.mode === "light"
|
||||
theme.palette.mode === 'light'
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.primary.dark,
|
||||
maxWidth: "600px",
|
||||
width: "100%",
|
||||
margin: "10px 0px",
|
||||
cursor: "pointer",
|
||||
"@media (max-width: 450px)": {
|
||||
width: "100%;",
|
||||
maxWidth: '600px',
|
||||
width: '100%',
|
||||
margin: '10px 0px',
|
||||
cursor: 'pointer',
|
||||
'@media (max-width: 450px)': {
|
||||
width: '100%;',
|
||||
},
|
||||
}));
|
||||
|
||||
export const CardContentContainer = styled(Box)(({ theme }) => ({
|
||||
backgroundColor:
|
||||
theme.palette.mode === "light"
|
||||
theme.palette.mode === 'light'
|
||||
? theme.palette.primary.dark
|
||||
: theme.palette.primary.light,
|
||||
margin: "5px 10px",
|
||||
borderRadius: "15px",
|
||||
margin: '5px 10px',
|
||||
borderRadius: '15px',
|
||||
}));
|
||||
|
||||
export const CardContentContainerComment = styled(Box)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.mode === "light" ? "#a9d9d038" : "#c3abe414",
|
||||
border: `1px solid ${theme.palette.primary.main}`,
|
||||
margin: "0px",
|
||||
padding: "8px 15px",
|
||||
borderRadius: "8px",
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
// backgroundColor: theme.palette.mode === 'light' ? '#a9d9d038' : '#c3abe414',
|
||||
// border: `1px solid ${theme.palette.primary.main}`,
|
||||
margin: '0px',
|
||||
// padding: '8px 15px',
|
||||
borderRadius: '8px',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}));
|
||||
|
||||
export const StyledCardHeader = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: "5px",
|
||||
padding: "7px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
gap: '5px',
|
||||
padding: '7px',
|
||||
});
|
||||
|
||||
export const StyledCardHeaderComment = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
gap: "7px",
|
||||
padding: "9px 7px",
|
||||
display: 'flex',
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'flex-start',
|
||||
gap: '7px',
|
||||
padding: '0px 7px 9px 0px',
|
||||
});
|
||||
|
||||
export const StyledCardCol = styled(Box)({
|
||||
display: "flex",
|
||||
overflow: "hidden",
|
||||
flexDirection: "column",
|
||||
gap: "2px",
|
||||
alignItems: "flex-start",
|
||||
width: "100%",
|
||||
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%",
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
flexDirection: 'column',
|
||||
gap: '2px',
|
||||
alignItems: 'flex-start',
|
||||
width: '100%',
|
||||
});
|
||||
|
||||
export const StyledCardContent = styled(Box)({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-start",
|
||||
padding: "5px 10px",
|
||||
gap: "10px",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
padding: '5px 10px',
|
||||
gap: '10px',
|
||||
});
|
||||
|
||||
export const StyledCardContentComment = styled(Box)({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "flex-start",
|
||||
padding: "5px 10px",
|
||||
gap: "10px",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'flex-start',
|
||||
// padding: '5px 10px',
|
||||
gap: '10px',
|
||||
});
|
||||
|
||||
export const StyledCardComment = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
letterSpacing: 0,
|
||||
fontWeight: 400,
|
||||
fontWeight: 300,
|
||||
color: theme.palette.text.primary,
|
||||
fontSize: "19px",
|
||||
wordBreak: "break-word",
|
||||
fontSize: '19px',
|
||||
wordBreak: 'break-word',
|
||||
}));
|
||||
|
||||
export const TitleText = styled(Typography)({
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
width: "100%",
|
||||
fontFamily: "Cairo, sans-serif",
|
||||
fontSize: "22px",
|
||||
lineHeight: "1.2",
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
width: '100%',
|
||||
fontSize: '22px',
|
||||
lineHeight: '1.2',
|
||||
});
|
||||
|
||||
export const AuthorText = styled(Typography)({
|
||||
fontFamily: "Raleway, sans-serif",
|
||||
fontSize: "16px",
|
||||
lineHeight: "1.2",
|
||||
fontSize: '16px',
|
||||
lineHeight: '1.2',
|
||||
});
|
||||
|
||||
export const AuthorTextComment = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Montserrat, sans-serif",
|
||||
fontSize: "17px",
|
||||
letterSpacing: "0.3px",
|
||||
fontWeight: 400,
|
||||
fontSize: '17px',
|
||||
letterSpacing: '0.3px',
|
||||
fontWeight: 500,
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: "none",
|
||||
userSelect: 'none',
|
||||
}));
|
||||
export const CreatedTextComment = styled(Typography)(({ theme }) => ({
|
||||
fontSize: '17px',
|
||||
letterSpacing: '0.3px',
|
||||
fontWeight: 300,
|
||||
color: theme.palette.text.primary,
|
||||
userSelect: 'none',
|
||||
}));
|
||||
|
||||
export const IconsBox = styled(Box)({
|
||||
display: "flex",
|
||||
gap: "3px",
|
||||
position: "absolute",
|
||||
top: "12px",
|
||||
right: "5px",
|
||||
transition: "all 0.3s ease-in-out",
|
||||
display: 'flex',
|
||||
gap: '3px',
|
||||
position: 'absolute',
|
||||
top: '12px',
|
||||
right: '5px',
|
||||
transition: 'all 0.3s ease-in-out',
|
||||
});
|
||||
|
||||
export const BookmarkIconContainer = styled(Box)({
|
||||
display: "flex",
|
||||
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;",
|
||||
backgroundColor: "#fbfbfb",
|
||||
color: "#50e3c2",
|
||||
padding: "5px",
|
||||
borderRadius: "3px",
|
||||
transition: "all 0.3s ease-in-out",
|
||||
"&:hover": {
|
||||
cursor: "pointer",
|
||||
transform: "scale(1.1)",
|
||||
display: 'flex',
|
||||
boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;',
|
||||
backgroundColor: '#fbfbfb',
|
||||
color: '#50e3c2',
|
||||
padding: '5px',
|
||||
borderRadius: '3px',
|
||||
transition: 'all 0.3s ease-in-out',
|
||||
'&:hover': {
|
||||
cursor: 'pointer',
|
||||
transform: 'scale(1.1)',
|
||||
},
|
||||
});
|
||||
|
||||
export const BlockIconContainer = styled(Box)({
|
||||
display: "flex",
|
||||
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;",
|
||||
backgroundColor: "#fbfbfb",
|
||||
color: "#c25252",
|
||||
padding: "5px",
|
||||
borderRadius: "3px",
|
||||
transition: "all 0.3s ease-in-out",
|
||||
"&:hover": {
|
||||
cursor: "pointer",
|
||||
transform: "scale(1.1)",
|
||||
display: 'flex',
|
||||
boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;',
|
||||
backgroundColor: '#fbfbfb',
|
||||
color: '#c25252',
|
||||
padding: '5px',
|
||||
borderRadius: '3px',
|
||||
transition: 'all 0.3s ease-in-out',
|
||||
'&:hover': {
|
||||
cursor: 'pointer',
|
||||
transform: 'scale(1.1)',
|
||||
},
|
||||
});
|
||||
|
||||
export const CommentsContainer = styled(Box)({
|
||||
width: "90%",
|
||||
maxWidth: "1000px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: "1",
|
||||
overflow: "auto",
|
||||
width: '100%',
|
||||
maxWidth: '1000px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flex: '1',
|
||||
overflow: 'auto',
|
||||
});
|
||||
|
||||
export const CommentContainer = styled(Box)({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
margin: "25px 0px 50px 0px",
|
||||
maxWidth: "100%",
|
||||
width: "100%",
|
||||
gap: "10px",
|
||||
padding: "0px 5px",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
margin: '10px 0px 50px 0px',
|
||||
maxWidth: '100%',
|
||||
width: '100%',
|
||||
gap: '10px',
|
||||
padding: '0px 5px',
|
||||
});
|
||||
|
||||
export const NoCommentsRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "start",
|
||||
flex: "1",
|
||||
padding: "10px 0px",
|
||||
fontFamily: "Mulish",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'start',
|
||||
flex: '1',
|
||||
padding: '10px 0px',
|
||||
letterSpacing: 0,
|
||||
fontWeight: 400,
|
||||
fontSize: "18px",
|
||||
fontSize: '18px',
|
||||
});
|
||||
|
||||
export const LoadMoreCommentsButtonRow = styled(Box)({
|
||||
display: "flex",
|
||||
display: 'flex',
|
||||
});
|
||||
|
||||
export const EditReplyButton = styled(Button)(({ theme }) => ({
|
||||
width: "30px",
|
||||
alignSelf: "flex-end",
|
||||
width: '30px',
|
||||
alignSelf: 'flex-end',
|
||||
background: theme.palette.primary.light,
|
||||
color: "#ffffff",
|
||||
color: '#ffffff',
|
||||
}));
|
||||
|
||||
export const LoadMoreCommentsButton = styled(Button)(({ theme }) => ({
|
||||
fontFamily: "Montserrat",
|
||||
fontWeight: 400,
|
||||
letterSpacing: "0.2px",
|
||||
fontSize: "15px",
|
||||
letterSpacing: '0.2px',
|
||||
fontSize: '15px',
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
color: "#ffffff",
|
||||
color: '#ffffff',
|
||||
}));
|
||||
|
||||
export const CommentActionButtonRow = styled(Box)({
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "5px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
});
|
||||
|
||||
export const CommentEditorContainer = styled(Box)({
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "start",
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'start',
|
||||
});
|
||||
|
||||
export const CommentDateText = styled(Typography)(({ theme }) => ({
|
||||
fontFamily: "Mulish",
|
||||
letterSpacing: 0,
|
||||
fontWeight: 400,
|
||||
fontSize: "13px",
|
||||
marginLeft: "5px",
|
||||
fontSize: '13px',
|
||||
marginLeft: '5px',
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
export const CommentInputContainer = styled(Box)({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
marginTop: "15px",
|
||||
width: "90%",
|
||||
maxWidth: "1000px",
|
||||
borderRadius: "8px",
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
marginBottom: "25px",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
marginTop: '15px',
|
||||
width: '90%',
|
||||
maxWidth: '1000px',
|
||||