feat(catalog): add 'image size' and 'show OP comment' options

This commit is contained in:
Tom (plebeius.eth)
2024-06-17 21:16:31 +02:00
parent bf806d6990
commit 7f3630e289
7 changed files with 104 additions and 16 deletions
@@ -47,6 +47,10 @@
margin-right: 5px; margin-right: 5px;
} }
.mobileCatalogOptionsPadding {
padding-top: 15px;
}
@media (max-width: 640px) { @media (max-width: 640px) {
.desktopBoardButtons { .desktopBoardButtons {
display: none; display: none;
+44 -2
View File
@@ -7,6 +7,8 @@ import useFeedResetStore from '../../stores/use-feed-reset-store';
import useTimeFilter from '../../hooks/use-time-filter'; import useTimeFilter from '../../hooks/use-time-filter';
import CatalogFilters from '../../views/catalog/catalog-filters/'; import CatalogFilters from '../../views/catalog/catalog-filters/';
import styles from './board-buttons.module.css'; import styles from './board-buttons.module.css';
import useCatalogFiltersStore from '../../stores/use-catalog-filters-store';
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
interface BoardButtonsProps { interface BoardButtonsProps {
address?: string | undefined; address?: string | undefined;
@@ -100,6 +102,35 @@ const SortOptions = () => {
); );
}; };
const ImageSizeOptions = () => {
const { imageSize, setImageSize } = useCatalogStyleStore();
return (
<>
<span>Image Size:</span>&nbsp;
<select value={imageSize} onChange={(e) => setImageSize(e.target.value as 'Small' | 'Large')}>
<option value='Small'>Small</option>
<option value='Large'>Large</option>
</select>
</>
);
};
const ShowOPCommentOption = () => {
const { showOPComment, setShowOPComment } = useCatalogStyleStore();
const { showTextOnlyThreads } = useCatalogFiltersStore();
return (
<>
<span>Show OP Comment:</span>&nbsp;
<select value={showOPComment ? 'On' : 'Off'} onChange={(e) => setShowOPComment(e.target.value === 'On')} disabled={showTextOnlyThreads}>
<option value='Off'>Off</option>
<option value='On'>On</option>
</select>
</>
);
};
export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView, isTopbar = false }: BoardButtonsProps) => { export const TimeFilter = ({ isInAllView, isInCatalogView, isInSubscriptionsView, isTopbar = false }: BoardButtonsProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const params = useParams(); const params = useParams();
@@ -174,7 +205,12 @@ export const MobileBoardButtons = () => {
<> <>
<hr /> <hr />
<div className={styles.options}> <div className={styles.options}>
<SortOptions /> <CatalogFilters /> <div>
<SortOptions /> <ImageSizeOptions />
</div>
<div className={styles.mobileCatalogOptionsPadding}>
<ShowOPCommentOption /> <CatalogFilters />
</div>
</div> </div>
</> </>
)} )}
@@ -227,7 +263,13 @@ export const DesktopBoardButtons = () => {
)} )}
[<RefreshButton />] [<RefreshButton />]
<span className={styles.rightSideButtons}> <span className={styles.rightSideButtons}>
{isInCatalogView && <SortOptions />} {isInCatalogView && (
<>
<SortOptions />
<ImageSizeOptions />
<ShowOPCommentOption />
</>
)}
{(isInAllView || isInSubscriptionsView) && ( {(isInAllView || isInSubscriptionsView) && (
<TimeFilter isInAllView={isInAllView} isInCatalogView={isInCatalogView} isInSubscriptionsView={isInSubscriptionsView} /> <TimeFilter isInAllView={isInAllView} isInCatalogView={isInCatalogView} isInSubscriptionsView={isInSubscriptionsView} />
)} )}
@@ -16,20 +16,24 @@
overflow: hidden; overflow: hidden;
} }
.large {
width: 270px !important;
}
.hidden { .hidden {
opacity: 0.5; opacity: 0.5;
} }
.hiddenThumbnail { .hiddenThumbnail {
width: 150px; width: var(--maxWidth);
height: 150px; height: var(--maxHeight);
background-color: var(--media-thumbnail-background-color); background-color: var(--media-thumbnail-background-color);
display: inline-block; display: inline-block;
} }
.spoilerThumbnail { .spoilerThumbnail {
width: 150px; width: var(--maxWidth);
height: 150px; height: var(--maxHeight);
display: inline-block; display: inline-block;
background-color: black; background-color: black;
color: white !important; color: white !important;
@@ -80,8 +84,8 @@
.post img, .post video, .post audio { .post img, .post video, .post audio {
box-shadow: 0 0 5px rgba(0, 0, 0, 0.25); box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
max-width: 150px; max-width: var(--maxWidth);
max-height: 150px; max-height: var(--maxHeight);
} }
.meta { .meta {
@@ -111,8 +115,8 @@
} }
.loadingSkeleton { .loadingSkeleton {
width: 150px; width: var(--maxWidth);
height: 150px; height: var(--maxHeight);
display: inline-block; display: inline-block;
} }
+16 -4
View File
@@ -7,6 +7,7 @@ import { useFloating, offset, shift, size, autoUpdate, Placement } from '@floati
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import { getFormattedTimeAgo } from '../../lib/utils/time-utils'; import { getFormattedTimeAgo } from '../../lib/utils/time-utils';
import { isAllView } from '../../lib/utils/view-utils'; import { isAllView } from '../../lib/utils/view-utils';
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
import useEditCommentPrivileges from '../../hooks/use-author-privileges'; import useEditCommentPrivileges from '../../hooks/use-author-privileges';
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame'; import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame';
@@ -50,7 +51,16 @@ export const CatalogPostMedia = ({ commentMediaInfo, isOutOfFeed, linkWidth, lin
displayHeight = 'unset'; displayHeight = 'unset';
} }
const thumbnailDimensions = { '--width': displayWidth, '--height': displayHeight } as React.CSSProperties; const { imageSize } = useCatalogStyleStore();
const maxWidth = imageSize === 'Large' ? '250px' : '150px';
const maxHeight = imageSize === 'Large' ? '250px' : '150px';
const CSSProperties = {
'--width': displayWidth,
'--height': displayHeight,
'--maxWidth': maxWidth,
'--maxHeight': maxHeight,
} as React.CSSProperties;
let thumbnailComponent: React.ReactNode = null; let thumbnailComponent: React.ReactNode = null;
@@ -74,7 +84,7 @@ export const CatalogPostMedia = ({ commentMediaInfo, isOutOfFeed, linkWidth, lin
} }
return ( return (
<div className={hasError ? '' : styles.mediaWrapper} style={thumbnailDimensions}> <div className={hasError ? '' : styles.mediaWrapper} style={CSSProperties}>
{!isLoaded && !hasError && type !== 'video' && type !== 'audio' && <span className={styles.loadingSkeleton} />} {!isLoaded && !hasError && type !== 'video' && type !== 'audio' && <span className={styles.loadingSkeleton} />}
{hasError ? <img className={styles.fileDeleted} src='/assets/filedeleted-res.gif' alt='' /> : thumbnailComponent} {hasError ? <img className={styles.fileDeleted} src='/assets/filedeleted-res.gif' alt='' /> : thumbnailComponent}
</div> </div>
@@ -179,9 +189,11 @@ const CatalogPost = ({ post }: { post: Comment }) => {
</div> </div>
); );
const { imageSize, showOPComment } = useCatalogStyleStore();
return ( return (
<> <>
<div className={styles.post}> <div className={`${styles.post} ${imageSize === 'Large' ? styles.large : ''}`}>
<div onMouseOver={() => setHoveredCid(isDescription ? 'd' : isRules ? 'r' : cid)} onMouseLeave={() => setHoveredCid(null)}> <div onMouseOver={() => setHoveredCid(isDescription ? 'd' : isRules ? 'r' : cid)} onMouseLeave={() => setHoveredCid(null)}>
{hidden ? ( {hidden ? (
<Link to={postLink}> <Link to={postLink}>
@@ -226,7 +238,7 @@ const CatalogPost = ({ post }: { post: Comment }) => {
<PostMenuDesktop post={post} /> <PostMenuDesktop post={post} />
</span> </span>
</div> </div>
{hasThumbnail ? postContent : <Link to={postLink}>{postContent}</Link>} {showOPComment && (hasThumbnail ? postContent : <Link to={postLink}>{postContent}</Link>)}
</div> </div>
</div> </div>
{hoveredCid === cid && {hoveredCid === cid &&
+1
View File
@@ -77,6 +77,7 @@ hr {
text-decoration: var(--button-text-decoration-mobile); text-decoration: var(--button-text-decoration-mobile);
user-select: none; user-select: none;
display: inline-block; display: inline-block;
cursor: pointer;
} }
select { select {
+23
View File
@@ -0,0 +1,23 @@
import { create } from 'zustand';
interface CatalogStyleStore {
imageSize: 'Small' | 'Large';
setImageSize: (size: 'Small' | 'Large') => void;
showOPComment: boolean;
setShowOPComment: (value: boolean) => void;
}
const useCatalogStyleStore = create<CatalogStyleStore>((set) => ({
imageSize: (localStorage.getItem('imageSize') as 'Small' | 'Large') || 'Small',
setImageSize: (size: 'Small' | 'Large') => {
set({ imageSize: size });
localStorage.setItem('imageSize', size);
},
showOPComment: localStorage.getItem('showOPComment') === 'false' ? false : true,
setShowOPComment: (value: boolean) => {
set({ showOPComment: value });
localStorage.setItem('showOPComment', value.toString());
},
}));
export default useCatalogStyleStore;
+4 -2
View File
@@ -18,6 +18,7 @@ import SettingsModal from '../../components/settings-modal';
import styles from './catalog.module.css'; import styles from './catalog.module.css';
import _ from 'lodash'; import _ from 'lodash';
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
import useCatalogStyleStore from '../../stores/use-catalog-style-store';
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {}; const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
@@ -77,8 +78,6 @@ const useFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolean, subp
return rows; return rows;
}; };
const columnWidth = 180;
const catalogFilter = (comment: Comment) => { const catalogFilter = (comment: Comment) => {
const commentMediaInfo = getCommentMediaInfo(comment); const commentMediaInfo = getCommentMediaInfo(comment);
const hasThumbnail = getHasThumbnail(commentMediaInfo, comment?.link); const hasThumbnail = getHasThumbnail(commentMediaInfo, comment?.link);
@@ -121,6 +120,9 @@ const Catalog = () => {
return [subplebbitAddress]; return [subplebbitAddress];
}, [isInAllView, isInSubscriptionsView, subplebbitAddress, defaultSubplebbits, subscriptions, showAdultBoards, showGoreBoards]); }, [isInAllView, isInSubscriptionsView, subplebbitAddress, defaultSubplebbits, subscriptions, showAdultBoards, showGoreBoards]);
const { imageSize } = useCatalogStyleStore();
const columnWidth = imageSize === 'Large' ? 270 : 180;
const columnCount = Math.floor(useWindowWidth() / columnWidth); const columnCount = Math.floor(useWindowWidth() / columnWidth);
// postPerPage based on columnCount for optimized feed, dont change value after first render // postPerPage based on columnCount for optimized feed, dont change value after first render
// eslint-disable-next-line // eslint-disable-next-line