mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-24 01:23:08 +03:00
feat(Activity): show the correct number of cards per row
This commit is contained in:
parent
d1a8ea2172
commit
2570a2b126
@ -195,3 +195,24 @@ export const filetypes = {
|
||||
};
|
||||
|
||||
export const linkPreviewSizeLimit = 5000000; //NOTE(martina): 5mb limit for twitter preview images
|
||||
|
||||
// NOTE(amine): used to calculate how many cards will fit into a row in sceneActivity
|
||||
export const grids = {
|
||||
activity: {
|
||||
profileInfo: {
|
||||
width: 260,
|
||||
},
|
||||
},
|
||||
object: {
|
||||
desktop: { width: 248, rowGap: 16 },
|
||||
mobile: { width: 166, rowGap: 8 },
|
||||
},
|
||||
collection: {
|
||||
desktop: { width: 432, rowGap: 16 },
|
||||
mobile: { width: 300, rowGap: 8 },
|
||||
},
|
||||
profile: {
|
||||
desktop: { width: 432, rowGap: 16 },
|
||||
mobile: { width: 344, rowGap: 8 },
|
||||
},
|
||||
};
|
||||
|
@ -235,14 +235,14 @@ export const IMAGE_FIT = css`
|
||||
`;
|
||||
|
||||
/* COMMON GRIDS */
|
||||
export const OBJECTS_PREVIEW_GRID = css`
|
||||
export const OBJECTS_PREVIEW_GRID = (theme) => css`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
|
||||
grid-gap: 24px 16px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.object.desktop.width}px, 1fr));
|
||||
grid-gap: 24px ${theme.grids.object.desktop.rowGap}px;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
grid-gap: 20px 8px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(166px, 1fr));
|
||||
grid-gap: 20px ${theme.grids.object.mobile.rowGap}px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.object.mobile.width}px, 1fr));
|
||||
}
|
||||
`;
|
||||
|
||||
@ -254,26 +254,24 @@ export const BUTTON_RESET = css`
|
||||
${HOVERABLE}
|
||||
`;
|
||||
|
||||
export const COLLECTIONS_PREVIEW_GRID = css`
|
||||
export const COLLECTIONS_PREVIEW_GRID = (theme) => css`
|
||||
display: grid;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(432px, 1fr));
|
||||
grid-gap: 24px 16px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.collection.desktop.width}px, 1fr));
|
||||
grid-gap: 24px ${theme.grids.collection.desktop.rowGap}px;
|
||||
|
||||
@media (max-width: ${Constants.sizes.desktop}px) {
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
grid-gap: 20px 8px;
|
||||
grid-gap: 20px ${theme.grids.collection.mobile.rowGap}px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.collection.mobile.width}px, 1fr));
|
||||
}
|
||||
`;
|
||||
|
||||
export const PROFILE_PREVIEW_GRID = css`
|
||||
export const PROFILE_PREVIEW_GRID = (theme) => css`
|
||||
display: grid;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(432px, 1fr));
|
||||
grid-gap: 24px 16px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.profile.desktop.width}px, 1fr));
|
||||
grid-gap: 24px ${theme.grids.profile.desktop.rowGap}px;
|
||||
|
||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||
grid-gap: 20px 8px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(344px, 1fr));
|
||||
grid-gap: 20px ${theme.grids.profile.mobile.rowGap}px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.profile.mobile.width}px, 1fr));
|
||||
}
|
||||
`;
|
||||
|
@ -29,13 +29,22 @@ const STYLES_VIEWMORE_CONTAINER = (theme) => css`
|
||||
}
|
||||
`;
|
||||
|
||||
export default function ActivityCollectionGroup({ onAction, viewer, group, ...props }) {
|
||||
export default function ActivityCollectionGroup({
|
||||
onAction,
|
||||
viewer,
|
||||
group,
|
||||
nbrOfCollectionsPerRow = 2,
|
||||
...props
|
||||
}) {
|
||||
const { owner, slate, type, createdAt } = group;
|
||||
const { elements, restElements } = React.useMemo(() => {
|
||||
if (!Array.isArray(slate)) {
|
||||
return { elements: [slate] };
|
||||
}
|
||||
return { elements: slate.slice(0, 2), restElements: slate.slice(2) };
|
||||
return {
|
||||
elements: slate.slice(0, nbrOfCollectionsPerRow),
|
||||
restElements: slate.slice(nbrOfCollectionsPerRow),
|
||||
};
|
||||
}, [slate]);
|
||||
|
||||
const [showMore, setShowMore] = React.useState(false);
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as React from "react";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Utilities from "~/common/utilities";
|
||||
import * as Styles from "~/common/styles";
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { motion } from "framer-motion";
|
||||
@ -8,20 +9,9 @@ import { ViewMoreContent, ProfileInfo } from "~/components/core/ActivityGroup/co
|
||||
|
||||
import ObjectPreview from "~/components/core/ObjectPreview";
|
||||
|
||||
const STYLES_OBJECT_GRID = (theme) => css`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
|
||||
grid-gap: 20px 12px;
|
||||
|
||||
@media (max-width: ${theme.sizes.mobile}px) {
|
||||
grid-row-gap: 24px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(169px, 1fr));
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_GROUP_GRID = (theme) => css`
|
||||
display: grid;
|
||||
grid-template-columns: 260px 1fr;
|
||||
grid-template-columns: ${theme.grids.activity.profileInfo.width}px 1fr;
|
||||
grid-row-gap: 32px;
|
||||
border-bottom: 1px solid ${theme.semantic.bgLight};
|
||||
padding-bottom: 24px;
|
||||
@ -38,14 +28,17 @@ const STYLES_VIEWMORE_CONTAINER = (theme) => css`
|
||||
}
|
||||
`;
|
||||
|
||||
export default function ActivityFileGroup({ viewer, group, onAction }) {
|
||||
export default function ActivityFileGroup({ viewer, group, onAction, nbrOfObjectsPerRow = 4 }) {
|
||||
const { file, owner, slate, type, createdAt } = group;
|
||||
|
||||
const { elements, restElements } = React.useMemo(() => {
|
||||
if (!Array.isArray(file)) {
|
||||
return { elements: [file] };
|
||||
}
|
||||
return { elements: file.slice(0, 4), restElements: file.slice(4) };
|
||||
return {
|
||||
elements: file.slice(0, nbrOfObjectsPerRow),
|
||||
restElements: file.slice(nbrOfObjectsPerRow),
|
||||
};
|
||||
}, [file]);
|
||||
|
||||
const [showMore, setShowMore] = React.useState(false);
|
||||
@ -78,7 +71,7 @@ export default function ActivityFileGroup({ viewer, group, onAction }) {
|
||||
onAction={onAction}
|
||||
/>
|
||||
<div>
|
||||
<div css={STYLES_OBJECT_GRID}>
|
||||
<div css={Styles.OBJECTS_PREVIEW_GRID}>
|
||||
{elements.map((file) => (
|
||||
<ObjectPreview viewer={viewer} owner={file.owner} key={file.id} file={file} />
|
||||
))}
|
||||
|
@ -30,14 +30,23 @@ const STYLES_VIEWMORE_CONTAINER = (theme) => css`
|
||||
}
|
||||
`;
|
||||
|
||||
export default function ActivityProfileGroup({ viewer, external, group, onAction }) {
|
||||
export default function ActivityProfileGroup({
|
||||
viewer,
|
||||
external,
|
||||
group,
|
||||
nbrOfProfilesPerRow = 2,
|
||||
onAction,
|
||||
}) {
|
||||
const { owner, user, createdAt } = group;
|
||||
|
||||
const { elements, restElements } = React.useMemo(() => {
|
||||
if (!Array.isArray(user)) {
|
||||
return { elements: [user] };
|
||||
}
|
||||
return { elements: user.slice(0, 3), restElements: user.slice(3) };
|
||||
return {
|
||||
elements: user.slice(0, nbrOfProfilesPerRow),
|
||||
restElements: user.slice(nbrOfProfilesPerRow),
|
||||
};
|
||||
}, [user]);
|
||||
|
||||
const [showMore, setShowMore] = React.useState(false);
|
||||
|
@ -16,7 +16,7 @@ const STYLES_GROUP_GRID = (theme) => css`
|
||||
padding-bottom: 24px;
|
||||
`;
|
||||
|
||||
export default function ActivityGroup({ onAction, viewer, external, group }) {
|
||||
export default function ActivityGroup({ onAction, viewer, external, group, nbrOfCardsPerRow }) {
|
||||
const { type } = group;
|
||||
if (
|
||||
type === "CREATE_FILE" ||
|
||||
@ -24,16 +24,36 @@ export default function ActivityGroup({ onAction, viewer, external, group }) {
|
||||
type === "LIKE_FILE" ||
|
||||
type === "SAVE_COPY"
|
||||
) {
|
||||
return <ActivityFileGroup viewer={viewer} onAction={onAction} group={group} />;
|
||||
return (
|
||||
<ActivityFileGroup
|
||||
nbrOfObjectsPerRow={nbrOfCardsPerRow.object}
|
||||
viewer={viewer}
|
||||
onAction={onAction}
|
||||
group={group}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "CREATE_SLATE" || type === "SUBSCRIBE_SLATE") {
|
||||
return <ActivityCollectionGroup onAction={onAction} viewer={viewer} group={group} />;
|
||||
return (
|
||||
<ActivityCollectionGroup
|
||||
onAction={onAction}
|
||||
viewer={viewer}
|
||||
group={group}
|
||||
nbrOfCollectionsPerRow={nbrOfCardsPerRow.collection}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "SUBSCRIBE_USER") {
|
||||
return (
|
||||
<ActivityProfileGroup onAction={onAction} viewer={viewer} external={external} group={group} />
|
||||
<ActivityProfileGroup
|
||||
nbrOfProfilesPerRow={nbrOfCardsPerRow.profile}
|
||||
onAction={onAction}
|
||||
viewer={viewer}
|
||||
external={external}
|
||||
group={group}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ export default function ThemeProvider({ children }) {
|
||||
font: Constants.font,
|
||||
typescale: Constants.typescale,
|
||||
semantic: Constants.semantic,
|
||||
grids: Constants.grids,
|
||||
...theme,
|
||||
}),
|
||||
[theme]
|
||||
|
@ -41,6 +41,9 @@ export default function SceneActivity({ page, viewer, external, onAction }) {
|
||||
});
|
||||
|
||||
const divRef = React.useRef();
|
||||
|
||||
const nbrOfCardsInRow = useNbrOfCardsPerRow(divRef);
|
||||
|
||||
useIntersection({
|
||||
ref: divRef,
|
||||
onIntersect: () => {
|
||||
@ -69,6 +72,7 @@ export default function SceneActivity({ page, viewer, external, onAction }) {
|
||||
<div css={STYLES_GROUPS_CONTAINER}>
|
||||
{feed?.map((group) => (
|
||||
<ActivityGroup
|
||||
nbrOfCardsPerRow={nbrOfCardsInRow}
|
||||
key={group.id}
|
||||
viewer={viewer}
|
||||
external={external}
|
||||
@ -84,3 +88,50 @@ export default function SceneActivity({ page, viewer, external, onAction }) {
|
||||
</WebsitePrototypeWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
let NbrOfCardsInRow = {};
|
||||
|
||||
function useNbrOfCardsPerRow(ref) {
|
||||
const calculateNbrOfCards = (card) => {
|
||||
const isMobile = window.matchMedia(`(max-width: ${Constants.sizes.mobile}px)`).matches;
|
||||
|
||||
const profileInfoWidth = isMobile ? 0 : Constants.grids.activity.profileInfo.width;
|
||||
const containerWidth = ref.current.offsetWidth - profileInfoWidth;
|
||||
|
||||
const nbrOfCardsWithoutGap = Math.floor(containerWidth / card.width);
|
||||
const gapsWidth = (nbrOfCardsWithoutGap - 1) * card.gap;
|
||||
return Math.floor((containerWidth - gapsWidth) / card.width) || 1;
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (JSON.stringify(NbrOfCardsInRow) !== "{}") return;
|
||||
|
||||
const isMobile = window.matchMedia(`(max-width: ${Constants.sizes.mobile}px)`).matches;
|
||||
const responsiveKey = isMobile ? "mobile" : "desktop";
|
||||
|
||||
const { width: objectPreviewWidth, rowGap: objectPreviewGridRowGap } =
|
||||
Constants.grids.object[responsiveKey];
|
||||
|
||||
NbrOfCardsInRow.object = calculateNbrOfCards({
|
||||
width: objectPreviewWidth,
|
||||
gap: objectPreviewGridRowGap,
|
||||
});
|
||||
|
||||
const { width: collectionPreviewWidth, rowGap: collectionPreviewGridRowGap } =
|
||||
Constants.grids.collection[responsiveKey];
|
||||
|
||||
NbrOfCardsInRow.collection = calculateNbrOfCards({
|
||||
width: collectionPreviewWidth,
|
||||
gap: collectionPreviewGridRowGap,
|
||||
});
|
||||
|
||||
const { width: profilePreviewWidth, rowGap: profilePreviewGridRowGap } =
|
||||
Constants.grids.profile[responsiveKey];
|
||||
NbrOfCardsInRow.profile = calculateNbrOfCards({
|
||||
width: profilePreviewWidth,
|
||||
gap: profilePreviewGridRowGap,
|
||||
});
|
||||
}, []);
|
||||
|
||||
return NbrOfCardsInRow;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user