1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 12:56:41 +07:00

sing create-react-app now

This commit is contained in:
Fedor Katurov 2020-11-19 17:27:19 +07:00
parent 332d09e3bd
commit a9c43e8976
41 changed files with 6207 additions and 15613 deletions

View file

@ -12,7 +12,7 @@ import * as MODAL_ACTIONS from '~/redux/modal/actions';
type IProps = HTMLAttributes<HTMLDivElement> & {
is_empty?: boolean;
is_loading?: boolean;
comment_group?: ICommentGroup;
comment_group: ICommentGroup;
comment_data: INodeState['comment_data'];
is_same?: boolean;
can_edit?: boolean;
@ -58,7 +58,7 @@ const Comment: FC<IProps> = memo(
<CommentContent
comment={comment}
key={comment.id}
can_edit={can_edit}
can_edit={!!can_edit}
onDelete={onDelete}
onEdit={onEdit}
modalShowPhotoswipe={modalShowPhotoswipe}

View file

@ -16,7 +16,7 @@ import * as UPLOAD_ACTIONS from '~/redux/uploads/actions';
import { selectUploads } from '~/redux/uploads/selectors';
import { IState } from '~/redux/store';
import { getFileType } from '~/utils/uploader';
import { getRandomPhrase } from '~/constants/phrases';
import { useRandomPhrase } from '~/constants/phrases';
import { ERROR_LITERAL } from '~/constants/errors';
import { CommentFormAttaches } from '~/components/comment/CommentFormAttaches';
import { CommentFormAttachButtons } from '~/components/comment/CommentFormButtons';
@ -153,7 +153,7 @@ const CommentFormUnconnected: FC<IProps> = memo(
nodeCancelCommentEdit(id);
}, [nodeCancelCommentEdit, comment.id]);
const placeholder = getRandomPhrase('SIMPLE');
const placeholder = useRandomPhrase('SIMPLE');
const clearError = useCallback(() => nodeSetCommentData(id, { error: '' }), [
id,

View file

@ -22,7 +22,7 @@
height: 100%;
top: 0;
left: 0;
background: url('~/sprites/stripes.svg') transparentize($color: #000000, $amount: 0.5);
background: url('../../../sprites/stripes.svg') transparentize($color: #000000, $amount: 0.5);
}
img {

View file

@ -29,7 +29,7 @@
left: 0;
width: 100%;
height: 100%;
background: url(~/sprites/stripes.svg) transparentize($content_bg, 0.2);
background: url(../../../sprites/stripes.svg) transparentize($content_bg, 0.2);
}
@include tablet {

View file

@ -1,4 +1,4 @@
import React, { FC, ReactComponentElement, DetailsHTMLAttributes, useEffect, useRef } from 'react';
import React, { DetailsHTMLAttributes, FC, useEffect, useRef } from 'react';
import styles from './styles.module.scss';
import StickySidebar from 'sticky-sidebar';
import classnames from 'classnames';

View file

@ -42,7 +42,7 @@
.text {
font: $font_18_regular;
line-height: 22px;
background: transparentize($color: $content_bg, $amount: 0.3) url('~/sprites/stripes.svg');
background: transparentize($color: $content_bg, $amount: 0.3) url('../../../sprites/stripes.svg');
padding: $gap;
box-sizing: border-box;
border-radius: $radius;

View file

@ -15,7 +15,7 @@
left: 0;
width: 100%;
height: 100%;
background: url('~/sprites/stripes.svg') rgba(0, 0, 0, 0.3);
background: url('../../../sprites/stripes.svg') rgba(0, 0, 0, 0.3);
z-index: 4;
pointer-events: none;
box-shadow: inset transparentize($color: white, $amount: 0.85) 0 1px;

View file

@ -1,6 +1,6 @@
import React, { FC, ChangeEvent, useCallback, useState, useEffect, LegacyRef } from 'react';
import classNames from 'classnames';
import * as styles from '~/styles/common/inputs.module.scss';
import styles from '~/styles/common/inputs.module.scss';
import { Icon } from '~/components/input/Icon';
import { IInputTextProps } from '~/redux/types';
import { LoaderCircle } from '~/components/input/LoaderCircle';

View file

@ -11,7 +11,7 @@ import React, {
import classNames from 'classnames';
import autosize from 'autosize';
import * as styles from '~/styles/common/inputs.module.scss';
import styles from '~/styles/common/inputs.module.scss';
import { Icon } from '../Icon';
type IProps = TextareaHTMLAttributes<HTMLTextAreaElement> & {

View file

@ -15,7 +15,7 @@
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5) url('~/sprites/dots.svg');
background: rgba(0, 0, 0, 0.5) url('../../../sprites/dots.svg');
}
}

View file

@ -24,7 +24,7 @@
cursor: pointer;
transition: all 0.25s;
user-select: none;
background: url('~/sprites/stripes.svg');
background: url('../../../sprites/stripes.svg');
position: relative;
&:hover {

View file

@ -3,7 +3,7 @@ import { INotification, NOTIFICATION_TYPES } from '~/redux/types';
import styles from './styles.module.scss';
import { NotificationMessage } from '../NotificationMessage';
import { Icon } from '~/components/input/Icon';
import { getRandomPhrase } from '~/constants/phrases';
import { useRandomPhrase } from '~/constants/phrases';
interface IProps {
notifications: INotification[];
@ -15,7 +15,7 @@ const NOTIFICATION_RENDERERS = {
};
const NotificationBubble: FC<IProps> = ({ notifications, onClick }) => {
const placeholder = getRandomPhrase('NOTHING_HERE');
const placeholder = useRandomPhrase('NOTHING_HERE');
return (
<div className={styles.wrap}>

View file

@ -2,11 +2,11 @@ import { IComment, INode } from '~/redux/types';
import { ISocialProvider } from '~/redux/auth/types';
export const API = {
BASE: process.env.API_HOST,
BASE: process.env.REACT_APP_API_HOST,
USER: {
LOGIN: '/user/login',
OAUTH_WINDOW: (provider: ISocialProvider) =>
`${process.env.API_HOST}oauth/${provider}/redirect`,
`${process.env.RACT_APP_API_HOST}oauth/${provider}/redirect`,
ME: '/user/',
PROFILE: (username: string) => `/user/user/${username}/profile`,
MESSAGES: (username: string) => `/user/user/${username}/messages`,

View file

@ -39,5 +39,5 @@ export const PHRASES = {
],
};
export const getRandomPhrase = (key: keyof typeof PHRASES) =>
export const useRandomPhrase = (key: keyof typeof PHRASES) =>
useMemo(() => PHRASES[key][Math.floor(Math.random() * PHRASES[key].length)], []);

View file

@ -1,6 +1,5 @@
import React, { FC } from 'react';
import { connect } from 'react-redux';
import { hot } from 'react-hot-loader';
import { ConnectedRouter } from 'connected-react-router';
import { history } from '~/redux/store';
import { MainLayout } from '~/containers/main/MainLayout';
@ -40,4 +39,4 @@ const Component: FC<IProps> = ({ modal: { is_shown } }) => {
);
};
export default connect(mapStateToProps, mapDispatchToProps)(hot(module)(Component));
export default connect(mapStateToProps, mapDispatchToProps)(Component);

View file

@ -8,7 +8,7 @@ import styles from './styles.module.scss';
import { Group } from '~/components/containers/Group';
import boris from '~/sprites/boris_robot.svg';
import { NodeNoComments } from '~/components/node/NodeNoComments';
import { getRandomPhrase } from '~/constants/phrases';
import { useRandomPhrase } from '~/constants/phrases';
import { NodeCommentForm } from '~/components/node/NodeCommentForm';
import * as NODE_ACTIONS from '~/redux/node/actions';
@ -19,7 +19,6 @@ import isBefore from 'date-fns/isBefore';
import { Card } from '~/components/containers/Card';
import { Footer } from '~/components/main/Footer';
import { Sticky } from '~/components/containers/Sticky';
import { Placeholder } from '~/components/placeholders/Placeholder';
import { selectBorisStats } from '~/redux/boris/selectors';
import { BorisStats } from '~/components/boris/BorisStats';
@ -58,7 +57,7 @@ const BorisLayoutUnconnected: FC<IProps> = ({
borisLoadStats,
stats,
}) => {
const title = getRandomPhrase('BORIS_TITLE');
const title = useRandomPhrase('BORIS_TITLE');
useEffect(() => {
const last_comment = comments[0];

View file

@ -36,7 +36,7 @@
width: 100%;
height: 100vh;
overflow: hidden;
background: 50% 0% no-repeat url('~/sprites/boris_bg.svg');
background: 50% 0% no-repeat url('../../../sprites/boris_bg.svg');
background-size: cover;
}

View file

@ -20,7 +20,7 @@
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
background: url('~/sprites/lost.svg') 50% 50% no-repeat;
background: url('../../../sprites/lost.svg') 50% 50% no-repeat;
background-size: cover;
text-transform: uppercase;
text-align: center;

View file

@ -1,89 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="theme-color" content="#222222">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,500,600,700,800&display=swap&subset=cyrillic"
rel="stylesheet" />
<title><%= htmlWebpackPlugin.options.title %></title>
<style>
#main_loader {
position: fixed;
width: 100%;
height: 100%;
background: #222222;
top: 0;
left: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font: 600 22px 'Montserrat';
color: white;
}
#main_loader>div {
margin: 3px 0;
}
@keyframes erdball {
0% {
transform: translate(0, 100%);
}
100% {
transform: translate(0, 0);
}
}
#preload_shade {
width: 120px;
height: 120px;
box-shadow: white 0 0 0 3px;
border-radius: 100%;
overflow: hidden;
position: relative;
margin-bottom: 15px !important;
}
#preload_shade>span {
width: 100%;
height: 100%;
box-shadow: white 0 0 0 2px;
border-radius: 100%;
overflow: hidden;
position: absolute;
top: 0;
left: 0;
animation: erdball 3s infinite;
will-change: transform;
}
#preload_shade>span:nth-child(2) {
animation-delay: -1s;
}
#preload_shade>span:nth-child(3) {
animation-delay: -2s;
}
</style>
</head>
<body>
<div id="main_loader">
<div id="preload_shade">
<span></span>
<span></span>
<span></span>
</div>
<div>СМИРЕННО</div>
<div>ОЖИДАЙТЕ</div>
</div>
<div id="app"></div>
</body>
</html>

View file

@ -17,55 +17,3 @@ render(
</Provider>,
document.getElementById('app')
);
/*
[stage 1]
- check if email is registered at social login
- profile cover upload
- illustrate login
- illustrate restoreRequestDialog
- friendship
- signup?
- text post can also has songs http://vault48.org/post5052
- fulltext search: https://github.com/typeorm/typeorm/issues/3191
- zoom: https://manuelstofer.github.io/pinchzoom/
- notifications (node, comment)
- social integration (assimilate)
- comment editing
Done:
- set file target on comment save, node save, profile upload
- delete comments
- import videos (partially)
- delete nodes
- user access time update
- import graffiti
- <...> format
- youtube embeds
- mobile header
- sticky header
- password restore
- avatar upload
- flow updates
- flow infinite scroll
- better node brief update
- fix: text nodes cell has no preview (actually, that's a problem of brief)
- relocate files
- backend: exclude node covers on import
- profile editing
- notifications (messages)
- profile modal
- messages
- better dialogs: https://codepen.io/muemue/pen/abbEMMy
- imagecaching at backend
- social integration (login, signup)
- boris with comments (import)
- boris with comments (layout)
- fix: user receives his own notifications :-(
- fix: node related and albums should exclude node itself
- fix: select node and edit it. All images will be not loaded
- fix: text nodes cell not clickable
- fix: text nodes should not have 'no comments yet badge
*/

7
src/react-app-env.d.ts vendored Normal file
View file

@ -0,0 +1,7 @@
/// <reference types="react-scripts" />
declare namespace NodeJS {
interface ProcessEnv {
readonly REACT_APP_API_URL: string;
readonly REACT_APP_REMOTE_CURRENT: string;
}
}

13
src/reportWebVitals.js Normal file
View file

@ -0,0 +1,13 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

5
src/setupTests.js Normal file
View file

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

View file

@ -1,4 +1,5 @@
// @import '~raleway-cyrillic/raleway.css';
@import "src/styles/variables";
html {
min-height: 100vh;

View file

@ -69,13 +69,13 @@ export const getURLFromString = (
): string => {
if (size) {
return url
.replace('REMOTE_CURRENT://', `${process.env.REMOTE_CURRENT}cache/${size}/`)
.replace('REMOTE_OLD://', process.env.REMOTE_OLD);
.replace('REMOTE_CURRENT://', `${process.env.REACT_APP_REMOTE_CURRENT}cache/${size}/`)
.replace('REMOTE_OLD://', process.env.REACT_APP_REMOTE_OLD);
}
return url
.replace('REMOTE_CURRENT://', process.env.REMOTE_CURRENT)
.replace('REMOTE_OLD://', process.env.REMOTE_OLD);
.replace('REMOTE_CURRENT://', process.env.REACT_APP_REMOTE_CURRENT)
.replace('REMOTE_OLD://', process.env.REACT_APP_REMOTE_OLD);
};
export const getURL = (file: Partial<IFile>, size?: typeof PRESETS[keyof typeof PRESETS]) => {