Skip to content

Commit

Permalink
Merge pull request #58 from wlee261/feat/themes-page-implementation
Browse files Browse the repository at this point in the history
feat: themes page implementation
  • Loading branch information
tjtanjin authored Oct 4, 2024
2 parents 91e6c4a + 7371bd0 commit d1e37a3
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 244 deletions.
29 changes: 21 additions & 8 deletions src/components/LandingPage/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,33 @@ export default function HeroSection() {
Browse, rate and share themes for your chatbot today and more!
</h3>
<div className="flex mt-6 flex-col items-center sm:flex-row gap-2">


<Link to={"/themes"}>
<button className='bg-accent-900 hover:bg-gradient-to-r hover:from-secondary-900 px-2 py-1 text-[14px] hover:to-primary-600 transition-colors duration-300 hover:text-accent-900 sm:px-4 sm:py-2 sm:text-lg rounded-lg'>
<Link to={"/themes"}>
<button
className="
bg-accent-900 hover:bg-gradient-to-r hover:from-secondary-900 px-2 py-1 text-[14px] hover:to-primary-600
transition-colors duration-300 hover:text-accent-900 sm:px-4 sm:py-2 sm:text-lg rounded-lg
"
>
Themes
</button>
</Link>
<Link to={"/plugins"}>
<button className='bg-accent-900 hover:bg-gradient-to-r hover:from-secondary-900 px-2 py-1 text-[14px] hover:to-primary-600 transition-colors duration-300 hover:text-accent-900 sm:px-4 sm:py-2 sm:text-lg rounded-lg'>
<Link to={"/plugins"}>
<button
className="
bg-accent-900 hover:bg-gradient-to-r hover:from-secondary-900 px-2 py-1 text-[14px] hover:to-primary-600
transition-colors duration-300 hover:text-accent-900 sm:px-4 sm:py-2 sm:text-lg rounded-lg
"
>
Plugins
</button>
</Link>
<Link to={"https://react-chatbotify.com"}>
<button className='bg-accent-900 hover:bg-gradient-to-r hover:from-secondary-900 px-2 py-1 text-[14px] hover:to-primary-600 transition-colors duration-300 hover:text-accent-900 sm:px-4 sm:py-2 sm:text-lg rounded-lg'>
<Link to={"https://react-chatbotify.com"}>
<button
className="
bg-accent-900 hover:bg-gradient-to-r hover:from-secondary-900 px-2 py-1 text-[14px] hover:to-primary-600
transition-colors duration-300 hover:text-accent-900 sm:px-4 sm:py-2 sm:text-lg rounded-lg
"
>
Documentation
</button>
</Link>
Expand Down
3 changes: 1 addition & 2 deletions src/components/NavigationBar/NavigationBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Link, useNavigate } from 'react-router-dom';

import { handleLogin } from '../../services/authService';
import { useAuth } from '../../context/AuthContext';
import { SiteConfig } from '../../constants/SiteConfig';
import logo from '../../assets/images/logo.png';
import AppThemeToggle from './AppThemeToggle';
import { useTranslation } from 'react-i18next';
Expand Down Expand Up @@ -41,7 +40,7 @@ const NavigationBar = () => {
const navbarRef = useRef<HTMLDivElement>(null)

useEffect(function(){
window.addEventListener('scroll',function(e){
window.addEventListener('scroll',function(){
if(navbarRef.current) {
if(window.scrollY >= 50) {
navbarRef.current.className = navBarClass + ' opacity-80 bg-black'
Expand Down
3 changes: 1 addition & 2 deletions src/components/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,13 @@ const SearchBar: React.FC<Props> = ({ onSearch }) => {

return (
<div className="mb-8">
<h2 className="text-lg font-semibold mb-4">Search</h2>
<input
type="text"
placeholder="Search themes..."
value={query}
onChange={handleChange}
onKeyDown={handleKeyDown}
className="w-full border rounded-md px-3 py-2"
className="border rounded-md px-2 py-1 w-3/4 bg-accent-800 text-xs"

/>
</div>
Expand Down
122 changes: 59 additions & 63 deletions src/components/Themes/ThemeCard.tsx
Original file line number Diff line number Diff line change
@@ -1,91 +1,87 @@
import React, { useState } from 'react';
import React, { useState } from "react";

import { Link } from 'react-router-dom';
import Skeleton from "react-loading-skeleton";

import ThemeModal from './ThemeModal';
import { Theme } from '../../interfaces/Theme';
import FavIcon from '../../assets/images/icon_favorite.svg';
import GitHubIcon from '../../assets/images/icon_github_white.svg';
import { Theme } from "../../interfaces/Theme";
import { useTranslation } from 'react-i18next';
import '../../styles/theme_card.css'
import "../../styles/theme_card.css";
import ThemeModal from "./ThemeModal";
import { InfoIcon } from "lucide-react";

type Props = {
theme: Theme
isPreviewed: boolean
onPreview: (name: string) => void
}
theme: Theme;
isPreviewed: boolean;
onPreview: (name: string) => void;
isLoading: boolean;
};

/**
* Theme card component to hold the details of each theme in the themes page.
*/
const ThemeCard: React.FC<Props> = ({ theme, isPreviewed, onPreview }) => {
const [isFav, setIsFav] = useState(false)
const [viewDetails, setViewDetails] = useState(false)
const ThemeCard: React.FC<Props> = ({ theme, isPreviewed, onPreview, isLoading }) => {
const [viewDetails, setViewDetails] = useState(false);

const onViewDetails = () => {
setViewDetails(true)
}
setViewDetails(true);
};

const onClickPreview = () => {
onPreview(theme.name)
}

const handleCheckboxChange = () => {
onClickPreview();
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {t} = useTranslation();

if (isLoading) {
return (
<div>
<div className="my-4 mx-2 hidden md:block">
<Skeleton height={452} />
</div>
<div className="my-4 mx-2 block md:hidden">
<Skeleton height={148} />
</div>
</div>
);
}

return (
<>
<div className="text-black w-[300px] h-[545px]">
<button
onClick={onViewDetails}
type="button"
className="relative group"
<div
className={`flex flex-row items-center md:items-start md:flex-col
md:w-64 p-4 my-4 mx-2 border-2 border-solid rounded-xl
${isPreviewed ? "border-blue-700" : "border-accent-600"}`}
>
<div
className="flex-1 basis-1/3 md:basis-1/2 mr-3 flex flex-row
overflow-hidden w-32 h-20 md:w-56 md:h-56 rounded-xl"
>
<img
src={theme.themeImg}
className="cursor-pointer w-full h-[400px] scale-80
group-hover:-translate-y-6 transition ease-in-out duration"
alt={theme.name}
/>
<div className="theme-card-details">View Details</div>
</button>
<div className="theme-card-info">
<div>
<div className="flex justify-between">
<p className="theme-card-title">{theme.name}</p>
<button
type="button"
aria-label="Favorite Button"
className={`theme-card-fav ${isFav && 'active'}`}
onClick={() => setIsFav((fav) => !fav)}
>
<img src={FavIcon} alt="fav-icon" />
</button>
</div>
<p className="text-[15px] opacity-80">{theme.description}</p>
</div>
<Link to={`/profile/${theme.github}`} className="theme-card-github">
<img src={GitHubIcon} alt="github-icon" />
</Link>
<div className="flex justify-between">
<h4 className="theme-card-author">{theme.authorName}</h4>
<button
className={`theme-card-preview ${isPreviewed ? 'active' : ''}`}
type="button"
onClick={onClickPreview}
>
Preview
<img src={theme.themeImg} alt={theme.name} className="w-60 h-60 object-cover object-left-top" />
</div>
<div className="flex-1 mr-4 basis-1/2 md:basis-1/3 flex flex-col md:pt-4">
<h2 className="text-accent-50 text-lg font-medium mt-[-4px]">{theme.name}</h2>
<span className="text-accent-300 text-sm">{theme.description}</span>
</div>
<div className="flex-1 basis-1/6 md:basis-1/6 flex flex-col">
<div className="flex items-center text-blue-500">
<button onClick={onViewDetails} className="text-sm my-4 w-fit mr-[3px]">
More Info
</button>
<InfoIcon size={15}/>
</div>
<label className=" ml-[2px] text-accent-50 text-sm md:text-base">
Select
<input type="checkbox" checked={isPreviewed} onChange={handleCheckboxChange} className="ml-2" />
</label>
</div>
</div>
<ThemeModal
isOpen={viewDetails}
theme={theme}
onClose={() => setViewDetails(false)}
/>
<ThemeModal isOpen={viewDetails} theme={theme} onClose={() => setViewDetails(false)} />
</>
)
}
);
};

export default ThemeCard
export default ThemeCard;
43 changes: 22 additions & 21 deletions src/components/Themes/ThemeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { downloadThemeContent } from '../../utils';
import { Theme } from '../../interfaces/Theme';

type ThemeModalProps = {
isOpen: boolean
onClose: () => void
theme: Theme
}
isOpen: boolean;
onClose: () => void;
theme: Theme;
};

/**
* Modal to popup for showing theme details.
*/
const ThemeModal: React.FC<ThemeModalProps> = ({ isOpen, onClose, theme }) => {
const modalRef = useRef<HTMLDivElement>(null)
const modalRef = useRef<HTMLDivElement>(null);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const {t} = useTranslation();
Expand All @@ -26,36 +26,37 @@ const ThemeModal: React.FC<ThemeModalProps> = ({ isOpen, onClose, theme }) => {
modalRef.current &&
!modalRef.current.contains(event.target as Node)
) {
onClose()
onClose();
}
}
};

if (isOpen) {
document.addEventListener('mousedown', handleClickOutside)
document.body.style.overflow = 'hidden'
document.addEventListener('mousedown', handleClickOutside);
document.body.style.overflow = 'hidden';
}

return () => {
document.removeEventListener('mousedown', handleClickOutside)
document.body.style.overflow = 'unset'
}
}, [isOpen, onClose])
document.removeEventListener('mousedown', handleClickOutside);
document.body.style.overflow = 'unset';
};
}, [isOpen, onClose]);

if (!isOpen) return null
if (!isOpen) return null;

const onDownload = () => {
downloadThemeContent(
theme.content.settings,
theme.content.inlineStyles,
theme.content.cssStyles,
theme.name
)
}
);
};

const modalContent = (
<div
className="fixed inset-0 z-50 overflow-y-auto bg-black bg-opacity-50
flex items-center justify-center pointer-events-auto">
flex items-center justify-center pointer-events-auto"
>
<div
ref={modalRef}
className="relative bg-white p-6 rounded-lg shadow-lg max-w-screen-lg w-full m-4"
Expand Down Expand Up @@ -129,12 +130,12 @@ const ThemeModal: React.FC<ThemeModalProps> = ({ isOpen, onClose, theme }) => {
</div>
</div>
</div>
)
);

return ReactDOM.createPortal(
modalContent,
document.getElementById('modal-container') || document.body
)
}
);
};

export default ThemeModal
export default ThemeModal;
Loading

0 comments on commit d1e37a3

Please sign in to comment.