mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-24 17:44:50 +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
|
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 */
|
/* COMMON GRIDS */
|
||||||
export const OBJECTS_PREVIEW_GRID = css`
|
export const OBJECTS_PREVIEW_GRID = (theme) => css`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.object.desktop.width}px, 1fr));
|
||||||
grid-gap: 24px 16px;
|
grid-gap: 24px ${theme.grids.object.desktop.rowGap}px;
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
grid-gap: 20px 8px;
|
grid-gap: 20px ${theme.grids.object.mobile.rowGap}px;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(166px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.object.mobile.width}px, 1fr));
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -254,26 +254,24 @@ export const BUTTON_RESET = css`
|
|||||||
${HOVERABLE}
|
${HOVERABLE}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const COLLECTIONS_PREVIEW_GRID = css`
|
export const COLLECTIONS_PREVIEW_GRID = (theme) => css`
|
||||||
display: grid;
|
display: grid;
|
||||||
display: grid;
|
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.collection.desktop.width}px, 1fr));
|
||||||
grid-template-columns: repeat(auto-fill, minmax(432px, 1fr));
|
grid-gap: 24px ${theme.grids.collection.desktop.rowGap}px;
|
||||||
grid-gap: 24px 16px;
|
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.desktop}px) {
|
@media (max-width: ${Constants.sizes.desktop}px) {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
grid-gap: 20px ${theme.grids.collection.mobile.rowGap}px;
|
||||||
grid-gap: 20px 8px;
|
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;
|
||||||
display: grid;
|
grid-template-columns: repeat(auto-fill, minmax(${theme.grids.profile.desktop.width}px, 1fr));
|
||||||
grid-template-columns: repeat(auto-fill, minmax(432px, 1fr));
|
grid-gap: 24px ${theme.grids.profile.desktop.rowGap}px;
|
||||||
grid-gap: 24px 16px;
|
|
||||||
|
|
||||||
@media (max-width: ${Constants.sizes.mobile}px) {
|
@media (max-width: ${Constants.sizes.mobile}px) {
|
||||||
grid-gap: 20px 8px;
|
grid-gap: 20px ${theme.grids.profile.mobile.rowGap}px;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(344px, 1fr));
|
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 { owner, slate, type, createdAt } = group;
|
||||||
const { elements, restElements } = React.useMemo(() => {
|
const { elements, restElements } = React.useMemo(() => {
|
||||||
if (!Array.isArray(slate)) {
|
if (!Array.isArray(slate)) {
|
||||||
return { elements: [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]);
|
}, [slate]);
|
||||||
|
|
||||||
const [showMore, setShowMore] = React.useState(false);
|
const [showMore, setShowMore] = React.useState(false);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as Strings from "~/common/strings";
|
import * as Strings from "~/common/strings";
|
||||||
import * as Utilities from "~/common/utilities";
|
import * as Utilities from "~/common/utilities";
|
||||||
|
import * as Styles from "~/common/styles";
|
||||||
|
|
||||||
import { css } from "@emotion/react";
|
import { css } from "@emotion/react";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
@ -8,20 +9,9 @@ import { ViewMoreContent, ProfileInfo } from "~/components/core/ActivityGroup/co
|
|||||||
|
|
||||||
import ObjectPreview from "~/components/core/ObjectPreview";
|
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`
|
const STYLES_GROUP_GRID = (theme) => css`
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 260px 1fr;
|
grid-template-columns: ${theme.grids.activity.profileInfo.width}px 1fr;
|
||||||
grid-row-gap: 32px;
|
grid-row-gap: 32px;
|
||||||
border-bottom: 1px solid ${theme.semantic.bgLight};
|
border-bottom: 1px solid ${theme.semantic.bgLight};
|
||||||
padding-bottom: 24px;
|
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 { file, owner, slate, type, createdAt } = group;
|
||||||
|
|
||||||
const { elements, restElements } = React.useMemo(() => {
|
const { elements, restElements } = React.useMemo(() => {
|
||||||
if (!Array.isArray(file)) {
|
if (!Array.isArray(file)) {
|
||||||
return { elements: [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]);
|
}, [file]);
|
||||||
|
|
||||||
const [showMore, setShowMore] = React.useState(false);
|
const [showMore, setShowMore] = React.useState(false);
|
||||||
@ -78,7 +71,7 @@ export default function ActivityFileGroup({ viewer, group, onAction }) {
|
|||||||
onAction={onAction}
|
onAction={onAction}
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div css={STYLES_OBJECT_GRID}>
|
<div css={Styles.OBJECTS_PREVIEW_GRID}>
|
||||||
{elements.map((file) => (
|
{elements.map((file) => (
|
||||||
<ObjectPreview viewer={viewer} owner={file.owner} key={file.id} file={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 { owner, user, createdAt } = group;
|
||||||
|
|
||||||
const { elements, restElements } = React.useMemo(() => {
|
const { elements, restElements } = React.useMemo(() => {
|
||||||
if (!Array.isArray(user)) {
|
if (!Array.isArray(user)) {
|
||||||
return { elements: [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]);
|
}, [user]);
|
||||||
|
|
||||||
const [showMore, setShowMore] = React.useState(false);
|
const [showMore, setShowMore] = React.useState(false);
|
||||||
|
@ -16,7 +16,7 @@ const STYLES_GROUP_GRID = (theme) => css`
|
|||||||
padding-bottom: 24px;
|
padding-bottom: 24px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function ActivityGroup({ onAction, viewer, external, group }) {
|
export default function ActivityGroup({ onAction, viewer, external, group, nbrOfCardsPerRow }) {
|
||||||
const { type } = group;
|
const { type } = group;
|
||||||
if (
|
if (
|
||||||
type === "CREATE_FILE" ||
|
type === "CREATE_FILE" ||
|
||||||
@ -24,16 +24,36 @@ export default function ActivityGroup({ onAction, viewer, external, group }) {
|
|||||||
type === "LIKE_FILE" ||
|
type === "LIKE_FILE" ||
|
||||||
type === "SAVE_COPY"
|
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") {
|
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") {
|
if (type === "SUBSCRIBE_USER") {
|
||||||
return (
|
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,
|
font: Constants.font,
|
||||||
typescale: Constants.typescale,
|
typescale: Constants.typescale,
|
||||||
semantic: Constants.semantic,
|
semantic: Constants.semantic,
|
||||||
|
grids: Constants.grids,
|
||||||
...theme,
|
...theme,
|
||||||
}),
|
}),
|
||||||
[theme]
|
[theme]
|
||||||
|
@ -41,6 +41,9 @@ export default function SceneActivity({ page, viewer, external, onAction }) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const divRef = React.useRef();
|
const divRef = React.useRef();
|
||||||
|
|
||||||
|
const nbrOfCardsInRow = useNbrOfCardsPerRow(divRef);
|
||||||
|
|
||||||
useIntersection({
|
useIntersection({
|
||||||
ref: divRef,
|
ref: divRef,
|
||||||
onIntersect: () => {
|
onIntersect: () => {
|
||||||
@ -69,6 +72,7 @@ export default function SceneActivity({ page, viewer, external, onAction }) {
|
|||||||
<div css={STYLES_GROUPS_CONTAINER}>
|
<div css={STYLES_GROUPS_CONTAINER}>
|
||||||
{feed?.map((group) => (
|
{feed?.map((group) => (
|
||||||
<ActivityGroup
|
<ActivityGroup
|
||||||
|
nbrOfCardsPerRow={nbrOfCardsInRow}
|
||||||
key={group.id}
|
key={group.id}
|
||||||
viewer={viewer}
|
viewer={viewer}
|
||||||
external={external}
|
external={external}
|
||||||
@ -84,3 +88,50 @@ export default function SceneActivity({ page, viewer, external, onAction }) {
|
|||||||
</WebsitePrototypeWrapper>
|
</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