bro got linted

This commit is contained in:
Barunes Padhy 2024-06-13 20:46:15 +01:00
parent 2369d5c8e6
commit d41d3501c3
38 changed files with 7328 additions and 1398 deletions

View File

@ -0,0 +1,34 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"indent": [
"error",
2
],
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"react/display-name": "off",
"quotes": [
"error",
"single"
],
"no-console": "error"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -43,9 +43,11 @@
"@types/react-dom": "^18.2.22", "@types/react-dom": "^18.2.22",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "^7.34.1", "eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6", "eslint-plugin-react-refresh": "^0.4.6",
"vite": "^5.2.0" "vite": "^5.2.0",
"vite-plugin-eslint": "^1.8.1"
} }
} }

View File

@ -21,9 +21,9 @@ import EditableDataService from './services/editable-data-service'
function App() { function App() {
const [userData, setUserData] = useState(null); const [userData, setUserData] = useState(null);
const [themeConfig, setThemeConfig] = useState(null); const [themeConfig, setThemeConfig] = useState(null);
const [globalTheme, setGlobalTheme] = useState("lightTheme"); const [globalTheme, setGlobalTheme] = useState('lightTheme');
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [notificationMessage, setNotificationMessage] = useState("") const [notificationMessage, setNotificationMessage] = useState('')
const notificationToggler = (message, color) => { const notificationToggler = (message, color) => {
setIsOpen(true) setIsOpen(true)
@ -47,23 +47,22 @@ function App() {
EditableDataService.getData('/data/shared/user-data/').then( response => { EditableDataService.getData('/data/shared/user-data/').then( response => {
let responseData = response.data[0] let responseData = response.data[0]
setUserData({ setUserData({
"name": responseData["name"], 'name': responseData['name'],
"introContent": responseData["intro_content"], 'introContent': responseData['intro_content'],
"profilePhoto": responseData["profile_photo"], 'profilePhoto': responseData['profile_photo'],
"builtWith": responseData["built_with"] 'builtWith': responseData['built_with']
}) })
document.title = responseData.name document.title = responseData.name
} })
)
EditableDataService.getData('/data/shared/theme-config/').then( response =>{ EditableDataService.getData('/data/shared/theme-config/').then( response =>{
let responseData = response.data[0] let responseData = response.data[0]
setThemeConfig({ setThemeConfig({
"defaultTheme": responseData["default_theme"], 'defaultTheme': responseData['default_theme'],
"darkTheme": JSON.parse(responseData["dark_theme"]), 'darkTheme': JSON.parse(responseData['dark_theme']),
"lightTheme": JSON.parse(responseData["light_theme"]) 'lightTheme': JSON.parse(responseData['light_theme'])
})
}) })
}
)
} }
useEffect(() => { useEffect(() => {
@ -76,19 +75,19 @@ function App() {
if (themeConfig && userData && globalTheme) if (themeConfig && userData && globalTheme)
return ( return (
<div className="app-container"> <div className='app-container'>
<Router> <Router>
<Header className="header" ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} notificationToggler={notificationToggler} setInfo={setInfo} /> <Header className='header' ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} notificationToggler={notificationToggler} setInfo={setInfo} />
<div className={`p-0 ${themeConfig[globalTheme].background}`}> <div className={`p-0 ${themeConfig[globalTheme].background}`}>
<Routes> <Routes>
<Route path="/" element={<Home notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} setInfo={setInfo} />} /> <Route path='/' element={<Home notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} setInfo={setInfo} />} />
<Route path="/categories" element={<CategoryList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} /> <Route path='/categories' element={<CategoryList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} />
<Route path="/categories/:categoryID" element={<BlogList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} /> <Route path='/categories/:categoryID' element={<BlogList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} />
<Route path="/blog/:blogID" element={<Blog notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} /> <Route path='/blog/:blogID' element={<Blog notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} />
</Routes> </Routes>
</div> </div>
<Footer notificationToggler={notificationToggler} setInfo={setInfo} className="footer" ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} /> <Footer notificationToggler={notificationToggler} setInfo={setInfo} className='footer' ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} />
<Notification style={{width: '20%'}} className="fixed-top" isOpen={isOpen} message={notificationMessage} /> <Notification style={{width: '20%'}} className='fixed-top' isOpen={isOpen} message={notificationMessage} />
</Router> </Router>
</div> </div>
); );

View File

@ -29,33 +29,32 @@ function BlogList(props) {
const [featuredBlogData, setFeaturedBlogData] = useState(null); const [featuredBlogData, setFeaturedBlogData] = useState(null);
const loadBlogs = () => { const loadBlogs = () => {
EditableDataService.getData(`/data/category/${categoryID}/`).then(response => { EditableDataService.getData(`/data/category/${categoryID}/`).then( response => {
let responseData = response.data let responseData = response.data
let blogMetadata = [] let blogMetadata = []
let localCategoryData = { let localCategoryData = {
"id": responseData["category_id"], 'id': responseData['category_id'],
"name": responseData["name"], 'name': responseData['name'],
"coverImage": responseData["cover_image"], 'coverImage': responseData['cover_image'],
"tagLine": responseData["tagline"], 'tagLine': responseData['tagline'],
"description": responseData["description"], 'description': responseData['description'],
"featuredBlog": responseData["featured_id"], 'featuredBlog': responseData['featured_id'],
"blogMetadata": responseData["blog_metadata"] 'blogMetadata': responseData['blog_metadata']
} }
for (let eachBlog of responseData["blog_metadata"]){ for (let eachBlog of responseData['blog_metadata']){
blogMetadata.push({ blogMetadata.push({
"id": eachBlog["blog_id"], 'id': eachBlog['blog_id'],
"name": eachBlog["name"], 'name': eachBlog['name'],
"description": eachBlog["description"], 'description': eachBlog['description'],
"tagLine": eachBlog["tagline"], 'tagLine': eachBlog['tagline'],
"coverImage": eachBlog["cover_image"], 'coverImage': eachBlog['cover_image'],
"parentCategory": eachBlog["parent_category"] 'parentCategory': eachBlog['parent_category']
}) })
} }
localCategoryData.blogMetadata = blogMetadata localCategoryData.blogMetadata = blogMetadata
setCategoryData(localCategoryData) setCategoryData(localCategoryData)
setFeaturedBlogData(blogMetadata.find(blog => blog.id === localCategoryData.featuredBlog)) setFeaturedBlogData(blogMetadata.find(blog => blog.id === localCategoryData.featuredBlog))
} });
);
} }
useEffect(() => { useEffect(() => {
@ -63,23 +62,23 @@ function BlogList(props) {
}, [categoryID]); }, [categoryID]);
const addNewBlog = () => { const addNewBlog = () => {
EditableDataService.createData(`/data/blog/create/`, { EditableDataService.createData('/data/blog/create/', {
"name": "Enter a blog name", 'name': 'Enter a blog name',
"description": "Enter a description", 'description': 'Enter a description',
"tagline": "Enter a tagline", 'tagline': 'Enter a tagline',
"cover_image": "", 'cover_image': '',
"content_body": "<p></p>", 'content_body': '<p></p>',
"parent_category": categoryID 'parent_category': categoryID
}).then(response => { }).then(() => {
props.notificationToggler("New blog created") props.notificationToggler('New blog created')
loadBlogs() loadBlogs()
}).catch(error => { }).catch(() => {
props.notificationToggler('Failed to add a new blog', 'danger'); props.notificationToggler('Failed to add a new blog', 'danger');
}); });
} }
const updateFeaturedBlog = (featuredId) => { const updateFeaturedBlog = (featuredId) => {
EditableDataService.updateData(`/data/category/update/${categoryID}/`, {"featured_id": featuredId}).then(response=>{ EditableDataService.updateData(`/data/category/update/${categoryID}/`, {'featured_id': featuredId}).then(() =>{
if (featuredId) if (featuredId)
props.notificationToggler('Blog set as featured') props.notificationToggler('Blog set as featured')
else props.notificationToggler('Featured blog removed') else props.notificationToggler('Featured blog removed')
@ -88,30 +87,30 @@ function BlogList(props) {
} }
if (GlobalTheme && ThemeConfig) { if (GlobalTheme && ThemeConfig) {
return ( return (
<Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}> <Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
<Col className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col> <Col className='d-md-block'><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate('/categories/')} className='ms-5 mt-5' outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} /> <CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} />
<Row className="justify-content-center align-items-center"> <Row className='justify-content-center align-items-center'>
<Col className="d-flex flex-column align-items-center"> <Col className='d-flex flex-column align-items-center'>
<div className="w-100"> <div className='w-100'>
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{ width: "100%", border: "none" }}> <Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{ width: '100%', border: 'none' }}>
<CardBody> <CardBody>
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1"> <CardTitle style={{ display: 'grid' }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag='h1'>
{`Blogs in ${categoryData.name}`} {`Blogs in ${categoryData.name}`}
<Button className='mt-2' color={ThemeConfig[GlobalTheme].buttonColor} outline onClick={() => addNewBlog()}>Add New</Button> <Button className='mt-2' color={ThemeConfig[GlobalTheme].buttonColor} outline onClick={() => addNewBlog()}>Add New</Button>
</CardTitle> </CardTitle>
</CardBody> </CardBody>
</Card> </Card>
</div> </div>
<div className="container"> <div className='container'>
{ {
featuredBlogData ? featuredBlogData ?
<CardListViewer <CardListViewer
key={featuredBlogData.id} key={featuredBlogData.id}
totalItems={featuredBlogData === 'nodata' ? 0 : 1} totalItems={featuredBlogData === 'nodata' ? 0 : 1}
cardType={"longCard"} cardType={'longCard'}
resourceType={"blog"} resourceType={'blog'}
textColor={ThemeConfig[GlobalTheme].textColor} textColor={ThemeConfig[GlobalTheme].textColor}
bgColor={ThemeConfig[GlobalTheme].background} bgColor={ThemeConfig[GlobalTheme].background}
borderColor={ThemeConfig[GlobalTheme].borderColor} borderColor={ThemeConfig[GlobalTheme].borderColor}
@ -119,16 +118,16 @@ return (
/> : '' /> : ''
} }
<Row> <Row>
{categoryData === 'loading' ? <Spinner /> : { categoryData === 'loading' ? <Spinner /> :
categoryData.blogMetadata.map((item, index) => ( categoryData.blogMetadata.map((item) => (
<Col key={item.blog_id}> <Col key={item.blog_id}>
<div className={`p-2 ml-2 ${ThemeConfig[GlobalTheme].textColor}`}> <div className={`p-2 ml-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<CardListViewer <CardListViewer
totalItems={categoryData.blogMetadata.length} totalItems={categoryData.blogMetadata.length}
featuredBlog={categoryData.featuredBlog} featuredBlog={categoryData.featuredBlog}
updateFeaturedBlog={updateFeaturedBlog} updateFeaturedBlog={updateFeaturedBlog}
cardType={"smallCard"} cardType={'smallCard'}
resourceType={"blog"} resourceType={'blog'}
textColor={ThemeConfig[GlobalTheme].textColor} textColor={ThemeConfig[GlobalTheme].textColor}
bgColor={ThemeConfig[GlobalTheme].background} bgColor={ThemeConfig[GlobalTheme].background}
borderColor={ThemeConfig[GlobalTheme].borderColor} borderColor={ThemeConfig[GlobalTheme].borderColor}
@ -143,11 +142,9 @@ return (
</Col> </Col>
</Row> </Row>
</Container> </Container>
); );
} else { } else {
return null; return null;
} }
} }
export default BlogList export default BlogList

View File

@ -11,7 +11,7 @@ import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { import {
Container,Row, Col,Spinner, UncontrolledCollapse, Button, ButtonGroup, Card, CardBody, Input, InputGroup, InputGroupText Container,Row, Col,Spinner, Button, ButtonGroup, Input, InputGroup, InputGroupText
} from 'reactstrap'; } from 'reactstrap';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
@ -39,17 +39,17 @@ function Blog(props) {
const toggle = () => setModal(!modal); const toggle = () => setModal(!modal);
const toggleFileModal = () => setFileModal(!fileModal); const toggleFileModal = () => setFileModal(!fileModal);
const setInfo = (event) => { const setInfo = () => {
EditableDataService.updateData(`/data/blog/update/${blogID}/`,{ EditableDataService.updateData(`/data/blog/update/${blogID}/`,{
"name": nameField.current.value, 'name': nameField.current.value,
"description": descriptionField.current.value, 'description': descriptionField.current.value,
"tagline": tagLineField.current.value, 'tagline': tagLineField.current.value,
"content_body": blogContent, 'content_body': blogContent,
"cover_image": coverImage ? coverImage !== '-' ? coverImage : '' : blogData.coverImage 'cover_image': coverImage ? coverImage !== '-' ? coverImage : '' : blogData.coverImage
}).then(response => { }).then(() => {
props.notificationToggler('Blog data saved!'); props.notificationToggler('Blog data saved!');
getInfo() getInfo()
}).catch(error => { }).catch(() => {
props.notificationToggler('Failed to update blog!', 'danger'); props.notificationToggler('Failed to update blog!', 'danger');
}); });
} }
@ -61,10 +61,10 @@ function Blog(props) {
} }
const deleteResource = () => { const deleteResource = () => {
EditableDataService.deleteData(`/data/blog/delete/${blogData.id}/`).then(response => { EditableDataService.deleteData(`/data/blog/delete/${blogData.id}/`).then(() => {
props.notificationToggler('Blog successfully deleted') props.notificationToggler('Blog successfully deleted')
navigate(`/categories/${blogData.parentCategory}`); navigate(`/categories/${blogData.parentCategory}`);
}).catch(error => { }).catch(() => {
props.notificationToggler('Failed to delete blog', 'danger'); props.notificationToggler('Failed to delete blog', 'danger');
}); });
toggle() toggle()
@ -74,16 +74,15 @@ function Blog(props) {
EditableDataService.getData(`/data/blog/${blogID}/`).then(response => { EditableDataService.getData(`/data/blog/${blogID}/`).then(response => {
let responseData = response.data let responseData = response.data
setBlogData({ setBlogData({
"id": responseData["blog_id"], 'id': responseData['blog_id'],
"name": responseData["name"], 'name': responseData['name'],
"description": responseData["description"], 'description': responseData['description'],
"tagLine": responseData["tagline"], 'tagLine': responseData['tagline'],
"coverImage": responseData["cover_image"], 'coverImage': responseData['cover_image'],
"parentCategory": responseData["parent_category"] 'parentCategory': responseData['parent_category']
}) })
setBlogContent(responseData["content_body"]) setBlogContent(responseData['content_body'])
} });
);
} }
useEffect(() => { useEffect(() => {
@ -102,25 +101,25 @@ function Blog(props) {
<Container fluid className={`${ThemeConfig[GlobalTheme].background}`}> <Container fluid className={`${ThemeConfig[GlobalTheme].background}`}>
<ModalComponent modalText={modalText} modalTitle={modalTitle} modal={modal} toggle={toggle} confirmAction={deleteResource}/> <ModalComponent modalText={modalText} modalTitle={modalTitle} modal={modal} toggle={toggle} confirmAction={deleteResource}/>
<MediaUpload setMedia={setCoverImage} notificationToggler={props.notificationToggler} modal={fileModal} toggle={toggleFileModal} resourceType='blog' resourceId={blogData.id}></MediaUpload> <MediaUpload setMedia={setCoverImage} notificationToggler={props.notificationToggler} modal={fileModal} toggle={toggleFileModal} resourceType='blog' resourceId={blogData.id}></MediaUpload>
<Col xs="3" className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/${blogData.parentCategory}`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col> <Col xs='3' className='d-md-block'><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/${blogData.parentCategory}`)} className='ms-5 mt-5' outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<CategoryBar currentPage={blogData.parentCategory} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/> <CategoryBar currentPage={blogData.parentCategory} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig}/>
<Row className="mb-4"> <Row className='mb-4'>
<Col className="p-0"> <Col className='p-0'>
{ {
blogData.coverImage !== "" ? blogData.coverImage !== '' ?
<img <img
src={EditableMediaService.getMedia(blogData.coverImage)} src={EditableMediaService.getMedia(blogData.coverImage)}
alt="Banner" alt='Banner'
style={{ width: '100%', height: 'auto', maxHeight: '20vh', objectFit: 'cover' }} style={{ width: '100%', height: 'auto', maxHeight: '20vh', objectFit: 'cover' }}
/>:"" />:''
} }
</Col> </Col>
</Row> </Row>
<Row className="mr-2 ml-2 mb-2 mt-1 blogContent"> <Row className='mr-2 ml-2 mb-2 mt-1 blogContent'>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
<Col xs={`${window.screen.width >= 765 ? '6':''}`}> <Col xs={`${window.screen.width >= 765 ? '6':''}`}>
<Button color='danger' onClick={() => showModal()} className="mb-5">Delete Blog</Button> <Button color='danger' onClick={() => showModal()} className='mb-5'>Delete Blog</Button>
<ButtonGroup className="mb-5 ms-5"> <ButtonGroup className='mb-5 ms-5'>
<Button <Button
outline outline
color={ThemeConfig[GlobalTheme].buttonColor} color={ThemeConfig[GlobalTheme].buttonColor}
@ -136,39 +135,33 @@ function Blog(props) {
Remove Cover Image Remove Cover Image
</Button> </Button>
</ButtonGroup> </ButtonGroup>
<InputGroup className="mb-3"> <InputGroup className='mb-3'>
<InputGroupText> <InputGroupText>Name</InputGroupText>
Name
</InputGroupText>
<Input innerRef={nameField} defaultValue={blogData.name} /> <Input innerRef={nameField} defaultValue={blogData.name} />
</InputGroup> </InputGroup>
<InputGroup className="mb-3"> <InputGroup className='mb-3'>
<InputGroupText> <InputGroupText>Description</InputGroupText>
Description
</InputGroupText>
<Input innerRef={descriptionField} defaultValue={blogData.description} /> <Input innerRef={descriptionField} defaultValue={blogData.description} />
</InputGroup> </InputGroup>
<InputGroup> <InputGroup>
<InputGroupText> <InputGroupText>Tagline</InputGroupText>
Tagline
</InputGroupText>
<Input innerRef={tagLineField} defaultValue={blogData.tagLine} /> <Input innerRef={tagLineField} defaultValue={blogData.tagLine} />
</InputGroup> </InputGroup>
</Col> </Col>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
</Row> </Row>
<Row className={`my-2 ${ThemeConfig[GlobalTheme].background}`}> <Row className={`my-2 ${ThemeConfig[GlobalTheme].background}`}>
<Col> <Col>
<hr style={{"borderColor": `${ThemeConfig[GlobalTheme].borderColor}`}} /> <hr style={{'borderColor': `${ThemeConfig[GlobalTheme].borderColor}`}} />
</Col> </Col>
</Row> </Row>
<Row className="mr-2 ml-2 mt-1"> <Row className='mr-2 ml-2 mt-1'>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
<Col className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`} style={{marginBottom: '25px'}}> <Col className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`} style={{marginBottom: '25px'}}>
<EditorComponent notificationToggler={props.notificationToggler} setContent={setBlogContent} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={blogContent} resourceType='blog' resourceId={blogData.id}/> <EditorComponent notificationToggler={props.notificationToggler} setContent={setBlogContent} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={blogContent} resourceType='blog' resourceId={blogData.id}/>
<Button className='mt-3 mb-2' onClick={(event) => setInfo(event)} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button> <Button className='mt-3 mb-2' onClick={(event) => setInfo(event)} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button>
</Col> </Col>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
</Row> </Row>
</Container> </Container>
); );

View File

@ -12,12 +12,9 @@ import {
Col, Col,
Container, Container,
Card, Card,
CardImg,
CardTitle, CardTitle,
CardText,
CardBody, CardBody,
Button, Button,
ButtonGroup
} from 'reactstrap'; } from 'reactstrap';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { faLeftLong } from '@fortawesome/free-solid-svg-icons'; import { faLeftLong } from '@fortawesome/free-solid-svg-icons';
@ -42,61 +39,58 @@ function Blogs(props) {
let localCategoryMetadata = [] let localCategoryMetadata = []
for (let eachResponse of responseData){ for (let eachResponse of responseData){
localCategoryMetadata.push({ localCategoryMetadata.push({
"id": eachResponse["category_id"], 'id': eachResponse['category_id'],
"name": eachResponse["name"], 'name': eachResponse['name'],
"featuredBlog": eachResponse["featured_id"], 'featuredBlog': eachResponse['featured_id'],
"description": eachResponse["description"], 'description': eachResponse['description'],
"tagLine": eachResponse["tagline"], 'tagLine': eachResponse['tagline'],
"coverImage": eachResponse["cover_image"] 'coverImage': eachResponse['cover_image']
}) })
} }
setCategoryMetadata(localCategoryMetadata) setCategoryMetadata(localCategoryMetadata)
} });
);
} }
const addToIdsToUpdate = (resourceObject) => { const addToIdsToUpdate = (resourceObject) => {
let localIdsToUpdate = {...idsToUpdate} let localIdsToUpdate = {...idsToUpdate}
localIdsToUpdate[resourceObject.id]={ localIdsToUpdate[resourceObject.id]={
"name": resourceObject.name, 'name': resourceObject.name,
"featured_blog": resourceObject.featuredBlog, 'featured_blog': resourceObject.featuredBlog,
"description": resourceObject.description, 'description': resourceObject.description,
"tagline": resourceObject.tagLine, 'tagline': resourceObject.tagLine,
"cover_image": resourceObject.coverImage 'cover_image': resourceObject.coverImage
} }
setIdsToUpdate(localIdsToUpdate) setIdsToUpdate(localIdsToUpdate)
} }
const deleteResource = (id) => { const deleteResource = (id) => {
EditableDataService.deleteData(`/data/category/delete/${id}/`).then(response => { EditableDataService.deleteData(`/data/category/delete/${id}/`).then(() => {
props.notificationToggler('Category successfully deleted') props.notificationToggler('Category successfully deleted')
setCategoryData() setCategoryData()
}).catch(error => { }).catch(() => {
props.notificationToggler('Failed to delete category', 'danger'); props.notificationToggler('Failed to delete category', 'danger');
}); });
} }
const addNewCategory = () => { const addNewCategory = () => {
EditableDataService.createData('/data/category/create/', { EditableDataService.createData('/data/category/create/', {
"name": "Enter name", 'name': 'Enter name',
"featured_id": "", 'featured_id': '',
"description": "Enter description", 'description': 'Enter description',
"tagline": "Enter tagline", 'tagline': 'Enter tagline',
"cover_image": "" 'cover_image': ''
}).then(response => { }).then(() => {
props.notificationToggler('Category created successfully') props.notificationToggler('Category created successfully')
setCategoryData() setCategoryData()}).catch(() => {
}
).catch(error => {
props.notificationToggler('Failed to add category', 'danger'); props.notificationToggler('Failed to add category', 'danger');
}); });
} }
const updateInfo = () => { const updateInfo = () => {
for (let id of Object.keys(idsToUpdate)) { for (let id of Object.keys(idsToUpdate)) {
EditableDataService.updateData(`/data/category/update/${id}/`, idsToUpdate[id]).then(response=>{ EditableDataService.updateData(`/data/category/update/${id}/`, idsToUpdate[id]).then( () =>{
props.notificationToggler('Category data updated successfully') props.notificationToggler('Category data updated successfully')
}).catch(error => { }).catch( () => {
props.notificationToggler('Failed to update category data', 'danger'); props.notificationToggler('Failed to update category data', 'danger');
}); });
} }
@ -106,32 +100,30 @@ function Blogs(props) {
if (GlobalTheme && ThemeConfig) { if (GlobalTheme && ThemeConfig) {
return ( return (
<Container fluid className={`p-0 mb-2 ${ThemeConfig[GlobalTheme].background}`}> <Container fluid className={`p-0 mb-2 ${ThemeConfig[GlobalTheme].background}`}>
<Col xs="3" className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col> <Col xs='3' className='d-md-block'><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate('/')} className='ms-5 mt-5' outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Row className="justify-content-center align-items-center"> <Row className='justify-content-center align-items-center'>
<Col className="d-flex flex-column align-items-center"> <Col className='d-flex flex-column align-items-center'>
<div className="w-100"> <div className='w-100'>
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: "100%", border: "none"}}> <Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: '100%', border: 'none'}}>
<CardBody> <CardBody>
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1"> <CardTitle style={{ display: 'grid' }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag='h1'>
{"Categories"} {'Categories'}
<Button className='mt-2' color={ThemeConfig[GlobalTheme].buttonColor} outline onClick={() => addNewCategory()}>Add New</Button> <Button className='mt-2' color={ThemeConfig[GlobalTheme].buttonColor} outline onClick={() => addNewCategory()}>Add New</Button>
</CardTitle> </CardTitle>
</CardBody> </CardBody>
</Card> </Card>
</div> </div>
<div className='' style={{ width: '70%', margin: 'auto' }}>
<div className="" style={{ width: '70%', margin: 'auto' }}>
{categoryMetadata.length > 0 ? {categoryMetadata.length > 0 ?
categoryMetadata.map((item, index) => ( categoryMetadata.map((item) => (
<CardListViewer <CardListViewer
key={item.id} key={item.id}
id = {item.id} id = {item.id}
totalItems={categoryMetadata.length} totalItems={categoryMetadata.length}
addToIdsToUpdate={addToIdsToUpdate} addToIdsToUpdate={addToIdsToUpdate}
cardType={"longCard"} cardType={'longCard'}
deleteResource={deleteResource} deleteResource={deleteResource}
resourceType={"categories"} resourceType={'categories'}
textColor={ThemeConfig[GlobalTheme].textColor} textColor={ThemeConfig[GlobalTheme].textColor}
bgColor={ThemeConfig[GlobalTheme].background} bgColor={ThemeConfig[GlobalTheme].background}
borderColor={ThemeConfig[GlobalTheme].borderColor} borderColor={ThemeConfig[GlobalTheme].borderColor}
@ -143,7 +135,6 @@ function Blogs(props) {
<Button className='mt-3 mb-2' onClick={() => updateInfo()} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button> <Button className='mt-3 mb-2' onClick={() => updateInfo()} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button>
</div> </div>
</Col> </Col>
</Row> </Row>
</Container> </Container>
); );

View File

@ -5,7 +5,7 @@ import MediaUpload from './shared/media-upload'
import EditableMediaService from '../services/editable-media-service' import EditableMediaService from '../services/editable-media-service'
function HomePage(props) { function HomePage(props) {
const [introContent, setIntroContent] = useState("") const [introContent, setIntroContent] = useState('')
const [profilePhoto, setProfilePhoto] = useState(false) const [profilePhoto, setProfilePhoto] = useState(false)
const [nameFieldInvalid, setNameFieldInvalid] = useState(false) const [nameFieldInvalid, setNameFieldInvalid] = useState(false)
const [modal, setModal] = useState(false) const [modal, setModal] = useState(false)
@ -16,21 +16,19 @@ function HomePage(props) {
const setInfo = async () => { const setInfo = async () => {
let response = await props.setInfo('/data/shared/update/user-data/', { let response = await props.setInfo('/data/shared/update/user-data/', {
"name": nameField.current.value, 'name': nameField.current.value,
"intro_content": introContent, 'intro_content': introContent,
"profile_photo": profilePhoto ? profilePhoto !== '-' ? profilePhoto : '' : UserData.profilePhoto 'profile_photo': profilePhoto ? profilePhoto !== '-' ? profilePhoto : '' : UserData.profilePhoto
}) })
console.log(response)
if (response === 200) if (response === 200)
props.notificationToggler("Data saved successfully!") props.notificationToggler('Data saved successfully!')
if ([500, 404, 403, 400].includes(response)) if ([500, 404, 403, 400].includes(response))
props.notificationToggler("Something failed!", "danger") props.notificationToggler('Something failed!', 'danger')
} }
const toggle = () => {setModal(!modal)} const toggle = () => {setModal(!modal)}
const showError = (elementValue, fieldType) => { const showError = (elementValue, fieldType) => {
console.log(elementValue)
if (fieldType === 'nameField'){ if (fieldType === 'nameField'){
if (elementValue === '') if (elementValue === '')
setNameFieldInvalid(true) setNameFieldInvalid(true)
@ -54,15 +52,15 @@ function HomePage(props) {
return ( return (
<Container fluid className={`${ThemeConfig[GlobalTheme].textColor} ${ThemeConfig[GlobalTheme].background}`}> <Container fluid className={`${ThemeConfig[GlobalTheme].textColor} ${ThemeConfig[GlobalTheme].background}`}>
<MediaUpload setMedia={setProfilePhoto} notificationToggler={props.notificationToggler} modal={modal} toggle={toggle} resourceType='homepage' resourceId='homepage' /> <MediaUpload setMedia={setProfilePhoto} notificationToggler={props.notificationToggler} modal={modal} toggle={toggle} resourceType='homepage' resourceId='homepage' />
<Row className="mb-4"> <Row className='mb-4'>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
<Col className="p-0"> <Col className='p-0'>
<Row className='d-md-block'> <Row className='d-md-block'>
<Col xs="4" className="d-none d-md-block"></Col> <Col xs='4' className='d-none d-md-block'></Col>
{UserData.profilePhoto !== "" && ( {UserData.profilePhoto !== '' && (
<center><img style={{ width: '180px', height: '180px', objectFit: 'cover' }} className="mt-5 mb-2 rounded-circle" src={EditableMediaService.getMedia(UserData.profilePhoto)} alt="Profile Photo" /></center> <center><img style={{ width: '180px', height: '180px', objectFit: 'cover' }} className='mt-5 mb-2 rounded-circle' src={EditableMediaService.getMedia(UserData.profilePhoto)} alt='Profile Photo' /></center>
)} )}
<Col xs="4" className="d-none d-md-block"></Col> <Col xs='4' className='d-none d-md-block'></Col>
</Row> </Row>
<Row> <Row>
<ButtonGroup className='mt-4'> <ButtonGroup className='mt-4'>
@ -83,25 +81,23 @@ function HomePage(props) {
</ButtonGroup> </ButtonGroup>
</Row> </Row>
</Col> </Col>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
</Row> </Row>
<Row className="mr-2 ml-2 mb-2 mt-1 blogContent"> <Row className='mr-2 ml-2 mb-2 mt-1 blogContent'>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
<Col md="6" xs="12"> <Col md='6' xs='12'>
<InputGroup className='mb-5'> <InputGroup className='mb-5'>
<InputGroupText>Name</InputGroupText> <InputGroupText>Name</InputGroupText>
<Input invalid={nameFieldInvalid} innerRef={nameField} defaultValue={UserData.name} onChange={() => showError(nameField.current.value, 'nameField')}/> <Input invalid={nameFieldInvalid} innerRef={nameField} defaultValue={UserData.name} onChange={() => showError(nameField.current.value, 'nameField')}/>
{nameFieldInvalid && <FormFeedback tooltip className="mt-1"> {nameFieldInvalid && <FormFeedback tooltip className='mt-1'>
This field cannot be empty This field cannot be empty
</FormFeedback>} </FormFeedback>}
</InputGroup> </InputGroup>
<EditorComponent notificationToggler={props.notificationToggler} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={UserData.introContent} setContent={setIntroContent} resourceType='homepage' resourceId='homepage' /> <EditorComponent notificationToggler={props.notificationToggler} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} content={UserData.introContent} setContent={setIntroContent} resourceType='homepage' resourceId='homepage' />
<Button className='mt-3 mb-2' onClick={() => setInfo()} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button> <Button className='mt-3 mb-2' onClick={() => setInfo()} color={ThemeConfig[GlobalTheme].buttonColor} outline>Save Data</Button>
</Col> </Col>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
</Row> </Row>
</Container> </Container>
); );
} }

View File

@ -46,11 +46,11 @@ function CardListViewer(props) {
setTaglineFieldInvalid(false) setTaglineFieldInvalid(false)
} }
props.addToIdsToUpdate({ props.addToIdsToUpdate({
"id": props.id, 'id': props.id,
"name": nameField.current.value, 'name': nameField.current.value,
"featuredBlog": "", 'featuredBlog': '',
"description": descriptionField.current.value, 'description': descriptionField.current.value,
"tagLine": taglineField.current.value, 'tagLine': taglineField.current.value,
}) })
} }
@ -72,15 +72,15 @@ function CardListViewer(props) {
return ( return (
<> <>
<ModalComponent modalText={modalText} modalTitle={modalTitle} modal={modal} toggle={toggle} confirmAction={deleteResource}/> <ModalComponent modalText={modalText} modalTitle={modalTitle} modal={modal} toggle={toggle} confirmAction={deleteResource}/>
<Card color={props.borderColor} outline className={`my-2 ${props.bgColor}`} style={{"width": props.cardType === "smallCard" ? "18rem": "100%"}}> <Card color={props.borderColor} outline className={`my-2 ${props.bgColor}`} style={{'width': props.cardType === 'smallCard' ? '18rem': '100%'}}>
<CardBody> <CardBody>
<CardTitle className={`mb-3 ${props.textColor}`} tag="h5"> <CardTitle className={`mb-3 ${props.textColor}`} tag='h5'>
<InputGroup> <InputGroup>
<InputGroupText> <InputGroupText>
Name Name
</InputGroupText> </InputGroupText>
<Input defaultValue={itemObject.name} invalid={nameFieldInvalid} innerRef={nameField} onChange={() => handleInputUpdate(nameField.current.value, 'nameField')}/> <Input defaultValue={itemObject.name} invalid={nameFieldInvalid} innerRef={nameField} onChange={() => handleInputUpdate(nameField.current.value, 'nameField')}/>
{nameFieldInvalid ? <FormFeedback tooltip className="mt-1"> {nameFieldInvalid ? <FormFeedback tooltip className='mt-1'>
This field cannot be empty This field cannot be empty
</FormFeedback>:''} </FormFeedback>:''}
</InputGroup> </InputGroup>
@ -91,7 +91,7 @@ function CardListViewer(props) {
Description Description
</InputGroupText> </InputGroupText>
<Input defaultValue={itemObject.description} invalid={descriptionFieldInvalid} innerRef={descriptionField} onChange={() => handleInputUpdate(descriptionField.current.value, 'descriptionField')}/> <Input defaultValue={itemObject.description} invalid={descriptionFieldInvalid} innerRef={descriptionField} onChange={() => handleInputUpdate(descriptionField.current.value, 'descriptionField')}/>
{descriptionFieldInvalid ? <FormFeedback tooltip className="mt-1"> {descriptionFieldInvalid ? <FormFeedback tooltip className='mt-1'>
This field cannot be empty This field cannot be empty
</FormFeedback>:''} </FormFeedback>:''}
</InputGroup> </InputGroup>
@ -103,7 +103,7 @@ function CardListViewer(props) {
Tagline Tagline
</InputGroupText> </InputGroupText>
<Input defaultValue={itemObject.tagLine} invalid={taglineFieldInvalid} innerRef={taglineField} onChange={() => handleInputUpdate(taglineField.current.value, 'taglineField')} /> <Input defaultValue={itemObject.tagLine} invalid={taglineFieldInvalid} innerRef={taglineField} onChange={() => handleInputUpdate(taglineField.current.value, 'taglineField')} />
{taglineFieldInvalid ? <FormFeedback tooltip className="mt-1"> {taglineFieldInvalid ? <FormFeedback tooltip className='mt-1'>
This field cannot be empty This field cannot be empty
</FormFeedback>:''} </FormFeedback>:''}
</InputGroup> </InputGroup>
@ -113,7 +113,7 @@ function CardListViewer(props) {
<Link className={`${props.textColor}`} to={`/${props.resourceType}/${itemObject.id}`}> <Link className={`${props.textColor}`} to={`/${props.resourceType}/${itemObject.id}`}>
Open this resource Open this resource
</Link> </Link>
<Button color='danger' onClick={() => showModal()} className="m-2">Delete Category</Button> <Button color='danger' onClick={() => showModal()} className='m-2'>Delete Category</Button>
</CardText> </CardText>
</CardBody> </CardBody>
</Card> </Card>
@ -121,17 +121,17 @@ function CardListViewer(props) {
) )
else else
return ( return (
<Card color={props.borderColor} outline className={`my-2 ${props.bgColor}`} style={{"width": props.cardType === "smallCard" ? "18rem": "100%"}}> <Card color={props.borderColor} outline className={`my-2 ${props.bgColor}`} style={{'width': props.cardType === 'smallCard' ? '18rem': '100%'}}>
{itemObject.coverImage !== "" ? <CardImg src={EditableMediaService.getMedia(itemObject.coverImage)} style={{ "height": "180px", "objectFit": "cover" }} top width="100%" /> : ""} {itemObject.coverImage !== '' ? <CardImg src={EditableMediaService.getMedia(itemObject.coverImage)} style={{ 'height': '180px', 'objectFit': 'cover' }} top width='100%' /> : ''}
<CardBody> <CardBody>
<Link to={`/${props.resourceType}/${itemObject.id}`}> <Link to={`/${props.resourceType}/${itemObject.id}`}>
<CardTitle className={`${props.textColor}`} tag="h3"> <CardTitle className={`${props.textColor}`} tag='h3'>
{itemObject.name} {itemObject.name}
</CardTitle> </CardTitle>
<CardText className={`${props.textColor}`} tag="h5"> <CardText className={`${props.textColor}`} tag='h5'>
{itemObject.description} {itemObject.description}
</CardText> </CardText>
<CardText tag="h6"> <CardText tag='h6'>
<small className={`${props.textColor}`}> <small className={`${props.textColor}`}>
{itemObject.tagLine} {itemObject.tagLine}
</small> </small>
@ -158,6 +158,6 @@ function CardListViewer(props) {
} }
else else
return(<h3 className={`${props.textColor}`}>No items found in this section</h3>) return(<h3 className={`${props.textColor}`}>No items found in this section</h3>)
} }
export default CardListViewer export default CardListViewer

View File

@ -13,12 +13,12 @@ function CategoryBar(props) {
let localCategoryMetadata = [] let localCategoryMetadata = []
for (let eachResponse of responseData){ for (let eachResponse of responseData){
localCategoryMetadata.push({ localCategoryMetadata.push({
"id": eachResponse["category_id"], 'id': eachResponse['category_id'],
"name": eachResponse["name"], 'name': eachResponse['name'],
"featuredBlog": eachResponse["featured_id"], 'featuredBlog': eachResponse['featured_id'],
"description": eachResponse["description"], 'description': eachResponse['description'],
"tagLine": eachResponse["tagline"], 'tagLine': eachResponse['tagline'],
"coverImage": eachResponse["cover_image"] 'coverImage': eachResponse['cover_image']
}) })
} }
setCategoryMetadata(localCategoryMetadata) setCategoryMetadata(localCategoryMetadata)
@ -46,15 +46,15 @@ function CategoryBar(props) {
<Col> <Col>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}>
{categoryMetadata.length > 0 ? {categoryMetadata.length > 0 ?
categoryMetadata.map((item, index) => ( categoryMetadata.map((item) => (
<Button <Button
key={item.id} key={item.id}
className="btn-lg" className='btn-lg'
color={`${ThemeConfig[GlobalTheme].buttonColor}`} color={`${ThemeConfig[GlobalTheme].buttonColor}`}
outline outline
active={props.currentPage === item.id} active={props.currentPage === item.id}
> >
<Link className="p-3" to={`/categories/${item.id}`}> <Link className='p-3' to={`/categories/${item.id}`}>
{item.name} {item.name}
</Link></Button> </Link></Button>
)) : <Spinner /> )) : <Spinner />
@ -65,6 +65,6 @@ function CategoryBar(props) {
</Row> </Row>
</Container> </Container>
); );
}; }
export default CategoryBar; export default CategoryBar;

View File

@ -4,8 +4,6 @@ import EditableDataService from '../../services/editable-data-service';
function FileComponent(props) { function FileComponent(props) {
const [file, setFile] = useState(null); const [file, setFile] = useState(null);
const [resourceType, setResourceType] = useState('');
const [resourceId, setResourceId] = useState('');
const handleFileChange = (event) => { const handleFileChange = (event) => {
setFile(event.target.files[0]); // Assuming single file upload setFile(event.target.files[0]); // Assuming single file upload
@ -20,7 +18,7 @@ function FileComponent(props) {
formData.append('resource_id', props.resourceId); formData.append('resource_id', props.resourceId);
try { try {
const response = await EditableDataService.createData('/data/upload/', formData); await EditableDataService.createData('/data/upload/', formData);
props.notificationToggler('Media uploaded successfully') props.notificationToggler('Media uploaded successfully')
} catch (error) { } catch (error) {
props.notificationToggler('Media upload failed', 'danger') props.notificationToggler('Media upload failed', 'danger')

View File

@ -4,14 +4,12 @@ import {
Container, Container,
Row, Row,
Col, Col,
Nav,
NavLink,
Spinner, Spinner,
Button, Button,
ButtonGroup ButtonGroup
} from 'reactstrap'; } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSun, faMoon, faPen, faBrush } from '@fortawesome/free-solid-svg-icons'; import { faBrush } from '@fortawesome/free-solid-svg-icons';
const Footer = (props) => { const Footer = (props) => {
const GlobalTheme = props.GlobalTheme; const GlobalTheme = props.GlobalTheme;
@ -21,23 +19,23 @@ const Footer = (props) => {
const setInfo = async (colorArea, color) => { const setInfo = async (colorArea, color) => {
let localThemeConfig = {...ThemeConfig} let localThemeConfig = {...ThemeConfig}
localThemeConfig[GlobalTheme].footer[colorArea] = `${color}` localThemeConfig[GlobalTheme].footer[colorArea] = `${color}`
let response = await props.setInfo('/data/shared/update/theme-config/', GlobalTheme === "darkTheme" ? { let response = await props.setInfo('/data/shared/update/theme-config/', GlobalTheme === 'darkTheme' ? {
"dark_theme": JSON.stringify(localThemeConfig[GlobalTheme]), 'dark_theme': JSON.stringify(localThemeConfig[GlobalTheme]),
}:{ }:{
"light_theme": JSON.stringify(localThemeConfig[GlobalTheme]), 'light_theme': JSON.stringify(localThemeConfig[GlobalTheme]),
}) })
if (response === 200) if (response === 200)
props.notificationToggler(`Color set for ${ThemeConfig[GlobalTheme].theme} successfully!`) props.notificationToggler(`Color set for ${ThemeConfig[GlobalTheme].theme} successfully!`)
if ([500, 404, 403].includes(response)) if ([500, 404, 403].includes(response))
props.notificationToggler("Something failed!", "danger") props.notificationToggler('Something failed!', 'danger')
} }
return ( return (
<footer className={`footer p-4 ${ThemeConfig ? ThemeConfig[GlobalTheme].footer['background'] + ' ' + ThemeConfig[GlobalTheme].footer['text'] : ""}`} id="site-footer"> <footer className={`footer p-4 ${ThemeConfig ? ThemeConfig[GlobalTheme].footer['background'] + ' ' + ThemeConfig[GlobalTheme].footer['text'] : ''}`} id='site-footer'>
<Container className='p-1'> <Container className='p-1'>
<Row> <Row>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px', marginRight: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px', marginRight: '15px'}}>
<Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`}> <Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}>
<FontAwesomeIcon icon={faBrush} /> Set color <FontAwesomeIcon icon={faBrush} /> Set color
</Button> </Button>
<Button <Button
@ -66,7 +64,7 @@ const Footer = (props) => {
onClick={() => setInfo('background', 'bg-dark')}/> onClick={() => setInfo('background', 'bg-dark')}/>
</ButtonGroup> </ButtonGroup>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}>
<Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`}> <Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}>
<FontAwesomeIcon icon={faBrush} /> Set footer text color <FontAwesomeIcon icon={faBrush} /> Set footer text color
</Button> </Button>
<Button <Button
@ -76,12 +74,12 @@ const Footer = (props) => {
color='dark' color='dark'
onClick={() => setInfo('text', 'text-black')}>Black</Button> onClick={() => setInfo('text', 'text-black')}>Black</Button>
</ButtonGroup> </ButtonGroup>
<Col md="12"> <Col md='12'>
<div className="blogContent text-center text-md-left mt-3"> <div className='blogContent text-center text-md-left mt-3'>
{new Date().getFullYear()}, <a className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href="/">{ UserData ? UserData.name : <Spinner> Loading... </Spinner> }</a> {new Date().getFullYear()}, <a className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href='/'>{ UserData ? UserData.name : <Spinner> Loading... </Spinner> }</a>
<br /> <br />
<div className='m-2'> <div className='m-2'>
{ UserData.builtWith ? <span>Built with <a target="_blank" className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href="https://github.com/barunespadhy/rangolio">Rangolio</a></span>:""} { UserData.builtWith ? <span>Built with <a target='_blank' className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href='https://github.com/barunespadhy/rangolio' rel="noreferrer">Rangolio</a></span>:''}
</div> </div>
</div> </div>
</Col> </Col>

View File

@ -27,7 +27,7 @@ function MediaLister(props) {
props.notificationToggler('Media deleted') props.notificationToggler('Media deleted')
fetchMedia() fetchMedia()
}) })
.catch(error => { .catch(() => {
props.notificationToggler('Error deleting media', 'danger') props.notificationToggler('Error deleting media', 'danger')
}); });
}; };

View File

@ -21,9 +21,7 @@ function Header(props) {
const ThemeConfig = props.ThemeConfig; const ThemeConfig = props.ThemeConfig;
const UserData = props.UserData; const UserData = props.UserData;
const [collapseClasses, setCollapseClasses] = useState('');
const [themeSelected, setThemeSelected] = useState('lightTheme'); const [themeSelected, setThemeSelected] = useState('lightTheme');
const [defaultThemeConfig, setDefaultThemeConfig] = useState('lightTheme');
const [modal, setModal] = useState(false) const [modal, setModal] = useState(false)
const toggle = () => {setModal(!modal)} const toggle = () => {setModal(!modal)}
@ -34,17 +32,17 @@ function Header(props) {
if (colorArea && color) if (colorArea && color)
localThemeConfig[GlobalTheme].navBar[colorArea] = `${color}` localThemeConfig[GlobalTheme].navBar[colorArea] = `${color}`
let response = await props.setInfo('/data/shared/update/theme-config/', GlobalTheme === "darkTheme" ? { let response = await props.setInfo('/data/shared/update/theme-config/', GlobalTheme === 'darkTheme' ? {
"default_theme": defaultThemeConfig, 'default_theme': defaultThemeConfig,
"dark_theme": JSON.stringify(localThemeConfig[GlobalTheme]), 'dark_theme': JSON.stringify(localThemeConfig[GlobalTheme]),
}:{ }:{
"default_theme": defaultThemeConfig, 'default_theme': defaultThemeConfig,
"light_theme": JSON.stringify(localThemeConfig[GlobalTheme]), 'light_theme': JSON.stringify(localThemeConfig[GlobalTheme]),
}) })
if (response === 200) if (response === 200)
props.notificationToggler(`Color set for ${ThemeConfig[GlobalTheme].theme} successfully!`) props.notificationToggler(`Color set for ${ThemeConfig[GlobalTheme].theme} successfully!`)
if ([500, 404, 403].includes(response)) if ([500, 404, 403].includes(response))
props.notificationToggler("Something failed!", "danger") props.notificationToggler('Something failed!', 'danger')
} }
useEffect(() => { useEffect(() => {
@ -53,41 +51,40 @@ function Header(props) {
useEffect(() => { useEffect(() => {
setThemeSelected(props.ThemeConfig.defaultTheme) setThemeSelected(props.ThemeConfig.defaultTheme)
setDefaultThemeConfig(props.ThemeConfig.defaultTheme)
}, []) }, [])
if (GlobalTheme && ThemeConfig && UserData) if (GlobalTheme && ThemeConfig && UserData)
return ( return (
<header className="header-global" id="site-header"> <header className='header-global' id='site-header'>
<Navbar className={`navbar-horizontal ${ThemeConfig[GlobalTheme].navBar['navBarTheme']} ${ThemeConfig[GlobalTheme].navBar['background']}`} <Navbar className={`navbar-horizontal ${ThemeConfig[GlobalTheme].navBar['navBarTheme']} ${ThemeConfig[GlobalTheme].navBar['background']}`}
expand="lg"> expand='lg'>
<Container> <Container>
<Publish notificationToggler={props.notificationToggler} modal={modal} toggle={toggle} /> <Publish notificationToggler={props.notificationToggler} modal={modal} toggle={toggle} />
<NavbarBrand> <NavbarBrand>
<Link to="/"> <Link to='/'>
{ {
UserData.profilePhoto !== "" ? UserData.profilePhoto !== '' ?
<img <img
style={{ width: '40px', height: '40px', objectFit: 'cover', 'marginRight': '10px' }} style={{ width: '40px', height: '40px', objectFit: 'cover', 'marginRight': '10px' }}
className="rounded-circle" className='rounded-circle'
src={EditableMediaService.getMedia(UserData.profilePhoto)} src={EditableMediaService.getMedia(UserData.profilePhoto)}
/> : "" /> : ''
} }
<Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} size="lg"> <Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`} size='lg'>
{ UserData ? UserData.name : <Spinner> Loading... </Spinner> } { UserData ? UserData.name : <Spinner> Loading... </Spinner> }
</Button> </Button>
</Link> </Link>
</NavbarBrand> </NavbarBrand>
<Nav className="ml-lg-auto" navbar> <Nav className='ml-lg-auto' navbar>
<NavItem> <NavItem>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px', marginRight: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px', marginRight: '15px'}}>
<Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`}> <Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}>
<Link to="/categories"> <Link to='/categories'>
<FontAwesomeIcon icon={faPen} /> Blogs <FontAwesomeIcon icon={faPen} /> Blogs
</Link> </Link>
</Button> </Button>
<Button <Button
color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}
outline outline
onClick={() => {setThemeSelected('lightTheme')}} onClick={() => {setThemeSelected('lightTheme')}}
active={themeSelected === 'lightTheme'} active={themeSelected === 'lightTheme'}
@ -95,7 +92,7 @@ function Header(props) {
<FontAwesomeIcon icon={faSun} /> Light Theme <FontAwesomeIcon icon={faSun} /> Light Theme
</Button> </Button>
<Button <Button
color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}
outline outline
onClick={() => {setThemeSelected('darkTheme')}} onClick={() => {setThemeSelected('darkTheme')}}
active={themeSelected === 'darkTheme'} active={themeSelected === 'darkTheme'}
@ -105,7 +102,7 @@ function Header(props) {
</ButtonGroup> </ButtonGroup>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px', marginRight: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px', marginRight: '15px'}}>
<Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`}> <Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}>
<FontAwesomeIcon icon={faBrush} /> Set color <FontAwesomeIcon icon={faBrush} /> Set color
</Button> </Button>
<Button <Button
@ -134,7 +131,7 @@ function Header(props) {
onClick={() => setInfo('background', 'bg-dark', ThemeConfig['defaultTheme'])}/> onClick={() => setInfo('background', 'bg-dark', ThemeConfig['defaultTheme'])}/>
</ButtonGroup> </ButtonGroup>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}>
<Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`}> <Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}>
<FontAwesomeIcon icon={faBrush} /> Set button color <FontAwesomeIcon icon={faBrush} /> Set button color
</Button> </Button>
<Button <Button
@ -145,20 +142,20 @@ function Header(props) {
onClick={() => setInfo('buttonColor', 'black', ThemeConfig['defaultTheme'])}>Black</Button> onClick={() => setInfo('buttonColor', 'black', ThemeConfig['defaultTheme'])}>Black</Button>
</ButtonGroup> </ButtonGroup>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}>
<Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`}> <Button disabled color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}>
<FontAwesomeIcon icon={faBrush} /> Default Theme <FontAwesomeIcon icon={faBrush} /> Default Theme
</Button> </Button>
<Button <Button
color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}
outline outline
onClick={() => setInfo(null, null, 'lightTheme')}>Light Theme</Button> onClick={() => setInfo(null, null, 'lightTheme')}>Light Theme</Button>
<Button <Button
color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}
outline outline
onClick={() => setInfo(null, null, 'darkTheme')}>Dark Theme</Button> onClick={() => setInfo(null, null, 'darkTheme')}>Dark Theme</Button>
</ButtonGroup> </ButtonGroup>
<Button <Button
color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}
className='ms-5' className='ms-5'
outline outline
onClick={() => toggle()} onClick={() => toggle()}

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Collapse, Button, CardBody, Card, Alert } from 'reactstrap'; import { Collapse, CardBody, Card, Alert } from 'reactstrap';
function Notification(props) { function Notification(props) {
return ( return (

View File

@ -16,8 +16,8 @@ function Publish(props) {
let publishMethods = [] let publishMethods = []
Object.entries(response.data).map(([key, value]) => ( Object.entries(response.data).map(([key, value]) => (
publishMethods.push({ publishMethods.push({
"key_name": key, 'key_name': key,
"name": value["name"] 'name': value['name']
}) })
)) ))
setPublishMethods(publishMethods) setPublishMethods(publishMethods)
@ -29,7 +29,7 @@ function Publish(props) {
const publishData = async (deploy_method) => { const publishData = async (deploy_method) => {
try { try {
setPublishSpinner(true) setPublishSpinner(true)
const response = await EditableDataService.getData(`/data/publish/${deploy_method}/`); await EditableDataService.getData(`/data/publish/${deploy_method}/`);
props.notificationToggler('Deployment Sucess') props.notificationToggler('Deployment Sucess')
setPublishSpinner(false) setPublishSpinner(false)
} catch (error) { } catch (error) {
@ -37,39 +37,30 @@ function Publish(props) {
setPublishSpinner(false) setPublishSpinner(false)
} }
}; };
return ( return (
<div> <div>
<Modal isOpen={props.modal} toggle={props.toggle}> <Modal isOpen={props.modal} toggle={props.toggle}>
<ModalHeader toggle={props.toggle}>Publish Website</ModalHeader> <ModalHeader toggle={props.toggle}>Publish Website</ModalHeader>
<ModalBody> <ModalBody>
<h4> <h4>Select a publish method</h4>
Select a publish method
</h4>
{ {
publishMethods ? publishMethods ?
publishMethods.map((item) => publishMethods.map((item) =>
<div className='mb-3'> <div key={item.key_name} className='mb-3'>
<Button <Button
key={item.key_name}
color='danger' color='danger'
onClick={() => publishData(item.key_name)} onClick={() => publishData(item.key_name)}
> >
{item.name} {item.name}
</Button> </Button>
</div> </div>):''
):""
} }
{ publishSpinner ? { publishSpinner ?
<h5> <h5>Publishing <Spinner /></h5> : ''
Publishing <Spinner />
</h5> : ""
} }
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button color="secondary" onClick={props.toggle}> <Button color='secondary' onClick={props.toggle}>Cancel</Button>
Cancel
</Button>
</ModalFooter> </ModalFooter>
</Modal> </Modal>
</div> </div>

View File

@ -1,7 +1,5 @@
/* /*
extension credits: Angelika Tyborska: https://angelika.me/2023/02/26/how-to-add-editing-image-alt-text-tiptap/ extension credits: Angelika Tyborska: https://angelika.me/2023/02/26/how-to-add-editing-image-alt-text-tiptap/
*/ */
import Image from '@tiptap/extension-image' import Image from '@tiptap/extension-image'
@ -32,7 +30,7 @@ function ImageNode(props) {
<span>!</span> <span>!</span>
} }
{ alt ? { alt ?
<span className="text">Alt text: "{alt}".</span>: <span className="text">Alt text: &ldquo;{alt}&ldquo;.</span>:
<span className="text">Alt text missing.</span> <span className="text">Alt text missing.</span>
} }
<Button className="edit" type="button" onClick={onEditAlt}> <Button className="edit" type="button" onClick={onEditAlt}>

View File

@ -1,6 +1,5 @@
import React, { useCallback, useEffect, useState } from 'react' import React, { useCallback, useEffect, useState } from 'react'
import { import { Button, ButtonGroup } from 'reactstrap';
Button, ButtonGroup, Label, Input } from 'reactstrap';
import { Color } from '@tiptap/extension-color' import { Color } from '@tiptap/extension-color'
import ListItem from '@tiptap/extension-list-item' import ListItem from '@tiptap/extension-list-item'
import TextStyle from '@tiptap/extension-text-style' import TextStyle from '@tiptap/extension-text-style'
@ -87,8 +86,7 @@ const MenuBar = (props) => {
<Button <Button
color={ThemeConfig[GlobalTheme].buttonColor} color={ThemeConfig[GlobalTheme].buttonColor}
onClick={() => editor.chain().focus().setTextAlign('left').run()} onClick={() => editor.chain().focus().setTextAlign('left').run()}
outline outline active={editor.isActive('left')}
active={editor.isActive('left')}
> >
<FontAwesomeIcon icon={faAlignLeft}/> <FontAwesomeIcon icon={faAlignLeft}/>
</Button> </Button>
@ -103,8 +101,7 @@ const MenuBar = (props) => {
<Button <Button
color={ThemeConfig[GlobalTheme].buttonColor} color={ThemeConfig[GlobalTheme].buttonColor}
onClick={() => editor.chain().focus().setTextAlign('right').run()} onClick={() => editor.chain().focus().setTextAlign('right').run()}
outline outline active={editor.isActive('right')}
active={editor.isActive('right')}
> >
<FontAwesomeIcon icon={faAlignRight}/> <FontAwesomeIcon icon={faAlignRight}/>
</Button> </Button>
@ -116,7 +113,7 @@ const MenuBar = (props) => {
> >
<FontAwesomeIcon icon={faAlignJustify}/> <FontAwesomeIcon icon={faAlignJustify}/>
</Button> </Button>
</ButtonGroup > </ButtonGroup>
<ButtonGroup className='mt-2' style={{marginLeft: '10px'}}> <ButtonGroup className='mt-2' style={{marginLeft: '10px'}}>
<Button <Button
color={ThemeConfig[GlobalTheme].buttonColor} color={ThemeConfig[GlobalTheme].buttonColor}

View File

@ -1,4 +1,4 @@
import React, { Suspense, lazy } from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client' import ReactDOM from 'react-dom/client'
import './index.css' import './index.css'
import App from './App' import App from './App'

View File

@ -1,7 +0,0 @@
import axios from 'axios'
const getData = (endPoint) => {
return axios.get(`/data/${endPoint}.json`)
}
export default { getData }

View File

@ -1,5 +0,0 @@
const getMedia = (mediaPath) => {
return `/data/${mediaPath}`;
}
export default { getMedia };

View File

@ -1,9 +1,10 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
import eslint from 'vite-plugin-eslint';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react(), eslint()],
base: '/static/', base: '/static/',
server: { server: {
proxy: { proxy: {

View File

@ -0,0 +1,34 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"indent": [
"error",
2
],
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"react/display-name": "off",
"quotes": [
"error",
"single"
],
"no-console": "error"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -46,9 +46,11 @@
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-react": "^7.34.1", "eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6", "eslint-plugin-react-refresh": "^0.4.6",
"vite": "^5.2.0" "vite": "^5.2.0",
"vite-plugin-eslint": "^1.8.1"
} }
} }

View File

@ -22,9 +22,9 @@ import DataService from './services/data-service'
function App() { function App() {
const [userData, setUserData] = useState(null); const [userData, setUserData] = useState(null);
const [themeConfig, setThemeConfig] = useState(null); const [themeConfig, setThemeConfig] = useState(null);
const [globalTheme, setGlobalTheme] = useState("lightTheme"); const [globalTheme, setGlobalTheme] = useState('lightTheme');
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [notificationMessage, setNotificationMessage] = useState("") const [notificationMessage, setNotificationMessage] = useState('')
const notificationToggler = (message) => { const notificationToggler = (message) => {
setIsOpen(true) setIsOpen(true)
@ -38,13 +38,11 @@ function App() {
DataService.getData('shared/user-data').then( response =>{ DataService.getData('shared/user-data').then( response =>{
setUserData(response.data) setUserData(response.data)
document.title = response.data.name document.title = response.data.name
} })
)
DataService.getData('shared/theme-config').then( response =>{ DataService.getData('shared/theme-config').then( response =>{
setThemeConfig(response.data) setThemeConfig(response.data)
setGlobalTheme(response.data.defaultTheme) setGlobalTheme(response.data.defaultTheme)
} })
)
},[]) },[])
const themeSwitcher = (theme) => { const themeSwitcher = (theme) => {
@ -53,20 +51,20 @@ function App() {
if (themeConfig) if (themeConfig)
return ( return (
<div className="app-container"> <div className='app-container'>
<Router> <Router>
<Header className="header" ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} /> <Header className='header' ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} />
<div className={`p-0 ${themeConfig[globalTheme].background}`}> <div className={`p-0 ${themeConfig[globalTheme].background}`}>
<Notification isOpen={isOpen} message={notificationMessage} /> <Notification isOpen={isOpen} message={notificationMessage} />
<Routes> <Routes>
<Route path="/" element={<Home GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} />} /> <Route path='/' element={<Home GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} />} />
<Route path="/categories" element={<CategoryList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} /> <Route path='/categories' element={<CategoryList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} />
<Route path="/categories/:categoryID" element={<BlogList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} /> <Route path='/categories/:categoryID' element={<BlogList notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} />
<Route path="/blog/:blogID" element={<Blog notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} /> <Route path='/blog/:blogID' element={<Blog notificationToggler={notificationToggler} GlobalTheme={globalTheme} ThemeConfig={themeConfig} />} />
<Route path="*" element={<NotFound validRoutes={['categories', 'blog']} GlobalTheme={globalTheme} ThemeConfig={themeConfig}/>} /> <Route path='*' element={<NotFound validRoutes={['categories', 'blog']} GlobalTheme={globalTheme} ThemeConfig={themeConfig}/>} />
</Routes> </Routes>
</div> </div>
<Footer className="footer" ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} /> <Footer className='footer' ThemeSwitcher={themeSwitcher} GlobalTheme={globalTheme} ThemeConfig={themeConfig} UserData={userData} />
</Router> </Router>
</div> </div>
); );

View File

@ -28,41 +28,39 @@ function BlogList(props) {
const [categoryData, setCategoryData] = useState(null); const [categoryData, setCategoryData] = useState(null);
const [featuredBlogData, setFeaturedBlogData] = useState('loading'); const [featuredBlogData, setFeaturedBlogData] = useState('loading');
const [currentPage, setCurrentPage] = useState('loading');
useEffect(() => { useEffect(() => {
DataService.getData(`category/${categoryID}/category-data`).then(response =>{ DataService.getData(`category/${categoryID}/category-data`).then(response =>{
setCategoryData(response.data); setCategoryData(response.data);
setFeaturedBlogData(response.data.blogMetadata.find(blog => blog.id === response.data.featuredBlog)) setFeaturedBlogData(response.data.blogMetadata.find(blog => blog.id === response.data.featuredBlog))
document.title = 'Blogs in ' + response.data.name document.title = 'Blogs in ' + response.data.name
} });
);
}, [categoryID]); }, [categoryID]);
if (GlobalTheme && ThemeConfig) { if (GlobalTheme && ThemeConfig) {
return ( return (
<Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}> <Container fluid className={`mb-2 p-0 ${ThemeConfig[GlobalTheme].background}`}>
<Col className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/categories/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col> <Col className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate('/categories/')} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} /> <CategoryBar currentPage={categoryID} GlobalTheme={GlobalTheme} ThemeConfig={ThemeConfig} />
<Row className="justify-content-center align-items-center"> <Row className="justify-content-center align-items-center">
<Col className="d-flex flex-column align-items-center"> <Col className="d-flex flex-column align-items-center">
<div className="w-100"> <div className="w-100">
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{ width: "100%", border: "none" }}> <Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{ width: '100%', border: 'none' }}>
<CardBody> <CardBody>
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1"> <CardTitle style={{ display: 'grid' }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag='h1'>
{categoryData ? `Blogs in ${categoryData.name}`:`Loading blogs ${<Spinner/>}`} {categoryData ? `Blogs in ${categoryData.name}`:`Loading blogs ${<Spinner/>}`}
</CardTitle> </CardTitle>
</CardBody> </CardBody>
</Card> </Card>
</div> </div>
<div className="container"> <div className='container'>
{ {
featuredBlogData ? featuredBlogData ?
<CardListViewer <CardListViewer
key={featuredBlogData.id} key={featuredBlogData.id}
totalItems={featuredBlogData === 'nodata' ? 0 : 1} totalItems={featuredBlogData === 'nodata' ? 0 : 1}
cardType={"longCard"} cardType={'longCard'}
resourceType={"blog"} resourceType={'blog'}
textColor={ThemeConfig[GlobalTheme].textColor} textColor={ThemeConfig[GlobalTheme].textColor}
bgColor={ThemeConfig[GlobalTheme].background} bgColor={ThemeConfig[GlobalTheme].background}
borderColor={ThemeConfig[GlobalTheme].borderColor} borderColor={ThemeConfig[GlobalTheme].borderColor}
@ -71,14 +69,14 @@ function BlogList(props) {
} }
<Row> <Row>
{categoryData ? {categoryData ?
categoryData.blogMetadata.map((item, index) => ( categoryData.blogMetadata.map((item) => (
<Col key={item.blog_id}> <Col key={item.blog_id}>
<div className={`p-2 ml-2 ${ThemeConfig[GlobalTheme].textColor}`}> <div className={`p-2 ml-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<CardListViewer <CardListViewer
totalItems={categoryData.blogMetadata.length} totalItems={categoryData.blogMetadata.length}
featuredBlog={categoryData.featuredBlog} featuredBlog={categoryData.featuredBlog}
cardType={"smallCard"} cardType={'smallCard'}
resourceType={"blog"} resourceType={'blog'}
textColor={ThemeConfig[GlobalTheme].textColor} textColor={ThemeConfig[GlobalTheme].textColor}
bgColor={ThemeConfig[GlobalTheme].background} bgColor={ThemeConfig[GlobalTheme].background}
borderColor={ThemeConfig[GlobalTheme].borderColor} borderColor={ThemeConfig[GlobalTheme].borderColor}

View File

@ -34,7 +34,7 @@ function Blog(props) {
node.attribs.target = '_blank'; node.attribs.target = '_blank';
} }
if (node.name === 'img') { if (node.name === 'img') {
const newClasses = `img-fluid mt-2 mb-2 rounded mx-auto d-block`; const newClasses = 'img-fluid mt-2 mb-2 rounded mx-auto d-block';
const existingClasses = node.attribs.class ? `${node.attribs.class} ` : ''; const existingClasses = node.attribs.class ? `${node.attribs.class} ` : '';
node.attribs.class = `${existingClasses}${newClasses}`; node.attribs.class = `${existingClasses}${newClasses}`;
} }
@ -47,8 +47,7 @@ function Blog(props) {
const parsedContent = parse(response.data.contentBody, { replace }); const parsedContent = parse(response.data.contentBody, { replace });
setBlogContent(parsedContent); setBlogContent(parsedContent);
document.title = response.data.name document.title = response.data.name
} });
);
}, []); }, []);
useEffect(() => { useEffect(() => {
@ -71,7 +70,7 @@ function Blog(props) {
src={MediaService.getMedia(blogData.coverImage)} src={MediaService.getMedia(blogData.coverImage)}
alt="Banner" alt="Banner"
style={{ width: '100%', height: 'auto', maxHeight: '20vh', objectFit: 'cover' }} style={{ width: '100%', height: 'auto', maxHeight: '20vh', objectFit: 'cover' }}
/>:"" />:''
} }
</Col> </Col>
</Row> </Row>
@ -101,7 +100,7 @@ function Blog(props) {
<Link className="p-3" to="#" onClick={(e) => { <Link className="p-3" to="#" onClick={(e) => {
e.preventDefault(); e.preventDefault();
navigator.clipboard.writeText(window.location.href).then(() => { navigator.clipboard.writeText(window.location.href).then(() => {
props.notificationToggler("Link copied") props.notificationToggler('Link copied')
}) })
return false; return false;
}}> }}>
@ -145,7 +144,7 @@ function Blog(props) {
</Row> </Row>
<Row className={`my-2 ${ThemeConfig[GlobalTheme].background}`}> <Row className={`my-2 ${ThemeConfig[GlobalTheme].background}`}>
<Col> <Col>
<hr style={{"borderColor": `${ThemeConfig[GlobalTheme].borderColor}`}} /> <hr style={{'borderColor': `${ThemeConfig[GlobalTheme].borderColor}`}} />
</Col> </Col>
</Row> </Row>

View File

@ -12,9 +12,7 @@ import {
Col, Col,
Container, Container,
Card, Card,
CardImg,
CardTitle, CardTitle,
CardText,
CardBody, CardBody,
Button Button
} from 'reactstrap'; } from 'reactstrap';
@ -40,28 +38,28 @@ function Blogs(props) {
return ( return (
<Container fluid className={`p-0 mb-2 ${ThemeConfig[GlobalTheme].background}`}> <Container fluid className={`p-0 mb-2 ${ThemeConfig[GlobalTheme].background}`}>
<Row className="justify-content-center align-items-center"> <Row className='justify-content-center align-items-center'>
<Col className="d-flex flex-column align-items-center"> <Col className='d-flex flex-column align-items-center'>
{/* Top Section - Categories */} {/* Top Section - Categories */}
<div className="w-100"> <div className='w-100'>
<Col xs="3" className="d-md-block"><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate(`/`)} className="ms-5 mt-5" outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col> <Col xs='3' className='d-md-block'><Button color={ThemeConfig[GlobalTheme].buttonColor} onClick={() => navigate('/')} className='ms-5 mt-5' outline><FontAwesomeIcon icon={faLeftLong}/></Button></Col>
<Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: "100%", border: "none"}}> <Card className={`my-2 ${ThemeConfig[GlobalTheme].background}`} style={{width: '100%', border: 'none'}}>
<CardBody> <CardBody>
<CardTitle style={{ display: "grid" }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag="h1"> <CardTitle style={{ display: 'grid' }} className={`${ThemeConfig[GlobalTheme].textColor} justify-content-center`} tag='h1'>
{"Categories"} {'Categories'}
</CardTitle> </CardTitle>
</CardBody> </CardBody>
</Card> </Card>
</div> </div>
{/* Bottom Section - Category Metadata or Spinner */} {/* Bottom Section - Category Metadata or Spinner */}
<div className="" style={{ width: '70%', margin: 'auto' }}> <div className='' style={{ width: '70%', margin: 'auto' }}>
{categoryMetadata ? {categoryMetadata ?
categoryMetadata.length > 0 ? categoryMetadata.map((item, index) => ( categoryMetadata.length > 0 ? categoryMetadata.map((item) => (
<CardListViewer <CardListViewer
key={item.id} key={item.id}
totalItems={categoryMetadata.length} totalItems={categoryMetadata.length}
cardType={"longCard"} cardType={'longCard'}
resourceType={"categories"} resourceType={'categories'}
textColor={ThemeConfig[GlobalTheme].textColor} textColor={ThemeConfig[GlobalTheme].textColor}
bgColor={ThemeConfig[GlobalTheme].background} bgColor={ThemeConfig[GlobalTheme].background}
borderColor={ThemeConfig[GlobalTheme].borderColor} borderColor={ThemeConfig[GlobalTheme].borderColor}

View File

@ -15,7 +15,7 @@ function HomePage(props) {
node.attribs.target = '_blank'; node.attribs.target = '_blank';
} }
if (node.name === 'img') { if (node.name === 'img') {
const newClasses = `img-fluid mt-2 mb-2 rounded mx-auto d-block`; const newClasses = 'img-fluid mt-2 mb-2 rounded mx-auto d-block';
const existingClasses = node.attribs.class ? `${node.attribs.class} ` : ''; const existingClasses = node.attribs.class ? `${node.attribs.class} ` : '';
node.attribs.class = `${existingClasses}${newClasses}`; node.attribs.class = `${existingClasses}${newClasses}`;
} }
@ -29,25 +29,25 @@ function HomePage(props) {
const UserData = props.UserData ? props.UserData : <Spinner> Loading... </Spinner> const UserData = props.UserData ? props.UserData : <Spinner> Loading... </Spinner>
const GlobalTheme = props.GlobalTheme; const GlobalTheme = props.GlobalTheme;
const ThemeConfig = props.ThemeConfig; const ThemeConfig = props.ThemeConfig;
const introContent = props.UserData ? parse(props.UserData.introContent, { replace }) : "" const introContent = props.UserData ? parse(props.UserData.introContent, { replace }) : ''
if (GlobalTheme && ThemeConfig) if (GlobalTheme && ThemeConfig)
return ( return (
<Container fluid className={`p-0 mt-5 ${ThemeConfig[GlobalTheme].background}`}> <Container fluid className={`p-0 mt-5 ${ThemeConfig[GlobalTheme].background}`}>
<div className="d-flex flex-column justify-content-center align-items-center min-vh-82"> <div className='d-flex flex-column justify-content-center align-items-center min-vh-82'>
<Row className="mb-4"> <Row className='mb-4'>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
<Col className="p-0"> <Col className='p-0'>
{UserData.profilePhoto !== "" ? <img style={{ width: '180px', height: '180px', objectFit: 'cover' }} className="rounded-circle" src={MediaService.getMedia(UserData.profilePhoto)} /> : ""} {UserData.profilePhoto !== '' ? <img style={{ width: '180px', height: '180px', objectFit: 'cover' }} className='rounded-circle' src={MediaService.getMedia(UserData.profilePhoto)} /> : ''}
</Col> </Col>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
</Row> </Row>
<Row className={`mb-5 mt-2 ${ThemeConfig[GlobalTheme].textColor}`}> <Row className={`mb-5 mt-2 ${ThemeConfig[GlobalTheme].textColor}`}>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
<Col className="p-4 blogContent"> <Col className='p-4 blogContent'>
<div className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`}>{introContent}</div> <div className={`blogContent ${ThemeConfig[GlobalTheme].textColor}`}>{introContent}</div>
</Col> </Col>
<Col xs="3" className="d-none d-md-block"></Col> <Col xs='3' className='d-none d-md-block'></Col>
</Row> </Row>
</div> </div>
</Container> </Container>

View File

@ -10,17 +10,15 @@ import { Link } from 'react-router-dom';
function CardListViewer(props) { function CardListViewer(props) {
const itemObject = props.itemObject const itemObject = props.itemObject
console.log(itemObject)
if (props.totalItems > 0 && itemObject && Object.keys(itemObject).length !== 0) if (props.totalItems > 0 && itemObject && Object.keys(itemObject).length !== 0)
return ( return (
<Card color={props.borderColor} outline className={`my-2 ${props.bgColor}`} style={{"width": props.cardType === "smallCard" ? "18rem": "100%"}}> <Card color={props.borderColor} outline className={`my-2 ${props.bgColor}`} style={{'width': props.cardType === 'smallCard' ? '18rem': '100%'}}>
{itemObject.coverImage ? <CardImg src={MediaService.getMedia(itemObject.coverImage)} style={{ "height": "180px", "objectFit": "cover" }} top width="100%" /> : ""} {itemObject.coverImage ? <CardImg src={MediaService.getMedia(itemObject.coverImage)} style={{ 'height': '180px', 'objectFit': 'cover' }} top width='100%' /> : ''}
<CardBody> <CardBody>
<Link to={`/${props.resourceType}/${itemObject.id}`}> <Link to={`/${props.resourceType}/${itemObject.id}`}>
<CardTitle className={`${props.textColor}`} tag="h5"> <CardTitle className={`${props.textColor}`} tag='h5'>
{itemObject.name} {itemObject.name}
</CardTitle> </CardTitle>
<CardText className={`${props.textColor}`}> <CardText className={`${props.textColor}`}>
@ -35,7 +33,7 @@ function CardListViewer(props) {
</CardBody> </CardBody>
</Card> </Card>
) )
else else
return(<h3 className={`${props.textColor}`}>No items found in this section</h3>) return(<h3 className={`${props.textColor}`}>No items found in this section</h3>)
} }

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import DataService from '../../services/data-service'; import DataService from '../../services/data-service';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Container, Row, Col, Button, Spinner, ListGroup, ListGroupItem, ButtonGroup } from 'reactstrap'; import { Container, Row, Col, Button, Spinner, ButtonGroup } from 'reactstrap';
function CategoryBar(props) { function CategoryBar(props) {
@ -30,7 +30,7 @@ function CategoryBar(props) {
<Col> <Col>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}>
{categoryMetadata.length > 0 ? {categoryMetadata.length > 0 ?
categoryMetadata.map((item, index) => ( categoryMetadata.map((item) => (
<Button <Button
key={item.id} key={item.id}
className="btn-lg" className="btn-lg"
@ -49,6 +49,6 @@ function CategoryBar(props) {
</Row> </Row>
</Container> </Container>
); );
}; }
export default CategoryBar; export default CategoryBar;

View File

@ -14,7 +14,7 @@ const Footer = (props) => {
if (UserData) if (UserData)
return ( return (
<footer className={`footer p-4 ${ThemeConfig ? ThemeConfig[GlobalTheme].footer['background'] + ' ' + ThemeConfig[GlobalTheme].footer['text'] : ""}`} id="site-footer"> <footer className={`footer p-4 ${ThemeConfig ? ThemeConfig[GlobalTheme].footer['background'] + ' ' + ThemeConfig[GlobalTheme].footer['text'] : ''}`} id="site-footer">
<Container className='p-1'> <Container className='p-1'>
<Row> <Row>
<Col md="12"> <Col md="12">
@ -22,7 +22,7 @@ const Footer = (props) => {
{new Date().getFullYear()}, <a className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href="/">{ UserData ? UserData.name : <Spinner> Loading... </Spinner> }</a> {new Date().getFullYear()}, <a className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href="/">{ UserData ? UserData.name : <Spinner> Loading... </Spinner> }</a>
<br /> <br />
<div className='m-2'> <div className='m-2'>
{ UserData.builtWith ? <span>Built with <a target="_blank" className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href="https://github.com/barunespadhy/rangolio">Rangolio</a></span>:""} { UserData.builtWith ? <span>Built with <a target="_blank" className={`${ThemeConfig[GlobalTheme].linkBackground} ${ThemeConfig[GlobalTheme].linkTextColor}`} href="https://github.com/barunespadhy/rangolio" rel="noreferrer">Rangolio</a></span>:''}
</div> </div>
</div> </div>
</Col> </Col>
@ -30,6 +30,6 @@ const Footer = (props) => {
</Container> </Container>
</footer> </footer>
); );
}; }
export default Footer; export default Footer;

View File

@ -2,15 +2,11 @@
import { import {
Navbar, Navbar,
NavbarBrand, NavbarBrand,
UncontrolledCollapse,
Row,
Col,
Nav, Nav,
NavItem, NavItem,
NavLink,
Container, Container,
Spinner, Spinner,
Button, ButtonGroup, Label, Input Button, ButtonGroup
} from 'reactstrap'; } from 'reactstrap';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import MediaService from '../../services/media-service' import MediaService from '../../services/media-service'
@ -23,8 +19,6 @@ function Header(props) {
const GlobalTheme = props.GlobalTheme; const GlobalTheme = props.GlobalTheme;
const ThemeConfig = props.ThemeConfig; const ThemeConfig = props.ThemeConfig;
const UserData = props.UserData; const UserData = props.UserData;
const [collapseClasses, setCollapseClasses] = useState('');
const [themeSelected, setThemeSelected] = useState('lightTheme'); const [themeSelected, setThemeSelected] = useState('lightTheme');
useEffect(() => { useEffect(() => {
@ -37,35 +31,35 @@ function Header(props) {
if (GlobalTheme && ThemeConfig && UserData) if (GlobalTheme && ThemeConfig && UserData)
return ( return (
<header className="header-global" id="site-header"> <header className='header-global' id='site-header'>
<Navbar className={`navbar-horizontal ${ThemeConfig[GlobalTheme].navBar['navBarTheme']} ${ThemeConfig[GlobalTheme].navBar['background']}`} <Navbar className={`navbar-horizontal ${ThemeConfig[GlobalTheme].navBar['navBarTheme']} ${ThemeConfig[GlobalTheme].navBar['background']}`}
expand="lg"> expand='lg'>
<Container> <Container>
<NavbarBrand> <NavbarBrand>
<Link to="/"> <Link to='/'>
{ {
UserData.profilePhoto !== "" ? UserData.profilePhoto !== '' ?
<img <img
style={{ width: '40px', height: '40px', objectFit: 'cover', 'marginRight': '10px' }} style={{ width: '40px', height: '40px', objectFit: 'cover', 'marginRight': '10px' }}
className="rounded-circle" className='rounded-circle'
src={MediaService.getMedia(UserData.profilePhoto)} src={MediaService.getMedia(UserData.profilePhoto)}
/> : "" /> : ''
} }
<Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} size="lg"> <Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`} size='lg'>
{ UserData ? UserData.name : <Spinner> Loading... </Spinner> } { UserData ? UserData.name : <Spinner> Loading... </Spinner> }
</Button> </Button>
</Link> </Link>
</NavbarBrand> </NavbarBrand>
<Nav className="ml-lg-auto" navbar> <Nav className='ml-lg-auto' navbar>
<NavItem> <NavItem>
<ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}> <ButtonGroup style={{marginTop: '15px', marginBottom: '15px'}}>
<Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`}> <Button color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}>
<Link to="/categories"> <Link to='/categories'>
<FontAwesomeIcon icon={faPen} /> Blogs <FontAwesomeIcon icon={faPen} /> Blogs
</Link> </Link>
</Button> </Button>
<Button <Button
color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}
outline outline
onClick={() => {setThemeSelected('lightTheme')}} onClick={() => {setThemeSelected('lightTheme')}}
active={themeSelected === 'lightTheme'} active={themeSelected === 'lightTheme'}
@ -73,7 +67,7 @@ function Header(props) {
<FontAwesomeIcon icon={faSun} /> Light Theme <FontAwesomeIcon icon={faSun} /> Light Theme
</Button> </Button>
<Button <Button
color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ""}`} color={`${ThemeConfig ? ThemeConfig[GlobalTheme].navBar['buttonColor'] : ''}`}
outline outline
onClick={() => {setThemeSelected('darkTheme')}} onClick={() => {setThemeSelected('darkTheme')}}
active={themeSelected === 'darkTheme'} active={themeSelected === 'darkTheme'}

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Collapse, Button, CardBody, Card, Alert } from 'reactstrap'; import { Collapse, CardBody, Card, Alert } from 'reactstrap';
function Notification(props) { function Notification(props) {
return ( return (

View File

@ -1,4 +1,4 @@
import React, { Suspense, lazy } from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client' import ReactDOM from 'react-dom/client'
import './index.css' import './index.css'
import App from './App.jsx' import App from './App.jsx'

View File

@ -1,17 +1,18 @@
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react' import react from '@vitejs/plugin-react'
import eslint from 'vite-plugin-eslint';
console.log(process.env.BUILD_ENV)
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
react(), react(),
eslint(),
process.env.BUILD_ENV === 'ghpages' ? { process.env.BUILD_ENV === 'ghpages' ? {
name: 'inject-ghpages-fix', name: 'inject-ghpages-fix',
transformIndexHtml(html) { transformIndexHtml(html) {
return html.replace( return html.replace(
'<div id="root"></div>', '<div id="root"></div>',
"<div id='root'></div><script type='text/javascript'>(function(l) {if (l.search[1] === '/' ) {var decoded = l.search.slice(1).split('&').map(function(s) {return s.replace(/~and~/g, '&')}).join('?');window.history.replaceState(null, null,l.pathname.slice(0, -1) + decoded + l.hash);}}(window.location))</script>" '<div id="root"></div><script type="text/javascript">(function(l) {if (l.search[1] === "/" ) {var decoded = l.search.slice(1).split("&").map(function(s) {return s.replace(/~and~/g, "&")}).join("?");window.history.replaceState(null, null,l.pathname.slice(0, -1) + decoded + l.hash);}}(window.location))</script>'
); );
} }
} : '' } : ''