Page MenuHomePhabricator

D4999.id16787.diff
No OneTemporary

D4999.id16787.diff

diff --git a/web/markdown/markdown.css b/web/markdown/markdown.css
--- a/web/markdown/markdown.css
+++ b/web/markdown/markdown.css
@@ -17,14 +17,9 @@
box-sizing: border-box;
width: 100%;
margin: 6px 0;
-}
-div.darkBackground blockquote {
- background: #a9a9a9;
- border-left: 5px solid #808080;
-}
-div.lightBackground blockquote {
- background: #d3d3d3;
- border-left: 5px solid #c0c0c0;
+ border-radius: 8px;
+ border-left-width: 8px;
+ border-left-style: solid;
}
div.markdown code {
diff --git a/web/markdown/markdown.react.js b/web/markdown/markdown.react.js
--- a/web/markdown/markdown.react.js
+++ b/web/markdown/markdown.react.js
@@ -13,16 +13,14 @@
};
function Markdown(props: Props): React.Node {
const { children, rules } = props;
- const { simpleMarkdownRules, useDarkStyle } = rules;
+ const { simpleMarkdownRules } = rules;
const markdownClassName = React.useMemo(
() =>
classNames({
[css.markdown]: true,
- [css.darkBackground]: useDarkStyle,
- [css.lightBackground]: !useDarkStyle,
}),
- [useDarkStyle],
+ [],
);
const parser = React.useMemo(
diff --git a/web/markdown/rules.react.js b/web/markdown/rules.react.js
--- a/web/markdown/rules.react.js
+++ b/web/markdown/rules.react.js
@@ -3,7 +3,9 @@
import _memoize from 'lodash/memoize';
import * as React from 'react';
import * as SimpleMarkdown from 'simple-markdown';
+import tinycolor from 'tinycolor2';
+import { threadInfoSelector } from 'lib/selectors/thread-selectors';
import { relativeMemberInfoSelectorForMembersOfThread } from 'lib/selectors/user-selectors';
import * as SharedMarkdown from 'lib/shared/markdown';
import type { RelativeMemberInfo } from 'lib/types/thread-types';
@@ -65,76 +67,117 @@
};
});
-const markdownRules: boolean => MarkdownRules = _memoize(useDarkStyle => {
- const linkMarkdownRules = linkRules(useDarkStyle);
+const markdownRules: (
+ useDarkStyle: boolean,
+ threadColor: ?string,
+) => MarkdownRules = _memoize(
+ (useDarkStyle, threadColor) => {
+ const linkMarkdownRules = linkRules(useDarkStyle);
- const simpleMarkdownRules = {
- ...linkMarkdownRules.simpleMarkdownRules,
- autolink: SimpleMarkdown.defaultRules.autolink,
- link: {
- ...linkMarkdownRules.simpleMarkdownRules.link,
- match: SimpleMarkdown.defaultRules.link.match,
- },
- blockQuote: {
- ...SimpleMarkdown.defaultRules.blockQuote,
- // match end of blockQuote by either \n\n or end of string
- match: SharedMarkdown.matchBlockQuote(SharedMarkdown.blockQuoteRegex),
- parse: SharedMarkdown.parseBlockQuote,
- },
- inlineCode: SimpleMarkdown.defaultRules.inlineCode,
- em: SimpleMarkdown.defaultRules.em,
- strong: SimpleMarkdown.defaultRules.strong,
- del: SimpleMarkdown.defaultRules.del,
- u: SimpleMarkdown.defaultRules.u,
- heading: {
- ...SimpleMarkdown.defaultRules.heading,
- match: SimpleMarkdown.blockRegex(SharedMarkdown.headingRegex),
- },
- mailto: SimpleMarkdown.defaultRules.mailto,
- codeBlock: {
- ...SimpleMarkdown.defaultRules.codeBlock,
- match: SimpleMarkdown.blockRegex(SharedMarkdown.codeBlockRegex),
- parse: (capture: SharedMarkdown.Capture) => ({
- content: capture[0].replace(/^ {4}/gm, ''),
- }),
- },
- fence: {
- ...SimpleMarkdown.defaultRules.fence,
- match: SimpleMarkdown.blockRegex(SharedMarkdown.fenceRegex),
- parse: (capture: SharedMarkdown.Capture) => ({
- type: 'codeBlock',
- content: capture[2],
- }),
- },
- json: {
- order: SimpleMarkdown.defaultRules.paragraph.order - 1,
- match: (source: string, state: SharedMarkdown.State) => {
- if (state.inline) {
- return null;
- }
- return SharedMarkdown.jsonMatch(source);
+ const simpleMarkdownRules = {
+ ...linkMarkdownRules.simpleMarkdownRules,
+ autolink: SimpleMarkdown.defaultRules.autolink,
+ link: {
+ ...linkMarkdownRules.simpleMarkdownRules.link,
+ match: SimpleMarkdown.defaultRules.link.match,
+ },
+ blockQuote: {
+ ...SimpleMarkdown.defaultRules.blockQuote,
+ // match end of blockQuote by either \n\n or end of string
+ match: SimpleMarkdown.blockRegex(SharedMarkdown.blockQuoteRegex),
+ parse(
+ capture: SharedMarkdown.Capture,
+ parse: SharedMarkdown.Parser,
+ state: SharedMarkdown.State,
+ ) {
+ const content = capture[1].replace(/^ *> ?/gm, '');
+ return {
+ content: parse(content, state),
+ };
+ },
+ // eslint-disable-next-line react/display-name
+ react: (
+ node: SharedMarkdown.SingleASTNode,
+ output: SharedMarkdown.Output<SharedMarkdown.ReactElement>,
+ state: SharedMarkdown.State,
+ ) => {
+ const backgroundColor = threadColor
+ ? tinycolor(threadColor).darken(20).toString()
+ : tinycolor('var(--text-message-default-background)')
+ .lighten(70)
+ .toString();
+ const borderLeftColor = threadColor
+ ? tinycolor(threadColor).darken(30).toString()
+ : tinycolor('var(--text-message-default-background)')
+ .lighten(50)
+ .toString();
+
+ return (
+ <blockquote
+ key={state.key}
+ style={{ backgroundColor, borderLeftColor }}
+ >
+ {output(node.content, state)}
+ </blockquote>
+ );
+ },
+ },
+ inlineCode: SimpleMarkdown.defaultRules.inlineCode,
+ em: SimpleMarkdown.defaultRules.em,
+ strong: SimpleMarkdown.defaultRules.strong,
+ del: SimpleMarkdown.defaultRules.del,
+ u: SimpleMarkdown.defaultRules.u,
+ heading: {
+ ...SimpleMarkdown.defaultRules.heading,
+ match: SimpleMarkdown.blockRegex(SharedMarkdown.headingRegex),
},
- parse: (capture: SharedMarkdown.Capture) => {
- const jsonCapture: SharedMarkdown.JSONCapture = (capture: any);
- return {
+ mailto: SimpleMarkdown.defaultRules.mailto,
+ codeBlock: {
+ ...SimpleMarkdown.defaultRules.codeBlock,
+ match: SimpleMarkdown.blockRegex(SharedMarkdown.codeBlockRegex),
+ parse: (capture: SharedMarkdown.Capture) => ({
+ content: capture[0].replace(/^ {4}/gm, ''),
+ }),
+ },
+ fence: {
+ ...SimpleMarkdown.defaultRules.fence,
+ match: SimpleMarkdown.blockRegex(SharedMarkdown.fenceRegex),
+ parse: (capture: SharedMarkdown.Capture) => ({
type: 'codeBlock',
- content: SharedMarkdown.jsonPrint(jsonCapture),
- };
+ content: capture[2],
+ }),
},
- },
- list: {
- ...SimpleMarkdown.defaultRules.list,
- match: SharedMarkdown.matchList,
- parse: SharedMarkdown.parseList,
- },
- escape: SimpleMarkdown.defaultRules.escape,
- };
- return {
- ...linkMarkdownRules,
- simpleMarkdownRules,
- useDarkStyle,
- };
-});
+ json: {
+ order: SimpleMarkdown.defaultRules.paragraph.order - 1,
+ match: (source: string, state: SharedMarkdown.State) => {
+ if (state.inline) {
+ return null;
+ }
+ return SharedMarkdown.jsonMatch(source);
+ },
+ parse: (capture: SharedMarkdown.Capture) => {
+ const jsonCapture: SharedMarkdown.JSONCapture = (capture: any);
+ return {
+ type: 'codeBlock',
+ content: SharedMarkdown.jsonPrint(jsonCapture),
+ };
+ },
+ },
+ list: {
+ ...SimpleMarkdown.defaultRules.list,
+ match: SharedMarkdown.matchList,
+ parse: SharedMarkdown.parseList,
+ },
+ escape: SimpleMarkdown.defaultRules.escape,
+ };
+ return {
+ ...linkMarkdownRules,
+ simpleMarkdownRules,
+ useDarkStyle,
+ };
+ },
+ (...args) => JSON.stringify(args),
+);
function useTextMessageRulesFunc(
threadID: ?string,
@@ -142,21 +185,30 @@
const threadMembers = useSelector(
relativeMemberInfoSelectorForMembersOfThread(threadID),
);
+
+ const threadColor = useSelector(state => {
+ if (threadID) {
+ const threadInfo = threadInfoSelector(state)[threadID];
+ return threadInfo ? threadInfo.color : null;
+ }
+ });
+
return React.useMemo(() => {
if (!threadMembers) {
return undefined;
}
return _memoize<[boolean], MarkdownRules>((useDarkStyle: boolean) =>
- textMessageRules(threadMembers, useDarkStyle),
+ textMessageRules(threadMembers, useDarkStyle, threadColor),
);
- }, [threadMembers]);
+ }, [threadMembers, threadColor]);
}
function textMessageRules(
members: $ReadOnlyArray<RelativeMemberInfo>,
useDarkStyle: boolean,
+ threadColor: ?string,
): MarkdownRules {
- const baseRules = markdownRules(useDarkStyle);
+ const baseRules = markdownRules(useDarkStyle, threadColor);
return {
...baseRules,
simpleMarkdownRules: {
@@ -182,7 +234,7 @@
function getDefaultTextMessageRules(): MarkdownRules {
if (!defaultTextMessageRules) {
- defaultTextMessageRules = textMessageRules([], false);
+ defaultTextMessageRules = textMessageRules([], false, null);
}
return defaultTextMessageRules;
}
diff --git a/web/modals/threads/settings/thread-settings-relationship-button.react.js b/web/modals/threads/settings/thread-settings-relationship-button.react.js
--- a/web/modals/threads/settings/thread-settings-relationship-button.react.js
+++ b/web/modals/threads/settings/thread-settings-relationship-button.react.js
@@ -1,4 +1,11 @@
// @flow
+import {
+ faUserMinus,
+ faUserPlus,
+ faUserShield,
+ faUserSlash,
+} from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import invariant from 'invariant';
import * as React from 'react';
@@ -24,6 +31,7 @@
import Button from '../../../components/button.react';
import { useSelector } from '../../../redux/redux-utils';
+import css from './thread-settings-relationship-tab.css';
const loadingStatusSelector = createLoadingStatusSelector(
updateRelationshipsActionTypes,
@@ -67,6 +75,35 @@
};
}, [relationshipButton, username]);
+ const icon = React.useMemo(() => {
+ let buttonIcon = null;
+
+ if (relationshipButton === relationshipButtons.FRIEND) {
+ buttonIcon = faUserPlus;
+ } else if (relationshipButton === relationshipButtons.UNFRIEND) {
+ buttonIcon = faUserMinus;
+ } else if (relationshipButton === relationshipButtons.BLOCK) {
+ buttonIcon = faUserShield;
+ } else if (relationshipButton === relationshipButtons.UNBLOCK) {
+ buttonIcon = faUserShield;
+ } else if (relationshipButton === relationshipButtons.ACCEPT) {
+ buttonIcon = faUserPlus;
+ } else if (relationshipButton === relationshipButtons.REJECT) {
+ buttonIcon = faUserSlash;
+ } else if (relationshipButton === relationshipButtons.WITHDRAW) {
+ buttonIcon = faUserMinus;
+ }
+
+ if (buttonIcon) {
+ return (
+ <FontAwesomeIcon
+ icon={buttonIcon}
+ className={css.relationshipButtonIcon}
+ />
+ );
+ }
+ }, [relationshipButton]);
+
const dispatchActionPromise = useDispatchActionPromise();
const callUpdateRelationships = useServerCall(updateRelationships);
@@ -91,7 +128,10 @@
return (
<Button variant={variant} onClick={onClick} disabled={disabled}>
- {text}
+ <div className={css.relationshipButtonContent}>
+ {icon}
+ <div className={css.relationshipButtonText}>{text}</div>
+ </div>
</Button>
);
}
diff --git a/web/modals/threads/settings/thread-settings-relationship-tab.css b/web/modals/threads/settings/thread-settings-relationship-tab.css
--- a/web/modals/threads/settings/thread-settings-relationship-tab.css
+++ b/web/modals/threads/settings/thread-settings-relationship-tab.css
@@ -3,3 +3,18 @@
flex-direction: column;
row-gap: 10px;
}
+
+div.relationshipButtonContent {
+ display: flex;
+ flex: 1;
+ align-items: center;
+}
+
+div.relationshipButtonText {
+ flex: 1;
+ margin: 0 24px;
+}
+
+svg.relationshipButtonIcon {
+ position: absolute;
+}

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 23, 6:59 AM (18 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2569541
Default Alt Text
D4999.id16787.diff (12 KB)

Event Timeline