mirror of
https://github.com/wassname/talk.git
synced 2026-09-16 12:47:05 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e85947af74 | ||
|
|
abfcdcc933 | ||
|
|
d001fcd456 | ||
|
|
a49b0d6fa7 | ||
|
|
f47c8661da | ||
|
|
d67c3d2907 | ||
|
|
3398bd12c4 | ||
|
|
fc6de50dde | ||
|
|
6c32316595 | ||
|
|
47abd030ef | ||
|
|
5ffb53d0eb | ||
|
|
af842e98ee | ||
|
|
281f19d21c | ||
|
|
45cd0e6628 | ||
|
|
adc508c7dc | ||
|
|
88a77f8712 | ||
|
|
5d2ab3d061 | ||
|
|
df6f666447 | ||
|
|
e412b27c1e | ||
|
|
0fe0be832e | ||
|
|
288809ee14 | ||
|
|
b97ec638b2 | ||
|
|
2bbfbc7ddd | ||
|
|
b029a01bd9 | ||
|
|
6fabeb2755 | ||
|
|
459e11a5fa | ||
|
|
ce7d6969dd | ||
|
|
6a8d6b07d6 | ||
|
|
8ede245a8d | ||
|
|
88eb9555c7 | ||
|
|
ce53134736 | ||
|
|
0f1dd7d707 | ||
|
|
9d02391062 | ||
|
|
8aac2d33fc | ||
|
|
3eddf5f155 | ||
|
|
94ff8ff880 | ||
|
|
7dfc064c9f | ||
|
|
d602cf873c | ||
|
|
79627af8d6 | ||
|
|
871d3f80c1 | ||
|
|
f7d01174d7 | ||
|
|
6966bb8d12 | ||
|
|
40ad2ed0cb | ||
|
|
802f656caa | ||
|
|
dfdea2b9d2 | ||
|
|
9a9c92d360 | ||
|
|
ceadcc7ae1 | ||
|
|
e0db803a21 | ||
|
|
7a099bbf05 | ||
|
|
51112a11c0 | ||
|
|
6e50b28d8b | ||
|
|
1f72cdbfb3 | ||
|
|
87aba459d6 | ||
|
|
9aa4591655 | ||
|
|
87d32680f0 | ||
|
|
25a1dcdf8d | ||
|
|
e90272aa58 | ||
|
|
bbbff98270 | ||
|
|
fe19ffd7e1 | ||
|
|
7f98f13990 | ||
|
|
1a9bd27236 | ||
|
|
536e804d61 | ||
|
|
43d5d56c90 | ||
|
|
cdcc991255 | ||
|
|
b221baff82 | ||
|
|
5b589bfe2b | ||
|
|
4f5c0e285c | ||
|
|
f26ab60398 | ||
|
|
e7f395190d | ||
|
|
ace252eb72 | ||
|
|
933d82e7c9 | ||
|
|
6e64e6a01c | ||
|
|
bb48e1fe33 | ||
|
|
58a91c2e42 | ||
|
|
6a5a18e3a4 | ||
|
|
d43fbe357a | ||
|
|
5c863f1307 | ||
|
|
d4cb9cde9b | ||
|
|
c59c345756 | ||
|
|
f8234e53ed | ||
|
|
7b2cdbad49 | ||
|
|
00e074d49d | ||
|
|
d848fc193e | ||
|
|
2acc761a5d | ||
|
|
0db5bc846d | ||
|
|
e57940c418 | ||
|
|
ccb8f1defa | ||
|
|
878c3bb3c0 | ||
|
|
86c81c7b9f | ||
|
|
302613a185 | ||
|
|
bf04b4c2a6 | ||
|
|
f3ef9ef778 | ||
|
|
db8c9de0e7 | ||
|
|
f2bf026740 | ||
|
|
625c38a758 | ||
|
|
caa4895b97 | ||
|
|
d1ee7d39f3 | ||
|
|
feaf4858df | ||
|
|
ebe7731222 | ||
|
|
8966dad344 | ||
|
|
4179306cd0 | ||
|
|
2c0153047e | ||
|
|
21cd47f6ed | ||
|
|
2f03b788a4 | ||
|
|
c19f4a35ca | ||
|
|
b39af1f7e6 | ||
|
|
a949d7e881 | ||
|
|
eee909f05b | ||
|
|
72e1b249b1 |
@@ -27,4 +27,3 @@ yarn.lock
|
|||||||
dist
|
dist
|
||||||
*.css.d.ts
|
*.css.d.ts
|
||||||
__generated__
|
__generated__
|
||||||
README.md.orig
|
|
||||||
|
|||||||
+34
-9
@@ -1,7 +1,7 @@
|
|||||||
const typescriptEslintRecommended = require("@typescript-eslint/eslint-plugin/dist/configs/eslint-recommended")
|
const typescriptEslintRecommended = require("@typescript-eslint/eslint-plugin/dist/configs/eslint-recommended")
|
||||||
.default.overrides[0];
|
.overrides[0];
|
||||||
const typescriptRecommended = require("@typescript-eslint/eslint-plugin/dist/configs/recommended.json");
|
const typescriptRecommended = require("@typescript-eslint/eslint-plugin/dist/configs/recommended.js");
|
||||||
const typescriptRecommendedTypeChecking = require("@typescript-eslint/eslint-plugin/dist/configs/recommended-requiring-type-checking.json");
|
const typescriptRecommendedTypeChecking = require("@typescript-eslint/eslint-plugin/dist/configs/recommended-requiring-type-checking.js");
|
||||||
const typescriptEslintPrettier = require("eslint-config-prettier/@typescript-eslint");
|
const typescriptEslintPrettier = require("eslint-config-prettier/@typescript-eslint");
|
||||||
const react = require("eslint-plugin-react").configs.recommended;
|
const react = require("eslint-plugin-react").configs.recommended;
|
||||||
const jsxA11y = require("eslint-plugin-jsx-a11y").configs.recommended;
|
const jsxA11y = require("eslint-plugin-jsx-a11y").configs.recommended;
|
||||||
@@ -21,6 +21,7 @@ const typescriptOverrides = {
|
|||||||
"@typescript-eslint/tslint",
|
"@typescript-eslint/tslint",
|
||||||
"react",
|
"react",
|
||||||
"jsx-a11y",
|
"jsx-a11y",
|
||||||
|
"react-hooks",
|
||||||
],
|
],
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
@@ -41,12 +42,21 @@ const typescriptOverrides = {
|
|||||||
"error",
|
"error",
|
||||||
{ default: "array-simple", readonly: "generic" },
|
{ default: "array-simple", readonly: "generic" },
|
||||||
],
|
],
|
||||||
"@typescript-eslint/ban-types": "error",
|
"@typescript-eslint/ban-types": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
types: {
|
||||||
|
"{}": false,
|
||||||
|
object: false,
|
||||||
|
extendDefaults: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
"@typescript-eslint/camelcase": "off",
|
"@typescript-eslint/camelcase": "off",
|
||||||
"@typescript-eslint/consistent-type-assertions": "error",
|
"@typescript-eslint/consistent-type-assertions": "error",
|
||||||
"@typescript-eslint/consistent-type-definitions": "error",
|
"@typescript-eslint/consistent-type-definitions": "error",
|
||||||
"@typescript-eslint/class-name-casing": "error",
|
|
||||||
"@typescript-eslint/explicit-function-return-type": "off",
|
"@typescript-eslint/explicit-function-return-type": "off",
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"@typescript-eslint/explicit-member-accessibility": [
|
"@typescript-eslint/explicit-member-accessibility": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
@@ -56,7 +66,6 @@ const typescriptOverrides = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"@typescript-eslint/indent": "off",
|
"@typescript-eslint/indent": "off",
|
||||||
"@typescript-eslint/interface-name-prefix": "error",
|
|
||||||
"@typescript-eslint/member-delimiter-style": "off",
|
"@typescript-eslint/member-delimiter-style": "off",
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
"@typescript-eslint/no-empty-function": "off",
|
||||||
"@typescript-eslint/no-empty-interface": "error",
|
"@typescript-eslint/no-empty-interface": "error",
|
||||||
@@ -64,7 +73,6 @@ const typescriptOverrides = {
|
|||||||
"@typescript-eslint/no-misused-new": "error",
|
"@typescript-eslint/no-misused-new": "error",
|
||||||
"@typescript-eslint/no-namespace": "error",
|
"@typescript-eslint/no-namespace": "error",
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
"@typescript-eslint/no-parameter-properties": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
"@typescript-eslint/no-unused-vars": [
|
||||||
"error",
|
"error",
|
||||||
{ args: "none", ignoreRestSiblings: true },
|
{ args: "none", ignoreRestSiblings: true },
|
||||||
@@ -85,11 +93,20 @@ const typescriptOverrides = {
|
|||||||
"react/prop-types": "off",
|
"react/prop-types": "off",
|
||||||
"react/no-unescaped-entities": "off",
|
"react/no-unescaped-entities": "off",
|
||||||
"no-empty-function": "off",
|
"no-empty-function": "off",
|
||||||
|
// (tessalt) disabled because video elements are only used to display gifs, which have no audio
|
||||||
|
"jsx-a11y/media-has-caption": "off",
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let typescriptTypeCheckingOverrides = {
|
const jestTypeCheckingOverrides = {
|
||||||
|
files: ["test/**/*.ts", "test/**/*.tsx"],
|
||||||
|
rules: {
|
||||||
|
"@typescript-eslint/no-floating-promises": "off",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const typescriptTypeCheckingOverrides = {
|
||||||
files: ["*.ts", "*.tsx"],
|
files: ["*.ts", "*.tsx"],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: [
|
project: [
|
||||||
@@ -116,12 +133,18 @@ let typescriptTypeCheckingOverrides = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"@typescript-eslint/no-misused-promises": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-assignment": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-call": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-return": "off",
|
||||||
// 28.11.19: (cvle) Disabled because behavior of regexp.exec seems different than str.match?
|
// 28.11.19: (cvle) Disabled because behavior of regexp.exec seems different than str.match?
|
||||||
"@typescript-eslint/prefer-regexp-exec": "off",
|
"@typescript-eslint/prefer-regexp-exec": "off",
|
||||||
"@typescript-eslint/require-await": "off",
|
"@typescript-eslint/require-await": "off",
|
||||||
"@typescript-eslint/no-misused-promises": "off",
|
"@typescript-eslint/restrict-template-expressions": "off",
|
||||||
"@typescript-eslint/unbound-method": "off", // 10.10.19: (cvle) seems to give false positive.
|
"@typescript-eslint/unbound-method": "off", // 10.10.19: (cvle) seems to give false positive.
|
||||||
}),
|
}),
|
||||||
|
overrides: [jestTypeCheckingOverrides],
|
||||||
};
|
};
|
||||||
|
|
||||||
const jestOverrides = {
|
const jestOverrides = {
|
||||||
@@ -153,6 +176,7 @@ module.exports = {
|
|||||||
"eslint:recommended",
|
"eslint:recommended",
|
||||||
"plugin:jsdoc/recommended",
|
"plugin:jsdoc/recommended",
|
||||||
"plugin:prettier/recommended",
|
"plugin:prettier/recommended",
|
||||||
|
"plugin:react-hooks/recommended",
|
||||||
],
|
],
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 2018,
|
ecmaVersion: 2018,
|
||||||
@@ -169,6 +193,7 @@ module.exports = {
|
|||||||
"eol-last": "off",
|
"eol-last": "off",
|
||||||
eqeqeq: "error",
|
eqeqeq: "error",
|
||||||
"guard-for-in": "error",
|
"guard-for-in": "error",
|
||||||
|
"jsdoc/check-param-names": "off",
|
||||||
"jsdoc/require-jsdoc": "off",
|
"jsdoc/require-jsdoc": "off",
|
||||||
"jsdoc/require-returns": "off",
|
"jsdoc/require-returns": "off",
|
||||||
"jsdoc/require-param": "off",
|
"jsdoc/require-param": "off",
|
||||||
|
|||||||
@@ -20,5 +20,4 @@ yarn.lock
|
|||||||
dist
|
dist
|
||||||
*.css.d.ts
|
*.css.d.ts
|
||||||
__generated__
|
__generated__
|
||||||
README.md.orig
|
|
||||||
persisted-queries.json
|
persisted-queries.json
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# .kodiak.toml
|
||||||
|
|
||||||
|
# Kodiak's configuration file should be placed at `.kodiak.toml` (repository
|
||||||
|
# root) or `.github/.kodiak.toml`.
|
||||||
|
# docs: https://kodiakhq.com/docs/config-reference
|
||||||
|
|
||||||
|
# version is the only required setting in a kodiak config.
|
||||||
|
# `1` is the only valid setting for this field.
|
||||||
|
version = 1
|
||||||
|
|
||||||
|
[merge]
|
||||||
|
# Label to enable Kodiak to merge a PR.
|
||||||
|
|
||||||
|
# By default, Kodiak will only act on PRs that have this label. You can disable
|
||||||
|
# this requirement via `merge.require_automerge_label`.
|
||||||
|
automerge_label = "🚀 merge it!" # default: "automerge"
|
||||||
|
|
||||||
|
# Kodiak will not merge a PR with any of these labels.
|
||||||
|
blocking_labels = ["don't merge"] # default: [], options: list of label names (e.g. ["wip"])
|
||||||
|
|
||||||
|
# Choose merge method for Kodiak to use.
|
||||||
|
#
|
||||||
|
# Kodiak will report a configuration error if the selected merge method is
|
||||||
|
# disabled for a repository.
|
||||||
|
#
|
||||||
|
# If you're using the "Require signed commits" GitHub Branch Protection setting
|
||||||
|
# to require commit signatures, _`"merge"` is the only compatible option_. Any
|
||||||
|
# other option will cause Kodiak to raise a configuration error.
|
||||||
|
method = "squash" # default: "merge", options: "merge", "squash", "rebase"
|
||||||
|
|
||||||
|
# Once a PR is merged, delete the branch. This option behaves like the GitHub
|
||||||
|
# repository setting "Automatically delete head branches", which automatically
|
||||||
|
# deletes head branches after pull requests are merged.
|
||||||
|
delete_branch_on_merge = true # default: false
|
||||||
|
|
||||||
|
# Don't wait for in-progress status checks on a PR to finish before updating the
|
||||||
|
# branch.
|
||||||
|
optimistic_updates = false # default: true
|
||||||
|
|
||||||
|
[merge.message]
|
||||||
|
# Strip HTML comments (`<!-- some HTML comment -->`) from merge commit body.
|
||||||
|
# This setting is useful for stripping HTML comments created by PR templates.
|
||||||
|
# This option only applies when `merge.message.body_type = "markdown"`.
|
||||||
|
strip_html_comments = true # default: false
|
||||||
Vendored
+1
-1
@@ -54,5 +54,5 @@
|
|||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"package-lock.json": true
|
"package-lock.json": true
|
||||||
},
|
},
|
||||||
"debug.node.autoAttach": "off",
|
"debug.node.autoAttach": "off"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ createComment.error
|
|||||||
- <a href="#unfeatureComment">unfeatureComment</a>
|
- <a href="#unfeatureComment">unfeatureComment</a>
|
||||||
- <a href="#updateNotificationSettings">updateNotificationSettings</a>
|
- <a href="#updateNotificationSettings">updateNotificationSettings</a>
|
||||||
- <a href="#updateStorySettings">updateStorySettings</a>
|
- <a href="#updateStorySettings">updateStorySettings</a>
|
||||||
|
- <a href="#updateUserMediaSettings">updateUserMediaSettings</a>
|
||||||
- <a href="#viewConversation">viewConversation</a>
|
- <a href="#viewConversation">viewConversation</a>
|
||||||
- <a href="#viewFullDiscussion">viewFullDiscussion</a>
|
- <a href="#viewFullDiscussion">viewFullDiscussion</a>
|
||||||
- <a href="#viewNewComments">viewNewComments</a>
|
- <a href="#viewNewComments">viewNewComments</a>
|
||||||
@@ -587,6 +588,17 @@ createComment.error
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
- <a id="updateUserMediaSettings">**updateUserMediaSettings.success**, **updateUserMediaSettings.error**</a>:
|
||||||
|
```ts
|
||||||
|
{
|
||||||
|
unfurlEmbeds?: boolean | null | undefined;
|
||||||
|
success: {};
|
||||||
|
error: {
|
||||||
|
message: string;
|
||||||
|
code?: string | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
- <a id="viewConversation">**viewConversation**</a>: This event is emitted when the viewer changes to the single conversation view.
|
- <a id="viewConversation">**viewConversation**</a>: This event is emitted when the viewer changes to the single conversation view.
|
||||||
```ts
|
```ts
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
|
||||||
|
# CSS Variables
|
||||||
|
|
||||||
|
Coral defines a set of CSS Variables that you can use to broadly customize the
|
||||||
|
look and feel of your comment stream. For example you can easily redefine the colors
|
||||||
|
or fonts that are being used.
|
||||||
|
|
||||||
|
To change the CSS Variables, use the following example in your custom CSS file:
|
||||||
|
|
||||||
|
```
|
||||||
|
:root {
|
||||||
|
--font-family-primary: 'Verdana';
|
||||||
|
--round-corners: 0px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following list contains the CSS Variables that can be customized.
|
||||||
|
|
||||||
|
**Info**: *Before 6.3.0 Coral uses a different set of CSS Variables. If you are still using
|
||||||
|
the old CSS Variables, please upgrade. Currently we have a compatibility layer to bridge the old CSS Variables to the new ones. This mechanism will be removed in the future.*
|
||||||
|
|
||||||
|
<!-- START docs:css-variables -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN npm run docs:css-variables -->
|
||||||
|
### Index
|
||||||
|
- <a href="#variables">Variables</a>
|
||||||
|
- <a href="#palette">palette</a>
|
||||||
|
- <a href="#palette-primary">palette-primary</a>
|
||||||
|
- <a href="#palette-background">palette-background</a>
|
||||||
|
- <a href="#palette-text">palette-text</a>
|
||||||
|
- <a href="#palette-grey">palette-grey</a>
|
||||||
|
- <a href="#palette-error">palette-error</a>
|
||||||
|
- <a href="#palette-success">palette-success</a>
|
||||||
|
- <a href="#palette-warning">palette-warning</a>
|
||||||
|
- <a href="#font-family">font-family</a>
|
||||||
|
- <a href="#font-weight">font-weight</a>
|
||||||
|
- <a href="#font-weight-primary">font-weight-primary</a>
|
||||||
|
- <a href="#font-weight-secondary">font-weight-secondary</a>
|
||||||
|
- <a href="#font-size">font-size</a>
|
||||||
|
- <a href="#shadow">shadow</a>
|
||||||
|
- <a href="#spacing">spacing</a>
|
||||||
|
- <a href="#mini-unit">mini-unit</a>
|
||||||
|
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
|
||||||
|
Use this to remove round corners or make them more round.
|
||||||
|
|
||||||
|
`--round-corners: 3px;`
|
||||||
|
|
||||||
|
### palette
|
||||||
|
|
||||||
|
`--palette-divider: rgba(0, 0, 0, 0.12);`
|
||||||
|
|
||||||
|
#### palette-primary
|
||||||
|
|
||||||
|
Color palette that is used as the primary color.
|
||||||
|
|
||||||
|
`--palette-primary-100: #EBF6FF; /* Before 6.3.0: --palette-primary-lightest */`
|
||||||
|
|
||||||
|
`--palette-primary-200: #B7DCFF; /* Before 6.3.0: --palette-primary-lighter */`
|
||||||
|
|
||||||
|
`--palette-primary-300: #61B3FF; /* Before 6.3.0: --palette-primary-light */`
|
||||||
|
|
||||||
|
`--palette-primary-400: #2897FF; /* Before 6.3.0: --palette-primary-main */`
|
||||||
|
|
||||||
|
`--palette-primary-500: #0070D9; /* Before 6.3.0: --palette-primary-main */`
|
||||||
|
|
||||||
|
`--palette-primary-600: #0062BE; /* Before 6.3.0: --palette-primary-main */`
|
||||||
|
|
||||||
|
`--palette-primary-700: #005AAE; /* Before 6.3.0: --palette-primary-main */`
|
||||||
|
|
||||||
|
`--palette-primary-800: #004688; /* Before 6.3.0: --palette-primary-dark */`
|
||||||
|
|
||||||
|
`--palette-primary-900: #00386D; /* Before 6.3.0: --palette-primary-darkest */`
|
||||||
|
|
||||||
|
#### palette-background
|
||||||
|
|
||||||
|
Color palette that is used for background colors.
|
||||||
|
|
||||||
|
`--palette-background-body: #FFFFFF;`
|
||||||
|
|
||||||
|
`--palette-background-popover: #FFFFFF;`
|
||||||
|
|
||||||
|
`--palette-background-tooltip: #65696B;`
|
||||||
|
|
||||||
|
`--palette-background-input: #FFFFFF;`
|
||||||
|
|
||||||
|
`--palette-background-input-disabled: #EFEFEF;`
|
||||||
|
|
||||||
|
#### palette-text
|
||||||
|
|
||||||
|
Color palette that is used for text.
|
||||||
|
|
||||||
|
`--palette-text-000: #FFFFFF; /* Before 6.3.0: --palette-text-light */`
|
||||||
|
|
||||||
|
`--palette-text-100: #65696B; /* Before 6.3.0: --palette-text-secondary */`
|
||||||
|
|
||||||
|
`--palette-text-500: #353F44; /* Before 6.3.0: --palette-text-primary */`
|
||||||
|
|
||||||
|
`--palette-text-900: #14171A; /* Before 6.3.0: --palette-text-dark */`
|
||||||
|
|
||||||
|
`--palette-text-placeholder: #9FA4A6; /* Before 6.3.0: --palette-grey-lighter */`
|
||||||
|
|
||||||
|
`--palette-text-input-disabled: #9FA4A6; /* Before 6.3.0: --palette-grey-lighter */`
|
||||||
|
|
||||||
|
#### palette-grey
|
||||||
|
|
||||||
|
Color palette that is used for grey shades.
|
||||||
|
|
||||||
|
`--palette-grey-100: #F4F7F7; /* Before 6.3.0: --palette-grey-lightest */`
|
||||||
|
|
||||||
|
`--palette-grey-200: #EAEFF0; /* Before 6.3.0: --palette-grey-lightest */`
|
||||||
|
|
||||||
|
`--palette-grey-300: #CBD1D2; /* Before 6.3.0: --palette-grey-lighter */`
|
||||||
|
|
||||||
|
`--palette-grey-400: #9FA4A6; /* Before 6.3.0: --palette-grey-lighter */`
|
||||||
|
|
||||||
|
`--palette-grey-500: #65696B; /* Before 6.3.0: --palette-grey-main */`
|
||||||
|
|
||||||
|
`--palette-grey-600: #49545C; /* Before 6.3.0: --palette-grey-dark */`
|
||||||
|
|
||||||
|
`--palette-grey-700: #32404D; /* Before 6.3.0: --palette-grey-darkest */`
|
||||||
|
|
||||||
|
`--palette-grey-800: #202E3E; /* Before 6.3.0: --palette-grey-darkest */`
|
||||||
|
|
||||||
|
`--palette-grey-900: #132033; /* Before 6.3.0: --palette-grey-darkest */`
|
||||||
|
|
||||||
|
#### palette-error
|
||||||
|
|
||||||
|
Color palette that is used for indicating something is error red.
|
||||||
|
|
||||||
|
`--palette-error-100: #FCE5D9; /* Before 6.3.0: --palette-error-lightest */`
|
||||||
|
|
||||||
|
`--palette-error-200: #FAC6B4; /* Before 6.3.0: --palette-error-lighter */`
|
||||||
|
|
||||||
|
`--palette-error-300: #F29D8B; /* Before 6.3.0: --palette-error-lighter */`
|
||||||
|
|
||||||
|
`--palette-error-400: #E5766C; /* Before 6.3.0: --palette-error-light */`
|
||||||
|
|
||||||
|
`--palette-error-500: #D53F3F; /* Before 6.3.0: --palette-error-main */`
|
||||||
|
|
||||||
|
`--palette-error-600: #B72E39; /* Before 6.3.0: --palette-error-main */`
|
||||||
|
|
||||||
|
`--palette-error-700: #991F34; /* Before 6.3.0: --palette-error-dark */`
|
||||||
|
|
||||||
|
`--palette-error-800: #7B142E; /* Before 6.3.0: --palette-error-darkest */`
|
||||||
|
|
||||||
|
`--palette-error-900: #660C2B; /* Before 6.3.0: --palette-error-darkest */`
|
||||||
|
|
||||||
|
#### palette-success
|
||||||
|
|
||||||
|
Color palette that is used for indicating something is success green.
|
||||||
|
|
||||||
|
`--palette-success-100: #D8F9D5; /* Before 6.3.0: --palette-success-lightest */`
|
||||||
|
|
||||||
|
`--palette-success-200: #ADF3AD; /* Before 6.3.0: --palette-success-lighter */`
|
||||||
|
|
||||||
|
`--palette-success-300: #7CDB85; /* Before 6.3.0: --palette-success-lighter */`
|
||||||
|
|
||||||
|
`--palette-success-400: #54B767; /* Before 6.3.0: --palette-success-light */`
|
||||||
|
|
||||||
|
`--palette-success-500: #268742; /* Before 6.3.0: --palette-success-main */`
|
||||||
|
|
||||||
|
`--palette-success-600: #1B743D; /* Before 6.3.0: --palette-success-main */`
|
||||||
|
|
||||||
|
`--palette-success-700: #136138; /* Before 6.3.0: --palette-success-dark */`
|
||||||
|
|
||||||
|
`--palette-success-800: #0C4E32; /* Before 6.3.0: --palette-success-darkest */`
|
||||||
|
|
||||||
|
`--palette-success-900: #07402E; /* Before 6.3.0: --palette-success-darkest */`
|
||||||
|
|
||||||
|
#### palette-warning
|
||||||
|
|
||||||
|
Color palette that is used for indicating a warning and is usually yellow.
|
||||||
|
|
||||||
|
`--palette-warning-100: #FFFACC; /* Before 6.3.0: --palette-warning-main */`
|
||||||
|
|
||||||
|
`--palette-warning-500: #FFE91F; /* Before 6.3.0: --palette-warning-main */`
|
||||||
|
|
||||||
|
### font-family
|
||||||
|
|
||||||
|
Different font families currently in use.
|
||||||
|
|
||||||
|
`--font-family-primary: "Open Sans"; /* Before 6.3.0: --font-family-sans-serif */`
|
||||||
|
|
||||||
|
`--font-family-secondary: "Nunito"; /* Before 6.3.0: --font-family-serif */`
|
||||||
|
|
||||||
|
### font-weight
|
||||||
|
|
||||||
|
Different font weights with matching values for the fonts.
|
||||||
|
|
||||||
|
#### font-weight-primary
|
||||||
|
|
||||||
|
`--font-weight-primary-bold: 700; /* Before 6.3.0: --font-weight-bold */`
|
||||||
|
|
||||||
|
`--font-weight-primary-semi-bold: 600; /* Before 6.3.0: --font-weight-medium */`
|
||||||
|
|
||||||
|
`--font-weight-primary-regular: 300; /* Before 6.3.0: --font-weight-light */`
|
||||||
|
|
||||||
|
#### font-weight-secondary
|
||||||
|
|
||||||
|
`--font-weight-secondary-bold: 700; /* Before 6.3.0: --font-weight-bold */`
|
||||||
|
|
||||||
|
`--font-weight-secondary-regular: 300; /* Before 6.3.0: --font-weight-light */`
|
||||||
|
|
||||||
|
### font-size
|
||||||
|
|
||||||
|
`--font-size-1: 0.75rem;`
|
||||||
|
|
||||||
|
`--font-size-2: 0.875rem;`
|
||||||
|
|
||||||
|
`--font-size-3: 1rem;`
|
||||||
|
|
||||||
|
`--font-size-4: 1.125rem;`
|
||||||
|
|
||||||
|
`--font-size-5: 1.25rem;`
|
||||||
|
|
||||||
|
`--font-size-6: 1.5rem;`
|
||||||
|
|
||||||
|
`--font-size-7: 1.75rem;`
|
||||||
|
|
||||||
|
`--font-size-8: 2rem;`
|
||||||
|
|
||||||
|
`--font-size-9: 2.25rem;`
|
||||||
|
|
||||||
|
`--font-size-icon-xl: 2.25rem;`
|
||||||
|
|
||||||
|
`--font-size-icon-lg: 1.5rem;`
|
||||||
|
|
||||||
|
`--font-size-icon-md: 1.125rem;`
|
||||||
|
|
||||||
|
`--font-size-icon-sm: 0.875rem;`
|
||||||
|
|
||||||
|
`--font-size-icon-xs: 0.75rem;`
|
||||||
|
|
||||||
|
### shadow
|
||||||
|
|
||||||
|
Different shadows that are currently used in Coral.
|
||||||
|
|
||||||
|
`--shadow-popover: 1px 0px 4px rgba(0, 0, 0, 0.25); /* Before 6.3.0: --elevation-main */`
|
||||||
|
|
||||||
|
### spacing
|
||||||
|
|
||||||
|
Different spacing units currenty used in Coral.
|
||||||
|
|
||||||
|
`--spacing-1: 4px;`
|
||||||
|
|
||||||
|
`--spacing-2: 8px;`
|
||||||
|
|
||||||
|
`--spacing-3: 12px;`
|
||||||
|
|
||||||
|
`--spacing-4: 16px;`
|
||||||
|
|
||||||
|
`--spacing-5: 24px;`
|
||||||
|
|
||||||
|
`--spacing-6: 32px;`
|
||||||
|
|
||||||
|
`--spacing-7: 44px;`
|
||||||
|
|
||||||
|
`--spacing-8: 60px;`
|
||||||
|
|
||||||
|
`--spacing-9: 84px;`
|
||||||
|
|
||||||
|
### mini-unit
|
||||||
|
|
||||||
|
Grid units for smaller and larger screens.
|
||||||
|
|
||||||
|
`--mini-unit-small: 4;`
|
||||||
|
|
||||||
|
`--mini-unit-large: 8;`
|
||||||
|
|
||||||
|
<!-- END docs:css-variables -->
|
||||||
@@ -1,39 +1,52 @@
|
|||||||
# Coral 
|
<p align="center">
|
||||||
|
<a href="https://coralproject.net" target="_blank"><img width="250" src="https://docs.coralproject.net/coral/images/coralproject_by_voxmedia.svg" alt="Coral by Vox Media" /></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
Online comments are broken. Our open-source commenting platform, Coral, rethinks
|
<p align="center">
|
||||||
how moderation, comment display, and conversation function, creating the
|
A better commenting experience from <a href="https://product.voxmedia.com/" target="_blank">Vox Media</a>.
|
||||||
opportunity for safer, smarter discussions around your work.
|
</p>
|
||||||
[Read more about Coral here](https://coralproject.net/talk).
|
|
||||||
|
|
||||||
Built with <3 by the Coral team, a part of [Vox Media](https://product.voxmedia.com/).
|
<p align="center">
|
||||||
|
<a href="https://circleci.com/gh/coralproject/talk" target="_blank"><img src="https://img.shields.io/circleci/build/gh/coralproject/talk?style=flat-square" alt="CircleCI" /></a>
|
||||||
|
<a href="https://hub.docker.com/r/coralproject/talk" target="_blank"><img src="https://img.shields.io/docker/v/coralproject/talk?label=docker%20hub&sort=semver&style=flat-square" alt="Docker Image Version" /></a>
|
||||||
|
<a href="https://hub.docker.com/r/coralproject/talk" target="_blank"><img src="https://img.shields.io/docker/image-size/coralproject/talk?label=docker%20image%20size&sort=semver&style=flat-square" alt="Docker Image Size" /></a>
|
||||||
|
<a href="https://twitter.com/coralproject" target="_blank"><img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/coralproject?style=flat-square"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
Preview Coral easily by running it via a Heroku App:
|
## Description
|
||||||
|
|
||||||
[](https://heroku.com/deploy?template=https://github.com/coralproject/talk)
|
Online comments are broken. Our open-source commenting platform,
|
||||||
|
[Coral](https://coralproject.net), rethinks how moderation, comment display, and
|
||||||
|
conversation function, creating the opportunity for safer, smarter discussions
|
||||||
|
around your work.
|
||||||
|
|
||||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
We offer hosting and support packages for Coral, as well as exclusive,
|
||||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
customer-only features. [Contact us](https://coralproject.net/pricing/) for more
|
||||||
## Table of Contents
|
information or [sign up for a webinar](https://coralproject.net).
|
||||||
|
|
||||||
- [Documentation](#documentation)
|
|
||||||
- [Pre-Launch Guide](#pre-launch-guide)
|
|
||||||
- [More Resources](#more-resources)
|
|
||||||
- [License](#license)
|
|
||||||
|
|
||||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
You can get started with Coral using our [Documentation](https://docs.coralproject.net/talk/).
|
If you're new to Coral, the [Coral documentation](https://docs.coralproject.net/)
|
||||||
|
is a great place to start running and developing with Coral.
|
||||||
|
|
||||||
## Pre-Launch Guide
|
You’ve installed Coral, and you’re preparing to launch it on your site. The real
|
||||||
|
community work starts now, before you go live. You have a unique opportunity
|
||||||
|
pre-launch to set your community up for success. Read our
|
||||||
|
[Community Guides](https://guides.coralproject.net/start-here/) to learn more.
|
||||||
|
|
||||||
You’ve installed Coral on your server, and you’re preparing to launch it on your site. The real community work starts now, before you go live. You have a unique opportunity pre-launch to set your community up for success. Read our [Community Guides](https://guides.coralproject.net/start-here/) to learn more.
|
## Support
|
||||||
|
|
||||||
## More Resources
|
We can help you set up Coral, migrate your comments from another system,
|
||||||
|
integrate your registration platform, pair with your programmers, and help you
|
||||||
|
with bespoke installs. To learn more, [contact us](https://coralproject.net/pricing/).
|
||||||
|
|
||||||
- [Learn more about Coral and sign up for a webinar](https://coralproject.net/)
|
## Contributing
|
||||||
|
|
||||||
|
Coral is a Apache-2.0 licensed open-source project built with <3 by the Coral
|
||||||
|
team, a part of [Vox Media](https://product.voxmedia.com/).
|
||||||
|
|
||||||
|
If you are interested in contributing to Coral, check out our [Contributor's Guide](CONTRIBUTING.md).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Coral is released under the [Apache License, v2.0](/LICENSE).
|
Coral is [Apache-2.0 licensed](LICENSE).
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Coral",
|
|
||||||
"description": "A better commenting experience from Vox Media.",
|
|
||||||
"env": {
|
|
||||||
"REWRITE_ENV": {
|
|
||||||
"description": "Used to rewrite the environment variables set by Heroku.",
|
|
||||||
"value": "REDIS_URI:REDIS_URL,MONGODB_URI:MONGO_URI"
|
|
||||||
},
|
|
||||||
"SIGNING_SECRET": {
|
|
||||||
"description": "The shared secret to use to sign JSON Web Tokens (JWT) with the selected signing algorithm.",
|
|
||||||
"generator": "secret"
|
|
||||||
},
|
|
||||||
"CONCURRENCY": {
|
|
||||||
"description": "The number of worker nodes to spawn to handle traffic.",
|
|
||||||
"value": "1"
|
|
||||||
},
|
|
||||||
"LOCALE": {
|
|
||||||
"description": "Specify the default locale to use for all requests without a locale specified",
|
|
||||||
"value": "en-US"
|
|
||||||
},
|
|
||||||
"ENABLE_GRAPHIQL": {
|
|
||||||
"description": "When true, this will enable the GraphiQL routes",
|
|
||||||
"value": "false"
|
|
||||||
},
|
|
||||||
"TRUST_PROXY": {
|
|
||||||
"description": "When set to 1, it instructs Coral to trust up to one proxy, this is needed for authentication support",
|
|
||||||
"value": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"addons": [
|
|
||||||
{
|
|
||||||
"plan": "mongolab:sandbox",
|
|
||||||
"as": "MONGO"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"plan": "rediscloud:30",
|
|
||||||
"as": "REDIS"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"success_url": "/install",
|
|
||||||
"website": "https://github.com/coralproject/talk"
|
|
||||||
}
|
|
||||||
+3
-3
@@ -42,8 +42,8 @@ exports.onCreateWebpackConfig = ({
|
|||||||
|
|
||||||
if (stage === "develop") {
|
if (stage === "develop") {
|
||||||
config.entry.commons.push(
|
config.entry.commons.push(
|
||||||
// Add our global css variables file.
|
// Add our stream css variables file.
|
||||||
`${srcDir}/core/client/ui/theme/variables.css.ts`
|
`${srcDir}/core/client/ui/theme/stream.css.ts`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ exports.onCreateWebpackConfig = ({
|
|||||||
if (stage === "build-javascript") {
|
if (stage === "build-javascript") {
|
||||||
config.entry.app = [
|
config.entry.app = [
|
||||||
config.entry.app,
|
config.entry.app,
|
||||||
`${appDir}/core/client/ui/theme/variables.css.ts`,
|
`${appDir}/core/client/ui/theme/stream.css.ts`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|||||||
Generated
+13399
-7918
File diff suppressed because it is too large
Load Diff
+79
-58
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@coralproject/talk",
|
"name": "@coralproject/talk",
|
||||||
"version": "6.2.2",
|
"version": "6.3.2",
|
||||||
"author": "The Coral Project",
|
"author": "The Coral Project",
|
||||||
"homepage": "https://coralproject.net/",
|
"homepage": "https://coralproject.net/",
|
||||||
"sideEffects": [
|
"sideEffects": [
|
||||||
@@ -21,13 +21,15 @@
|
|||||||
],
|
],
|
||||||
"description": "A better commenting experience from Vox Media.",
|
"description": "A better commenting experience from Vox Media.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"clean": "gulp clean",
|
||||||
"build": "NODE_ENV=production npm-run-all generate-persist --parallel build:client build:server",
|
"build": "NODE_ENV=production npm-run-all generate-persist --parallel build:client build:server",
|
||||||
"build:development": "NODE_ENV=development npm-run-all generate --parallel build:client build:server",
|
"build:development": "NODE_ENV=development npm-run-all generate --parallel build:client build:server",
|
||||||
"build:client": "ts-node --transpile-only ./scripts/build.ts",
|
"build:client": "ts-node --transpile-only ./scripts/build.ts",
|
||||||
"build:server": "gulp server",
|
"build:server": "gulp server",
|
||||||
"migration:create": "ts-node --transpile-only ./scripts/migration/create.ts",
|
"migration:create": "ts-node --transpile-only ./scripts/migration/create.ts",
|
||||||
"docs:events": "ts-node ./scripts/generateEventDocs.ts ./src/core/client/stream/events.ts ./CLIENT_EVENTS.md",
|
"docs:events": "ts-node ./scripts/generateEventDocs.ts ./src/core/client/stream/events.ts ./CLIENT_EVENTS.md",
|
||||||
"doctoc": "doctoc --maxlevel=3 --title '## Table of Contents' README.md CLIENT_EVENTS.md CONTRIBUTING.md WEBHOOKS.md EXTERNAL_MODERATION_PHASES.md",
|
"docs:css-variables": "ts-node ./scripts/generateCSSVariablesDocs.ts ./src/core/client/ui/theme/streamVariables.ts ./CSS_VARIABLES.md",
|
||||||
|
"doctoc": "doctoc --maxlevel=3 --title '## Table of Contents' CLIENT_EVENTS.md CONTRIBUTING.md WEBHOOKS.md EXTERNAL_MODERATION_PHASES.md",
|
||||||
"generate": "npm-run-all generate:css-types generate:schema generate:relay",
|
"generate": "npm-run-all generate:css-types generate:schema generate:relay",
|
||||||
"generate-persist": "npm-run-all generate:css-types generate:schema generate:relay-persist",
|
"generate-persist": "npm-run-all generate:css-types generate:schema generate:relay-persist",
|
||||||
"generate:css-types": "tcm src/core/client/",
|
"generate:css-types": "tcm src/core/client/",
|
||||||
@@ -41,7 +43,7 @@
|
|||||||
"generate:schema": "node ./scripts/generateSchemaTypes.js",
|
"generate:schema": "node ./scripts/generateSchemaTypes.js",
|
||||||
"docz": "docz",
|
"docz": "docz",
|
||||||
"start": "NODE_ENV=production node dist/index.js",
|
"start": "NODE_ENV=production node dist/index.js",
|
||||||
"start:development": "NODE_ENV=development CONCURRENCY=${CONCURRENCY:-1} TS_NODE_PROJECT=./src/tsconfig.json ts-node-dev --inspect --transpile-only --no-notify -r tsconfig-paths/register ./src/index.ts",
|
"start:development": "NODE_ENV=development TS_NODE_PROJECT=./src/tsconfig.json ts-node-dev --inspect --transpile-only --no-notify -r tsconfig-paths/register ./src/index.ts",
|
||||||
"start:webpackDevServer": "ts-node --transpile-only ./scripts/start.ts",
|
"start:webpackDevServer": "ts-node --transpile-only ./scripts/start.ts",
|
||||||
"lint": "npm-run-all --parallel lint:* tscheck:*",
|
"lint": "npm-run-all --parallel lint:* tscheck:*",
|
||||||
"lint:server": "eslint 'src/**/*.{js,ts,tsx}' --ignore-pattern 'src/core/client/**'",
|
"lint:server": "eslint 'src/**/*.{js,ts,tsx}' --ignore-pattern 'src/core/client/**'",
|
||||||
@@ -64,14 +66,17 @@
|
|||||||
"@fluent/dom": "^0.6.0",
|
"@fluent/dom": "^0.6.0",
|
||||||
"@hapi/joi": "^17.1.1",
|
"@hapi/joi": "^17.1.1",
|
||||||
"@metascraper/helpers": "^5.11.6",
|
"@metascraper/helpers": "^5.11.6",
|
||||||
|
"@rudderstack/rudder-sdk-node": "0.0.2",
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
"akismet-api": "^5.0.0",
|
"akismet-api": "^5.0.0",
|
||||||
"apollo-server-express": "^2.11.0",
|
"apollo-server-core": "^2.14.4",
|
||||||
|
"apollo-server-express": "^2.14.2",
|
||||||
"archiver": "^3.1.1",
|
"archiver": "^3.1.1",
|
||||||
"basic-auth": "^2.0.1",
|
"basic-auth": "^2.0.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bull": "^3.13.0",
|
"bull": "^3.13.0",
|
||||||
"bunyan": "^1.8.12",
|
"bunyan": "^1.8.12",
|
||||||
|
"bytes": "^3.1.0",
|
||||||
"cheerio": "^1.0.0-rc.3",
|
"cheerio": "^1.0.0-rc.3",
|
||||||
"consolidate": "0.14.0",
|
"consolidate": "0.14.0",
|
||||||
"content-security-policy-builder": "^2.1.0",
|
"content-security-policy-builder": "^2.1.0",
|
||||||
@@ -84,6 +89,7 @@
|
|||||||
"dataloader": "1.4.0",
|
"dataloader": "1.4.0",
|
||||||
"dompurify": "^2.0.8",
|
"dompurify": "^2.0.8",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"emailjs": "^3.2.0",
|
||||||
"env-rewrite": "^1.0.2",
|
"env-rewrite": "^1.0.2",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-enforces-ssl": "^1.1.0",
|
"express-enforces-ssl": "^1.1.0",
|
||||||
@@ -93,8 +99,7 @@
|
|||||||
"graphql-config": "^2.2.2",
|
"graphql-config": "^2.2.2",
|
||||||
"graphql-extensions": "^0.11.0",
|
"graphql-extensions": "^0.11.0",
|
||||||
"graphql-fields": "2.0.3",
|
"graphql-fields": "2.0.3",
|
||||||
"graphql-import": "^0.7.1",
|
"graphql-playground-html": "1.6.13",
|
||||||
"graphql-playground-html": "^1.6.13",
|
|
||||||
"graphql-redis-subscriptions": "^2.2.1",
|
"graphql-redis-subscriptions": "^2.2.1",
|
||||||
"graphql-subscriptions": "^1.1.0",
|
"graphql-subscriptions": "^1.1.0",
|
||||||
"graphql-tools": "^4.0.7",
|
"graphql-tools": "^4.0.7",
|
||||||
@@ -107,7 +112,7 @@
|
|||||||
"juice": "^6.0.0",
|
"juice": "^6.0.0",
|
||||||
"jwks-rsa": "^1.7.0",
|
"jwks-rsa": "^1.7.0",
|
||||||
"linkifyjs": "^2.1.9",
|
"linkifyjs": "^2.1.9",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.19",
|
||||||
"long-settimeout": "^1.0.1",
|
"long-settimeout": "^1.0.1",
|
||||||
"lru-cache": "^5.1.1",
|
"lru-cache": "^5.1.1",
|
||||||
"luxon": "^1.22.2",
|
"luxon": "^1.22.2",
|
||||||
@@ -115,11 +120,10 @@
|
|||||||
"metascraper-description": "^5.11.6",
|
"metascraper-description": "^5.11.6",
|
||||||
"metascraper-image": "^5.11.6",
|
"metascraper-image": "^5.11.6",
|
||||||
"metascraper-title": "^5.11.6",
|
"metascraper-title": "^5.11.6",
|
||||||
"mongodb": "^3.5.5",
|
"mongodb": "^3.5.9",
|
||||||
"mongodb-core": "^3.2.7",
|
"mongodb-core": "^3.2.7",
|
||||||
"ms": "^2.1.2",
|
"ms": "^2.1.2",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"nodemailer": "^6.4.6",
|
|
||||||
"nunjucks": "^3.2.1",
|
"nunjucks": "^3.2.1",
|
||||||
"on-finished": "^2.3.0",
|
"on-finished": "^2.3.0",
|
||||||
"passport": "^0.4.1",
|
"passport": "^0.4.1",
|
||||||
@@ -135,7 +139,6 @@
|
|||||||
"source-map-support": "^0.5.16",
|
"source-map-support": "^0.5.16",
|
||||||
"stack-utils": "^2.0.1",
|
"stack-utils": "^2.0.1",
|
||||||
"striptags": "^3.1.1",
|
"striptags": "^3.1.1",
|
||||||
"throng": "^4.0.0",
|
|
||||||
"tsscmp": "^1.0.6",
|
"tsscmp": "^1.0.6",
|
||||||
"url-regex": "^5.0.0",
|
"url-regex": "^5.0.0",
|
||||||
"uuid": "^7.0.3",
|
"uuid": "^7.0.3",
|
||||||
@@ -143,13 +146,13 @@
|
|||||||
"xregexp": "^4.3.0"
|
"xregexp": "^4.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.9.0",
|
"@babel/core": "^7.10.3",
|
||||||
"@babel/preset-env": "^7.9.0",
|
"@babel/preset-env": "^7.10.3",
|
||||||
"@babel/preset-react": "^7.9.4",
|
"@babel/preset-react": "^7.10.1",
|
||||||
"@babel/preset-typescript": "^7.9.0",
|
"@babel/preset-typescript": "^7.10.1",
|
||||||
"@babel/runtime-corejs3": "^7.9.2",
|
"@babel/runtime-corejs3": "^7.10.3",
|
||||||
"@coralproject/npm-run-all": "^4.1.5",
|
"@coralproject/npm-run-all": "^4.1.5",
|
||||||
"@coralproject/rte": "^0.11.1",
|
"@coralproject/rte": "^1.2.3",
|
||||||
"@fluent/react": "^0.11.1",
|
"@fluent/react": "^0.11.1",
|
||||||
"@intervolga/optimize-cssnano-plugin": "^1.0.6",
|
"@intervolga/optimize-cssnano-plugin": "^1.0.6",
|
||||||
"@types/archiver": "^3.1.0",
|
"@types/archiver": "^3.1.0",
|
||||||
@@ -157,13 +160,14 @@
|
|||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
"@types/bull": "^3.12.1",
|
"@types/bull": "^3.12.1",
|
||||||
"@types/bunyan": "^1.8.6",
|
"@types/bunyan": "^1.8.6",
|
||||||
|
"@types/bytes": "^3.1.0",
|
||||||
"@types/case-sensitive-paths-webpack-plugin": "^2.1.4",
|
"@types/case-sensitive-paths-webpack-plugin": "^2.1.4",
|
||||||
"@types/cheerio": "^0.22.17",
|
"@types/cheerio": "^0.22.17",
|
||||||
"@types/classnames": "^2.2.10",
|
"@types/classnames": "^2.2.10",
|
||||||
"@types/common-tags": "^1.8.0",
|
"@types/common-tags": "^1.8.0",
|
||||||
"@types/compression-webpack-plugin": "^2.0.1",
|
"@types/compression-webpack-plugin": "^2.0.1",
|
||||||
"@types/consolidate": "0.14.0",
|
"@types/consolidate": "0.14.0",
|
||||||
"@types/convict": "^4.2.1",
|
"@types/convict": "^5.2.1",
|
||||||
"@types/cookie": "^0.3.3",
|
"@types/cookie": "^0.3.3",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/cors": "^2.8.6",
|
"@types/cors": "^2.8.6",
|
||||||
@@ -183,10 +187,10 @@
|
|||||||
"@types/html-minifier": "^3.5.3",
|
"@types/html-minifier": "^3.5.3",
|
||||||
"@types/html-minifier-terser": "^5.0.0",
|
"@types/html-minifier-terser": "^5.0.0",
|
||||||
"@types/html-to-text": "^1.4.31",
|
"@types/html-to-text": "^1.4.31",
|
||||||
"@types/html-webpack-plugin": "^3.2.2",
|
"@types/html-webpack-plugin": "^3.2.3",
|
||||||
"@types/ioredis": "^4.14.9",
|
"@types/ioredis": "^4.14.9",
|
||||||
"@types/jest": "^25.1.4",
|
"@types/jest": "^26.0.3",
|
||||||
"@types/jest-axe": "^3.2.1",
|
"@types/jest-axe": "^3.2.2",
|
||||||
"@types/jsdom": "^16.2.0",
|
"@types/jsdom": "^16.2.0",
|
||||||
"@types/jsonwebtoken": "^8.3.8",
|
"@types/jsonwebtoken": "^8.3.8",
|
||||||
"@types/linkifyjs": "^2.1.3",
|
"@types/linkifyjs": "^2.1.3",
|
||||||
@@ -199,7 +203,6 @@
|
|||||||
"@types/ms": "^0.7.31",
|
"@types/ms": "^0.7.31",
|
||||||
"@types/node": "^12.12.34",
|
"@types/node": "^12.12.34",
|
||||||
"@types/node-fetch": "^2.5.5",
|
"@types/node-fetch": "^2.5.5",
|
||||||
"@types/nodemailer": "^6.4.0",
|
|
||||||
"@types/nunjucks": "^3.1.3",
|
"@types/nunjucks": "^3.1.3",
|
||||||
"@types/on-finished": "^2.3.1",
|
"@types/on-finished": "^2.3.1",
|
||||||
"@types/passport": "^1.0.3",
|
"@types/passport": "^1.0.3",
|
||||||
@@ -218,6 +221,7 @@
|
|||||||
"@types/react-responsive": "^8.0.2",
|
"@types/react-responsive": "^8.0.2",
|
||||||
"@types/react-test-renderer": "^16.9.2",
|
"@types/react-test-renderer": "^16.9.2",
|
||||||
"@types/react-transition-group": "^4.2.4",
|
"@types/react-transition-group": "^4.2.4",
|
||||||
|
"@types/recharts": "^1.8.9",
|
||||||
"@types/recompose": "^0.30.7",
|
"@types/recompose": "^0.30.7",
|
||||||
"@types/relay-runtime": "^8.0.7",
|
"@types/relay-runtime": "^8.0.7",
|
||||||
"@types/sane": "^2.0.0",
|
"@types/sane": "^2.0.0",
|
||||||
@@ -227,26 +231,25 @@
|
|||||||
"@types/source-map-support": "^0.5.1",
|
"@types/source-map-support": "^0.5.1",
|
||||||
"@types/stack-trace": "0.0.29",
|
"@types/stack-trace": "0.0.29",
|
||||||
"@types/stack-utils": "^1.0.1",
|
"@types/stack-utils": "^1.0.1",
|
||||||
"@types/throng": "^4.0.2",
|
|
||||||
"@types/uuid": "^7.0.2",
|
"@types/uuid": "^7.0.2",
|
||||||
"@types/verror": "^1.10.3",
|
"@types/verror": "^1.10.3",
|
||||||
"@types/vinyl": "^2.0.4",
|
"@types/vinyl": "^2.0.4",
|
||||||
"@types/webpack": "^4.41.10",
|
"@types/webpack": "^4.41.17",
|
||||||
"@types/webpack-assets-manifest": "^3.0.0",
|
"@types/webpack-assets-manifest": "^3.0.1",
|
||||||
"@types/webpack-bundle-analyzer": "^2.13.3",
|
"@types/webpack-bundle-analyzer": "^3.8.0",
|
||||||
"@types/webpack-dev-server": "^3.10.1",
|
"@types/webpack-dev-server": "^3.11.0",
|
||||||
"@types/ws": "^7.2.3",
|
"@types/ws": "^7.2.3",
|
||||||
"@types/xregexp": "^4.3.0",
|
"@types/xregexp": "^4.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.26.0",
|
"@typescript-eslint/eslint-plugin": "^3.4.0",
|
||||||
"@typescript-eslint/eslint-plugin-tslint": "^2.26.0",
|
"@typescript-eslint/eslint-plugin-tslint": "^3.4.0",
|
||||||
"@typescript-eslint/parser": "^2.26.0",
|
"@typescript-eslint/parser": "^3.4.0",
|
||||||
"autoprefixer": "^9.7.5",
|
"autoprefixer": "^9.7.5",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-jest": "^25.2.4",
|
"babel-jest": "^26.1.0",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"babel-plugin-lodash": "^3.3.4",
|
"babel-plugin-lodash": "^3.3.4",
|
||||||
"babel-plugin-module-resolver": "^4.0.0",
|
"babel-plugin-module-resolver": "^4.0.0",
|
||||||
"babel-plugin-relay": "^9.0.0",
|
"babel-plugin-relay": "^9.1.0",
|
||||||
"babel-plugin-use-lodash-es": "^0.2.0",
|
"babel-plugin-use-lodash-es": "^0.2.0",
|
||||||
"bowser": "^2.9.0",
|
"bowser": "^2.9.0",
|
||||||
"case-sensitive-paths-webpack-plugin": "^2.3.0",
|
"case-sensitive-paths-webpack-plugin": "^2.3.0",
|
||||||
@@ -266,13 +269,14 @@
|
|||||||
"docz": "^v2.3.0-alpha.14",
|
"docz": "^v2.3.0-alpha.14",
|
||||||
"enzyme": "^3.11.0",
|
"enzyme": "^3.11.0",
|
||||||
"enzyme-adapter-react-16": "^1.15.2",
|
"enzyme-adapter-react-16": "^1.15.2",
|
||||||
"enzyme-to-json": "^3.4.4",
|
"enzyme-to-json": "^3.5.0",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^7.3.1",
|
||||||
"eslint-config-prettier": "^6.10.1",
|
"eslint-config-prettier": "^6.11.0",
|
||||||
"eslint-plugin-jsdoc": "^22.1.0",
|
"eslint-plugin-jsdoc": "^28.5.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
"eslint-plugin-jsx-a11y": "^6.3.1",
|
||||||
"eslint-plugin-prettier": "^3.1.2",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-react": "^7.19.0",
|
"eslint-plugin-react": "^7.20.0",
|
||||||
|
"eslint-plugin-react-hooks": "^4.0.8",
|
||||||
"eventemitter2": "^6.3.1",
|
"eventemitter2": "^6.3.1",
|
||||||
"farce": "^0.2.8",
|
"farce": "^0.2.8",
|
||||||
"final-form": "4.18.6",
|
"final-form": "4.18.6",
|
||||||
@@ -282,23 +286,23 @@
|
|||||||
"fork-ts-checker-webpack-plugin": "^4.1.2",
|
"fork-ts-checker-webpack-plugin": "^4.1.2",
|
||||||
"found": "^0.4.10",
|
"found": "^0.4.10",
|
||||||
"found-relay": "^0.7.0",
|
"found-relay": "^0.7.0",
|
||||||
"graphql-schema-linter": "^0.2.4",
|
"graphql-schema-linter": "^0.4.0",
|
||||||
"graphql-schema-typescript": "^1.3.2",
|
"graphql-schema-typescript": "^1.3.2",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-babel": "^8.0.0",
|
"gulp-babel": "^8.0.0",
|
||||||
"gulp-cli": "^2.2.0",
|
"gulp-cli": "^2.3.0",
|
||||||
"gulp-sourcemaps": "^2.6.5",
|
"gulp-sourcemaps": "^2.6.5",
|
||||||
"gulp-typescript": "^6.0.0-alpha.1",
|
"gulp-typescript": "^6.0.0-alpha.1",
|
||||||
"html-webpack-plugin": "^4.0.4",
|
"html-webpack-plugin": "^4.0.4",
|
||||||
"husky": "^4.2.3",
|
"husky": "^4.2.3",
|
||||||
"intersection-observer": "^0.7.0",
|
"intersection-observer": "^0.7.0",
|
||||||
"jest": "^25.2.4",
|
"jest": "^26.1.0",
|
||||||
"jest-axe": "^3.4.0",
|
"jest-axe": "^3.4.0",
|
||||||
"jest-junit": "^10.0.0",
|
"jest-junit": "^11.0.1",
|
||||||
"jest-localstorage-mock": "^2.4.0",
|
"jest-localstorage-mock": "^2.4.2",
|
||||||
"jest-mock-console": "^1.0.0",
|
"jest-mock-console": "^1.0.1",
|
||||||
"keymaster": "^1.6.2",
|
"keymaster": "^1.6.2",
|
||||||
"lint-staged": "^10.1.1",
|
"lint-staged": "^10.2.11",
|
||||||
"loader-utils": "^2.0.0",
|
"loader-utils": "^2.0.0",
|
||||||
"lodash-es": "^4.17.15",
|
"lodash-es": "^4.17.15",
|
||||||
"marked": "^0.8.2",
|
"marked": "^0.8.2",
|
||||||
@@ -336,10 +340,11 @@
|
|||||||
"react-test-renderer": "^16.13.1",
|
"react-test-renderer": "^16.13.1",
|
||||||
"react-timeago": "^4.4.0",
|
"react-timeago": "^4.4.0",
|
||||||
"react-transition-group": "^4.3.0",
|
"react-transition-group": "^4.3.0",
|
||||||
|
"recharts": "^1.8.5",
|
||||||
"recompose": "^0.30.0",
|
"recompose": "^0.30.0",
|
||||||
"regenerator-runtime": "^0.13.5",
|
"regenerator-runtime": "^0.13.5",
|
||||||
"relay-compiler": "^9.0.0",
|
"relay-compiler": "^9.0.0",
|
||||||
"relay-compiler-language-typescript": "^12.0.0",
|
"relay-compiler-language-typescript": "^12.0.3",
|
||||||
"relay-local-schema": "^0.8.0",
|
"relay-local-schema": "^0.8.0",
|
||||||
"relay-runtime": "^9.0.0",
|
"relay-runtime": "^9.0.0",
|
||||||
"resize-observer-polyfill": "^1.5.1",
|
"resize-observer-polyfill": "^1.5.1",
|
||||||
@@ -356,29 +361,37 @@
|
|||||||
"terser-webpack-plugin": "^2.3.5",
|
"terser-webpack-plugin": "^2.3.5",
|
||||||
"thread-loader": "^2.1.3",
|
"thread-loader": "^2.1.3",
|
||||||
"timekeeper": "^2.2.0",
|
"timekeeper": "^2.2.0",
|
||||||
"ts-jest": "^25.3.0",
|
"ts-jest": "26.1.1",
|
||||||
"ts-loader": "^6.2.2",
|
"ts-loader": "^7.0.5",
|
||||||
"ts-node": "^8.8.1",
|
"ts-node": "^8.10.2",
|
||||||
"ts-node-dev": "^1.0.0-pre.44",
|
"ts-node-dev": "1.0.0-pre.44",
|
||||||
"tsconfig-paths": "^3.9.0",
|
"tsconfig-paths": "^3.9.0",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.2.0",
|
"tsconfig-paths-webpack-plugin": "^3.2.0",
|
||||||
"tslint": "^6.1.0",
|
"tslint": "^6.1.2",
|
||||||
"typed-css-modules": "^0.6.3",
|
"typed-css-modules": "^0.6.4",
|
||||||
"typeface-manuale": "^1.1.4",
|
"typeface-manuale": "^1.1.4",
|
||||||
"typeface-nunito": "^1.1.3",
|
"typeface-nunito": "^1.1.3",
|
||||||
"typeface-open-sans": "^0.0.75",
|
"typeface-open-sans": "^0.0.75",
|
||||||
"typeface-source-sans-pro": "^1.1.5",
|
"typeface-source-sans-pro": "^1.1.5",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.9.5",
|
||||||
"typescript-snapshots-plugin": "^1.7.0",
|
"typescript-snapshots-plugin": "^1.7.0",
|
||||||
"wait-for-expect": "^1.3.0",
|
"wait-for-expect": "^1.3.0",
|
||||||
"webpack": "^4.42.1",
|
"webpack": "^4.43.0",
|
||||||
"webpack-assets-manifest": "^3.1.1",
|
"webpack-assets-manifest": "^3.1.1",
|
||||||
"webpack-bundle-analyzer": "^3.6.1",
|
"webpack-bundle-analyzer": "^3.8.0",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.10.3",
|
"webpack-dev-server": "^3.11.0",
|
||||||
"whatwg-fetch": "^3.0.0"
|
"whatwg-fetch": "^3.0.0"
|
||||||
},
|
},
|
||||||
"dependencies-pins-documentation": {
|
"dependencies-pins-documentation": {
|
||||||
|
"ts-node-dev@1.0.0-pre.44": [
|
||||||
|
"Newer versions unbearibly slow"
|
||||||
|
],
|
||||||
|
"ts-jest@25.4.0": [
|
||||||
|
"Newer versions require every definition file to be included",
|
||||||
|
"in tsconfig.json in the `files` field. This is cumbersome and",
|
||||||
|
"here is a discussion of it: https://github.com/kulshekhar/ts-jest/issues/1604"
|
||||||
|
],
|
||||||
"wait-for-expect@1.x.x": [
|
"wait-for-expect@1.x.x": [
|
||||||
"Newer versions breaks the use of jest fake timers"
|
"Newer versions breaks the use of jest fake timers"
|
||||||
],
|
],
|
||||||
@@ -396,6 +409,11 @@
|
|||||||
"Newer versions has problems with radio and checkbox fields.",
|
"Newer versions has problems with radio and checkbox fields.",
|
||||||
"Update when the following issue is resolved:",
|
"Update when the following issue is resolved:",
|
||||||
"https://github.com/final-form/react-final-form/issues/683"
|
"https://github.com/final-form/react-final-form/issues/683"
|
||||||
|
],
|
||||||
|
"graphql-playground-html@1.6.13": [
|
||||||
|
"A template was broken in a release.",
|
||||||
|
"Update when the following issue is resolved:",
|
||||||
|
"https://github.com/prisma-labs/graphql-playground/pull/1238"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
@@ -413,7 +431,10 @@
|
|||||||
"{src/core/client/stream/events.ts,scripts/generateEventDocs.ts,CLIENT_EVENTS.md}": [
|
"{src/core/client/stream/events.ts,scripts/generateEventDocs.ts,CLIENT_EVENTS.md}": [
|
||||||
"npm run docs:events -- --verify"
|
"npm run docs:events -- --verify"
|
||||||
],
|
],
|
||||||
"{README,CLIENT_EVENTS,CONTRIBUTING,WEBHOOKS,EXTERNAL_MODERATION_PHASES}.md": [
|
"{src/core/client/ui/theme/sharedVariables.ts,src/core/client/ui/theme/streamVariables.ts,scripts/generateCSSVariablesDocs.ts,CSS_VARIABLES.md}": [
|
||||||
|
"npm run docs:css-variables -- --verify"
|
||||||
|
],
|
||||||
|
"{CLIENT_EVENTS,CONTRIBUTING,WEBHOOKS,EXTERNAL_MODERATION_PHASES}.md": [
|
||||||
"npm run doctoc"
|
"npm run doctoc"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,306 @@
|
|||||||
|
import { stripIndent } from "common-tags";
|
||||||
|
import fs from "fs";
|
||||||
|
import { kebabCase, trim } from "lodash";
|
||||||
|
import path from "path";
|
||||||
|
import ts from "typescript";
|
||||||
|
|
||||||
|
import colors from "../src/core/client/ui/theme/colors";
|
||||||
|
|
||||||
|
/** We collect inforamtion from the AST and put it into DocEntry */
|
||||||
|
interface DocEntry {
|
||||||
|
/** Name of property */
|
||||||
|
key: string;
|
||||||
|
/** Documentation if available */
|
||||||
|
docs?: string;
|
||||||
|
/** Value if it is a leaf */
|
||||||
|
value?: string;
|
||||||
|
/** Children if it is a node */
|
||||||
|
children?: DocEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We use this regexp to find a previous block that we
|
||||||
|
* are going to update in the readme file.
|
||||||
|
*/
|
||||||
|
const BLOCK_REGEXP = /<!-- START docs:css-variables -->(.|\n)*<!-- END docs:css-variables -->/gm;
|
||||||
|
|
||||||
|
/** Sort doc entries will sort childrenless entries first */
|
||||||
|
function sortDocEntries(data: DocEntry[]) {
|
||||||
|
data.forEach((d) => {
|
||||||
|
if (d.children) {
|
||||||
|
d.children = sortDocEntries(d.children);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data.sort((a, b) => {
|
||||||
|
if (a.children && !b.children) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (b.children && !a.children) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Generate documentation for all classes in a set of .ts files */
|
||||||
|
function gatherEntries(
|
||||||
|
fileName: string,
|
||||||
|
options: ts.CompilerOptions
|
||||||
|
): DocEntry[] {
|
||||||
|
// Build a program using the set of root file names in fileNames
|
||||||
|
const program = ts.createProgram([fileName], options);
|
||||||
|
|
||||||
|
// Get the checker, we will use it to find more about classes
|
||||||
|
const checker = program.getTypeChecker();
|
||||||
|
|
||||||
|
const data: DocEntry[] = [];
|
||||||
|
const currentSourceFile = program.getSourceFile(fileName)!;
|
||||||
|
|
||||||
|
ts.forEachChild(currentSourceFile, visit);
|
||||||
|
|
||||||
|
return sortDocEntries(data);
|
||||||
|
|
||||||
|
/** visit nodes finding css variables */
|
||||||
|
function visit(node: ts.Node) {
|
||||||
|
if (ts.isVariableStatement(node)) {
|
||||||
|
// TODO (cvle) - Currently the variable name is hardcoded. We might want to change that.
|
||||||
|
if (!node.getFullText().includes("streamVariables")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const firstChild = node.declarationList.declarations[0];
|
||||||
|
if (ts.isVariableDeclaration(firstChild)) {
|
||||||
|
const symbol = checker.getSymbolAtLocation(firstChild.name);
|
||||||
|
if (symbol) {
|
||||||
|
const type = checker.getTypeOfSymbolAtLocation(
|
||||||
|
symbol,
|
||||||
|
symbol.valueDeclaration
|
||||||
|
);
|
||||||
|
type.getProperties().forEach((property) => {
|
||||||
|
serializePropertySymbol(property);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This will evaluate `symbol` and addthe doc entries */
|
||||||
|
function serializePropertySymbol(symbol: ts.Symbol, parent?: DocEntry) {
|
||||||
|
const entry: DocEntry = { key: symbol.name };
|
||||||
|
const pt = checker.getTypeOfSymbolAtLocation(
|
||||||
|
symbol,
|
||||||
|
symbol.valueDeclaration
|
||||||
|
);
|
||||||
|
if (pt.symbol?.name === "__object") {
|
||||||
|
pt.getProperties().forEach((p2) => {
|
||||||
|
serializePropertySymbol(p2, entry);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
entry.value = symbol.valueDeclaration
|
||||||
|
// Last child contains value.
|
||||||
|
.getChildAt(symbol.valueDeclaration.getChildCount() - 1)!
|
||||||
|
.getFullText();
|
||||||
|
}
|
||||||
|
entry.docs = ts.displayPartsToString(
|
||||||
|
symbol.getDocumentationComment(checker)
|
||||||
|
);
|
||||||
|
if (parent) {
|
||||||
|
if (parent.children) {
|
||||||
|
parent.children.push(entry);
|
||||||
|
} else {
|
||||||
|
parent.children = [entry];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds any references to `object` by `variableName` and replaces the text
|
||||||
|
* with the actual value.
|
||||||
|
*
|
||||||
|
* E.g. `replaceObjectVariablesInText("colors.teal100", colors, "colors") === "#E2FAF7"`;
|
||||||
|
*/
|
||||||
|
function replaceObjectVariablesInText(
|
||||||
|
text: string,
|
||||||
|
object: any,
|
||||||
|
variableName: string
|
||||||
|
) {
|
||||||
|
let result = text;
|
||||||
|
Object.keys(object).forEach((c: string) => {
|
||||||
|
if (typeof object[c] === "object") {
|
||||||
|
result = replaceObjectVariablesInText(
|
||||||
|
result,
|
||||||
|
object[c],
|
||||||
|
`${variableName}.${c}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
result = result.replace(`${variableName}.${c}`, object[c]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* transforms value to be used in the documentation.
|
||||||
|
*/
|
||||||
|
function transformValue(value: string) {
|
||||||
|
let compat = "";
|
||||||
|
value = trim(value);
|
||||||
|
// Detect compat value.
|
||||||
|
if (value.startsWith("compat")) {
|
||||||
|
const result = /compat\((.*), *"(.*)"\)/.exec(value);
|
||||||
|
if (!result) {
|
||||||
|
throw new Error("Unrecognized compat format");
|
||||||
|
}
|
||||||
|
value = result[1];
|
||||||
|
compat = result[2];
|
||||||
|
}
|
||||||
|
// If it's a raw string, evaluate it to get rid of the initial quotes.
|
||||||
|
if (value[0] === '"' || value[0] === "'") {
|
||||||
|
// eslint-disable-next-line no-eval
|
||||||
|
value = eval(value);
|
||||||
|
}
|
||||||
|
// Replace all references to colors.
|
||||||
|
value = replaceObjectVariablesInText(value, colors, "colors");
|
||||||
|
if (compat) {
|
||||||
|
// add compat information.
|
||||||
|
return `${value}; /* Before 6.3.0: --${compat} */`;
|
||||||
|
}
|
||||||
|
return `${value};`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prefixLines(text: string, prefix: string) {
|
||||||
|
return text.split("\n").join(`\n${prefix}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function entries2Summary(
|
||||||
|
entries: DocEntry[],
|
||||||
|
keyprefix = "",
|
||||||
|
nestprefix = ""
|
||||||
|
): string {
|
||||||
|
let doc = "";
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (!entry.children) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const header = kebabCase(keyprefix + entry.key);
|
||||||
|
doc += `${nestprefix}- <a href="#${header}">${header}</a>\n`;
|
||||||
|
if (entry.children) {
|
||||||
|
doc += entries2Summary(
|
||||||
|
entry.children,
|
||||||
|
keyprefix + entry.key + "-",
|
||||||
|
nestprefix + " "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
function entries2Doc(entries: DocEntry[], header = "###", prefix = ""): string {
|
||||||
|
let doc = "";
|
||||||
|
entries.forEach((entry) => {
|
||||||
|
if (entry.children) {
|
||||||
|
doc += `\n${header} ${kebabCase(prefix + entry.key)}\n`;
|
||||||
|
if (entry.docs) {
|
||||||
|
doc += `\n${entry.docs}\n`;
|
||||||
|
}
|
||||||
|
doc += entries2Doc(
|
||||||
|
entry.children,
|
||||||
|
header + "#",
|
||||||
|
`${prefix}${entry.key}-`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (entry.docs) {
|
||||||
|
doc += `\n${entry.docs}\n`;
|
||||||
|
}
|
||||||
|
doc += `\n\`--${kebabCase(prefix + entry.key)}: ${transformValue(
|
||||||
|
entry.value!
|
||||||
|
)}\`\n`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append or update previous documention in markdownFile.
|
||||||
|
*
|
||||||
|
* @param markdownFile The markdown file we want to inject the docs too.
|
||||||
|
* @param entries data as returned by gatherEntries.
|
||||||
|
*/
|
||||||
|
function emitDocs(markdownFile: string, entries: DocEntry[], verify = false) {
|
||||||
|
const previousContent = fs.existsSync(markdownFile)
|
||||||
|
? fs.readFileSync(markdownFile).toString()
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const summary = entries2Summary(entries, "", " ");
|
||||||
|
const list = entries2Doc(entries);
|
||||||
|
|
||||||
|
const output = stripIndent`
|
||||||
|
<!-- START docs:css-variables -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN npm run docs:css-variables -->
|
||||||
|
### Index
|
||||||
|
- <a href="#variables">Variables</a>
|
||||||
|
${prefixLines(summary, " ")}
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
${prefixLines(list, " ")}
|
||||||
|
<!-- END docs:css-variables -->
|
||||||
|
`;
|
||||||
|
|
||||||
|
let newContent;
|
||||||
|
// Find previous block.
|
||||||
|
if (BLOCK_REGEXP.test(previousContent)) {
|
||||||
|
newContent = previousContent.replace(BLOCK_REGEXP, output);
|
||||||
|
} else {
|
||||||
|
newContent = previousContent + "\n" + output;
|
||||||
|
}
|
||||||
|
if (previousContent === newContent) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`${markdownFile} is up to date`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (verify) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(
|
||||||
|
`${markdownFile} is outdated, please run \`npm run docs:css-variables\``
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(markdownFile, newContent);
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(`Successfully injected documentation into ${markdownFile}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
if (process.argv.length < 4) {
|
||||||
|
throw new Error("Must provide path to css variables and a markdown file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const variableFile = process.argv[2];
|
||||||
|
const markdownFile = process.argv[3];
|
||||||
|
|
||||||
|
// Find tsconfig file.
|
||||||
|
const configFile = ts.findConfigFile(variableFile, fs.existsSync);
|
||||||
|
if (!configFile) {
|
||||||
|
throw new Error("tsconfig file not found");
|
||||||
|
}
|
||||||
|
const configText = fs.readFileSync(configFile).toString();
|
||||||
|
const result = ts.parseConfigFileTextToJson(configFile, configText);
|
||||||
|
if (result.error) {
|
||||||
|
throw result.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the JSON raw data into actual consumable compiler options.
|
||||||
|
const config = ts.parseJsonConfigFileContent(
|
||||||
|
result.config,
|
||||||
|
ts.sys,
|
||||||
|
path.dirname(configFile)
|
||||||
|
);
|
||||||
|
|
||||||
|
const entries = gatherEntries(variableFile, config.options);
|
||||||
|
emitDocs(markdownFile, entries, process.argv[4] === "--verify");
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env ts-node
|
#!/usr/bin/env ts-node
|
||||||
|
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
|
|
||||||
// Apply all the configuration provided in the .env file if it isn't already in
|
// Apply all the configuration provided in the .env file if it isn't already in
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default class CommandExecutor implements Executor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public execute(filePath: string) {
|
public execute(filePath: string): void {
|
||||||
this.spawnProcessPotentiallyDebounced();
|
this.spawnProcessPotentiallyDebounced();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,14 +99,14 @@ export default class LongRunningExecutor implements Executor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is called before exiting.
|
// This is called before exiting.
|
||||||
public async onCleanup() {
|
public async onCleanup(): Promise<void> {
|
||||||
this.restartDebounced.cancel();
|
this.restartDebounced.cancel();
|
||||||
if (this.isRunning) {
|
if (this.isRunning) {
|
||||||
await this.kill();
|
await this.kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public execute(filePath: string) {
|
public execute(filePath: string): void {
|
||||||
if (this.isRunning) {
|
if (this.isRunning) {
|
||||||
this.restartDebounced();
|
this.restartDebounced();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -80,7 +80,10 @@ function filterOnly(
|
|||||||
}) as Config["watchers"];
|
}) as Config["watchers"];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function watch(config: Config, options: Options = {}) {
|
export default async function watch(
|
||||||
|
config: Config,
|
||||||
|
options: Options = {}
|
||||||
|
): Promise<void> {
|
||||||
Joi.assert(config, configSchema);
|
Joi.assert(config, configSchema);
|
||||||
const watcher: Watcher = config.backend || new SaneWatcher();
|
const watcher: Watcher = config.backend || new SaneWatcher();
|
||||||
const rootDir = config.rootDir || process.cwd();
|
const rootDir = config.rootDir || process.cwd();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import convict from "convict";
|
import convict from "convict";
|
||||||
|
import os from "os";
|
||||||
|
|
||||||
import { LOCALES } from "../common/helpers/i18n/locales";
|
import { LOCALES } from "../common/helpers/i18n/locales";
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ const config = convict({
|
|||||||
maxCores: {
|
maxCores: {
|
||||||
doc: "Set maximum of available cores",
|
doc: "Set maximum of available cores",
|
||||||
format: "nat",
|
format: "nat",
|
||||||
default: require("os").cpus().length,
|
default: os.cpus().length,
|
||||||
env: "WEBPACK_MAX_CORES",
|
env: "WEBPACK_MAX_CORES",
|
||||||
arg: "maxCores",
|
arg: "maxCores",
|
||||||
},
|
},
|
||||||
@@ -77,6 +78,7 @@ export type Config = typeof config;
|
|||||||
|
|
||||||
export const createClientEnv = (c: Config) => ({
|
export const createClientEnv = (c: Config) => ({
|
||||||
NODE_ENV: c.get("env"),
|
NODE_ENV: c.get("env"),
|
||||||
|
WEBPACK: "true",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup the base configuration.
|
// Setup the base configuration.
|
||||||
|
|||||||
@@ -109,10 +109,10 @@ export default function createWebpackConfig(
|
|||||||
...ifBuild(
|
...ifBuild(
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: isProduction
|
filename: isProduction
|
||||||
? "assets/css/[name].[hash].css"
|
? "assets/css/[name].[contenthash].css"
|
||||||
: "assets/css/[name].css",
|
: "assets/css/[name].css",
|
||||||
chunkFilename: isProduction
|
chunkFilename: isProduction
|
||||||
? "assets/css/[id].[hash].css"
|
? "assets/css/[id].[contenthash].css"
|
||||||
: "assets/css/[id].css",
|
: "assets/css/[id].css",
|
||||||
}),
|
}),
|
||||||
isProduction &&
|
isProduction &&
|
||||||
@@ -217,10 +217,10 @@ export default function createWebpackConfig(
|
|||||||
// Generated JS file names (with nested folders).
|
// Generated JS file names (with nested folders).
|
||||||
// There will be one main bundle, and one file per asynchronous chunk.
|
// There will be one main bundle, and one file per asynchronous chunk.
|
||||||
filename: isProduction
|
filename: isProduction
|
||||||
? "assets/js/[name].[chunkhash].js"
|
? "assets/js/[name].[contenthash].js"
|
||||||
: "assets/js/[name].js",
|
: "assets/js/[name].js",
|
||||||
chunkFilename: isProduction
|
chunkFilename: isProduction
|
||||||
? "assets/js/[name].[chunkhash].chunk.js"
|
? "assets/js/[name].[contenthash].chunk.js"
|
||||||
: "assets/js/[name].chunk.js",
|
: "assets/js/[name].chunk.js",
|
||||||
// We inferred the "public path" (such as / or /my-project) from homepage.
|
// We inferred the "public path" (such as / or /my-project) from homepage.
|
||||||
publicPath,
|
publicPath,
|
||||||
@@ -351,7 +351,7 @@ export default function createWebpackConfig(
|
|||||||
options: {
|
options: {
|
||||||
limit: 10000,
|
limit: 10000,
|
||||||
name: isProduction
|
name: isProduction
|
||||||
? "assets/media/[name].[hash].[ext]"
|
? "assets/media/[name].[contenthash].[ext]"
|
||||||
: "assets/media/[name].[ext]",
|
: "assets/media/[name].[ext]",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -468,7 +468,7 @@ export default function createWebpackConfig(
|
|||||||
loader: require.resolve("css-loader"),
|
loader: require.resolve("css-loader"),
|
||||||
options: {
|
options: {
|
||||||
modules: {
|
modules: {
|
||||||
localIdentName: "[name]-[local]-[hash:base64:5]",
|
localIdentName: "[name]-[local]-[contenthash]",
|
||||||
},
|
},
|
||||||
importLoaders: 1,
|
importLoaders: 1,
|
||||||
sourceMap: !disableSourcemaps,
|
sourceMap: !disableSourcemaps,
|
||||||
@@ -499,7 +499,7 @@ export default function createWebpackConfig(
|
|||||||
loader: require.resolve("file-loader"),
|
loader: require.resolve("file-loader"),
|
||||||
options: {
|
options: {
|
||||||
name: isProduction
|
name: isProduction
|
||||||
? "assets/media/[name].[hash:8].[ext]"
|
? "assets/media/[name].[contenthash].[ext]"
|
||||||
: "assets/media/[name].[ext]",
|
: "assets/media/[name].[ext]",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ export default {
|
|||||||
appPublicPath: resolveSrc("core/build/publicPath.js"),
|
appPublicPath: resolveSrc("core/build/publicPath.js"),
|
||||||
appLocales: resolveSrc("locales"),
|
appLocales: resolveSrc("locales"),
|
||||||
appThemeVariables: resolveSrc("core/client/ui/theme/variables.ts"),
|
appThemeVariables: resolveSrc("core/client/ui/theme/variables.ts"),
|
||||||
appThemeVariablesCSS: resolveSrc("core/client/ui/theme/variables.css"),
|
appSassLikeVariables: resolveSrc("core/client/ui/theme/sassLikeVariables.ts"),
|
||||||
|
appThemeStreamCSS: resolveSrc("core/client/ui/theme/stream.css"),
|
||||||
|
appThemeAdminCSS: resolveSrc("core/client/ui/theme/admin.css"),
|
||||||
appThemeMixinsCSS: resolveSrc("core/client/ui/theme/mixins.css"),
|
appThemeMixinsCSS: resolveSrc("core/client/ui/theme/mixins.css"),
|
||||||
|
|
||||||
appStreamHTML: resolveSrc("core/client/stream/index.html"),
|
appStreamHTML: resolveSrc("core/client/stream/index.html"),
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ require("ts-node/register");
|
|||||||
const kebabCase = require("lodash/kebabCase");
|
const kebabCase = require("lodash/kebabCase");
|
||||||
const mapKeys = require("lodash/mapKeys");
|
const mapKeys = require("lodash/mapKeys");
|
||||||
const mapValues = require("lodash/mapValues");
|
const mapValues = require("lodash/mapValues");
|
||||||
const pickBy = require("lodash/pickBy");
|
|
||||||
const flat = require("flat");
|
const flat = require("flat");
|
||||||
const paths = require("./paths").default;
|
const paths = require("./paths").default;
|
||||||
const autoprefixer = require("autoprefixer");
|
const autoprefixer = require("autoprefixer");
|
||||||
@@ -17,23 +16,28 @@ const postcssMixins = require("postcss-mixins");
|
|||||||
const postcssPrependImports = require("postcss-prepend-imports");
|
const postcssPrependImports = require("postcss-prepend-imports");
|
||||||
const postcssAdvancedVariables = require("postcss-advanced-variables");
|
const postcssAdvancedVariables = require("postcss-advanced-variables");
|
||||||
|
|
||||||
delete require.cache[paths.appThemeVariables];
|
delete require.cache[paths.appSassLikeVariables];
|
||||||
const variables = require(paths.appThemeVariables).default;
|
const sassLikeVariables = require(paths.appSassLikeVariables).default;
|
||||||
const flatKebabVariables = mapKeys(
|
|
||||||
mapValues(flat(variables, { delimiter: "-" }), (v) => v.toString()),
|
const kebabs = mapKeys(
|
||||||
|
mapValues(flat(sassLikeVariables, { delimiter: "-" }), (v) => v.toString()),
|
||||||
(_, k) => kebabCase(k)
|
(_, k) => kebabCase(k)
|
||||||
);
|
);
|
||||||
|
|
||||||
// These are sass style variables used in media queries.
|
// Generate sass-style variables to inject into css
|
||||||
const mediaQueryVariables = mapValues(
|
const postCssVariables = mapValues(kebabs, (value, key) => {
|
||||||
pickBy(flatKebabVariables, (v, k) => k.startsWith("breakpoints-")),
|
|
||||||
// Add unit to breakpoints.
|
// Add unit to breakpoints.
|
||||||
// Add 1 to support mobile first approach where we start
|
// Add 1 to support mobile first approach where we start
|
||||||
// with the smallest screen and gradually add styling for the
|
// with the smallest screen and gradually add styling for the
|
||||||
// next bigger screen. This is realized using `min-width` without
|
// next bigger screen. This is realized using `min-width` without
|
||||||
// ever using `max-width`.
|
// ever using `max-width`.
|
||||||
(v) => `${Number.parseInt(v, 10) + 1}px`
|
if (key.toString().startsWith("breakpoints-")) {
|
||||||
);
|
return `${Number.parseInt(value, 10) + 1}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default return the raw value
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// Necessary for external CSS imports to work
|
// Necessary for external CSS imports to work
|
||||||
@@ -52,7 +56,7 @@ module.exports = {
|
|||||||
// Support nesting.
|
// Support nesting.
|
||||||
postcssNested(),
|
postcssNested(),
|
||||||
// Sass style variables to be used in media queries.
|
// Sass style variables to be used in media queries.
|
||||||
postcssAdvancedVariables({ variables: mediaQueryVariables }),
|
postcssAdvancedVariables({ variables: postCssVariables }),
|
||||||
// Reduce some calc()
|
// Reduce some calc()
|
||||||
postcssCalcFunction(),
|
postcssCalcFunction(),
|
||||||
// Provides a modern CSS environment.
|
// Provides a modern CSS environment.
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
.bar {
|
.bar {
|
||||||
height: calc(6 * var(--mini-unit));
|
height: calc(6 * var(--mini-unit));
|
||||||
background-color: var(--palette-text-primary);
|
background-color: var(--palette-text-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
.centered {
|
.centered {
|
||||||
margin: 10% auto;
|
margin: 10% auto;
|
||||||
padding: 0 calc(0.5 * var(--mini-unit));
|
padding: 0 calc(0.5 * var(--mini-unit));
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { Delay, Flex, Spinner } from "coral-ui/components";
|
import { Delay, Flex, Spinner } from "coral-ui/components/v2";
|
||||||
|
|
||||||
const Loading: FunctionComponent = () => (
|
const Loading: FunctionComponent = () => (
|
||||||
<Flex justifyContent="center">
|
<Flex justifyContent="center">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { initLocalState } from "./local";
|
|||||||
import localesData from "./locales";
|
import localesData from "./locales";
|
||||||
|
|
||||||
// Import css variables.
|
// Import css variables.
|
||||||
import "coral-ui/theme/variables.css";
|
import "coral-ui/theme/stream.css";
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
await injectConditionalPolyfills();
|
await injectConditionalPolyfills();
|
||||||
@@ -30,4 +30,4 @@ async function main() {
|
|||||||
ReactDOM.render(<Index />, document.getElementById("app"));
|
ReactDOM.render(<Index />, document.getElementById("app"));
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
void main();
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.content {
|
||||||
|
font-family: var(--font-family-secondary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
|
font-size: var(--font-size-6);
|
||||||
|
line-height: 1.17;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { HorizontalGutter, Typography } from "coral-ui/components";
|
import { HorizontalGutter } from "coral-ui/components/v2";
|
||||||
|
|
||||||
|
import styles from "./NotFound.css";
|
||||||
|
|
||||||
const NotFound: FunctionComponent = () => (
|
const NotFound: FunctionComponent = () => (
|
||||||
<HorizontalGutter container="main">
|
<HorizontalGutter container="main">
|
||||||
<Typography variant="heading3" container="h1">
|
<Localized id="notFound">
|
||||||
Not Found
|
<div className={styles.content}>Not Found</div>
|
||||||
</Typography>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</HorizontalGutter>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
.title {
|
.title {
|
||||||
font-family: var(--font-family-serif);
|
font-family: var(--font-family-secondary);
|
||||||
font-weight: 600;
|
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-size: calc(48rem / var(--rem-base));
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
line-height: calc(42em / 48);
|
font-size: var(--font-size-6);
|
||||||
text-align: center;
|
line-height: 1.17;
|
||||||
|
|
||||||
color: var(--palette-common-black);
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
padding-left: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -18,14 +19,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sectionText {
|
.sectionText {
|
||||||
font-family: var(--font-family-sans-serif);
|
font-family: var(--font-family-primary);
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-size: calc(24rem / var(--rem-base));
|
font-weight: var(--font-weight-primary-regular);
|
||||||
line-height: calc(34em / 24);
|
font-size: var(--font-size-3);
|
||||||
letter-spacing: 0.3px;
|
line-height: 1.25;
|
||||||
|
|
||||||
color: var(--palette-text-primary);
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list {
|
.list {
|
||||||
@@ -34,7 +36,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list li {
|
.list li {
|
||||||
margin-bottom: calc(16em / 24);
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listContent {
|
.listContent {
|
||||||
@@ -43,6 +45,6 @@
|
|||||||
|
|
||||||
.bullet {
|
.bullet {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 24px;
|
min-width: 16px;
|
||||||
margin-right: var(--spacing-2);
|
margin-right: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Localized } from "@fluent/react/compat";
|
|||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { Flex, HorizontalGutter, Icon, Typography } from "coral-ui/components";
|
import { Flex, HorizontalGutter, Icon } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import styles from "./DownloadDescription.css";
|
import styles from "./DownloadDescription.css";
|
||||||
|
|
||||||
@@ -10,84 +10,72 @@ const DownloadDescription: FunctionComponent = () => {
|
|||||||
return (
|
return (
|
||||||
<HorizontalGutter size="double">
|
<HorizontalGutter size="double">
|
||||||
<Localized id="download-landingPage-title">
|
<Localized id="download-landingPage-title">
|
||||||
<h1 className={styles.title}>Download Your Comment History</h1>
|
<h1 className={styles.title}>Download your comment history</h1>
|
||||||
</Localized>
|
</Localized>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
<Localized id="download-landingPage-description">
|
<Localized id="download-landingPage-description">
|
||||||
<Typography variant="bodyCopy" className={styles.sectionText}>
|
<div className={styles.sectionText}>
|
||||||
Your comment history will be downloaded into a .zip file. After
|
Your comment history will be downloaded into a .zip file. After
|
||||||
your comment history is unzipped you will have a comma separated
|
your comment history is unzipped you will have a comma separated
|
||||||
value (or .csv) file that you can easily import into your favorite
|
value (or .csv) file that you can easily import into your favorite
|
||||||
spreadsheet application.
|
spreadsheet application.
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.section}>
|
<div className={styles.section}>
|
||||||
<Localized id="download-landingPage-contentsDescription">
|
<Localized id="download-landingPage-contentsDescription">
|
||||||
<Typography variant="bodyCopy" className={styles.sectionText}>
|
<div className={styles.sectionText}>
|
||||||
For each of your comments the following information is included:
|
For each of your comments the following information is included:
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<ul className={styles.list}>
|
<ul className={styles.list}>
|
||||||
<li>
|
<li>
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="flex-start">
|
||||||
<Icon size="lg" className={styles.bullet}>
|
<Icon size="md" className={styles.bullet}>
|
||||||
check
|
check
|
||||||
</Icon>
|
</Icon>
|
||||||
<Localized id="download-landingPage-contentsDate">
|
<Localized id="download-landingPage-contentsDate">
|
||||||
<Typography
|
<div className={cn(styles.sectionText, styles.listContent)}>
|
||||||
variant="bodyCopy"
|
|
||||||
className={cn(styles.sectionText, styles.listContent)}
|
|
||||||
>
|
|
||||||
When you wrote the comment
|
When you wrote the comment
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</Flex>
|
</Flex>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="flex-start">
|
||||||
<Icon size="lg" className={styles.bullet}>
|
<Icon size="md" className={styles.bullet}>
|
||||||
check
|
check
|
||||||
</Icon>
|
</Icon>
|
||||||
<Localized id="download-landingPage-contentsUrl">
|
<Localized id="download-landingPage-contentsUrl">
|
||||||
<Typography
|
<div className={cn(styles.sectionText, styles.listContent)}>
|
||||||
variant="bodyCopy"
|
|
||||||
className={cn(styles.sectionText, styles.listContent)}
|
|
||||||
>
|
|
||||||
The permalink URL for the comment
|
The permalink URL for the comment
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</Flex>
|
</Flex>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="flex-start">
|
||||||
<Icon size="lg" className={styles.bullet}>
|
<Icon size="md" className={styles.bullet}>
|
||||||
check
|
check
|
||||||
</Icon>
|
</Icon>
|
||||||
<Localized id="download-landingPage-contentsText">
|
<Localized id="download-landingPage-contentsText">
|
||||||
<Typography
|
<div className={cn(styles.sectionText, styles.listContent)}>
|
||||||
variant="bodyCopy"
|
|
||||||
className={cn(styles.sectionText, styles.listContent)}
|
|
||||||
>
|
|
||||||
The comment text
|
The comment text
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</Flex>
|
</Flex>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Flex alignItems="center">
|
<Flex alignItems="flex-start">
|
||||||
<Icon size="lg" className={styles.bullet}>
|
<Icon size="md" className={styles.bullet}>
|
||||||
check
|
check
|
||||||
</Icon>
|
</Icon>
|
||||||
<Localized id="download-landingPage-contentsStoryUrl">
|
<Localized id="download-landingPage-contentsStoryUrl">
|
||||||
<Typography
|
<div className={cn(styles.sectionText, styles.listContent)}>
|
||||||
variant="bodyCopy"
|
|
||||||
className={cn(styles.sectionText, styles.listContent)}
|
|
||||||
>
|
|
||||||
The URL on the article or story where the comment appears
|
The URL on the article or story where the comment appears
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</Flex>
|
</Flex>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
.form {
|
.form {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.downloadButton {
|
|
||||||
font-size: calc(18rem / var(--rem-base));
|
|
||||||
line-height: calc(23em / 18);
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React, { FunctionComponent, useCallback, useState } from "react";
|
import React, { FunctionComponent, useCallback, useState } from "react";
|
||||||
|
|
||||||
import { Button, HorizontalGutter } from "coral-ui/components";
|
import { HorizontalGutter } from "coral-ui/components/v2";
|
||||||
|
import { Button } from "coral-ui/components/v3";
|
||||||
|
|
||||||
import styles from "./DownloadForm.css";
|
import styles from "./DownloadForm.css";
|
||||||
|
|
||||||
@@ -25,15 +26,16 @@ const DownloadForm: FunctionComponent<Props> = ({ token }) => {
|
|||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
>
|
>
|
||||||
<input name="token" type="hidden" value={token} />
|
<input name="token" type="hidden" value={token} />
|
||||||
<Localized id="download-landingPage-downloadComments">
|
<Localized id="download-landingPage-download">
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
paddingSize="medium"
|
||||||
disabled={submitted}
|
disabled={submitted}
|
||||||
className={styles.downloadButton}
|
upperCase
|
||||||
>
|
>
|
||||||
Download My Comment History
|
Download
|
||||||
</Button>
|
</Button>
|
||||||
</Localized>
|
</Localized>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
.root {
|
.root {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
max-width: calc(70 * var(--mini-unit));
|
max-width: calc(70 * var(--spacing-2));
|
||||||
|
|
||||||
@media (min-width: $breakpoints-xs) {
|
@media (min-width: $breakpoints-xs) {
|
||||||
max-width: calc(90 * var(--mini-unit));
|
max-width: calc(60 * var(--spacing-2));
|
||||||
}
|
}
|
||||||
|
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useToken } from "coral-framework/hooks";
|
|||||||
import { createFetch } from "coral-framework/lib/relay";
|
import { createFetch } from "coral-framework/lib/relay";
|
||||||
import { withRouteConfig } from "coral-framework/lib/router";
|
import { withRouteConfig } from "coral-framework/lib/router";
|
||||||
import { parseHashQuery } from "coral-framework/utils";
|
import { parseHashQuery } from "coral-framework/utils";
|
||||||
import { HorizontalGutter } from "coral-ui/components";
|
import { HorizontalGutter } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import DownloadDescription from "./DownloadDescription";
|
import DownloadDescription from "./DownloadDescription";
|
||||||
import DownloadForm from "./DownloadForm";
|
import DownloadForm from "./DownloadForm";
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
.icon {
|
|
||||||
margin-right: var(--spacing-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.callout {
|
|
||||||
justify-content: left;
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,21 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { CallOut, Flex, Icon } from "coral-ui/components";
|
import { Icon } from "coral-ui/components/v2";
|
||||||
|
import { CallOut } from "coral-ui/components/v3";
|
||||||
import styles from "./Sorry.css";
|
|
||||||
|
|
||||||
const Sorry: FunctionComponent = () => {
|
const Sorry: FunctionComponent = () => {
|
||||||
return (
|
return (
|
||||||
<CallOut color="error" fullWidth className={styles.callout}>
|
<CallOut
|
||||||
<Flex>
|
color="error"
|
||||||
<Icon size="md" className={styles.icon}>
|
icon={<Icon>error</Icon>}
|
||||||
error
|
titleWeight="semiBold"
|
||||||
</Icon>
|
title={
|
||||||
<Localized id="download-landingPage-sorry">
|
<Localized id="download-landingPage-sorry">
|
||||||
Your download link is invalid.
|
Your download link is invalid.
|
||||||
</Localized>
|
</Localized>
|
||||||
</Flex>
|
}
|
||||||
</CallOut>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
.title {
|
||||||
|
font-family: var(--font-family-secondary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
|
font-size: var(--font-size-6);
|
||||||
|
line-height: 1.17;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-regular);
|
||||||
|
font-size: var(--font-size-3);
|
||||||
|
line-height: 1.25;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-bold);
|
||||||
|
font-size: var(--font-size-2);
|
||||||
|
line-height: 1.14;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.labelDescription {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-regular);
|
||||||
|
font-size: var(--font-size-2);
|
||||||
|
line-height: 1.285;
|
||||||
|
|
||||||
|
color: var(--palette-text-100);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
margin-top: var(--spacing-5);
|
||||||
|
margin-bottom: var(--spacing-1);
|
||||||
|
}
|
||||||
@@ -5,10 +5,12 @@ import { Form } from "react-final-form";
|
|||||||
|
|
||||||
import { InvalidRequestError } from "coral-framework/lib/errors";
|
import { InvalidRequestError } from "coral-framework/lib/errors";
|
||||||
import { useMutation } from "coral-framework/lib/relay";
|
import { useMutation } from "coral-framework/lib/relay";
|
||||||
import { Button, HorizontalGutter, Typography } from "coral-ui/components";
|
import { Button } from "coral-ui/components/v3";
|
||||||
|
|
||||||
import ConfirmMutation from "./ConfirmMutation";
|
import ConfirmMutation from "./ConfirmMutation";
|
||||||
|
|
||||||
|
import styles from "./Confirm.css";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
token: string;
|
token: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -33,18 +35,18 @@ const ConfirmForm: React.FunctionComponent<Props> = ({ onSuccess, token }) => {
|
|||||||
<Form onSubmit={onSubmit}>
|
<Form onSubmit={onSubmit}>
|
||||||
{({ handleSubmit, submitting }) => (
|
{({ handleSubmit, submitting }) => (
|
||||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||||
<HorizontalGutter size="double">
|
<div>
|
||||||
<HorizontalGutter>
|
<div>
|
||||||
<Localized id="confirmEmail-emailConfirmation">
|
<Localized id="confirmEmail-confirmYourEmailAddress">
|
||||||
<Typography variant="heading1">Email Confirmation</Typography>
|
<div className={styles.title}>Confirm your email address</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="confirmEmail-pleaseClickToConfirm">
|
<Localized id="confirmEmail-pleaseClickToConfirm">
|
||||||
<Typography variant="bodyCopy">
|
<div className={styles.description}>
|
||||||
Click below to confirm your email address.
|
Click below to confirm your email address.
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
<HorizontalGutter>
|
<div>
|
||||||
<Localized id="confirmEmail-confirmEmail">
|
<Localized id="confirmEmail-confirmEmail">
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
@@ -52,12 +54,14 @@ const ConfirmForm: React.FunctionComponent<Props> = ({ onSuccess, token }) => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
upperCase
|
||||||
|
className={styles.submit}
|
||||||
>
|
>
|
||||||
Confirm email
|
Confirm email
|
||||||
</Button>
|
</Button>
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { CallOut, HorizontalGutter, Typography } from "coral-ui/components";
|
import { CallOut } from "coral-ui/components/v3";
|
||||||
|
|
||||||
|
import styles from "./Confirm.css";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
reason: React.ReactNode;
|
reason: React.ReactNode;
|
||||||
@@ -9,23 +11,27 @@ interface Props {
|
|||||||
|
|
||||||
const Sorry: React.FunctionComponent<Props> = ({ reason }) => {
|
const Sorry: React.FunctionComponent<Props> = ({ reason }) => {
|
||||||
return (
|
return (
|
||||||
<HorizontalGutter size="double">
|
<div>
|
||||||
<Localized id="confirmEmail-oopsSorry">
|
<Localized id="confirmEmail-oopsSorry">
|
||||||
<Typography variant="heading1">Oops Sorry!</Typography>
|
<div className={styles.title}>Oops Sorry!</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<CallOut color="error" fullWidth>
|
<CallOut
|
||||||
{reason ? (
|
color="error"
|
||||||
reason
|
titleWeight="semiBold"
|
||||||
) : (
|
title={
|
||||||
<Localized id="account-tokenNotFound">
|
reason ? (
|
||||||
<span data-testid="invalid-link">
|
reason
|
||||||
The specified link is invalid, check to see if it was copied
|
) : (
|
||||||
correctly.
|
<Localized id="account-tokenNotFound">
|
||||||
</span>
|
<span data-testid="invalid-link">
|
||||||
</Localized>
|
The specified link is invalid, check to see if it was copied
|
||||||
)}
|
correctly.
|
||||||
</CallOut>
|
</span>
|
||||||
</HorizontalGutter>
|
</Localized>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { HorizontalGutter, Typography } from "coral-ui/components";
|
import styles from "./Confirm.css";
|
||||||
|
|
||||||
const Success: React.FunctionComponent = () => {
|
const Success: React.FunctionComponent = () => {
|
||||||
return (
|
return (
|
||||||
<HorizontalGutter size="double">
|
<div>
|
||||||
<Localized id="confirmEmail-successfullyConfirmed">
|
<Localized id="confirmEmail-successfullyConfirmed">
|
||||||
<Typography variant="heading1">Email successfully confirmed</Typography>
|
<div className={styles.title}>Email successfully confirmed</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="confirmEmail-youMayClose">
|
<Localized id="confirmEmail-youMayClose">
|
||||||
<Typography variant="bodyCopy">
|
<div className={styles.description}>You may now close this window.</div>
|
||||||
You may now close this window.
|
|
||||||
</Typography>
|
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { CallOut, HorizontalGutter, Typography } from "coral-ui/components";
|
import { CallOut } from "coral-ui/components/v3";
|
||||||
|
|
||||||
|
import styles from "./Unsubscribe.css";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
reason: React.ReactNode;
|
reason: React.ReactNode;
|
||||||
@@ -9,23 +11,27 @@ interface Props {
|
|||||||
|
|
||||||
const Sorry: React.FunctionComponent<Props> = ({ reason }) => {
|
const Sorry: React.FunctionComponent<Props> = ({ reason }) => {
|
||||||
return (
|
return (
|
||||||
<HorizontalGutter size="double">
|
<div>
|
||||||
<Localized id="unsubscribe-oopsSorry">
|
<Localized id="unsubscribe-oopsSorry">
|
||||||
<Typography variant="heading1">Oops Sorry!</Typography>
|
<div className={styles.title}>Oops Sorry!</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<CallOut color="error" fullWidth>
|
<CallOut
|
||||||
{reason ? (
|
color="error"
|
||||||
reason
|
titleWeight="semiBold"
|
||||||
) : (
|
title={
|
||||||
<Localized id="account-tokenNotFound">
|
reason ? (
|
||||||
<span data-testid="invalid-link">
|
reason
|
||||||
The specified link is invalid, check to see if it was copied
|
) : (
|
||||||
correctly.
|
<Localized id="account-tokenNotFound">
|
||||||
</span>
|
<span data-testid="invalid-link">
|
||||||
</Localized>
|
The specified link is invalid, check to see if it was copied
|
||||||
)}
|
correctly.
|
||||||
</CallOut>
|
</span>
|
||||||
</HorizontalGutter>
|
</Localized>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { HorizontalGutter, Typography } from "coral-ui/components";
|
import styles from "./Unsubscribe.css";
|
||||||
|
|
||||||
const Success: React.FunctionComponent = () => {
|
const Success: React.FunctionComponent = () => {
|
||||||
return (
|
return (
|
||||||
<HorizontalGutter data-testid="success" size="double">
|
<div data-testid="success">
|
||||||
<Localized id="unsubscribe-successfullyUnsubscribed">
|
<Localized id="unsubscribe-unsubscribedSuccessfully">
|
||||||
<Typography variant="heading1">
|
<div className={styles.title}>
|
||||||
You are now unsubscribed from all notifications
|
Unsubscribed successfully from email notifications
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
<Localized id="unsubscribe-youMayNowClose">
|
||||||
|
<div className={styles.description}>You may now close this window</div>
|
||||||
|
</Localized>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
.title {
|
||||||
|
font-family: var(--font-family-secondary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
|
font-size: var(--font-size-6);
|
||||||
|
line-height: 1.17;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-regular);
|
||||||
|
font-size: var(--font-size-3);
|
||||||
|
line-height: 1.25;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-bold);
|
||||||
|
font-size: var(--font-size-2);
|
||||||
|
line-height: 1.14;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.labelDescription {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-regular);
|
||||||
|
font-size: var(--font-size-2);
|
||||||
|
line-height: 1.285;
|
||||||
|
|
||||||
|
color: var(--palette-text-100);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
margin-top: var(--spacing-5);
|
||||||
|
margin-bottom: var(--spacing-1);
|
||||||
|
}
|
||||||
@@ -5,15 +5,12 @@ import { Form } from "react-final-form";
|
|||||||
|
|
||||||
import { InvalidRequestError } from "coral-framework/lib/errors";
|
import { InvalidRequestError } from "coral-framework/lib/errors";
|
||||||
import { useMutation } from "coral-framework/lib/relay";
|
import { useMutation } from "coral-framework/lib/relay";
|
||||||
import {
|
import { Button, CallOut } from "coral-ui/components/v3";
|
||||||
Button,
|
|
||||||
CallOut,
|
|
||||||
HorizontalGutter,
|
|
||||||
Typography,
|
|
||||||
} from "coral-ui/components";
|
|
||||||
|
|
||||||
import UnsubscribeNotificationsMutation from "./UnsubscribeNotificationsMutation";
|
import UnsubscribeNotificationsMutation from "./UnsubscribeNotificationsMutation";
|
||||||
|
|
||||||
|
import styles from "./Unsubscribe.css";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
token: string;
|
token: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -42,30 +39,34 @@ const UnsubscribeForm: React.FunctionComponent<Props> = ({
|
|||||||
<Form onSubmit={onSubmit}>
|
<Form onSubmit={onSubmit}>
|
||||||
{({ handleSubmit, submitting, submitError }) => (
|
{({ handleSubmit, submitting, submitError }) => (
|
||||||
<form onSubmit={handleSubmit}>
|
<form onSubmit={handleSubmit}>
|
||||||
<HorizontalGutter>
|
<div>
|
||||||
|
<Localized id="unsubscribe-unsubscribeFromEmails">
|
||||||
|
<div className={styles.title}>
|
||||||
|
Unsubscribe from email notifications
|
||||||
|
</div>
|
||||||
|
</Localized>
|
||||||
<Localized id="unsubscribe-clickToConfirm">
|
<Localized id="unsubscribe-clickToConfirm">
|
||||||
<Typography variant="heading1">
|
<div className={styles.description}>
|
||||||
Click below to confirm that you want to unsubscribe from all
|
Click below to confirm that you want to unsubscribe from all
|
||||||
notifications.
|
notifications.
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
{submitError && (
|
{submitError && <CallOut color="error" title={submitError} />}
|
||||||
<CallOut color="error" fullWidth>
|
<Localized id="unsubscribe-submit-unsubscribe">
|
||||||
{submitError}
|
|
||||||
</CallOut>
|
|
||||||
)}
|
|
||||||
<Localized id="unsubscribe-confirm">
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
|
paddingSize="medium"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
|
upperCase
|
||||||
fullWidth
|
fullWidth
|
||||||
|
className={styles.submit}
|
||||||
>
|
>
|
||||||
Confirm
|
Unsubscribe
|
||||||
</Button>
|
</Button>
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
.title {
|
||||||
|
font-family: var(--font-family-secondary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
|
font-size: var(--font-size-6);
|
||||||
|
line-height: 1.17;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-regular);
|
||||||
|
font-size: var(--font-size-3);
|
||||||
|
line-height: 1.25;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-bold);
|
||||||
|
font-size: var(--font-size-2);
|
||||||
|
line-height: 1.14;
|
||||||
|
|
||||||
|
color: var(--palette-text-500);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.labelDescription {
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-primary-regular);
|
||||||
|
font-size: var(--font-size-2);
|
||||||
|
line-height: 1.285;
|
||||||
|
|
||||||
|
color: var(--palette-text-100);
|
||||||
|
|
||||||
|
margin-bottom: var(--spacing-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit {
|
||||||
|
margin-top: var(--spacing-5);
|
||||||
|
margin-bottom: var(--spacing-1);
|
||||||
|
}
|
||||||
@@ -4,26 +4,20 @@ import React, { useCallback } from "react";
|
|||||||
import { Field, Form } from "react-final-form";
|
import { Field, Form } from "react-final-form";
|
||||||
|
|
||||||
import { InvalidRequestError } from "coral-framework/lib/errors";
|
import { InvalidRequestError } from "coral-framework/lib/errors";
|
||||||
import { colorFromMeta, ValidationMessage } from "coral-framework/lib/form";
|
import { colorFromMeta } from "coral-framework/lib/form";
|
||||||
import { useMutation } from "coral-framework/lib/relay";
|
import { useMutation } from "coral-framework/lib/relay";
|
||||||
import {
|
import {
|
||||||
composeValidators,
|
composeValidators,
|
||||||
required,
|
required,
|
||||||
validatePassword,
|
validatePassword,
|
||||||
} from "coral-framework/lib/validation";
|
} from "coral-framework/lib/validation";
|
||||||
import {
|
import { FormField, PasswordField } from "coral-ui/components/v2";
|
||||||
Button,
|
import { Button, CallOut, ValidationMessage } from "coral-ui/components/v3";
|
||||||
CallOut,
|
|
||||||
FormField,
|
|
||||||
HorizontalGutter,
|
|
||||||
InputDescription,
|
|
||||||
InputLabel,
|
|
||||||
PasswordField,
|
|
||||||
Typography,
|
|
||||||
} from "coral-ui/components";
|
|
||||||
|
|
||||||
import ResetPasswordMutation from "./ResetPasswordMutation";
|
import ResetPasswordMutation from "./ResetPasswordMutation";
|
||||||
|
|
||||||
|
import styles from "./Reset.css";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
token: string;
|
token: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@@ -60,22 +54,20 @@ const ResetPasswordForm: React.FunctionComponent<Props> = ({
|
|||||||
<Form onSubmit={onSubmit}>
|
<Form onSubmit={onSubmit}>
|
||||||
{({ handleSubmit, submitting, submitError }) => (
|
{({ handleSubmit, submitting, submitError }) => (
|
||||||
<form autoComplete="off" onSubmit={handleSubmit}>
|
<form autoComplete="off" onSubmit={handleSubmit}>
|
||||||
<HorizontalGutter size="double">
|
<div>
|
||||||
<HorizontalGutter>
|
<div>
|
||||||
<Localized id="resetPassword-resetYourPassword">
|
<Localized id="resetPassword-resetYourPassword">
|
||||||
<Typography variant="heading1">
|
<div className={styles.title}>Reset your password</div>
|
||||||
Reset your password
|
|
||||||
</Typography>
|
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="resetPassword-pleaseEnterNewPassword">
|
<Localized id="resetPassword-pleaseEnterNewPassword">
|
||||||
<Typography variant="bodyCopy">
|
<div className={styles.description}>
|
||||||
Please enter a new password to use to sign in to your
|
Please enter a new password to use to sign in to your
|
||||||
account. Make sure it is unique and be sure to keep it
|
account. Make sure it is unique and be sure to keep it
|
||||||
secure.
|
secure.
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
<HorizontalGutter>
|
<div>
|
||||||
<Field
|
<Field
|
||||||
name="password"
|
name="password"
|
||||||
validate={composeValidators(required, validatePassword)}
|
validate={composeValidators(required, validatePassword)}
|
||||||
@@ -83,15 +75,17 @@ const ResetPasswordForm: React.FunctionComponent<Props> = ({
|
|||||||
{({ input, meta }) => (
|
{({ input, meta }) => (
|
||||||
<FormField>
|
<FormField>
|
||||||
<Localized id="resetPassword-passwordLabel">
|
<Localized id="resetPassword-passwordLabel">
|
||||||
<InputLabel htmlFor={input.name}>Password</InputLabel>
|
<label className={styles.label} htmlFor={input.name}>
|
||||||
|
Password
|
||||||
|
</label>
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized
|
<Localized
|
||||||
id="resetPassword-passwordDescription"
|
id="resetPassword-passwordDescription"
|
||||||
$minLength={8}
|
$minLength={8}
|
||||||
>
|
>
|
||||||
<InputDescription>
|
<div className={styles.labelDescription}>
|
||||||
{"Must be at least {$minLength} characters"}
|
{"Must be at least {$minLength} characters"}
|
||||||
</InputDescription>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized
|
<Localized
|
||||||
id="resetPassword-passwordTextField"
|
id="resetPassword-passwordTextField"
|
||||||
@@ -107,28 +101,27 @@ const ResetPasswordForm: React.FunctionComponent<Props> = ({
|
|||||||
{...input}
|
{...input}
|
||||||
/>
|
/>
|
||||||
</Localized>
|
</Localized>
|
||||||
<ValidationMessage meta={meta} fullWidth />
|
<ValidationMessage meta={meta} />
|
||||||
</FormField>
|
</FormField>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
{submitError && (
|
{submitError && <CallOut color="error" title={submitError} />}
|
||||||
<CallOut color="error" fullWidth>
|
|
||||||
{submitError}
|
|
||||||
</CallOut>
|
|
||||||
)}
|
|
||||||
<Localized id="resetPassword-resetPassword">
|
<Localized id="resetPassword-resetPassword">
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
paddingSize="medium"
|
||||||
disabled={submitting}
|
disabled={submitting}
|
||||||
|
upperCase
|
||||||
fullWidth
|
fullWidth
|
||||||
|
className={styles.submit}
|
||||||
>
|
>
|
||||||
Reset Password
|
Reset Password
|
||||||
</Button>
|
</Button>
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { CallOut, HorizontalGutter, Typography } from "coral-ui/components";
|
import { CallOut } from "coral-ui/components/v3";
|
||||||
|
|
||||||
|
import styles from "./Reset.css";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
reason: React.ReactNode;
|
reason: React.ReactNode;
|
||||||
@@ -9,23 +11,27 @@ interface Props {
|
|||||||
|
|
||||||
const Sorry: React.FunctionComponent<Props> = ({ reason }) => {
|
const Sorry: React.FunctionComponent<Props> = ({ reason }) => {
|
||||||
return (
|
return (
|
||||||
<HorizontalGutter size="double">
|
<div>
|
||||||
<Localized id="resetPassword-oopsSorry">
|
<Localized id="resetPassword-oopsSorry">
|
||||||
<Typography variant="heading1">Oops Sorry!</Typography>
|
<div className={styles.title}>Oops Sorry!</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<CallOut color="error" fullWidth>
|
<CallOut
|
||||||
{reason ? (
|
color="error"
|
||||||
reason
|
titleWeight="semiBold"
|
||||||
) : (
|
title={
|
||||||
<Localized id="account-tokenNotFound">
|
reason ? (
|
||||||
<span data-testid="invalid-link">
|
reason
|
||||||
The specified link is invalid, check to see if it was copied
|
) : (
|
||||||
correctly.
|
<Localized id="account-tokenNotFound">
|
||||||
</span>
|
<span data-testid="invalid-link">
|
||||||
</Localized>
|
The specified link is invalid, check to see if it was copied
|
||||||
)}
|
correctly.
|
||||||
</CallOut>
|
</span>
|
||||||
</HorizontalGutter>
|
</Localized>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { HorizontalGutter, Typography } from "coral-ui/components";
|
import styles from "./Reset.css";
|
||||||
|
|
||||||
const Success: React.FunctionComponent = () => {
|
const Success: React.FunctionComponent = () => {
|
||||||
return (
|
return (
|
||||||
<HorizontalGutter size="double">
|
<div>
|
||||||
<Localized id="resetPassword-successfullyReset">
|
<Localized id="resetPassword-successfullyReset">
|
||||||
<Typography variant="heading1">Password successfully reset</Typography>
|
<div className={styles.title}>Password successfully reset</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
<Localized id="resetPassword-youMayClose">
|
<Localized id="resetPassword-youMayClose">
|
||||||
<Typography variant="bodyCopy">
|
<div className={styles.description}>
|
||||||
You may now close this window and sign in to your account with your
|
You may now close this window and sign in to your account with your
|
||||||
new password.
|
new password.
|
||||||
</Typography>
|
</div>
|
||||||
</Localized>
|
</Localized>
|
||||||
</HorizontalGutter>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,29 +20,22 @@ exports[`renders form 1`] = `
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onSubmit={[Function]}
|
onSubmit={[Function]}
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-double"
|
<div>
|
||||||
>
|
<div
|
||||||
<div
|
className="Confirm-title"
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-full"
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
className="Box-root Typography-root Typography-heading1 Typography-colorTextPrimary"
|
|
||||||
>
|
>
|
||||||
Email Confirmation
|
Confirm your email address
|
||||||
</h1>
|
</div>
|
||||||
<p
|
<div
|
||||||
className="Box-root Typography-root Typography-bodyCopy Typography-colorTextPrimary"
|
className="Confirm-description"
|
||||||
>
|
>
|
||||||
Click below to confirm your email address.
|
Click below to confirm your email address.
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-full"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled Button-fullWidth"
|
className="BaseButton-root Button-base Button-filled Button-fontSizeSmall Button-textAlignCenter Button-fontFamilyPrimary Button-fontWeightPrimaryBold Button-paddingSizeSmall Button-colorPrimary Button-upperCase Button-fullWidth Confirm-submit"
|
||||||
data-color="primary"
|
|
||||||
data-variant="filled"
|
data-variant="filled"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
@@ -79,25 +72,34 @@ exports[`renders missing confirm token 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="ConfirmRoute-root"
|
className="ConfirmRoute-root"
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-double"
|
<div
|
||||||
>
|
className="Confirm-title"
|
||||||
<h1
|
|
||||||
className="Box-root Typography-root Typography-heading1 Typography-colorTextPrimary"
|
|
||||||
>
|
>
|
||||||
Oops Sorry!
|
Oops Sorry!
|
||||||
</h1>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="CallOut-root CallOut-colorError CallOut-fullWidth"
|
className="CallOut-root CallOut-error CallOut-leftBorder"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="CallOut-inner"
|
className="CallOut-container"
|
||||||
>
|
>
|
||||||
<span
|
<div
|
||||||
data-testid="invalid-link"
|
className="CallOut-content"
|
||||||
>
|
>
|
||||||
The specified link is invalid, check to see if it was copied correctly.
|
<div
|
||||||
</span>
|
className="CallOut-title CallOut-titleSemiBold"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
data-testid="invalid-link"
|
||||||
|
>
|
||||||
|
The specified link is invalid, check to see if it was copied correctly.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="CallOut-body"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,41 +21,35 @@ exports[`renders form 1`] = `
|
|||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onSubmit={[Function]}
|
onSubmit={[Function]}
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-double"
|
<div>
|
||||||
>
|
<div
|
||||||
<div
|
className="Reset-title"
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-full"
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
className="Box-root Typography-root Typography-heading1 Typography-colorTextPrimary"
|
|
||||||
>
|
>
|
||||||
Reset your password
|
Reset your password
|
||||||
</h1>
|
</div>
|
||||||
<p
|
<div
|
||||||
className="Box-root Typography-root Typography-bodyCopy Typography-colorTextPrimary"
|
className="Reset-description"
|
||||||
>
|
>
|
||||||
Please enter a new password to use to sign in to your account.
|
Please enter a new password to use to sign in to your account.
|
||||||
Make sure it is unique and be sure to keep it secure.
|
Make sure it is unique and be sure to keep it secure.
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-full"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
className="Box-root HorizontalGutter-root FormField-root HorizontalGutter-half"
|
className="Box-root HorizontalGutter-root FormField-root HorizontalGutter-spacing-2"
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
className="Box-root Typography-root Typography-inputLabel Typography-colorTextPrimary InputLabel-root"
|
className="Reset-label"
|
||||||
htmlFor="password"
|
htmlFor="password"
|
||||||
>
|
>
|
||||||
Password
|
Password
|
||||||
</label>
|
</label>
|
||||||
<p
|
<div
|
||||||
className="Box-root Typography-root Typography-fieldDescription Typography-colorTextSecondary"
|
className="Reset-labelDescription"
|
||||||
>
|
>
|
||||||
Must be at least 8 characters
|
Must be at least 8 characters
|
||||||
</p>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="PasswordField-fullWidth PasswordField-root"
|
className="PasswordField-fullWidth PasswordField-root"
|
||||||
>
|
>
|
||||||
@@ -67,6 +61,7 @@ Make sure it is unique and be sure to keep it secure.
|
|||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
autoCorrect="off"
|
autoCorrect="off"
|
||||||
className="PasswordField-colorRegular PasswordField-fullWidth PasswordField-input"
|
className="PasswordField-colorRegular PasswordField-fullWidth PasswordField-input"
|
||||||
|
data-testid="password-field"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
@@ -97,8 +92,7 @@ Make sure it is unique and be sure to keep it secure.
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled Button-fullWidth"
|
className="BaseButton-root Button-base Button-filled Button-fontSizeSmall Button-textAlignCenter Button-fontFamilyPrimary Button-fontWeightPrimaryBold Button-paddingSizeMedium Button-colorPrimary Button-upperCase Button-fullWidth Reset-submit"
|
||||||
data-color="primary"
|
|
||||||
data-variant="filled"
|
data-variant="filled"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
@@ -136,25 +130,34 @@ exports[`renders missing reset token 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="ResetRoute-root"
|
className="ResetRoute-root"
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-double"
|
<div
|
||||||
>
|
className="Reset-title"
|
||||||
<h1
|
|
||||||
className="Box-root Typography-root Typography-heading1 Typography-colorTextPrimary"
|
|
||||||
>
|
>
|
||||||
Oops Sorry!
|
Oops Sorry!
|
||||||
</h1>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="CallOut-root CallOut-colorError CallOut-fullWidth"
|
className="CallOut-root CallOut-error CallOut-leftBorder"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="CallOut-inner"
|
className="CallOut-container"
|
||||||
>
|
>
|
||||||
<span
|
<div
|
||||||
data-testid="invalid-link"
|
className="CallOut-content"
|
||||||
>
|
>
|
||||||
The specified link is invalid, check to see if it was copied correctly.
|
<div
|
||||||
</span>
|
className="CallOut-title CallOut-titleSemiBold"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
data-testid="invalid-link"
|
||||||
|
>
|
||||||
|
The specified link is invalid, check to see if it was copied correctly.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="CallOut-body"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,17 +22,19 @@ exports[`renders form 1`] = `
|
|||||||
<form
|
<form
|
||||||
onSubmit={[Function]}
|
onSubmit={[Function]}
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-full"
|
<div
|
||||||
>
|
className="Unsubscribe-title"
|
||||||
<h1
|
>
|
||||||
className="Box-root Typography-root Typography-heading1 Typography-colorTextPrimary"
|
Unsubscribe from email notifications
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="Unsubscribe-description"
|
||||||
>
|
>
|
||||||
Click below to confirm that you want to unsubscribe from all notifications.
|
Click below to confirm that you want to unsubscribe from all notifications.
|
||||||
</h1>
|
</div>
|
||||||
<button
|
<button
|
||||||
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled Button-fullWidth"
|
className="BaseButton-root Button-base Button-filled Button-fontSizeSmall Button-textAlignCenter Button-fontFamilyPrimary Button-fontWeightPrimaryBold Button-paddingSizeMedium Button-colorPrimary Button-upperCase Button-fullWidth Unsubscribe-submit"
|
||||||
data-color="primary"
|
|
||||||
data-variant="filled"
|
data-variant="filled"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
@@ -42,7 +44,7 @@ exports[`renders form 1`] = `
|
|||||||
onTouchEnd={[Function]}
|
onTouchEnd={[Function]}
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Confirm
|
Unsubscribe
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@@ -69,25 +71,34 @@ exports[`renders missing confirm token 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="UnsubscribeRoute-root"
|
className="UnsubscribeRoute-root"
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
className="Box-root HorizontalGutter-root HorizontalGutter-double"
|
<div
|
||||||
>
|
className="Unsubscribe-title"
|
||||||
<h1
|
|
||||||
className="Box-root Typography-root Typography-heading1 Typography-colorTextPrimary"
|
|
||||||
>
|
>
|
||||||
Oops Sorry!
|
Oops Sorry!
|
||||||
</h1>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="CallOut-root CallOut-colorError CallOut-fullWidth"
|
className="CallOut-root CallOut-error CallOut-leftBorder"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="CallOut-inner"
|
className="CallOut-container"
|
||||||
>
|
>
|
||||||
<span
|
<div
|
||||||
data-testid="invalid-link"
|
className="CallOut-content"
|
||||||
>
|
>
|
||||||
The specified link is invalid, check to see if it was copied correctly.
|
<div
|
||||||
</span>
|
className="CallOut-title CallOut-titleSemiBold"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
data-testid="invalid-link"
|
||||||
|
>
|
||||||
|
The specified link is invalid, check to see if it was copied correctly.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="CallOut-body"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -53,9 +53,7 @@ it("renders form", async () => {
|
|||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await waitForElement(() =>
|
await waitForElement(() =>
|
||||||
within(root).getByText("Email Confirmation", {
|
within(root).getByText("Confirm your email address")
|
||||||
exact: false,
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
expect(within(root).toJSON()).toMatchSnapshot();
|
expect(within(root).toJSON()).toMatchSnapshot();
|
||||||
@@ -130,9 +128,7 @@ it("submits form", async () => {
|
|||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await waitForElement(() =>
|
await waitForElement(() =>
|
||||||
within(root).getByText("Email Confirmation", {
|
within(root).getByText("Confirm your email address")
|
||||||
exact: false,
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const form = within(root).getByType("form");
|
const form = within(root).getByType("form");
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
.root {
|
.root {
|
||||||
color: var(--v2-palette-success-main);
|
color: var(--palette-success-500);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.historyIcon {
|
.historyIcon {
|
||||||
color: var(--v2-palette-text-secondary);
|
color: var(--palette-text-100);
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.root {
|
.root {
|
||||||
padding: var(--v2-spacing-2) var(--v2-spacing-1);
|
padding: var(--spacing-2) var(--spacing-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.leftCol {
|
.leftCol {
|
||||||
@@ -8,5 +8,5 @@
|
|||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
padding-top: 3px;
|
padding-top: 3px;
|
||||||
margin-right: var(--v2-spacing-2);
|
margin-right: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$decisionHistoryBorderColor: var(--v2-colors-grey-300);
|
$decisionHistoryBorderColor: var(--palette-grey-300);
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
.root {
|
.root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: var(--v2-font-size-1);
|
font-size: var(--font-size-1);
|
||||||
line-height: var(--v2-line-height-reset);
|
line-height: 1.33;
|
||||||
color: var(--v2-colors-mono-100);
|
color: var(--palette-text-100);
|
||||||
padding: 0 var(--v2-spacing-1);
|
padding: 0 var(--spacing-1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
font-family: var(--v2-font-family-primary);
|
font-family: var(--font-family-primary);
|
||||||
font-weight: var(--v2-font-weight-primary-regular);
|
font-weight: var(--font-weight-primary-regular);
|
||||||
font-size: var(--v2-font-size-2);
|
font-size: var(--font-size-2);
|
||||||
line-height: var(--v2-line-height-body-short);
|
line-height: 1.285;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
.root {
|
.root {
|
||||||
margin-top: var(--v2-spacing-1);
|
margin-top: var(--spacing-1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
$moderateCardDecisionHistoryLinkTextColor: var(--v2-colors-teal-700);
|
$moderateCardDecisionHistoryLinkTextColor: $colors-teal-700;
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
line-height: var(--v2-line-height-reset);
|
font-weight: var(--font-weight-primary-bold);
|
||||||
font-weight: var(--v2-font-weight-primary-bold);
|
font-family: var(--font-family-primary);
|
||||||
font-family: var(--v2-font-family-primary);
|
font-size: var(--font-size-1);
|
||||||
font-size: var(--v2-font-size-1);
|
line-height: 1.33;
|
||||||
color: $moderateCardDecisionHistoryLinkTextColor;
|
color: $moderateCardDecisionHistoryLinkTextColor;
|
||||||
font-style: var(--v2-font-style-underline);
|
font-style: var(--font-style-underline);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
/* Fallback end */
|
/* Fallback end */
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
color: var(--v2-palette-text-primary);
|
color: var(--palette-text-500);
|
||||||
font-weight: var(--v2-font-weight-primary-semi-bold);
|
font-weight: var(--font-weight-primary-semi-bold);
|
||||||
font-family: var(--v2-font-family-primary);
|
font-family: var(--font-family-primary);
|
||||||
line-height: var(--v2-line-height-body-short);
|
font-size: var(--font-size-2);
|
||||||
font-size: var(--v2-font-size-2);
|
line-height: 1.285;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
.root {
|
.root {
|
||||||
color: var(--v2-palette-error-main);
|
color: var(--palette-error-500);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
$moderateCardDecisionHistoryLinkTextColor: var(--v2-colors-teal-700);
|
$moderateCardDecisionHistoryLinkTextColor: $colors-teal-700;
|
||||||
$moderateCardDecisionHistoryBorderColor: var(--v2-colors-grey-300);
|
$moderateCardDecisionHistoryBorderColor: var(--palette-grey-300);
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
font-size: var(--v2-font-size-2);
|
font-size: var(--font-size-2);
|
||||||
font-weight: var(--v2-font-weight-primary-bold);
|
font-weight: var(--font-weight-primary-bold);
|
||||||
font-family: var(--v2-font-family-primary);
|
font-family: var(--font-family-primary);
|
||||||
line-height: var(--v2-line-height-reset);
|
line-height: 1.14;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: $moderateCardDecisionHistoryLinkTextColor;
|
color: $moderateCardDecisionHistoryLinkTextColor;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-top: 1px solid $moderateCardDecisionHistoryBorderColor;
|
border-top: 1px solid $moderateCardDecisionHistoryBorderColor;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: var(--v2-spacing-1);
|
padding-top: var(--spacing-1);
|
||||||
padding-bottom: var(--v2-spacing-1);
|
padding-bottom: var(--spacing-1);
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
color: var(--v2-palette-grey-lighter);
|
color: var(--palette-grey-300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
$timestampColor: var(--v2-colors-mono-100);
|
$timestampColor: var(--palette-text-100);
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
color: $timestampColor;
|
color: $timestampColor;
|
||||||
font-family: var(--v2-font-family-primary);
|
font-family: var(--font-family-primary);
|
||||||
font-weight: var(--v2-font-weight-primary-bold);
|
font-weight: var(--font-weight-primary-bold);
|
||||||
font-size: var(--v2-font-size-1);
|
font-size: var(--font-size-1);
|
||||||
line-height: var(--v2-line-height-reset);
|
line-height: 1.33;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
$decisionHistoryBorderColor: var(--v2-colors-grey-300);
|
$decisionHistoryBorderColor: var(--palette-grey-300);
|
||||||
$decisionHistoryTitleBackgroundColor: var(--v2-colors-grey-200);
|
$decisionHistoryTitleBackgroundColor: var(--palette-grey-200);
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
background: $decisionHistoryTitleBackgroundColor;
|
background: $decisionHistoryTitleBackgroundColor;
|
||||||
padding: var(--v2-spacing-1);
|
padding: var(--spacing-1);
|
||||||
color: var(--v2-palette-text-primary);
|
color: var(--palette-text-500);
|
||||||
border-bottom: 1px solid $decisionHistoryBorderColor;
|
border-bottom: 1px solid $decisionHistoryBorderColor;
|
||||||
font-size: var(--v2-font-size-icon-medium);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin-right: var(--v2-spacing-2);
|
font-size: var(--font-size-icon-md);
|
||||||
|
margin-right: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-weight: var(--v2-font-weight-primary-bold);
|
font-weight: var(--font-weight-primary-bold);
|
||||||
color: var(--v2-palette-text-primary);
|
color: var(--palette-text-500);
|
||||||
font-size: var(--v2-font-size-2);
|
font-size: var(--font-size-2);
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
font-family: var(--v2-font-family-primary);
|
font-family: var(--font-family-primary);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
$moderateCardDecisionHistoryColor: var(--v2-colors-mono-900);
|
$moderateCardDecisionHistoryColor: var(--palette-text-900);
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
color: $moderateCardDecisionHistoryColor;
|
color: $moderateCardDecisionHistoryColor;
|
||||||
font-weight: var(--v2-font-weight-secondary-bold);
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
font-family: var(--v2-font-family-secondary);
|
font-family: var(--font-family-secondary);
|
||||||
line-height: var(--v2-line-height-body-short);
|
line-height: 1.3;
|
||||||
font-size: var(--v2-font-size-3);
|
font-size: var(--font-size-3);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -11,9 +11,7 @@ exports[`renders correctly 1`] = `
|
|||||||
className="DecisionHistoryLoading-container"
|
className="DecisionHistoryLoading-container"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
>
|
>
|
||||||
<Delay
|
<Delay>
|
||||||
ms={500}
|
|
||||||
>
|
|
||||||
<withPropsOnChange(Spinner)
|
<withPropsOnChange(Spinner)
|
||||||
size="sm"
|
size="sm"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import useNotification from "./useNotification";
|
import useNotification from "./useNotification";
|
||||||
|
|
||||||
const NotificationContainer: FunctionComponent<{}> = () => {
|
const NotificationContainer: FunctionComponent<{}> = () => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useRouter } from "found";
|
import { useRouter } from "found";
|
||||||
|
import { setLongTimeout } from "long-settimeout";
|
||||||
import { ReactNode, useContext } from "react";
|
import { ReactNode, useContext } from "react";
|
||||||
|
|
||||||
import { NotificationContext } from "./GlobalNotificationContext";
|
import { NotificationContext } from "./GlobalNotificationContext";
|
||||||
@@ -17,7 +18,7 @@ function useNotification() {
|
|||||||
const setMessage = (message: ReactNode, timeout?: number) => {
|
const setMessage = (message: ReactNode, timeout?: number) => {
|
||||||
dispatch({ type: "SET_MESSAGE", message });
|
dispatch({ type: "SET_MESSAGE", message });
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
setTimeout(() => {
|
setLongTimeout(() => {
|
||||||
dispatch({ type: "CLEAR_MESSAGE" });
|
dispatch({ type: "CLEAR_MESSAGE" });
|
||||||
}, timeout);
|
}, timeout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { PropTypesOf } from "coral-framework/types";
|
import { PropTypesOf } from "coral-framework/types";
|
||||||
import { LogoHorizontal } from "coral-ui/components";
|
import { LogoHorizontal } from "coral-ui/components/v2";
|
||||||
import { AppBar, Begin, Divider, End } from "coral-ui/components/v2/AppBar";
|
import { AppBar, Begin, Divider, End } from "coral-ui/components/v2/AppBar";
|
||||||
|
|
||||||
import { DecisionHistoryButton } from "./DecisionHistory";
|
import { DecisionHistoryButton } from "./DecisionHistory";
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ import Navigation from "./Navigation";
|
|||||||
|
|
||||||
it("renders correctly", () => {
|
it("renders correctly", () => {
|
||||||
const renderer = createRenderer();
|
const renderer = createRenderer();
|
||||||
renderer.render(<Navigation showConfigure />);
|
renderer.render(<Navigation showConfigure showDashboard={true} />);
|
||||||
expect(renderer.getRenderOutput()).toMatchSnapshot();
|
expect(renderer.getRenderOutput()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import NavigationLink from "./NavigationLink";
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
showConfigure: boolean;
|
showConfigure: boolean;
|
||||||
|
showDashboard: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Navigation: FunctionComponent<Props> = (props) => (
|
const Navigation: FunctionComponent<Props> = (props) => (
|
||||||
@@ -25,6 +26,11 @@ const Navigation: FunctionComponent<Props> = (props) => (
|
|||||||
<NavigationLink to="/admin/configure">Configure</NavigationLink>
|
<NavigationLink to="/admin/configure">Configure</NavigationLink>
|
||||||
</Localized>
|
</Localized>
|
||||||
)}
|
)}
|
||||||
|
{props.showDashboard && (
|
||||||
|
<Localized id="navigation-dashboard">
|
||||||
|
<NavigationLink to="/admin/dashboard">Dashboard</NavigationLink>
|
||||||
|
</Localized>
|
||||||
|
)}
|
||||||
</AppBarNavigation>
|
</AppBarNavigation>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ class NavigationContainer extends React.Component<Props> {
|
|||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<Navigation
|
<Navigation
|
||||||
|
showDashboard={
|
||||||
|
!!this.props.viewer && can(this.props.viewer, Ability.VIEW_STATISTICS)
|
||||||
|
}
|
||||||
showConfigure={
|
showConfigure={
|
||||||
!!this.props.viewer &&
|
!!this.props.viewer &&
|
||||||
can(this.props.viewer, Ability.CHANGE_CONFIGURATION)
|
can(this.props.viewer, Ability.CHANGE_CONFIGURATION)
|
||||||
|
|||||||
@@ -38,5 +38,14 @@ exports[`renders correctly 1`] = `
|
|||||||
Configure
|
Configure
|
||||||
</NavigationLink>
|
</NavigationLink>
|
||||||
</Localized>
|
</Localized>
|
||||||
|
<Localized
|
||||||
|
id="navigation-dashboard"
|
||||||
|
>
|
||||||
|
<NavigationLink
|
||||||
|
to="/admin/dashboard"
|
||||||
|
>
|
||||||
|
Dashboard
|
||||||
|
</NavigationLink>
|
||||||
|
</Localized>
|
||||||
</withPropsOnChange(Navigation)>
|
</withPropsOnChange(Navigation)>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
$userMenuButtonColor: var(--v2-colors-mono-100);
|
$userMenuButtonColor: var(--palette-text-100);
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
@@ -11,9 +11,9 @@ $userMenuButtonColor: var(--v2-colors-mono-100);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.buttonText {
|
.buttonText {
|
||||||
font-family: var(--v2-font-family-secondary);
|
font-family: var(--font-family-secondary);
|
||||||
color: $userMenuButtonColor;
|
color: $userMenuButtonColor;
|
||||||
font-size: var(--v2-font-size-4);
|
font-size: var(--font-size-4);
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
margin-right: 1px;
|
margin-right: 1px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.version {
|
.version {
|
||||||
font-size: calc(10rem / var(--rem-base));
|
font-size: 0.625rem;
|
||||||
color: var(--palette-text-secondary);
|
color: var(--palette-text-100);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-bottom: var(--spacing-3);
|
padding-bottom: var(--spacing-3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { Typography } from "coral-ui/components";
|
import { Typography } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import styles from "./Version.css";
|
import styles from "./Version.css";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
.container {
|
.container {
|
||||||
width: 385px;
|
width: 385px;
|
||||||
background-color: var(--v2-colors-grey-100);
|
background-color: var(--palette-grey-100);
|
||||||
border: 1px solid var(--v2-colors-grey-300);
|
border: 1px solid var(--palette-grey-300);
|
||||||
margin-top: 70px;
|
margin-top: 70px;
|
||||||
padding: var(--v2-spacing-6);
|
padding: var(--spacing-6);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
$comment-content: var(--v2-colors-mono-900);
|
$comment-content: var(--palette-text-900);
|
||||||
$comment-blockquote-bg: var(--v2-colors-grey-100);
|
$comment-blockquote-bg: var(--palette-grey-100);
|
||||||
$comment-highlight-bg: var(--v2-colors-yellow-500);
|
$comment-highlight-bg: var(--palette-warning-500);
|
||||||
$comment-link: var(--v2-palette-primary-main);
|
$comment-link: $colors-teal-700;
|
||||||
$comment-link-active: var(--v2-palette-primary-darkest);
|
$comment-link-active: $colors-teal-900;
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
composes: bodyCommentV2 from "~coral-ui/shared/typography.css";
|
font-size: var(--font-size-3);
|
||||||
font-family: var(--v2-font-family-primary);
|
font-weight: var(--font-weight-primary-regular);
|
||||||
font-size: var(--v2-font-size-3);
|
font-family: var(--font-family-primary);
|
||||||
line-height: var(--v2-line-height-body-comment);
|
line-height: 1.45;
|
||||||
color: $comment-content;
|
color: $comment-content;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
|
|
||||||
b,
|
b,
|
||||||
strong {
|
strong {
|
||||||
font-weight: var(--v2-font-weight-primary-bold);
|
font-weight: var(--font-weight-primary-bold);
|
||||||
}
|
}
|
||||||
i,
|
i,
|
||||||
em {
|
em {
|
||||||
|
|||||||
@@ -1,20 +1,50 @@
|
|||||||
import cn from "classnames";
|
import cn from "classnames";
|
||||||
import React, { FunctionComponent, useMemo } from "react";
|
import React, { FunctionComponent, useMemo } from "react";
|
||||||
import striptags from "striptags";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getPhrasesRegExp,
|
getPhrasesRegExp,
|
||||||
GetPhrasesRegExpOptions,
|
GetPhrasesRegExpOptions,
|
||||||
markHTMLNode,
|
markHTMLNode,
|
||||||
} from "coral-admin/helpers";
|
} from "coral-admin/helpers";
|
||||||
import { createPurify } from "coral-common/utils/purify";
|
import {
|
||||||
|
ALL_FEATURES,
|
||||||
|
createSanitize,
|
||||||
|
Sanitize,
|
||||||
|
} from "coral-common/helpers/sanitize";
|
||||||
|
|
||||||
import styles from "./CommentContent.css";
|
import styles from "./CommentContent.css";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a purify instance that will be used to handle HTML content.
|
* Return a purify instance that will be used to handle HTML content.
|
||||||
*/
|
*/
|
||||||
const purify = createPurify(window, false);
|
const getSanitize: (highlight: boolean) => Sanitize = (() => {
|
||||||
|
let sanitizers: Record<"default" | "highlight", Sanitize> | null = null;
|
||||||
|
return (highlight: boolean) => {
|
||||||
|
if (!sanitizers) {
|
||||||
|
sanitizers = {
|
||||||
|
default: createSanitize(window, {
|
||||||
|
// Allow all RTE features to be displayed.
|
||||||
|
features: ALL_FEATURES,
|
||||||
|
}),
|
||||||
|
highlight: createSanitize(window, {
|
||||||
|
// We need normalized text nodes to mark nodes for suspect/banned words.
|
||||||
|
normalize: true,
|
||||||
|
// Allow all RTE features to be displayed.
|
||||||
|
features: ALL_FEATURES,
|
||||||
|
config: {
|
||||||
|
FORBID_TAGS: highlight
|
||||||
|
? ["b", "strong", "i", "em", "s", "span"]
|
||||||
|
: [],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (highlight) {
|
||||||
|
return sanitizers.highlight!;
|
||||||
|
}
|
||||||
|
return sanitizers.default!;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -51,15 +81,7 @@ const CommentContent: FunctionComponent<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize the input for display.
|
// Sanitize the input for display.
|
||||||
let html = purify.sanitize(children);
|
const node = getSanitize(highlight)(children);
|
||||||
if (highlight) {
|
|
||||||
html = striptags(html, ["a"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We create a Shadow DOM Tree with the HTML body content and use it as a
|
|
||||||
// parser.
|
|
||||||
const node = document.createElement("div");
|
|
||||||
node.innerHTML = html;
|
|
||||||
|
|
||||||
// If the expression is available, then mark the nodes.
|
// If the expression is available, then mark the nodes.
|
||||||
if (expression) {
|
if (expression) {
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
$moderateCardIconColor: var(--v2-colors-mono-100);
|
$moderateCardIconColor: var(--palette-text-100);
|
||||||
$moderateCardInReplyToColor: var(--v2-colors-mono-100);
|
$moderateCardInReplyToColor: var(--palette-text-100);
|
||||||
$moderateCardInReplyToUsernameColor: var(--v2-colors-mono-500);
|
$moderateCardInReplyToUsernameColor: var(--palette-text-500);
|
||||||
$moderateCardUsernameBackgroundHover: var(--v2-colors-grey-200);
|
$moderateCardUsernameBackgroundHover: var(--palette-grey-200);
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
color: $moderateCardIconColor;
|
color: $moderateCardIconColor;
|
||||||
}
|
}
|
||||||
.inReplyTo {
|
.inReplyTo {
|
||||||
color: $moderateCardInReplyToColor;
|
color: $moderateCardInReplyToColor;
|
||||||
font-family: var(--v2-font-family-primary);
|
font-family: var(--font-family-primary);
|
||||||
font-weight: var(--v2-font-weight-primary-regular);
|
font-weight: var(--font-weight-primary-regular);
|
||||||
font-size: var(--v2-font-size-2);
|
font-size: var(--font-size-2);
|
||||||
line-height: var(--v2-line-height-reset);
|
line-height: 1.14;
|
||||||
}
|
}
|
||||||
.username {
|
.username {
|
||||||
color: $moderateCardInReplyToUsernameColor;
|
color: $moderateCardInReplyToUsernameColor;
|
||||||
font-family: var(--v2-font-family-secondary);
|
font-family: var(--font-family-secondary);
|
||||||
font-weight: var(--v2-font-weight-secondary-bold);
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
font-size: var(--v2-font-size-3);
|
font-size: var(--font-size-3);
|
||||||
line-height: var(--v2-line-height-reset);
|
line-height: 1;
|
||||||
|
|
||||||
padding: var(--spacing-1);
|
padding: var(--spacing-1);
|
||||||
|
|
||||||
@@ -38,5 +38,5 @@ $moderateCardUsernameBackgroundHover: var(--v2-colors-grey-200);
|
|||||||
.usernameButton {
|
.usernameButton {
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
|
|
||||||
margin-left: calc(-1 * var(--v2-spacing-1));
|
margin-left: calc(-1 * var(--spacing-1));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
$moderateCardUsernameColor: var(--v2-colors-mono-900);
|
$moderateCardUsernameColor: var(--palette-text-900);
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
font-size: var(--v2-font-size-3);
|
font-size: var(--font-size-3);
|
||||||
font-weight: var(--v2-font-weight-secondary-bold);
|
font-weight: var(--font-weight-secondary-bold);
|
||||||
font-family: var(--v2-font-family-secondary);
|
font-family: var(--font-family-secondary);
|
||||||
line-height: var(--v2-line-height-reset);
|
line-height: 1;
|
||||||
color: $moderateCardUsernameColor;
|
color: $moderateCardUsernameColor;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
$moderateCardUsernameBackgroundHover: var(--v2-colors-grey-200);
|
$moderateCardUsernameBackgroundHover: var(--palette-grey-200);
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
margin-right: var(--mini-unit);
|
margin-right: var(--mini-unit);
|
||||||
padding: var(--spacing-1);
|
padding: var(--spacing-1);
|
||||||
margin-left: calc(-1 * var(--v2-spacing-1));
|
margin-left: calc(-1 * var(--spacing-1));
|
||||||
|
|
||||||
line-height: var(--v2-line-height-reset);
|
line-height: 1;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $moderateCardUsernameBackgroundHover;
|
background-color: $moderateCardUsernameBackgroundHover;
|
||||||
border-radius: var(--v2-round-corners);
|
border-radius: var(--round-corners);
|
||||||
border-style: none;
|
border-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
background-color: $moderateCardUsernameBackgroundHover;
|
background-color: $moderateCardUsernameBackgroundHover;
|
||||||
border-radius: var(--v2-round-corners);
|
border-radius: var(--round-corners);
|
||||||
border-style: none;
|
border-style: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import cn from "classnames";
|
|||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { BaseButton } from "coral-ui/components/v2";
|
import { BaseButton } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import Username from "./Username";
|
import Username from "./Username";
|
||||||
|
|
||||||
import styles from "./UsernameButton.css";
|
import styles from "./UsernameButton.css";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
import { Modal } from "coral-ui/components";
|
import { Modal } from "coral-ui/components/v2";
|
||||||
|
|
||||||
import ConversationModalQuery from "./ConversationModalQuery";
|
import ConversationModalQuery from "./ConversationModalQuery";
|
||||||
|
|
||||||
|
|||||||
+11
-11
@@ -1,31 +1,31 @@
|
|||||||
$conversationModalHighlightBackground: var(--v2-colors-teal-100);
|
$conversationModalHighlightBackground: $colors-teal-100;
|
||||||
$conversationModalCommentText: var(--v2-colors-mono-500);
|
$conversationModalCommentText: var(--palette-text-500);
|
||||||
.root {
|
.root {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.line {
|
.line {
|
||||||
border-color: var(--v2-colors-grey-400);
|
border-color: var(--palette-grey-400);
|
||||||
}
|
}
|
||||||
|
|
||||||
.adornments {
|
.adornments {
|
||||||
margin-right: var(--v2-spacing-2);
|
margin-right: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
margin-top: var(--v2-spacing-2);
|
margin-top: var(--spacing-2);
|
||||||
margin-bottom: var(--v2-spacing-2);
|
margin-bottom: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.highlightedCircle {
|
.highlightedCircle {
|
||||||
margin-top: var(--v2-spacing-1);
|
margin-top: var(--spacing-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.highlighted {
|
.highlighted {
|
||||||
background-color: $conversationModalHighlightBackground;
|
background-color: $conversationModalHighlightBackground;
|
||||||
padding: var(--v2-spacing-2);
|
padding: var(--spacing-2);
|
||||||
padding-top: var(--v2-spacing-1);
|
padding-top: var(--spacing-1);
|
||||||
margin-bottom: var(--v2-spacing-2);
|
margin-bottom: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.commentText {
|
.commentText {
|
||||||
@@ -33,5 +33,5 @@ $conversationModalCommentText: var(--v2-colors-mono-500);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.showReplies {
|
.showReplies {
|
||||||
padding-left: var(--v2-spacing-2);
|
padding-left: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -3,6 +3,7 @@ import cn from "classnames";
|
|||||||
import React, { FunctionComponent, useCallback, useState } from "react";
|
import React, { FunctionComponent, useCallback, useState } from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
|
import { MediaContainer } from "coral-admin/components/MediaContainer";
|
||||||
import { withFragmentContainer } from "coral-framework/lib/relay";
|
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -95,6 +96,7 @@ const ConversationModalCommentContainer: FunctionComponent<Props> = ({
|
|||||||
{comment.body}
|
{comment.body}
|
||||||
</CommentContent>
|
</CommentContent>
|
||||||
)}
|
)}
|
||||||
|
<MediaContainer comment={comment} />
|
||||||
</div>
|
</div>
|
||||||
</HorizontalGutter>
|
</HorizontalGutter>
|
||||||
</Flex>
|
</Flex>
|
||||||
@@ -104,7 +106,7 @@ const ConversationModalCommentContainer: FunctionComponent<Props> = ({
|
|||||||
<Localized id="conversation-modal-reply-show-replies">
|
<Localized id="conversation-modal-reply-show-replies">
|
||||||
<Button
|
<Button
|
||||||
color="mono"
|
color="mono"
|
||||||
variant="outline"
|
variant="outlined"
|
||||||
onClick={onShowReplies}
|
onClick={onShowReplies}
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
@@ -153,6 +155,7 @@ const enhanced = withFragmentContainer<Props>({
|
|||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
...MediaContainer_comment
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
})(ConversationModalCommentContainer);
|
})(ConversationModalCommentContainer);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
.root {
|
.root {
|
||||||
}
|
}
|
||||||
.topCircle {
|
.topCircle {
|
||||||
margin-right: var(--v2-spacing-2);
|
margin-right: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottomCircleContainer {
|
.bottomCircleContainer {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
padding-top: var(--v2-spacing-1);
|
padding-top: var(--spacing-1);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -1,17 +1,17 @@
|
|||||||
$modal-header-text: var(--v2-colors-mono-900);
|
$modal-header-text: var(--palette-text-900);
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-size: var(--v2-font-size-4);
|
font-size: var(--font-size-4);
|
||||||
font-family: var(--v2-font-family-primary);
|
font-family: var(--font-family-primary);
|
||||||
font-weight: var(--v2-font-weight-primary-regular);
|
font-weight: var(--font-weight-primary-regular);
|
||||||
line-height: var(--v2-line-height-title);
|
line-height: 1.11;
|
||||||
color: $modal-header-text;
|
color: $modal-header-text;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversationTitle {
|
.conversationTitle {
|
||||||
font-weight: var(--v2-font-weight-primary-semi-bold);
|
font-weight: var(--font-weight-primary-semi-bold);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: var(--v2-spacing-2);
|
margin-bottom: var(--spacing-2);
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -39,7 +39,12 @@ const ConversationModalHeaderContainer: FunctionComponent<Props> = ({
|
|||||||
: comment.story.url}
|
: comment.story.url}
|
||||||
</h1>
|
</h1>
|
||||||
<Localized id="conversation-modal-header-moderate-link">
|
<Localized id="conversation-modal-header-moderate-link">
|
||||||
<Button variant="outline" color="mono" uppercase onClick={onModerate}>
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
color="mono"
|
||||||
|
uppercase
|
||||||
|
onClick={onModerate}
|
||||||
|
>
|
||||||
Moderate story
|
Moderate story
|
||||||
</Button>
|
</Button>
|
||||||
</Localized>
|
</Localized>
|
||||||
|
|||||||
@@ -4,5 +4,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
padding: var(--v2-spacing-4);
|
padding: var(--spacing-4);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
.comment {
|
.comment {
|
||||||
padding-left: calc(var(--v2-spacing-4));
|
padding-left: calc(var(--spacing-4));
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding-left: calc(var(--v2-spacing-4));
|
padding-left: calc(var(--spacing-4));
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -62,7 +62,7 @@ const ConversationModalRepliesContainer: FunctionComponent<Props> = ({
|
|||||||
<div className={styles.footer}>
|
<div className={styles.footer}>
|
||||||
{!showReplies && comment.replyCount > 0 && (
|
{!showReplies && comment.replyCount > 0 && (
|
||||||
<Localized id="conversation-modal-replies-show">
|
<Localized id="conversation-modal-replies-show">
|
||||||
<Button variant="outline" fullWidth onClick={onShowReplies}>
|
<Button variant="outlined" fullWidth onClick={onShowReplies}>
|
||||||
Show replies
|
Show replies
|
||||||
</Button>
|
</Button>
|
||||||
</Localized>
|
</Localized>
|
||||||
@@ -71,7 +71,7 @@ const ConversationModalRepliesContainer: FunctionComponent<Props> = ({
|
|||||||
comment.replyCount > replies.length &&
|
comment.replyCount > replies.length &&
|
||||||
replies.length > 0 && (
|
replies.length > 0 && (
|
||||||
<Localized id="conversation-modal-replies-show-more">
|
<Localized id="conversation-modal-replies-show-more">
|
||||||
<Button variant="outline" fullWidth onClick={loadMore}>
|
<Button variant="outlined" fullWidth onClick={loadMore}>
|
||||||
Show more replies
|
Show more replies
|
||||||
</Button>
|
</Button>
|
||||||
</Localized>
|
</Localized>
|
||||||
|
|||||||
+5
-9
@@ -1,5 +1,5 @@
|
|||||||
import { Localized } from "@fluent/react/compat";
|
import { Localized } from "@fluent/react/compat";
|
||||||
import React, { FunctionComponent, useMemo } from "react";
|
import React, { FunctionComponent } from "react";
|
||||||
import { graphql } from "react-relay";
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
import { QueryRenderData, QueryRenderer } from "coral-framework/lib/relay";
|
import { QueryRenderData, QueryRenderer } from "coral-framework/lib/relay";
|
||||||
@@ -60,17 +60,13 @@ const ConversationModalRepliesQuery: FunctionComponent<Props> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const replies = useMemo(
|
|
||||||
() => props.comment!.replies.edges.map((edge) => edge.node),
|
|
||||||
[props.comment.replies]
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{replies.map((reply) => (
|
{props.comment.replies.edges.map((reply) => (
|
||||||
<div key={reply.id}>
|
<div key={reply.node.id}>
|
||||||
<ConversationModalCommentContainer
|
<ConversationModalCommentContainer
|
||||||
key={reply.id}
|
key={reply.node.id}
|
||||||
comment={reply}
|
comment={reply.node}
|
||||||
settings={props.settings}
|
settings={props.settings}
|
||||||
isHighlighted={false}
|
isHighlighted={false}
|
||||||
isReply={true}
|
isReply={true}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { Localized } from "@fluent/react/compat";
|
||||||
|
import React, { FunctionComponent, useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import { BaseButton, Flex, Icon } from "coral-ui/components/v2";
|
||||||
|
|
||||||
|
import styles from "./Media.css";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
still: string | null;
|
||||||
|
title: string | null;
|
||||||
|
width: number | null;
|
||||||
|
height: number | null;
|
||||||
|
video: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GiphyMedia: FunctionComponent<Props> = ({
|
||||||
|
still,
|
||||||
|
title,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
video,
|
||||||
|
}) => {
|
||||||
|
const [showAnimated, setShowAnimated] = useState(false);
|
||||||
|
const toggleImage = useCallback(() => {
|
||||||
|
setShowAnimated(!showAnimated);
|
||||||
|
}, [showAnimated]);
|
||||||
|
return (
|
||||||
|
<div className={styles.embed}>
|
||||||
|
{!showAnimated && still && (
|
||||||
|
<BaseButton onClick={toggleImage} className={styles.toggle}>
|
||||||
|
<img
|
||||||
|
src={still}
|
||||||
|
className={styles.image}
|
||||||
|
width={width || undefined}
|
||||||
|
height={height || undefined}
|
||||||
|
alt={title || ""}
|
||||||
|
/>
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
className={styles.toggleTrigger}
|
||||||
|
>
|
||||||
|
<Icon size="xl" className={styles.playIcon}>
|
||||||
|
play_circle_outline
|
||||||
|
</Icon>
|
||||||
|
<Localized id="moderate-comment-play-gif">
|
||||||
|
<p className={styles.playText}>Play GIF</p>
|
||||||
|
</Localized>
|
||||||
|
</Flex>
|
||||||
|
</BaseButton>
|
||||||
|
)}
|
||||||
|
{showAnimated && video && (
|
||||||
|
<BaseButton onClick={toggleImage}>
|
||||||
|
<video
|
||||||
|
className={styles.image}
|
||||||
|
width={width || undefined}
|
||||||
|
height={height || undefined}
|
||||||
|
title={title || ""}
|
||||||
|
autoPlay
|
||||||
|
loop
|
||||||
|
>
|
||||||
|
<source src={video} type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
</BaseButton>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GiphyMedia;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
.embed {
|
||||||
|
margin: var(--spacing-2) 0;
|
||||||
|
|
||||||
|
max-width: 100%;
|
||||||
|
& > iframe {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleTrigger {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(101, 105, 107, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.playIcon {
|
||||||
|
color: var(--palette-text-000);
|
||||||
|
}
|
||||||
|
|
||||||
|
.playText {
|
||||||
|
color: var(--palette-text-000);
|
||||||
|
font-size: var(--font-size-2);
|
||||||
|
font-weight: var(--font-weight-primary-bold);
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import React, { FunctionComponent } from "react";
|
||||||
|
import { graphql } from "react-relay";
|
||||||
|
|
||||||
|
import { withFragmentContainer } from "coral-framework/lib/relay";
|
||||||
|
import {} from "coral-ui/components/v2";
|
||||||
|
|
||||||
|
import { MediaContainer_comment } from "coral-admin/__generated__/MediaContainer_comment.graphql";
|
||||||
|
|
||||||
|
import GiphyMedia from "./GiphyMedia";
|
||||||
|
import TwitterMedia from "./TwitterMedia";
|
||||||
|
import YouTubeMedia from "./YouTubeMedia";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
comment: MediaContainer_comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MediaContainer: FunctionComponent<Props> = ({ comment }) => {
|
||||||
|
if (!comment || !comment.revision || !comment.revision.media) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{comment.revision.media.__typename === "GiphyMedia" && (
|
||||||
|
<GiphyMedia
|
||||||
|
still={comment.revision.media.still}
|
||||||
|
video={comment.revision.media.video}
|
||||||
|
title={comment.revision.media.title}
|
||||||
|
width={comment.revision.media.width}
|
||||||
|
height={comment.revision.media.height}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{comment.revision.media.__typename === "TwitterMedia" && (
|
||||||
|
<TwitterMedia
|
||||||
|
url={comment.revision.media.url}
|
||||||
|
width={comment.revision.media.width}
|
||||||
|
siteID={comment.site.id}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{comment.revision.media.__typename === "YouTubeMedia" && (
|
||||||
|
<YouTubeMedia
|
||||||
|
url={comment.revision.media.url}
|
||||||
|
width={comment.revision.media.width}
|
||||||
|
height={comment.revision.media.height}
|
||||||
|
siteID={comment.site.id}
|
||||||
|
still={comment.revision.media.still}
|
||||||
|
title={comment.revision.media.title}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const enhanced = withFragmentContainer<Props>({
|
||||||
|
comment: graphql`
|
||||||
|
fragment MediaContainer_comment on Comment {
|
||||||
|
site {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
revision {
|
||||||
|
media {
|
||||||
|
__typename
|
||||||
|
... on GiphyMedia {
|
||||||
|
url
|
||||||
|
title
|
||||||
|
width
|
||||||
|
height
|
||||||
|
still
|
||||||
|
video
|
||||||
|
}
|
||||||
|
... on TwitterMedia {
|
||||||
|
url
|
||||||
|
width
|
||||||
|
}
|
||||||
|
... on YouTubeMedia {
|
||||||
|
url
|
||||||
|
still
|
||||||
|
title
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})(MediaContainer);
|
||||||
|
|
||||||
|
export default enhanced;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
import styles from "./Media.css";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
url: string;
|
||||||
|
width: number | null;
|
||||||
|
siteID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TwitterMedia: FunctionComponent<Props> = ({ url, width, siteID }) => {
|
||||||
|
const cleanUrl = encodeURIComponent(url);
|
||||||
|
return (
|
||||||
|
<div className={styles.embed}>
|
||||||
|
<iframe
|
||||||
|
frameBorder="0"
|
||||||
|
width={width || 450}
|
||||||
|
allowFullScreen
|
||||||
|
title="oEmbed"
|
||||||
|
src={`/api/oembed?type=twitter&url=${cleanUrl}&siteID=${siteID}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TwitterMedia;
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { Localized } from "@fluent/react/compat";
|
||||||
|
import React, { FunctionComponent, useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import { BaseButton, Flex, Icon } from "coral-ui/components/v2";
|
||||||
|
|
||||||
|
import styles from "./Media.css";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
url: string;
|
||||||
|
still: string;
|
||||||
|
width: number | null;
|
||||||
|
height: number | null;
|
||||||
|
title: string | null;
|
||||||
|
siteID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const YouTubeMedia: FunctionComponent<Props> = ({
|
||||||
|
url,
|
||||||
|
still,
|
||||||
|
title,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
siteID,
|
||||||
|
}) => {
|
||||||
|
const [showAnimated, setShowAnimated] = useState(false);
|
||||||
|
const toggleImage = useCallback(() => {
|
||||||
|
setShowAnimated(!showAnimated);
|
||||||
|
}, [showAnimated]);
|
||||||
|
const cleanUrl = encodeURIComponent(url);
|
||||||
|
return (
|
||||||
|
<div className={styles.embed}>
|
||||||
|
{!showAnimated && still && (
|
||||||
|
<BaseButton onClick={toggleImage} className={styles.toggle}>
|
||||||
|
<img src={still} className={styles.image} alt={title || ""} />
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="center"
|
||||||
|
className={styles.toggleTrigger}
|
||||||
|
>
|
||||||
|
<Icon size="xl" className={styles.playIcon}>
|
||||||
|
play_circle_outline
|
||||||
|
</Icon>
|
||||||
|
<Localized id="moderate-comment-load-video">
|
||||||
|
<p className={styles.playText}>Load Video</p>
|
||||||
|
</Localized>
|
||||||
|
</Flex>
|
||||||
|
</BaseButton>
|
||||||
|
)}
|
||||||
|
{showAnimated && (
|
||||||
|
<iframe
|
||||||
|
frameBorder="0"
|
||||||
|
width={width || 480}
|
||||||
|
height={height || 270}
|
||||||
|
allowFullScreen
|
||||||
|
title="oEmbed"
|
||||||
|
src={`/api/oembed?type=youtube&url=${cleanUrl}&siteID=${siteID}`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default YouTubeMedia;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export { default as MediaContainer } from "./MediaContainer";
|
||||||
|
export { default as GiphyMedia } from "./GiphyMedia";
|
||||||
|
export { default as TwitterMedia } from "./TwitterMedia";
|
||||||
|
export { default as YouTubeMedia } from "./YouTubeMedia";
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
$modal-body-text: $colors-mono-500;
|
||||||
|
|
||||||
|
.root {
|
||||||
|
font-size: var(--font-size-3);
|
||||||
|
font-family: var(--font-family-primary);
|
||||||
|
font-weight: var(--font-weight-primary-regular);
|
||||||
|
line-height: 1.3;
|
||||||
|
color: $modal-body-text;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import React, { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
import styles from "./ModalBodyText.css";
|
||||||
|
|
||||||
|
const ModalBodyText: FunctionComponent = ({ children }) => (
|
||||||
|
<p className={styles.root}>{children}</p>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ModalBodyText;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user