1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-24 20:36:40 +07:00

made sample profile page

This commit is contained in:
Fedor Katurov 2021-10-01 12:01:11 +07:00
parent b43fb35b47
commit a808045a7d
17 changed files with 118 additions and 179 deletions

View file

@ -3,7 +3,7 @@ import { useCommentFormFormik } from '~/utils/hooks/useCommentFormFormik';
import { FormikProvider } from 'formik';
import { LocalCommentFormTextarea } from '~/components/comment/LocalCommentFormTextarea';
import { Button } from '~/components/input/Button';
import { FileUploaderProvider, useFileUploader } from '~/utils/hooks/fileUploader';
import { FileUploaderProvider, useFileUploader } from '~/utils/hooks/useFileUploader';
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS } from '~/redux/uploads/constants';
import { CommentFormAttachButtons } from '~/components/comment/CommentFormAttachButtons';
import { CommentFormFormatButtons } from '~/components/comment/CommentFormFormatButtons';

View file

@ -7,7 +7,7 @@ import { SortEnd } from 'react-sortable-hoc';
import { moveArrItem } from '~/utils/fn';
import { useDropZone } from '~/utils/hooks';
import { COMMENT_FILE_TYPES, UPLOAD_TYPES } from '~/redux/uploads/constants';
import { useFileUploaderContext } from '~/utils/hooks/fileUploader';
import { useFileUploaderContext } from '~/utils/hooks/useFileUploader';
const CommentFormAttaches: FC = () => {
const uploader = useFileUploaderContext();

View file

@ -10,11 +10,20 @@ interface Props extends DivProps {
url?: string;
username?: string;
size?: number;
preset?: typeof PRESETS[keyof typeof PRESETS];
innerRef?: React.Ref<any>;
}
const Avatar: FC<Props> = ({ url, username, size, className, innerRef, ...rest }) => {
const backgroundImage = !!url ? `url('${getURLFromString(url, PRESETS.avatar)}')` : undefined;
const Avatar: FC<Props> = ({
url,
username,
size,
className,
innerRef,
preset = PRESETS.avatar,
...rest
}) => {
const backgroundImage = !!url ? `url('${getURLFromString(url, preset)}')` : undefined;
const onOpenProfile = useCallback(() => openUserProfile(username), [username]);
return (

View file

@ -11,7 +11,7 @@ import { NodeEditorProps } from '~/redux/node/types';
import { useNodeImages } from '~/utils/hooks/node/useNodeImages';
import { useNodeAudios } from '~/utils/hooks/node/useNodeAudios';
import { useNodeFormContext } from '~/utils/hooks/useNodeFormFormik';
import { useFileUploaderContext } from '~/utils/hooks/fileUploader';
import { useFileUploaderContext } from '~/utils/hooks/useFileUploader';
type IProps = NodeEditorProps;

View file

@ -3,7 +3,7 @@ import styles from './styles.module.scss';
import { Icon } from '~/components/input/Icon';
import { UPLOAD_TYPES } from '~/redux/uploads/constants';
import { IEditorComponentProps } from '~/redux/node/types';
import { useFileUploaderContext } from '~/utils/hooks/fileUploader';
import { useFileUploaderContext } from '~/utils/hooks/useFileUploader';
import { getFileType } from '~/utils/uploader';
import { useNodeFormContext } from '~/utils/hooks/useNodeFormFormik';
import { Button } from '~/components/input/Button';

View file

@ -11,7 +11,7 @@ import { getURL } from '~/utils/dom';
import { Icon } from '~/components/input/Icon';
import { PRESETS } from '~/constants/urls';
import { IEditorComponentProps } from '~/redux/node/types';
import { useFileUploader, useFileUploaderContext } from '~/utils/hooks/fileUploader';
import { useFileUploader, useFileUploaderContext } from '~/utils/hooks/useFileUploader';
import { useNodeFormContext } from '~/utils/hooks/useNodeFormFormik';
import { getFileType } from '~/utils/uploader';

View file

@ -6,7 +6,7 @@ import { selectUploads } from '~/redux/uploads/selectors';
import { ImageGrid } from '~/components/editors/ImageGrid';
import styles from './styles.module.scss';
import { NodeEditorProps } from '~/redux/node/types';
import { useFileUploaderContext } from '~/utils/hooks/fileUploader';
import { useFileUploaderContext } from '~/utils/hooks/useFileUploader';
type IProps = NodeEditorProps;

View file

@ -7,7 +7,7 @@ import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
import { prop } from 'ramda';
import { useNodeFormFormik } from '~/utils/hooks/useNodeFormFormik';
import { EditorButtons } from '~/components/editors/EditorButtons';
import { FileUploaderProvider, useFileUploader } from '~/utils/hooks/fileUploader';
import { FileUploaderProvider, useFileUploader } from '~/utils/hooks/useFileUploader';
import { UPLOAD_SUBJECTS, UPLOAD_TARGETS } from '~/redux/uploads/constants';
import { FormikProvider } from 'formik';
import { INode } from '~/redux/types';

View file

@ -9,6 +9,9 @@ import classNames from 'classnames';
import styles from './styles.module.scss';
import markdown from '~/styles/common/markdown.module.scss';
import { ProfileAvatar } from '~/containers/profile/ProfileAvatar';
import { Avatar } from '~/components/common/Avatar';
import { Markdown } from '~/components/containers/Markdown';
interface IProps {
profile: IAuthState['profile'];
@ -16,17 +19,15 @@ interface IProps {
}
const ProfilePageLeft: FC<IProps> = ({ username, profile }) => {
const thumb = useMemo(() => {
if (!profile || !profile.user || !profile.user.photo) return '';
return getURL(profile.user.photo, PRESETS.small_hero);
}, [profile]);
return (
<div className={styles.wrap}>
<div className={styles.avatar} style={{ backgroundImage: `url('${thumb}')` }} />
<Avatar
username={username}
url={profile.user?.photo?.url}
className={styles.avatar}
preset={PRESETS['600']}
/>
<div className={styles.region_wrap}>
<div className={styles.region}>
<div className={styles.name}>
{profile.is_loading ? <Placeholder /> : profile?.user?.fullname}
@ -35,30 +36,13 @@ const ProfilePageLeft: FC<IProps> = ({ username, profile }) => {
<div className={styles.username}>
{profile.is_loading ? <Placeholder /> : `~${profile?.user?.username}`}
</div>
<div className={styles.menu}>
<Link to={`${URLS.PROFILE_PAGE(username)}/`}>
<Icon icon="profile" size={20} />
Профиль
</Link>
<Link to={`${URLS.PROFILE_PAGE(username)}/settings`}>
<Icon icon="settings" size={20} />
Настройки
</Link>
<Link to={`${URLS.PROFILE_PAGE(username)}/messages`}>
<Icon icon="messages" size={20} />
Сообщения
</Link>
</div>
</div>
</div>
{profile && profile.user && profile.user.description && false && (
<div className={classNames(styles.description, markdown.wrapper)}>
{formatText(profile?.user?.description || '')}
</div>
{profile && profile.user && profile.user.description && (
<Markdown
className={styles.description}
dangerouslySetInnerHTML={{ __html: formatText(profile.user.description) }}
/>
)}
</div>
);

View file

@ -1,92 +1,51 @@
@import "src/styles/variables";
.wrap {
@include outer_shadow;
padding: $gap $gap $gap * 2;
box-sizing: border-box;
display: flex;
align-items: stretch;
justify-content: stretch;
flex-direction: column;
background: $comment_bg;
height: 100%;
border-radius: $radius;
}
.avatar {
width: 100%;
padding-bottom: 75%;
border-radius: 0 $radius 0 0;
background: 50% 50% no-repeat;
background-size: cover;
}
.region_wrap {
width: 100%;
// padding: 0 10px;
position: relative;
margin-top: -$radius;
box-sizing: border-box;
height: 0;
padding-bottom: 100%;
margin-bottom: $gap * 2;
}
.region {
// background: $content_bg;
background: darken($content_bg, 2%);
width: 100%;
border-radius: 0 $radius $radius 0;
text-align: center;
}
.name {
font: $font_24_semibold;
color: white;
padding: $gap $gap 0 $gap;
text-transform: uppercase;
width: 100%;
box-sizing: border-box;
margin-bottom: 4px;
}
.username {
font: $font_14_semibold;
padding: 0 $gap $gap $gap;
font: $font_14_regular;
box-sizing: border-box;
width: 100%;
color: transparentize(white, 0.5);
margin-top: $gap / 2;
}
.menu {
padding: $gap 0 $gap 0;
display: flex;
align-items: stretch;
width: 100%;
flex-direction: column;
box-sizing: border-box;
display: none;
a {
width: 100%;
color: inherit;
text-decoration: none;
text-transform: uppercase;
font: $font_18_semibold;
padding: $gap $gap;
display: flex;
align-items: center;
justify-content: flex-start;
opacity: 0.5;
box-sizing: border-box;
transition: opacity 0.25s;
&:hover {
opacity: 1;
}
}
svg {
margin-right: $gap;
fill: currentColor;
}
}
.description {
padding: $gap;
box-sizing: border-box;
// background: darken($content_bg, 2%);
background: darken($content_bg, 4%);
// margin: 0 $gap;
border-radius: 0 0 $radius $radius;
@include clamp(3, 21px * 3);
line-height: 21px;
font: $font_14_regular;
margin-top: $gap * 3;
display: none;
}

View file

@ -9,66 +9,15 @@
$cols: $content_width / $cell;
@mixin fluid {
@media(min-width: $content_width) {
.fluid & {
@content
}
}
}
.container {
max-width: $content_width;
width: 100%;
&.fluid {
padding: 0 $gap;
box-sizing: border-box;
max-width: none;
}
}
.grid {
width: 100%;
box-sizing: border-box;
display: grid;
grid-template-columns: repeat(auto-fit, minmax($cell - 5, 1fr));
grid-template-rows: 50vh $cell;
grid-auto-rows: $cell;
grid-auto-flow: row dense;
grid-column-gap: $gap;
grid-row-gap: $gap;
@include fluid {
grid-template-columns: repeat(auto-fit, minmax($fluid_cell - 5, 1fr));
grid-template-rows: $fluid_cell;
grid-auto-rows: $fluid_cell;
}
@media (max-width: ($cell + 10) * 3) {
grid-template-columns: repeat(auto-fill, minmax($fluid_cell - 20, 1fr));
grid-auto-rows: $fluid_cell;
grid-template-rows: calc(50vw - 10px) $fluid_cell;
}
@media (max-width: $cell_tablet) {
grid-template-rows: calc(66vw - 10px) auto $fluid_cell;
}
@media (max-width: $cell_mobile) {
// rework stamp, so it will be shown as smaller one on mobiles
grid-template-columns: repeat(auto-fill, minmax(calc(50vw - 20px), 1fr));
grid-template-rows: calc(80vw - 10px) auto 50vw;
grid-auto-rows: 50vw;
}
@media (max-width: ($fluid_cell + 5) * 1.5 + 20) {
grid-template-columns: repeat(auto-fill, minmax(calc(50vw - 20px), 1fr));
grid-template-rows: calc(80vw - 10px) auto 50vw;
grid-auto-rows: 50vw;
}
@include flow_grid;
}
.pad_last {
@ -86,15 +35,6 @@ $cols: $content_width / $cell;
align-items: center;
justify-content: center;
font: $font_24_semibold;
@include fluid {
grid-row-end: span 2;
grid-column-end: span 4;
@media(max-width: $content_width) {
grid-column-end: -1;
}
}
}
.stamp {

View file

@ -4,9 +4,13 @@ import { Route, RouteComponentProps, Switch } from 'react-router';
import { useDispatch } from 'react-redux';
import { authLoadProfile } from '~/redux/auth/actions';
import { useShallowSelect } from '~/utils/hooks/useShallowSelect';
import { selectAuthProfile } from '~/redux/auth/selectors';
import { selectAuthProfile, selectUser } from '~/redux/auth/selectors';
import { ProfilePageLeft } from '~/containers/profile/ProfilePageLeft';
import { Container } from '~/containers/main/Container';
import { FlowGrid } from '~/components/flow/FlowGrid';
import { FlowLayout } from '~/layouts/FlowLayout';
import { Sticky } from '~/components/containers/Sticky';
import { selectFlow } from '~/redux/flow/selectors';
type Props = RouteComponentProps<{ username: string }> & {};
@ -15,6 +19,9 @@ const ProfileLayout: FC<Props> = ({
params: { username },
},
}) => {
const { nodes } = useShallowSelect(selectFlow);
const user = useShallowSelect(selectUser);
const dispatch = useDispatch();
useEffect(() => {
@ -25,7 +32,15 @@ const ProfileLayout: FC<Props> = ({
return (
<Container className={styles.wrap}>
<div className={styles.left}>
<Sticky>
<ProfilePageLeft profile={profile} username={username} />
</Sticky>
</div>
<div className={styles.grid}>
<FlowGrid nodes={nodes} user={user} onChangeCellView={console.log} />
</div>
</Container>
);
};

View file

@ -1,20 +1,16 @@
@import "src/styles/variables";
.wrap {
flex: 1;
display: flex;
align-items: stretch;
justify-content: stretch;
border-radius: $radius;
display: grid;
grid-template-columns: $cell auto;
grid-column-gap: $gap;
}
.grid {
@include flow_grid;
}
.left {
flex: 1;
background: darken($content_bg, 2%);
border-radius: 0 $radius $radius 0;
box-sizing: border-box;
}
.right {
flex: 4;
}

View file

@ -268,3 +268,39 @@ $sidebar_border: transparentize(white, 0.95);
$color: mix($wisegreen, $content_bg, 30%);
background: linear-gradient(170deg, lighten($color, 10%), $color);
}
@mixin flow_grid {
width: 100%;
box-sizing: border-box;
display: grid;
grid-template-columns: repeat(auto-fit, minmax($cell - 5, 1fr));
grid-auto-rows: $cell;
grid-auto-flow: row dense;
grid-column-gap: $gap;
grid-row-gap: $gap;
@media (max-width: ($cell + 10) * 3) {
grid-template-columns: repeat(auto-fill, minmax($fluid_cell - 20, 1fr));
grid-auto-rows: $fluid_cell;
grid-template-rows: calc(50vw - 10px) $fluid_cell;
}
@media (max-width: $cell_tablet) {
grid-template-rows: calc(66vw - 10px) auto $fluid_cell;
}
@media (max-width: $cell_mobile) {
// rework stamp, so it will be shown as smaller one on mobiles
grid-template-columns: repeat(auto-fill, minmax(calc(50vw - 20px), 1fr));
grid-template-rows: calc(80vw - 10px) auto 50vw;
grid-auto-rows: 50vw;
}
@media (max-width: ($fluid_cell + 5) * 1.5 + 20) {
grid-template-columns: repeat(auto-fill, minmax(calc(50vw - 20px), 1fr));
grid-template-rows: calc(80vw - 10px) auto 50vw;
grid-auto-rows: 50vw;
}
}

View file

@ -2,7 +2,7 @@ import { IComment, INode } from '~/redux/types';
import { useCallback, useEffect, useRef } from 'react';
import { FormikHelpers, useFormik, useFormikContext } from 'formik';
import { array, object, string } from 'yup';
import { FileUploader } from '~/utils/hooks/fileUploader';
import { FileUploader } from '~/utils/hooks/useFileUploader';
import { useDispatch } from 'react-redux';
import { nodePostLocalComment } from '~/redux/node/actions';

View file

@ -1,5 +1,5 @@
import { IComment, INode } from '~/redux/types';
import { FileUploader } from '~/utils/hooks/fileUploader';
import { FileUploader } from '~/utils/hooks/useFileUploader';
import { useCallback, useEffect, useRef } from 'react';
import { FormikHelpers, useFormik, useFormikContext } from 'formik';
import { object, string } from 'yup';