Browse Source

Fix markdown textarea autosizing, fix thumbnail icon

unoptim
GreatBearShark 2 years ago
parent
commit
db5b45c165
  1. 1
      package.json
  2. 169
      src/components/AutosizeTextArea.tsx
  3. 2
      src/components/ErrorFallback.tsx
  4. 15
      src/components/markdown-textarea.tsx
  5. 11
      src/components/post-listing.tsx
  6. 12
      src/components/post.tsx
  7. 6
      src/custom.css
  8. 12
      yarn.lock

1
package.json

@ -46,6 +46,7 @@
"i18next": "^19.6.3",
"js-cookie": "^2.2.1",
"jwt-decode": "^2.2.0",
"line-height": "^0.3.1",
"lodash.isequal": "^4.5.0",
"markdown-it": "^11.0.0",
"markdown-it-container": "^3.0.0",

169
src/components/AutosizeTextArea.tsx

@ -0,0 +1,169 @@
import React from 'react';
// import * as PropTypes from "prop-types";
import autosize from 'autosize';
import * as _getLineHeight from 'line-height';
const getLineHeight = _getLineHeight as (element: HTMLElement) => number | null;
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace TextareaAutosize {
export type RequiredProps = Pick<
React.HTMLProps<HTMLTextAreaElement>,
Exclude<keyof React.HTMLProps<HTMLTextAreaElement>, 'ref'>
> & {
/** Called whenever the textarea resizes */
onResize?: (e: Event) => void;
/** Minimum number of visible rows */
rows?: React.HTMLProps<HTMLTextAreaElement>['rows'];
/** Maximum number of visible rows */
maxRows?: number;
/** Initialize `autosize` asynchronously.
* Enable it if you are using StyledComponents
* This is forced to true when `maxRows` is set.
*/
async?: boolean;
};
export type DefaultProps = {
rows: number;
async: boolean;
};
export type Props = RequiredProps & Partial<DefaultProps>;
export type State = {
lineHeight: number | null;
};
}
const RESIZED = 'autosize:resized';
type InnerProps = TextareaAutosize.Props & {
innerRef: React.Ref<HTMLTextAreaElement> | null;
};
/**
* A light replacement for built-in textarea component
* which automaticaly adjusts its height to match the content
*/
class TextareaAutosizeClass extends React.Component<
InnerProps,
TextareaAutosize.State
> {
static defaultProps: TextareaAutosize.DefaultProps = {
rows: 1,
async: false,
};
// static propTypes: {
// [key in keyof InnerProps]: PropTypes.Requireable<any>
// } = {
// rows: PropTypes.number,
// maxRows: PropTypes.number,
// onResize: PropTypes.func,
// innerRef: PropTypes.any,
// async: PropTypes.bool
// };
state: TextareaAutosize.State = {
lineHeight: null,
};
textarea: HTMLTextAreaElement | null = null;
currentValue: InnerProps['value'];
onResize = (e: Event): void => {
if (this.props.onResize) {
this.props.onResize(e);
}
};
componentDidMount() {
const { maxRows, async } = this.props;
if (typeof maxRows === 'number') {
this.updateLineHeight();
}
if (typeof maxRows === 'number' || async) {
/*
the defer is needed to:
- force "autosize" to activate the scrollbar when this.props.maxRows is passed
- support StyledComponents (see #71)
*/
setTimeout(() => this.textarea && autosize(this.textarea));
} else {
this.textarea && autosize(this.textarea);
}
if (this.textarea) {
this.textarea.addEventListener(RESIZED, this.onResize);
}
}
componentWillUnmount() {
if (this.textarea) {
this.textarea.removeEventListener(RESIZED, this.onResize);
autosize.destroy(this.textarea);
}
}
updateLineHeight = () => {
if (this.textarea) {
this.setState({
lineHeight: getLineHeight(this.textarea),
});
}
};
onChange = (e: React.SyntheticEvent<HTMLTextAreaElement>) => {
const { onChange } = this.props;
this.currentValue = e.currentTarget.value;
onChange && onChange(e);
};
render() {
const {
props: {
onResize,
maxRows,
onChange,
style,
innerRef,
children,
...props
},
state: { lineHeight },
} = this;
const maxHeight = maxRows && lineHeight ? lineHeight * maxRows : null;
return (
<textarea
{...props}
onChange={this.onChange}
style={maxHeight ? { ...style, maxHeight } : style}
ref={element => {
this.textarea = element;
if (typeof this.props.innerRef === 'function') {
this.props.innerRef(element);
} else if (this.props.innerRef) {
(this.props.innerRef as any).current = element;
}
}}
>
{children}
</textarea>
);
}
componentDidUpdate() {
this.textarea && autosize.update(this.textarea);
}
}
export const AutosizeTextArea = React.forwardRef(
(
props: TextareaAutosize.Props,
ref: React.Ref<HTMLTextAreaElement> | null
) => {
return <TextareaAutosizeClass {...props} innerRef={ref} />;
}
);

2
src/components/ErrorFallback.tsx

@ -26,10 +26,10 @@ export default function ErrorFallback() {
<Heading as="h3">Something Went Wrong</Heading>
<Text my={1}>Help Us Out By Letting Us Know What Happened</Text>
<Block my={3}>
{/* @ts-ignore */}
<Button
as="a"
css={{ width: '100%', color: '#fff !important' }}
// @ts-ignore
href="https://www.chapo.chat/create_post?community=feedback"
>
Create a Bug Report

15
src/components/markdown-textarea.tsx

@ -18,6 +18,7 @@ import { linkEvent } from '../linkEvent';
import 'emoji-mart/css/emoji-mart.css';
import { Picker } from 'emoji-mart';
import { customEmojis } from '../custom-emojis';
import { AutosizeTextArea } from './AutosizeTextArea';
interface MarkdownTextAreaProps {
initialContent: string;
@ -139,7 +140,19 @@ export class MarkdownTextArea extends Component<
<Prompt when={!!this.state.content} message={i18n.t('block_leaving')} />
<div className="form-group row">
<div className="col-sm-12">
<textarea
{/* <textarea
id={this.id}
className={`form-control ${this.state.previewMode && 'd-none'}`}
value={this.state.content}
onChange={this.handleContentChange}
onKeyDown={this.handleKeydown}
// onPaste={linkEvent(this, this.handleImageUploadPaste)}
required
disabled={this.props.disabled}
rows={2}
maxLength={10000}
/> */}
<AutosizeTextArea
id={this.id}
className={`form-control ${this.state.previewMode && 'd-none'}`}
value={this.state.content}

11
src/components/post-listing.tsx

@ -157,7 +157,12 @@ const PostActionButton = props => (
);
const PostIcon = props => (
<Box p={1} bg="background" className="mobile-icon-overlay">
<Box
p={1}
bg="background"
css={{ opacity: '60%' }}
className="mobile-icon-overlay"
>
<Icon size="18px" className="icon" {...props} />
</Box>
);
@ -284,7 +289,7 @@ const MobilePostListing = ({
// (contentExpanded || (imageHeight && imageHeight < 300)) && 'expanded'
// }`}
className={`collapsed-content collapsed-image ${
imageExpanded && 'expanded'
(imageExpanded || showBody) && 'expanded'
}`}
my={1}
onClick={() => setImageExpanded(prevState => !prevState)}
@ -299,7 +304,7 @@ const MobilePostListing = ({
alt={post.name}
src={post.url}
/>
<MobilePostIcon post={post} />
{!showBody && !imageExpanded && <MobilePostIcon post={post} />}
</Block>
)}
{isVideo(post.url) && (

12
src/components/post.tsx

@ -239,8 +239,8 @@ export class Post extends Component<any, PostState> {
{this.state.commentViewType == CommentViewType.Chat &&
this.commentsFlat()}
</>
) : (
<SpinnerSection />
) : (
<SpinnerSection />
)}
</div>
@ -472,7 +472,7 @@ export class Post extends Component<any, PostState> {
},
online: data.online,
loading: false,
})
});
document.title = `${this.state.post.name} - ${this.state.siteRes.site.name}`;
// Get cross-posts
@ -494,10 +494,10 @@ export class Post extends Component<any, PostState> {
// Necessary since it might be a user reply
if (data.recipient_ids.length == 0) {
this.state.comments.unshift(data.comment);
// this.state.comments.unshift(data.comment);
this.setState({
comments: [data.comment, ...this.state.comments]
})
comments: [data.comment, ...this.state.comments],
});
}
} else if (isCommentChanged(res.op)) {
let data = res.data as CommentResponse;

6
src/custom.css

@ -796,15 +796,15 @@ button:hover [type="button"]:hover {
height:100%;
position:absolute;
left: 0;
top: 10px;
top: 0px;
right: 0;
bottom: 0;
background-image: linear-gradient(to bottom, transparent, var(--theme-ui-colors-background,#222));
background-image: linear-gradient(to bottom, transparent, #222);
pointer-events: none;
}
.collapsed-image:after {
top: 200px;
top: 100px;
}
.collapsed-content.expanded:after {

12
yarn.lock

@ -5588,6 +5588,11 @@ [email protected]^1.2.1:
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
[email protected]~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/computed-style/-/computed-style-0.1.4.tgz#7f344fd8584b2e425bedca4a1afc0e300bb05d74"
integrity sha1-fzRP2FhLLkJb7cpKGvwOMAuwXXQ=
[email protected]:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -9984,6 +9989,13 @@ [email protected]~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
[email protected]^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/line-height/-/line-height-0.3.1.tgz#4b1205edde182872a5efa3c8f620b3187a9c54c9"
integrity sha1-SxIF7d4YKHKl76PI9iCzGHqcVMk=
dependencies:
computed-style "~0.1.3"
[email protected]^1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"

Loading…
Cancel
Save