mirror of
https://github.com/plebbit/seedit.git
synced 2026-05-18 21:57:54 -04:00
feat(comments): add comments view
This commit is contained in:
@@ -14,7 +14,7 @@ const AccountBar: FC = () => {
|
||||
<div className={styles.header}>
|
||||
<span className={styles.user}>
|
||||
<Link to='/user' onClick={(e) => e.preventDefault()}>
|
||||
{account?.author.shortAddress}
|
||||
{account?.author?.shortAddress}
|
||||
</Link>
|
||||
</span>
|
||||
<span className={styles.separator}>|</span>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
.pageName {
|
||||
font-weight: bold;
|
||||
margin-right: 1ex;
|
||||
font-variant: small-caps;
|
||||
font-size: 1.2em;
|
||||
padding: 43px 0 0 15px;
|
||||
}
|
||||
|
||||
.pageName a {
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tabMenu {
|
||||
list-style: none;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
margin-bottom: -43px;
|
||||
padding-left: 5px;
|
||||
transform: translateY(0.5px);
|
||||
}
|
||||
|
||||
.tabMenu li {
|
||||
display: inline;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tabMenu li a {
|
||||
padding: 2px 6px 0 6px;
|
||||
text-decoration: none;
|
||||
line-height: 20px;
|
||||
color: var(--text-secondary);
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-bottom: 1px solid var(--background);
|
||||
}
|
||||
34
src/components/header/comments-buttons/comments-buttons.tsx
Normal file
34
src/components/header/comments-buttons/comments-buttons.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { FC } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import styles from './comments-buttons.module.css';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
|
||||
const CommentsButtons: FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const { subplebbitAddress, commentCid } = useParams();
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||
const { title, shortAddress } = subplebbit || {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className={styles.pageName}>
|
||||
<Link
|
||||
to={`/p/${subplebbitAddress}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
{title || shortAddress}
|
||||
</Link>
|
||||
</span>
|
||||
<ul className={styles.tabMenu}>
|
||||
<li>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${commentCid}`}>{t('header_comments')}</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommentsButtons;
|
||||
1
src/components/header/comments-buttons/index.ts
Normal file
1
src/components/header/comments-buttons/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {default} from './comments-buttons';
|
||||
@@ -31,40 +31,6 @@
|
||||
transform: translateY(0.5px);
|
||||
}
|
||||
|
||||
.tabMenu {
|
||||
list-style: none;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
margin-bottom: -43px;
|
||||
padding-left: 15px;
|
||||
transform: translateY(0.5px);
|
||||
}
|
||||
|
||||
.tabMenu li {
|
||||
display: inline;
|
||||
font-weight: bold;
|
||||
padding: 0px 3px;
|
||||
}
|
||||
|
||||
.tabMenu li .selected {
|
||||
color: var(--text-secondary);
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-bottom: 1px solid var(--background);
|
||||
}
|
||||
|
||||
.tabMenu li .choice {
|
||||
color: var(--text-primary);
|
||||
background-color: var(--background-secondary);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.tabMenu li a {
|
||||
padding: 2px 6px 0 6px;
|
||||
text-decoration: none;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.temporary {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { FC, useState, useEffect } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { FC } from 'react';
|
||||
import { Link, useLocation, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styles from './header.module.css';
|
||||
import useTheme from '../../hooks/use-theme';
|
||||
import AccountBar from './account-bar';
|
||||
|
||||
const choices = ['/hot', '/new', '/active', '/controversialAll', '/topAll'];
|
||||
import { SortButtons, CommentsButtons } from '../header';
|
||||
|
||||
// prettier-ignore
|
||||
const availableLanguages = ['ar', 'bn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fil', 'fr', 'he', 'hi', 'hu', 'id', 'it', 'ja', 'ko', 'mr', 'nl', 'no', 'pl', 'pt', 'ro', 'ru', 'sq', 'sv', 'te', 'th', 'tr', 'uk', 'ur', 'vi', 'zh'];
|
||||
|
||||
// TODO: move to settings page
|
||||
const Theme: FC = () => {
|
||||
const [theme, setTheme] = useTheme();
|
||||
const { t } = useTranslation();
|
||||
@@ -24,6 +24,7 @@ const Theme: FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// TODO: move to settings page
|
||||
const Language: FC = () => {
|
||||
const { i18n } = useTranslation();
|
||||
const { changeLanguage, language } = i18n;
|
||||
@@ -46,32 +47,17 @@ const Language: FC = () => {
|
||||
};
|
||||
|
||||
const Header: FC = () => {
|
||||
const { sortType } = useParams<{ sortType: string }>();
|
||||
const { t } = useTranslation();
|
||||
const [theme] = useTheme();
|
||||
const [selected, setSelected] = useState(sortType || '/topMonth');
|
||||
const { sortType, subplebbitAddress, commentCid } = useParams();
|
||||
const location = useLocation();
|
||||
|
||||
const labels = [t('header_hot'), t('header_new'), t('header_active'), t('header_controversial'), t('header_top')];
|
||||
let buttons = null;
|
||||
|
||||
useEffect(() => {
|
||||
if (sortType) {
|
||||
setSelected('/' + sortType);
|
||||
} else {
|
||||
setSelected('/hot');
|
||||
}
|
||||
}, [sortType]);
|
||||
|
||||
const handleSelect = (choice: string) => {
|
||||
setSelected(choice);
|
||||
};
|
||||
|
||||
const menuItems = choices.map((choice, index) => (
|
||||
<li key={choice}>
|
||||
<Link to={choice} className={selected === choice ? styles.selected : styles.choice} onClick={() => handleSelect(choice)}>
|
||||
{labels[index]}
|
||||
</Link>
|
||||
</li>
|
||||
));
|
||||
if (location.pathname === `/p/${subplebbitAddress}/c/${commentCid}`) {
|
||||
buttons = <CommentsButtons />;
|
||||
} else if ((location.pathname === `/`) || (sortType && ['hot', 'new', 'active', 'controversialAll', 'topAll'].includes(sortType))) {
|
||||
buttons = <SortButtons />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.header}>
|
||||
@@ -81,14 +67,7 @@ const Header: FC = () => {
|
||||
<img className={styles.logo} src='/assets/logo/seedit.png' alt='logo' />
|
||||
<img src={`${process.env.PUBLIC_URL}/assets/logo/seedit-text-${theme === 'black' ? 'dark' : 'light'}.svg`} className={styles.logoText} alt='logo' />
|
||||
</Link>
|
||||
<ul className={styles.tabMenu}>
|
||||
{menuItems}
|
||||
<li>
|
||||
<Link to='/wiki' className={styles.choice} onClick={(event) => event.preventDefault()}>
|
||||
{t('header_wiki')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
{buttons}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
export {default} from './header';
|
||||
export {default as AccountBar} from './account-bar';
|
||||
export {default as AccountBar} from './account-bar';
|
||||
export {default as SortButtons} from './sort-buttons';
|
||||
export {default as CommentsButtons} from './comments-buttons';
|
||||
1
src/components/header/sort-buttons/index.ts
Normal file
1
src/components/header/sort-buttons/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {default} from './sort-buttons';
|
||||
33
src/components/header/sort-buttons/sort-buttons.module.css
Normal file
33
src/components/header/sort-buttons/sort-buttons.module.css
Normal file
@@ -0,0 +1,33 @@
|
||||
.tabMenu {
|
||||
list-style: none;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
margin-bottom: -43px;
|
||||
padding-left: 15px;
|
||||
transform: translateY(0.5px);
|
||||
}
|
||||
|
||||
.tabMenu li {
|
||||
display: inline;
|
||||
font-weight: bold;
|
||||
padding: 0px 3px;
|
||||
}
|
||||
|
||||
.tabMenu li .selected {
|
||||
color: var(--text-secondary);
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-bottom: 1px solid var(--background);
|
||||
}
|
||||
|
||||
.tabMenu li .choice {
|
||||
color: var(--text-primary);
|
||||
background-color: var(--background-secondary);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.tabMenu li a {
|
||||
padding: 2px 6px 0 6px;
|
||||
text-decoration: none;
|
||||
line-height: 20px;
|
||||
}
|
||||
47
src/components/header/sort-buttons/sort-buttons.tsx
Normal file
47
src/components/header/sort-buttons/sort-buttons.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styles from './sort-buttons.module.css';
|
||||
|
||||
const choices = ['/hot', '/new', '/active', '/controversialAll', '/topAll'];
|
||||
|
||||
const SortButtons: FC = () => {
|
||||
const { sortType } = useParams<{ sortType: string }>();
|
||||
const { t } = useTranslation();
|
||||
const [selected, setSelected] = useState(sortType || '/topMonth');
|
||||
|
||||
const labels = [t('header_hot'), t('header_new'), t('header_active'), t('header_controversial'), t('header_top')];
|
||||
|
||||
const handleSelect = (choice: string) => {
|
||||
setSelected(choice);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (sortType) {
|
||||
setSelected('/' + sortType);
|
||||
} else {
|
||||
setSelected('/hot');
|
||||
}
|
||||
}, [sortType]);
|
||||
|
||||
const menuItems = choices.map((choice, index) => (
|
||||
<li key={choice}>
|
||||
<Link to={choice} className={selected === choice ? styles.selected : styles.choice} onClick={() => handleSelect(choice)}>
|
||||
{labels[index]}
|
||||
</Link>
|
||||
</li>
|
||||
));
|
||||
|
||||
return (
|
||||
<ul className={styles.tabMenu}>
|
||||
{menuItems}
|
||||
<li>
|
||||
<Link to='/wiki' className={styles.choice} onClick={(event) => event.preventDefault()}>
|
||||
{t('header_wiki')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default SortButtons;
|
||||
@@ -12,7 +12,7 @@ interface PostToolsProps {
|
||||
const PostTools: FC<PostToolsProps> = ({ commentCid }) => {
|
||||
const comment = useComment({ commentCid });
|
||||
const subplebbitAddress = comment.subplebbitAddress;
|
||||
const { cid, replyCount, spoiler } = comment;
|
||||
const { cid, replyCount, spoiler } = comment || {};
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
|
||||
@@ -67,12 +67,12 @@ const Post: FC<PostProps> = ({ post, index }) => {
|
||||
<ExpandButton commentCid={cid} expanded={expanded} hasThumbnail={hasThumbnail} toggleExpanded={toggleExpanded} />
|
||||
<p className={styles.tagline}>
|
||||
{t('post_submitted')} {utils.getFormattedTime(timestamp)} {t('post_by')}
|
||||
<Link className={styles.author} to={`u/${author.shortAddress}`} onClick={(e) => e.preventDefault()}>
|
||||
u/{author.shortAddress}
|
||||
<Link className={styles.author} to={`u/${author?.shortAddress}`} onClick={(e) => e.preventDefault()}>
|
||||
u/{author?.shortAddress}
|
||||
</Link>
|
||||
{t('post_to')}
|
||||
<Link className={styles.subplebbit} to={`p/${subplebbitAddress}`} onClick={(e) => e.preventDefault()}>
|
||||
p/{subplebbit.shortAddress}
|
||||
p/{subplebbit?.shortAddress}
|
||||
</Link>
|
||||
</p>
|
||||
<PostTools commentCid={cid} />
|
||||
|
||||
Reference in New Issue
Block a user