[CORL-129] Render Community Guidelines (#2191)

* chore: Rename InnerProps to Props

* feat: Render community guidelines

* chore: refactor schema communityGuidelines* settings into it's own type

* test: update snapshots
This commit is contained in:
Kiwi
2019-02-13 18:06:42 +01:00
committed by GitHub
parent f4037ce6fb
commit 51880bcfc9
64 changed files with 1365 additions and 184 deletions
+2 -1
View File
@@ -14,5 +14,6 @@
"tslint.exclude": "**/node_modules/**",
"tslint.autoFixOnSave": true,
"tslint.jsEnable": true,
"typescript.tsdk": "node_modules/typescript/lib"
"typescript.tsdk": "node_modules/typescript/lib",
"postcss.validate": false
}
+318
View File
@@ -2387,6 +2387,12 @@
"integrity": "sha512-YiVw0M9q9CeynfRKhZYaX2/aCXlCIBpM4eARlPXdv+XVoGVb5iPFaZIlKiMUJ8eWKOhlqi8U6GvOAn8yhR4//Q==",
"dev": true
},
"@types/marked": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.6.0.tgz",
"integrity": "sha512-TxwhgR9VsIfRDJ3WwFokG8Xu+ea0nYGDRHdI783WJ983uffatz0ytIeUEIBOwPvRy241KRSNVyywQltuTqDh0w==",
"dev": true
},
"@types/mime": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz",
@@ -6404,6 +6410,12 @@
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0="
},
"camelcase-css": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
"dev": true
},
"camelcase-keys": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
@@ -20397,6 +20409,75 @@
}
}
},
"postcss-js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.0.tgz",
"integrity": "sha512-9kAApW9G5kN8FkQ0ZdvSmbgbHIRrKmXtde2ZWYbwrW51gfEWfGsLlUu57mTpioPrmQlQFOgEvaeGYp+poqlX0A==",
"dev": true,
"requires": {
"camelcase-css": "^2.0.0",
"postcss": "^7.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"postcss": {
"version": "7.0.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz",
"integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"postcss-lab-function": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz",
@@ -20905,6 +20986,107 @@
}
}
},
"postcss-mixins": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/postcss-mixins/-/postcss-mixins-6.2.1.tgz",
"integrity": "sha512-XfItKgFHAPKa4mayLVwoASYzzRLyW64mEtsVZz7LT7ElrprVZx9D5ivqOi5oQCkUxyiLs9sjg4aiRxr+gK9xkQ==",
"dev": true,
"requires": {
"globby": "^8.0.1",
"postcss": "^7.0.6",
"postcss-js": "^2.0.0",
"postcss-simple-vars": "^5.0.1",
"sugarss": "^2.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"globby": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz",
"integrity": "sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==",
"dev": true,
"requires": {
"array-union": "^1.0.1",
"dir-glob": "2.0.0",
"fast-glob": "^2.0.2",
"glob": "^7.1.2",
"ignore": "^3.3.5",
"pify": "^3.0.0",
"slash": "^1.0.0"
}
},
"postcss": {
"version": "7.0.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz",
"integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"postcss-modules-extract-imports": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz",
@@ -21992,6 +22174,74 @@
}
}
},
"postcss-simple-vars": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-5.0.1.tgz",
"integrity": "sha512-nlulz+X0i8CH2e9IbxFfMD9rG4fGx+O4hH7Pwj0bZalRx91gvli85DAymqBQ35X7VBUackGD2iNj7DgsCbwQug==",
"dev": true,
"requires": {
"postcss": "^7.0.2"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"postcss": {
"version": "7.0.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz",
"integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"postcss-svgo": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.1.tgz",
@@ -25377,6 +25627,74 @@
"ws": "^5.2.0"
}
},
"sugarss": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz",
"integrity": "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==",
"dev": true,
"requires": {
"postcss": "^7.0.2"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"postcss": {
"version": "7.0.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.14.tgz",
"integrity": "sha512-NsbD6XUUMZvBxtQAJuWDJeeC4QFsmWsfozWxCJPWf3M55K9iu2iMDaKqyoOdTJ1R4usBXuxlVFAIo8rZPQD4Bg==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"superagent": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz",
+3
View File
@@ -155,6 +155,7 @@
"@types/linkifyjs": "^2.1.0",
"@types/lodash": "^4.14.118",
"@types/luxon": "^0.5.3",
"@types/marked": "^0.6.0",
"@types/mini-css-extract-plugin": "^0.2.0",
"@types/mongodb": "^3.1.14",
"@types/ms": "^0.7.30",
@@ -240,6 +241,7 @@
"lint-staged": "^7.3.0",
"loader-utils": "^1.1.0",
"lodash-es": "^4.17.11",
"marked": "^0.6.0",
"material-design-icons": "^3.0.1",
"mini-css-extract-plugin": "^0.5.0",
"npm-run-all": "^4.1.3",
@@ -249,6 +251,7 @@
"postcss-font-magician": "^2.2.1",
"postcss-import": "^11.1.0",
"postcss-loader": "^3.0.0",
"postcss-mixins": "^6.2.1",
"postcss-nested": "^4.1.1",
"postcss-prepend-imports": "^1.0.1",
"postcss-preset-env": "^6.5.0",
+1
View File
@@ -21,6 +21,7 @@ export default {
appLocales: resolveSrc("locales"),
appThemeVariables: resolveSrc("core/client/ui/theme/variables.ts"),
appThemeVariablesCSS: resolveSrc("core/client/ui/theme/variables.css"),
appThemeMixinsCSS: resolveSrc("core/client/ui/theme/mixins.css"),
appStreamHTML: resolveSrc("core/client/stream/index.html"),
appStreamLocalesTemplate: resolveSrc("core/client/stream/locales.ts"),
+4 -1
View File
@@ -13,6 +13,7 @@ const postcssVariables = require("postcss-css-variables");
const postcssPresetEnv = require("postcss-preset-env");
const postcssNested = require("postcss-nested");
const postcssImport = require("postcss-import");
const postcssMixins = require("postcss-mixins");
const postcssPrependImports = require("postcss-prepend-imports");
const postcssAdvancedVariables = require("postcss-advanced-variables");
@@ -48,10 +49,12 @@ module.exports = {
// This allows us to define dynamic css variables.
postcssPrependImports({
path: "",
files: [paths.appThemeVariablesCSS],
files: [paths.appThemeVariablesCSS, paths.appThemeMixinsCSS],
}),
// Needed by above plugin.
postcssImport(),
// Support mixins.
postcssMixins(),
// Support nesting.
postcssNested(),
// Sass style variables to be used in media queries.
@@ -33,7 +33,7 @@ const GuidelinesConfig: StatelessComponent<Props> = ({ disabled }) => (
Show Community Guidelines Summary
</InputLabel>
</Localized>
<OnOffField name="communityGuidelinesEnable" disabled={disabled} />
<OnOffField name="communityGuidelines.enabled" disabled={disabled} />
</FormField>
<FormField>
@@ -56,7 +56,7 @@ const GuidelinesConfig: StatelessComponent<Props> = ({ disabled }) => (
</Localized>
</FormField>
<Field name="communityGuidelines">
<Field name="communityGuidelines.content">
{({ input, meta }) => (
<>
<Suspense fallback={<Spinner />}>
@@ -27,8 +27,10 @@ class GuidelinesConfigContainer extends React.Component<Props> {
const enhanced = withFragmentContainer<Props>({
settings: graphql`
fragment GuidelinesConfigContainer_settings on Settings {
communityGuidelinesEnable
communityGuidelines
communityGuidelines {
enabled
content
}
}
`,
})(GuidelinesConfigContainer);
@@ -131,8 +131,8 @@ exports[`renders configure general 1`] = `
checked={false}
className="RadioButton-input"
disabled={false}
id="communityGuidelinesEnable-true"
name="communityGuidelinesEnable"
id="communityGuidelines.enabled-true"
name="communityGuidelines.enabled"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
@@ -141,7 +141,7 @@ exports[`renders configure general 1`] = `
/>
<label
className="RadioButton-label"
htmlFor="communityGuidelinesEnable-true"
htmlFor="communityGuidelines.enabled-true"
>
On
</label>
@@ -153,8 +153,8 @@ exports[`renders configure general 1`] = `
checked={true}
className="RadioButton-input"
disabled={false}
id="communityGuidelinesEnable-fase"
name="communityGuidelinesEnable"
id="communityGuidelines.enabled-fase"
name="communityGuidelines.enabled"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
@@ -163,7 +163,7 @@ exports[`renders configure general 1`] = `
/>
<label
className="RadioButton-label"
htmlFor="communityGuidelinesEnable-fase"
htmlFor="communityGuidelines.enabled-fase"
>
Off
</label>
@@ -201,7 +201,7 @@ Markdown can be found
>
<textarea
id="configure-general-guidelines-content"
name="communityGuidelines"
name="communityGuidelines.content"
onChange={[Function]}
value=""
/>
@@ -72,10 +72,10 @@ it("change community guidlines", async () => {
let settingsRecord = cloneDeep(settings);
const updateSettingsStub = createSinonStub(s =>
s.onFirstCall().callsFake((_: any, data: any) => {
expect(data.input.settings.communityGuidelines).toEqual(
expect(data.input.settings.communityGuidelines.content).toEqual(
"This is the community guidlines summary"
);
expect(data.input.settings.communityGuidelinesEnable).toEqual(true);
expect(data.input.settings.communityGuidelines.enabled).toEqual(true);
settingsRecord = merge(settingsRecord, data.input.settings);
return {
settings: settingsRecord,
+4 -2
View File
@@ -17,8 +17,10 @@ export const settings = {
customCssUrl: null,
domains: ["localhost:8080"],
editCommentWindowLength: 30000,
communityGuidelinesEnable: false,
communityGuidelines: "",
communityGuidelines: {
enabled: false,
content: "",
},
organizationContactEmail: "coral@test.com",
organizationName: "Coral",
integrations: {
@@ -5,7 +5,7 @@ import CopyToClipboard from "react-copy-to-clipboard";
import { Button } from "talk-ui/components";
import { PropTypesOf } from "talk-ui/types";
interface InnerProps extends PropTypesOf<typeof Button> {
interface Props extends PropTypesOf<typeof Button> {
text: string;
}
@@ -13,7 +13,7 @@ interface State {
copied: boolean;
}
class CopyButton extends React.Component<InnerProps> {
class CopyButton extends React.Component<Props> {
private timeout: any = null;
public state: State = {
@@ -0,0 +1,41 @@
.root {
@mixin bodyCopy;
b,
strong {
font-weight: var(--font-weight-medium);
}
h1 {
@mixin heading1;
}
h2 {
@mixin heading2;
}
h3 {
@mixin heading3;
}
h4 {
@mixin heading4;
}
h5 {
@mixin heading5;
}
*:first-child {
margin-top: 0;
}
*:last-child {
margin-bottom: 0;
}
blockquote {
background-color: rgba(255, 255, 255, 0.66);
padding: var(--spacing-unit);
margin: calc(2 * var(--spacing-unit)) 0 calc(2 * var(--spacing-unit))
var(--spacing-unit);
border-radius: var(--round-corners);
&::after {
content: none;
}
&::before {
content: none;
}
}
}
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import Markdown from "./Markdown";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<Markdown>**bold**</Markdown>);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,33 @@
import cn from "classnames";
import marked from "marked";
import React, { AllHTMLAttributes, PureComponent } from "react";
import styles from "./Markdown.css";
const renderer = new marked.Renderer();
// Set link target to `_parent` to work properly in an embed.
renderer.link = (href, title, text) =>
`<a target="_parent" href="${href}" ${
title ? `title="${title}"` : ""
}>${text}</a>`;
marked.setOptions({ renderer, gfm: true, breaks: true });
interface Props extends AllHTMLAttributes<HTMLDivElement> {
children: string;
}
export default class Markdown extends PureComponent<Props> {
public render() {
const { children, className, ...rest } = this.props;
const html = marked(children);
return (
<div
className={cn(styles.root, className)}
{...rest}
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}
}
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<div
className="Markdown-root"
dangerouslySetInnerHTML={
Object {
"__html": "<p><strong>bold</strong></p>
",
}
}
/>
`;
@@ -3,4 +3,5 @@ export { default as PasswordField } from "./PasswordField";
export { default as FacebookButton } from "./FacebookButton";
export { default as GoogleButton } from "./GoogleButton";
export { default as OIDCButton } from "./OIDCButton";
export { default as Markdown } from "./Markdown";
export { default as DurationField, DURATION_UNIT } from "./DurationField";
@@ -2,16 +2,43 @@ $minHeight: 200px;
$fullscreenZIndex: 10;
.wrapper {
/* Fix blockquote styling of MDL: https://github.com/google/material-design-lite/issues/2037 */
@mixin bodyCopy;
b,
strong {
font-weight: var(--font-weight-medium);
}
h1 {
@mixin heading1;
}
h2 {
@mixin heading2;
}
h3 {
@mixin heading3;
}
h4 {
@mixin heading4;
}
h5 {
@mixin heading5;
}
*:first-child {
margin-top: 0;
}
*:last-child {
margin-bottom: 0;
}
blockquote {
> p:first-child {
padding-top: 16px;
}
> p:last-child {
margin-bottom: 0;
}
background-color: rgba(0, 0, 0, 0.075);
padding: var(--spacing-unit);
margin: calc(2 * var(--spacing-unit)) 0 calc(2 * var(--spacing-unit))
var(--spacing-unit);
border-radius: var(--round-corners);
&::after {
margin-left: -0.5em;
content: none;
}
&::before {
content: none;
}
}
}
@@ -5,11 +5,11 @@ import { AppContainerLocal as Local } from "talk-stream/__generated__/AppContain
import App from "../components/App";
interface InnerProps {
interface Props {
local: Local;
}
class AppContainer extends React.Component<InnerProps> {
class AppContainer extends React.Component<Props> {
public render() {
const {
local: { activeTab },
@@ -17,13 +17,13 @@ import {
import TabBar from "../components/TabBar";
interface InnerProps {
interface Props {
story: StoryData | null;
local: Local;
setActiveTab: SetActiveTabMutation;
}
export class TabBarContainer extends Component<InnerProps> {
export class TabBarContainer extends Component<Props> {
private handleSetActiveTab = (tab: SetActiveTabInput["tab"]) => {
this.props.setActiveTab({ tab });
};
@@ -55,7 +55,7 @@ const enhanced = withSetActiveTabMutation(
}
`
)(
withFragmentContainer<InnerProps>({
withFragmentContainer<Props>({
story: graphql`
fragment TabBarContainer_story on Story {
commentCounts {
@@ -22,7 +22,7 @@ import { Popup } from "talk-ui/components";
import { urls } from "talk-framework/helpers";
import UserBoxAuthenticated from "../components/UserBoxAuthenticated";
interface InnerProps {
interface Props {
local: Local;
me: MeData | null;
settings: SettingsData;
@@ -31,7 +31,7 @@ interface InnerProps {
signOut: SignOutMutation;
}
export class UserBoxContainer extends Component<InnerProps> {
export class UserBoxContainer extends Component<Props> {
private handleFocus = () => this.props.setAuthPopupState({ focus: true });
private handleBlur = () => this.props.setAuthPopupState({ focus: false });
private handleClose = () => this.props.setAuthPopupState({ open: false });
@@ -124,7 +124,7 @@ const enhanced = withSignOutMutation(
}
`
)(
withFragmentContainer<InnerProps>({
withFragmentContainer<Props>({
me: graphql`
fragment UserBoxContainer_me on User {
username
@@ -10,11 +10,11 @@ import { TabBarQueryLocal as Local } from "talk-stream/__generated__/TabBarQuery
import TabBarContainer from "../containers/TabBarContainer";
interface InnerProps {
interface Props {
local: Local;
}
class TabBarQuery extends Component<InnerProps> {
class TabBarQuery extends Component<Props> {
public render() {
const { storyID, storyURL } = this.props.local;
return (
@@ -0,0 +1,10 @@
import React from "react";
import { createRenderer } from "react-test-renderer/shallow";
import CommunityGuidelines from "./CommunityGuidelines";
it("renders correctly", () => {
const renderer = createRenderer();
renderer.render(<CommunityGuidelines>**bold**</CommunityGuidelines>);
expect(renderer.getRenderOutput()).toMatchSnapshot();
});
@@ -0,0 +1,18 @@
import React, { StatelessComponent } from "react";
import { Markdown } from "talk-framework/components";
import { CallOut } from "talk-ui/components";
interface Props {
children: string;
}
const CommunityGuidelines: StatelessComponent<Props> = props => {
return (
<CallOut color="primary">
<Markdown>{props.children}</Markdown>
</CallOut>
);
};
export default CommunityGuidelines;
@@ -5,11 +5,11 @@ import { Flex, TextField } from "talk-ui/components";
import styles from "./PermalinkPopover.css";
interface InnerProps {
interface Props {
permalinkURL: string;
}
class PermalinkPopover extends React.Component<InnerProps> {
class PermalinkPopover extends React.Component<Props> {
public render() {
const { permalinkURL } = this.props;
return (
@@ -7,6 +7,7 @@ import UserBoxContainer from "talk-stream/containers/UserBoxContainer";
import { Button, HorizontalGutter, Spinner } from "talk-ui/components";
import CommentContainer from "../containers/CommentContainer";
import CommunityGuidelinesContainer from "../containers/CommunityGuidelinesContainer";
import PostCommentFormContainer from "../containers/PostCommentFormContainer";
import ReplyListContainer from "../containers/ReplyListContainer";
import PostCommentFormFake from "./PostCommentFormFake";
@@ -22,7 +23,8 @@ export interface StreamProps {
PropTypesOf<typeof ReplyListContainer>["story"];
settings: PropTypesOf<typeof CommentContainer>["settings"] &
PropTypesOf<typeof ReplyListContainer>["settings"] &
PropTypesOf<typeof UserBoxContainer>["settings"];
PropTypesOf<typeof UserBoxContainer>["settings"] &
PropTypesOf<typeof CommunityGuidelinesContainer>["settings"];
comments: ReadonlyArray<
{ id: string } & PropTypesOf<typeof CommentContainer>["comment"] &
PropTypesOf<typeof ReplyListContainer>["comment"]
@@ -43,8 +45,9 @@ export interface StreamProps {
const Stream: StatelessComponent<StreamProps> = props => {
return (
<HorizontalGutter className={styles.root} size="double">
<HorizontalGutter size="half">
<HorizontalGutter>
<UserBoxContainer me={props.me} settings={props.settings} />
<CommunityGuidelinesContainer settings={props.settings} />
{props.me ? (
<PostCommentFormContainer storyID={props.story.id} />
) : (
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<withPropsOnChange(CallOut)
color="primary"
>
<Markdown>
**bold**
</Markdown>
</withPropsOnChange(CallOut)>
`;
@@ -5,9 +5,7 @@ exports[`renders correctly 1`] = `
className="Stream-root"
size="double"
>
<ForwardRef(forwardRef)
size="half"
>
<ForwardRef(forwardRef)>
<withContext(createMutationContainer(withContext(createMutationContainer(withContext(createMutationContainer(withContext(withLocalStateContainer(Relay(UserBoxContainer)))))))))
me={null}
settings={
@@ -19,6 +17,16 @@ exports[`renders correctly 1`] = `
}
}
/>
<Relay(CommunityGuidelinesContainerProps)
settings={
Object {
"reaction": Object {
"icon": "thumb_up_alt",
"label": "Respect",
},
}
}
/>
<PostCommentFormFake />
</ForwardRef(forwardRef)>
<SortMenu
@@ -136,9 +144,7 @@ exports[`when there is more disables load more button 1`] = `
className="Stream-root"
size="double"
>
<ForwardRef(forwardRef)
size="half"
>
<ForwardRef(forwardRef)>
<withContext(createMutationContainer(withContext(createMutationContainer(withContext(createMutationContainer(withContext(withLocalStateContainer(Relay(UserBoxContainer)))))))))
me={null}
settings={
@@ -150,6 +156,16 @@ exports[`when there is more disables load more button 1`] = `
}
}
/>
<Relay(CommunityGuidelinesContainerProps)
settings={
Object {
"reaction": Object {
"icon": "thumb_up_alt",
"label": "Respect",
},
}
}
/>
<PostCommentFormFake />
</ForwardRef(forwardRef)>
<SortMenu
@@ -281,9 +297,7 @@ exports[`when there is more renders a load more button 1`] = `
className="Stream-root"
size="double"
>
<ForwardRef(forwardRef)
size="half"
>
<ForwardRef(forwardRef)>
<withContext(createMutationContainer(withContext(createMutationContainer(withContext(createMutationContainer(withContext(withLocalStateContainer(Relay(UserBoxContainer)))))))))
me={null}
settings={
@@ -295,6 +309,16 @@ exports[`when there is more renders a load more button 1`] = `
}
}
/>
<Relay(CommunityGuidelinesContainerProps)
settings={
Object {
"reaction": Object {
"icon": "thumb_up_alt",
"label": "Respect",
},
}
}
/>
<PostCommentFormFake />
</ForwardRef(forwardRef)>
<SortMenu
@@ -426,9 +450,7 @@ exports[`when use is logged in renders correctly 1`] = `
className="Stream-root"
size="double"
>
<ForwardRef(forwardRef)
size="half"
>
<ForwardRef(forwardRef)>
<withContext(createMutationContainer(withContext(createMutationContainer(withContext(createMutationContainer(withContext(withLocalStateContainer(Relay(UserBoxContainer)))))))))
me={Object {}}
settings={
@@ -440,6 +462,16 @@ exports[`when use is logged in renders correctly 1`] = `
}
}
/>
<Relay(CommunityGuidelinesContainerProps)
settings={
Object {
"reaction": Object {
"icon": "thumb_up_alt",
"label": "Respect",
},
}
}
/>
<withContext(withContext(createMutationContainer(PostCommentFormContainer)))
storyID="story-id"
/>
@@ -30,7 +30,7 @@ import PermalinkButtonContainer from "./PermalinkButtonContainer";
import ReplyCommentFormContainer from "./ReplyCommentFormContainer";
import ReportButtonContainer from "./ReportButtonContainer";
interface InnerProps {
interface Props {
me: MeData | null;
comment: CommentData;
story: StoryData;
@@ -56,7 +56,7 @@ interface State {
editable: boolean;
}
export class CommentContainer extends Component<InnerProps, State> {
export class CommentContainer extends Component<Props, State> {
private uneditableTimer: any;
public state = {
@@ -65,7 +65,7 @@ export class CommentContainer extends Component<InnerProps, State> {
editable: this.isEditable(),
};
constructor(props: InnerProps) {
constructor(props: Props) {
super(props);
if (this.isEditable()) {
this.uneditableTimer = this.updateWhenNotEditable();
@@ -245,7 +245,7 @@ export class CommentContainer extends Component<InnerProps, State> {
const enhanced = withSetCommentIDMutation(
withShowAuthPopupMutation(
withFragmentContainer<InnerProps>({
withFragmentContainer<Props>({
me: graphql`
fragment CommentContainer_me on User {
id
@@ -6,11 +6,11 @@ import { CommentsPaneContainerLocal as Local } from "talk-stream/__generated__/C
import CommentsPane from "../components/CommentsPane";
interface InnerProps {
interface Props {
local: Local;
}
const CommentsPaneContainer: StatelessComponent<InnerProps> = ({
const CommentsPaneContainer: StatelessComponent<Props> = ({
local: { commentID },
}) => {
return <CommentsPane showPermalinkView={!!commentID} />;
@@ -0,0 +1,39 @@
import React, { StatelessComponent } from "react";
import { graphql } from "react-relay";
import { withFragmentContainer } from "talk-framework/lib/relay";
import { CommunityGuidelinesContainer_settings as SettingsData } from "talk-stream/__generated__/CommunityGuidelinesContainer_settings.graphql";
import CommunityGuidelines from "../components/CommunityGuidelines";
interface Props {
settings: SettingsData;
}
export const CommunityGuidelinesContainerProps: StatelessComponent<Props> = ({
settings,
}) => {
if (
!settings.communityGuidelines.enabled ||
!settings.communityGuidelines.content
) {
return null;
}
return (
<CommunityGuidelines>
{settings.communityGuidelines.content}
</CommunityGuidelines>
);
};
const enhanced = withFragmentContainer<Props>({
settings: graphql`
fragment CommunityGuidelinesContainer_settings on Settings {
communityGuidelines {
enabled
content
}
}
`,
})(CommunityGuidelinesContainerProps);
export default enhanced;
@@ -18,7 +18,7 @@ import EditCommentForm, {
EditCommentFormProps,
} from "../components/EditCommentForm";
interface InnerProps {
interface Props {
editComment: EditCommentMutation;
comment: CommentData;
onClose?: () => void;
@@ -31,7 +31,7 @@ interface State {
expired: boolean;
}
export class EditCommentFormContainer extends Component<InnerProps, State> {
export class EditCommentFormContainer extends Component<Props, State> {
private expiredTimer: any;
public state: State = {
@@ -39,7 +39,7 @@ export class EditCommentFormContainer extends Component<InnerProps, State> {
expired: !isBeforeDate(this.props.comment.editing.editableUntil),
};
constructor(props: InnerProps) {
constructor(props: Props) {
super(props);
this.expiredTimer = this.updateWhenExpired();
}
@@ -113,7 +113,7 @@ const enhanced = withContext(({ sessionStorage, browserInfo }) => ({
autofocus: !browserInfo.ios,
}))(
withEditCommentMutation(
withFragmentContainer<InnerProps>({
withFragmentContainer<Props>({
comment: graphql`
fragment EditCommentFormContainer_comment on Comment {
id
@@ -10,7 +10,7 @@ import { LocalReplyListContainer_story as StoryData } from "talk-stream/__genera
import ReplyList from "../components/ReplyList";
interface InnerProps {
interface Props {
indentLevel: number;
me: MeData;
story: StoryData;
@@ -24,7 +24,7 @@ interface InnerProps {
* ultimate threading level to only display the newly created comments
* from the current user.
*/
export class LocalReplyListContainer extends Component<InnerProps> {
export class LocalReplyListContainer extends Component<Props> {
public render() {
if (!this.props.comment.localReplies) {
return null;
@@ -43,7 +43,7 @@ export class LocalReplyListContainer extends Component<InnerProps> {
}
}
const enhanced = withFragmentContainer<InnerProps>({
const enhanced = withFragmentContainer<Props>({
me: graphql`
fragment LocalReplyListContainer_me on User {
...CommentContainer_me
@@ -6,12 +6,12 @@ import { PermalinkButtonContainer_story as StoryData } from "talk-stream/__gener
import PermalinkButton from "../components/PermalinkButton";
interface InnerProps {
interface Props {
story: StoryData;
commentID: string;
}
export const PermalinkButtonContainerProps: StatelessComponent<InnerProps> = ({
export const PermalinkButtonContainerProps: StatelessComponent<Props> = ({
story,
commentID,
}) => {
@@ -23,7 +23,7 @@ export const PermalinkButtonContainerProps: StatelessComponent<InnerProps> = ({
);
};
const enhanced = withFragmentContainer<InnerProps>({
const enhanced = withFragmentContainer<Props>({
story: graphql`
fragment PermalinkButtonContainer_story on Story {
url
@@ -13,7 +13,7 @@ import PostCommentForm, {
PostCommentFormProps,
} from "../components/PostCommentForm";
interface InnerProps {
interface Props {
createComment: CreateCommentMutation;
storyID: string;
sessionStorage: PromisifiedStorage;
@@ -26,10 +26,10 @@ interface State {
const contextKey = "postCommentFormBody";
export class PostCommentFormContainer extends Component<InnerProps, State> {
export class PostCommentFormContainer extends Component<Props, State> {
public state: State = { initialized: false };
constructor(props: InnerProps) {
constructor(props: Props) {
super(props);
this.init();
}
@@ -18,7 +18,7 @@ import ReplyCommentForm, {
ReplyCommentFormProps,
} from "../components/ReplyCommentForm";
interface InnerProps {
interface Props {
createCommentReply: CreateCommentReplyMutation;
sessionStorage: PromisifiedStorage;
comment: CommentData;
@@ -33,11 +33,11 @@ interface State {
initialized: boolean;
}
export class ReplyCommentFormContainer extends Component<InnerProps, State> {
export class ReplyCommentFormContainer extends Component<Props, State> {
public state: State = { initialized: false };
private contextKey = `replyCommentFormBody-${this.props.comment.id}`;
constructor(props: InnerProps) {
constructor(props: Props) {
super(props);
this.init();
}
@@ -129,7 +129,7 @@ const enhanced = withContext(({ sessionStorage, browserInfo }) => ({
autofocus: !browserInfo.ios,
}))(
withCreateCommentReplyMutation(
withFragmentContainer<InnerProps>({
withFragmentContainer<Props>({
story: graphql`
fragment ReplyCommentFormContainer_story on Story {
id
@@ -22,7 +22,7 @@ import LocalReplyListContainer from "./LocalReplyListContainer";
type UnpackArray<T> = T extends ReadonlyArray<infer U> ? U : any;
type ReplyNode5 = UnpackArray<Comment5Data["replies"]["edges"]>["node"];
export interface BaseProps {
interface BaseProps {
me: MeData | null;
story: StoryData;
comment: CommentData;
@@ -32,7 +32,7 @@ export interface BaseProps {
localReply: boolean | undefined;
}
export type InnerProps = BaseProps & {
type Props = BaseProps & {
ReplyListComponent:
| React.ComponentType<{ [P in FragmentKeys<BaseProps>]: any }>
| undefined;
@@ -44,7 +44,7 @@ interface FragmentVariables {
cursor?: string;
orderBy: COMMENT_SORT;
}
export class ReplyListContainer extends React.Component<InnerProps> {
export class ReplyListContainer extends React.Component<Props> {
public state = {
disableShowAll: false,
};
@@ -113,12 +113,12 @@ function createReplyListContainer(
settings: GraphQLTaggedNode;
},
query: GraphQLTaggedNode,
ReplyListComponent?: InnerProps["ReplyListComponent"],
ReplyListComponent?: Props["ReplyListComponent"],
localReply?: boolean
) {
return withProps({ indentLevel, ReplyListComponent, localReply })(
withPaginationContainer<
InnerProps,
Props,
ReplyListContainer1PaginationQueryVariables,
FragmentVariables
>(fragments, {
@@ -13,7 +13,7 @@ import {
import Stream from "../components/Stream";
interface InnerProps {
interface Props {
story: StoryData;
settings: SettingsData;
me: MeData | null;
@@ -30,7 +30,7 @@ graphql`
}
`;
export class StreamContainer extends React.Component<InnerProps> {
export class StreamContainer extends React.Component<Props> {
public state = {
disableLoadMore: false,
refetching: false,
@@ -100,7 +100,7 @@ interface FragmentVariables {
}
const enhanced = withPaginationContainer<
InnerProps,
Props,
StreamContainerPaginationQueryVariables,
FragmentVariables
>(
@@ -138,6 +138,7 @@ const enhanced = withPaginationContainer<
...ReplyListContainer1_settings
...CommentContainer_settings
...UserBoxContainer_settings
...CommunityGuidelinesContainer_settings
}
`,
},
@@ -14,7 +14,7 @@ import { PermalinkViewQueryLocal as Local } from "talk-stream/__generated__/Perm
import { Delay, Spinner } from "talk-ui/components";
import PermalinkViewContainer from "../containers/PermalinkViewContainer";
interface InnerProps {
interface Props {
local: Local;
}
@@ -49,7 +49,7 @@ export const render = ({
);
};
const PermalinkViewQuery: StatelessComponent<InnerProps> = ({
const PermalinkViewQuery: StatelessComponent<Props> = ({
local: { commentID, storyID, storyURL },
}) => (
<QueryRenderer<QueryTypes>
@@ -41,7 +41,7 @@ const RadioField: StatelessComponent<
</Field>
);
interface InnerProps {
interface Props {
id: string;
onCancel: () => void;
onResize: () => void;
@@ -57,7 +57,7 @@ export interface FormProps {
additionalDetails?: string;
}
class ReportCommentForm extends React.Component<InnerProps> {
class ReportCommentForm extends React.Component<Props> {
public render() {
const { onCancel, onSubmit, onResize, id } = this.props;
return (
@@ -6,13 +6,13 @@ import { PropTypesOf } from "talk-ui/types";
import ReportCommentFormContainer from "../containers/ReportCommentFormContainer";
import styles from "./ReportPopover.css";
interface InnerProps {
interface Props {
comment: PropTypesOf<typeof ReportCommentFormContainer>["comment"];
onClose: () => void;
onResize: () => void;
}
class ReportPopover extends React.Component<InnerProps> {
class ReportPopover extends React.Component<Props> {
public render() {
const { onClose, onResize, comment } = this.props;
return (
@@ -5,11 +5,11 @@ import { Button, HorizontalGutter, Typography } from "talk-ui/components";
import styles from "./ThankYou.css";
interface InnerProps {
interface Props {
onDismiss: () => void;
}
class ReportForm extends React.Component<InnerProps> {
class ReportForm extends React.Component<Props> {
public render() {
const { onDismiss } = this.props;
const Content: StatelessComponent = ({ children }) => (
@@ -13,7 +13,7 @@ import { Delay, Spinner } from "talk-ui/components";
import ProfileContainer from "../containers/ProfileContainer";
interface InnerProps {
interface Props {
local: Local;
}
@@ -56,7 +56,7 @@ export const render = ({
);
};
const ProfileQuery: StatelessComponent<InnerProps> = ({
const ProfileQuery: StatelessComponent<Props> = ({
local: { storyID, storyURL },
}) => (
<QueryRenderer<QueryTypes>
@@ -0,0 +1,523 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders comment stream with community guidelines 1`] = `
<section
aria-labelledby="tab-COMMENTS"
className="App-tabContent"
data-testid="current-tab-pane"
id="tabPane-COMMENTS"
role="tabpanel"
>
<div
className="HorizontalGutter-root Stream-root HorizontalGutter-double"
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Flex-root Flex-flex Flex-itemGutter Flex-alignCenter"
>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorPrimary Button-variantUnderlined"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
Sign in
</button>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorPrimary Button-variantOutlined"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
Register
</button>
</div>
<div
className="CallOut-root CallOut-colorPrimary"
>
<div
className="Markdown-root"
dangerouslySetInnerHTML={
Object {
"__html": "<h2 id=\\"community-guidelines\\">Community Guidelines</h2>
",
}
}
/>
</div>
<div
className="HorizontalGutter-root PostCommentFormFake-root HorizontalGutter-full"
>
<div
aria-hidden="true"
>
<div>
<div
className=""
>
<div
aria-hidden="true"
className="RTE-placeholder RTE-placeholder "
>
Post a comment
</div>
<div
aria-placeholder="Post a comment"
className="RTE-contentEditable RTE-content RTE-contentEditableDisabled"
contentEditable={false}
dangerouslySetInnerHTML={
Object {
"__html": "",
}
}
disabled={true}
onBlur={[Function]}
onChange={[Function]}
onCut={[Function]}
onFocus={[Function]}
onInput={[Function]}
onKeyDown={[Function]}
onPaste={[Function]}
onSelect={[Function]}
/>
<div
className="RTE-toolbar RTE-toolbarDisabled RTE-toolbarBottom Toolbar-toolbar"
>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Bold"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-md"
>
format_bold
</span>
</button>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Italic"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-md"
>
format_italic
</span>
</button>
<button
className="Button-button"
disabled={false}
onClick={[Function]}
title="Blockquote"
type="button"
>
<span
aria-hidden="true"
className="Icon-root Icon-md"
>
format_quote
</span>
</button>
</div>
</div>
</div>
</div>
<button
className="BaseButton-root Button-root Button-sizeRegular Button-colorPrimary Button-variantFilled Button-fullWidth Button-disabled"
disabled={true}
onBlur={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="submit"
>
Sign in and Join the Conversation
</button>
</div>
</div>
<div>
<div
className="Flex-root Flex-flex Flex-itemGutter Flex-justifyFlexEnd Flex-alignCenter"
>
<label
className="Typography-root Typography-bodyCopyBold Typography-colorTextPrimary"
htmlFor="talk-comments-sortMenu"
>
Sort By
</label>
<span
className="SelectField-root"
>
<select
className="SelectField-select undefined"
id="talk-comments-sortMenu"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
value="CREATED_AT_DESC"
>
<option
value="CREATED_AT_DESC"
>
Newest
</option>
<option
value="CREATED_AT_ASC"
>
Oldest
</option>
<option
value="REPLIES_DESC"
>
Most Replies
</option>
<option
value="RESPECT_DESC"
>
Most Reactions
</option>
</select>
<span
aria-hidden={true}
className="SelectField-afterWrapper undefined"
>
<span
aria-hidden="true"
className="Icon-root Icon-sm"
>
expand_more
</span>
</span>
</span>
</div>
<hr
className="Divider-root"
/>
</div>
<div
aria-live="polite"
className="HorizontalGutter-root HorizontalGutter-full"
data-testid="comments-stream-log"
id="talk-comments-stream-log"
role="log"
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
data-testid="comment-comment-0"
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Indent-root"
>
<div
className=""
>
<div
className="Comment-root"
role="article"
>
<div
className="Flex-root Flex-flex Flex-justifySpaceBetween Flex-directionRow"
>
<div
className="Flex-root Flex-flex Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Markus
</span>
<div
className="Flex-root Flex-flex Flex-itemGutter Flex-alignBaseline Flex-directionRow"
>
<time
className="Timestamp-root RelativeTime-root"
dateTime="2018-07-06T18:24:00.000Z"
title="2018-07-06T18:24:00.000Z"
>
2018-07-06T18:24:00.000Z
</time>
</div>
</div>
</div>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="HTMLContent-root"
dangerouslySetInnerHTML={
Object {
"__html": "Joining Too",
}
}
/>
<div
className="Flex-root Flex-flex Flex-justifySpaceBetween"
>
<div
className="Flex-root Flex-flex Flex-halfItemGutter Flex-directionRow"
>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
id="comments-commentContainer-replyButton-comment-0"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Reply
</span>
</button>
<div
className="Popover-root"
>
<button
aria-controls="permalink-popover-comment-0"
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Share
</span>
</button>
<div
aria-hidden={true}
aria-labelledby="permalink-popover-comment-0-ariainfo"
id="permalink-popover-comment-0"
role="popup"
>
<div
className="AriaInfo-root"
id="permalink-popover-comment-0-ariainfo"
>
A dialog showing a permalink to the comment
</div>
</div>
</div>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Respect
</span>
</button>
</div>
<div
className="Flex-root Flex-flex Flex-halfItemGutter Flex-directionRow"
>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
disabled={false}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Report
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
data-testid="comment-comment-1"
>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Indent-root"
>
<div
className=""
>
<div
className="Comment-root"
role="article"
>
<div
className="Flex-root Flex-flex Flex-justifySpaceBetween Flex-directionRow"
>
<div
className="Flex-root Flex-flex Flex-halfItemGutter Flex-alignBaseline Flex-directionColumn"
>
<span
className="Typography-root Typography-heading3 Typography-colorTextPrimary Username-root"
>
Lukas
</span>
<div
className="Flex-root Flex-flex Flex-itemGutter Flex-alignBaseline Flex-directionRow"
>
<time
className="Timestamp-root RelativeTime-root"
dateTime="2018-07-06T18:24:00.000Z"
title="2018-07-06T18:24:00.000Z"
>
2018-07-06T18:24:00.000Z
</time>
</div>
</div>
</div>
<div
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="HTMLContent-root"
dangerouslySetInnerHTML={
Object {
"__html": "What's up?",
}
}
/>
<div
className="Flex-root Flex-flex Flex-justifySpaceBetween"
>
<div
className="Flex-root Flex-flex Flex-halfItemGutter Flex-directionRow"
>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
id="comments-commentContainer-replyButton-comment-1"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Reply
</span>
</button>
<div
className="Popover-root"
>
<button
aria-controls="permalink-popover-comment-1"
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Share
</span>
</button>
<div
aria-hidden={true}
aria-labelledby="permalink-popover-comment-1-ariainfo"
id="permalink-popover-comment-1"
role="popup"
>
<div
className="AriaInfo-root"
id="permalink-popover-comment-1-ariainfo"
>
A dialog showing a permalink to the comment
</div>
</div>
</div>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Respect
</span>
</button>
</div>
<div
className="Flex-root Flex-flex Flex-halfItemGutter Flex-directionRow"
>
<button
className="BaseButton-root Button-root Button-sizeSmall Button-colorRegular Button-variantGhost"
disabled={false}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseOut={[Function]}
onMouseOver={[Function]}
onTouchEnd={[Function]}
type="button"
>
<span>
Report
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
`;
@@ -43,7 +43,7 @@ exports[`renders app with comment stream 1`] = `
className="HorizontalGutter-root Stream-root HorizontalGutter-double"
>
<div
className="HorizontalGutter-root HorizontalGutter-half"
className="HorizontalGutter-root HorizontalGutter-full"
>
<div
className="Flex-root Flex-flex Flex-itemGutter Flex-alignCenter"
@@ -0,0 +1,41 @@
import sinon from "sinon";
import { waitForElement, within } from "talk-framework/testHelpers";
import { settings, stories } from "../fixtures";
import create from "./create";
function createTestRenderer() {
const resolvers = {
Query: {
story: sinon.stub().returns(stories[0]),
settings: sinon.stub().returns({
...settings,
communityGuidelines: {
content: "## Community Guidelines",
enabled: true,
},
}),
},
};
const { testRenderer } = create({
// Set this to true, to see graphql responses.
logNetwork: false,
resolvers,
initLocalState: localRecord => {
localRecord.setValue(stories[0].id, "storyID");
},
});
return { testRenderer, resolvers };
}
it("renders comment stream with community guidelines", async () => {
const { testRenderer } = createTestRenderer();
await waitForElement(() =>
within(testRenderer.root).getByText("Community Guidelines", {
exact: false,
})
);
const tabPane = within(testRenderer.root).getByTestID("current-tab-pane");
expect(within(tabPane).toJSON()).toMatchSnapshot();
});
+4
View File
@@ -7,6 +7,10 @@ import {
export const settings = {
id: "settings",
communityGuidelines: {
enabled: false,
content: "",
},
auth: {
integrations: {
facebook: {
@@ -6,7 +6,7 @@ import { PropTypesOf } from "talk-ui/types";
import styles from "./AriaInfo.css";
interface InnerProps extends AllHTMLAttributes<HTMLElement> {
interface Props extends AllHTMLAttributes<HTMLElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
@@ -18,7 +18,7 @@ interface InnerProps extends AllHTMLAttributes<HTMLElement> {
forwardRef?: Ref<HTMLElement>;
}
const AriaInfo: StatelessComponent<InnerProps> = props => {
const AriaInfo: StatelessComponent<Props> = props => {
const { component, className, classes, forwardRef: ref, ...rest } = props;
const Component: React.ComponentType<
React.HTMLAttributes<HTMLElement> & React.ClassAttributes<HTMLElement>
@@ -19,7 +19,7 @@ import { PropTypesOf } from "talk-ui/types";
import styles from "./BaseButton.css";
interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
/** If set renders an anchor tag instead */
anchor?: boolean;
href?: string;
@@ -52,7 +52,7 @@ interface InnerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
* A button whose styling is stripped off to a minimum and supports
* keyboard focus. It is the base for our other buttons.
*/
const BaseButton: StatelessComponent<InnerProps> = ({
const BaseButton: StatelessComponent<Props> = ({
anchor,
className,
classes,
@@ -11,7 +11,7 @@ import styles from "./Button.css";
// This should extend from BaseButton instead but we can't because of this bug
// TODO: add bug link.
interface InnerProps extends Omit<BaseButtonProps, "ref"> {
interface Props extends Omit<BaseButtonProps, "ref"> {
/** If set renders an anchor tag instead */
anchor?: boolean;
href?: string;
@@ -43,8 +43,8 @@ interface InnerProps extends Omit<BaseButtonProps, "ref"> {
forwardRef?: Ref<HTMLButtonElement>;
}
export class Button extends React.Component<InnerProps> {
public static defaultProps: Partial<InnerProps> = {
export class Button extends React.Component<Props> {
public static defaultProps: Partial<Props> = {
size: "regular",
variant: "regular",
color: "regular",
@@ -7,7 +7,7 @@ import { PropTypesOf } from "talk-ui/types";
import styles from "./ButtonIcon.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
interface Props extends HTMLAttributes<HTMLSpanElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
@@ -23,7 +23,7 @@ interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
forwardRef?: Ref<HTMLSpanElement>;
}
export const ButtonIcon: StatelessComponent<InnerProps> = props => {
export const ButtonIcon: StatelessComponent<Props> = props => {
const { classes, className, forwardRef, ...rest } = props;
const rootClassName = cn(classes.root, className);
return <Icon className={rootClassName} {...rest} ref={forwardRef} />;
@@ -31,7 +31,7 @@ export const ButtonIcon: StatelessComponent<InnerProps> = props => {
ButtonIcon.defaultProps = {
size: "sm",
} as Partial<InnerProps>;
} as Partial<Props>;
const enhanced = withForwardRef(withStyles(styles)(ButtonIcon));
export type ButtonIconProps = PropTypesOf<typeof enhanced>;
+2 -2
View File
@@ -8,7 +8,7 @@ import { PropTypesOf } from "talk-ui/types";
import styles from "./Flex.css";
interface InnerProps {
interface Props {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
@@ -33,7 +33,7 @@ interface InnerProps {
forwardRef?: Ref<HTMLDivElement>;
}
const Flex: StatelessComponent<InnerProps> = props => {
const Flex: StatelessComponent<Props> = props => {
const {
classes,
className,
@@ -9,14 +9,14 @@ import HorizontalGutter from "../HorizontalGutter";
import styles from "./FormField.css";
interface InnerProps extends Omit<PropTypesOf<typeof HorizontalGutter>, "ref"> {
interface Props extends Omit<PropTypesOf<typeof HorizontalGutter>, "ref"> {
children: ReactNode;
classes: typeof styles;
id?: string;
className?: string;
}
const FormField: StatelessComponent<InnerProps> = props => {
const FormField: StatelessComponent<Props> = props => {
const { classes, className, children, ...rest } = props;
return (
@@ -6,7 +6,7 @@ import { PropTypesOf } from "talk-ui/types";
import styles from "./HorizontalGutter.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
interface Props extends HTMLAttributes<HTMLSpanElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
@@ -29,7 +29,7 @@ interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
container?: React.ReactElement<any> | React.ComponentType<any> | string;
}
const HorizontalGutter: StatelessComponent<InnerProps> = props => {
const HorizontalGutter: StatelessComponent<Props> = props => {
const { classes, className, size, forwardRef, container, ...rest } = props;
const rootClassName = cn(classes.root, className, classes[size!]);
@@ -51,7 +51,7 @@ const HorizontalGutter: StatelessComponent<InnerProps> = props => {
HorizontalGutter.defaultProps = {
size: "full",
container: "div",
} as Partial<InnerProps>;
} as Partial<Props>;
const enhanced = withForwardRef(withStyles(styles)(HorizontalGutter));
export type HorizontalGutterProps = PropTypesOf<typeof enhanced>;
+3 -3
View File
@@ -6,7 +6,7 @@ import { PropTypesOf } from "talk-ui/types";
import styles from "./Icon.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
interface Props extends HTMLAttributes<HTMLSpanElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
@@ -22,7 +22,7 @@ interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
forwardRef?: Ref<HTMLSpanElement>;
}
const Icon: StatelessComponent<InnerProps> = props => {
const Icon: StatelessComponent<Props> = props => {
const { classes, className, size, forwardRef, ...rest } = props;
const rootClassName = cn(classes.root, className, classes[size!]);
return (
@@ -37,7 +37,7 @@ const Icon: StatelessComponent<InnerProps> = props => {
Icon.defaultProps = {
size: "sm",
} as Partial<InnerProps>;
} as Partial<Props>;
const enhanced = withForwardRef(withStyles(styles)(Icon));
export type IconProps = PropTypesOf<typeof enhanced>;
@@ -9,7 +9,7 @@ import UIContext from "../UIContext";
type Breakpoints = keyof typeof theme.breakpoints;
interface InnerProps {
interface Props {
/** greater than or equal width. */
gteWidth?: Breakpoints;
@@ -35,7 +35,7 @@ interface InnerProps {
values?: Partial<MediaQueryMatchers>;
}
export const MatchMedia: StatelessComponent<InnerProps> = props => {
export const MatchMedia: StatelessComponent<Props> = props => {
const { speech, gteWidth, gtWidth, lteWidth, ltWidth, ...rest } = props;
const mapped = {
// TODO: Temporarily map newer speech to older aural type until
@@ -55,7 +55,7 @@ export const MatchMedia: StatelessComponent<InnerProps> = props => {
return <Responsive {...rest} {...mapped} />;
};
const MatchMediaWithContext: StatelessComponent<InnerProps> = props => (
const MatchMediaWithContext: StatelessComponent<Props> = props => (
<UIContext.Consumer>
{({ mediaQueryValues }) => (
<MatchMedia {...props} values={mediaQueryValues} />
@@ -6,7 +6,7 @@ import { withForwardRef, withStyles } from "talk-ui/hocs";
import styles from "./MessageIcon.css";
interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
interface Props extends HTMLAttributes<HTMLSpanElement> {
/**
* This prop can be used to add custom classnames.
* It is handled by the `withStyles `HOC.
@@ -22,7 +22,7 @@ interface InnerProps extends HTMLAttributes<HTMLSpanElement> {
forwardRef?: Ref<HTMLSpanElement>;
}
export const MessageIcon: StatelessComponent<InnerProps> = props => {
export const MessageIcon: StatelessComponent<Props> = props => {
const { classes, className, forwardRef, ...rest } = props;
const rootClassName = cn(classes.root, className);
return <Icon className={rootClassName} {...rest} ref={forwardRef} />;
@@ -8,7 +8,7 @@ import { PropTypesOf } from "talk-ui/types";
import styles from "./RelativeTime.css";
interface InnerProps {
interface Props {
date: string;
live?: boolean;
classes: typeof styles;
@@ -22,7 +22,7 @@ interface InnerProps {
const defaultFormatter: Formatter = (value, unit, suffix, timestamp: string) =>
new Date(timestamp).toISOString();
const RelativeTime: React.StatelessComponent<InnerProps> = props => {
const RelativeTime: React.StatelessComponent<Props> = props => {
const { date, classes, live, className, formatter } = props;
return (
<UIContext.Consumer>
@@ -22,7 +22,7 @@ type Variant =
// Based on Typography Component of Material UI.
// https://github.com/mui-org/material-ui/blob/303199d39b42a321d28347d8440d69166f872f27/packages/material-ui/src/Typography/Typography.js
interface InnerProps extends HTMLAttributes<any> {
interface Props extends HTMLAttributes<any> {
/**
* Set the text-align on the component.
*/
@@ -83,7 +83,7 @@ interface InnerProps extends HTMLAttributes<any> {
forwardRef?: Ref<HTMLElement>;
}
const Typography: StatelessComponent<InnerProps> = props => {
const Typography: StatelessComponent<Props> = props => {
const {
align,
classes,
@@ -155,7 +155,7 @@ Typography.defaultProps = {
noWrap: false,
paragraph: false,
variant: "bodyCopy",
} as Partial<InnerProps>;
} as Partial<Props>;
const enhanced = withForwardRef(withStyles(styles)(Typography));
export type TypographyProps = PropTypesOf<typeof enhanced>;
+6 -36
View File
@@ -57,56 +57,26 @@
}
.heading1 {
font-size: calc(24rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(26em / 24);
letter-spacing: calc(0.2em / 24);
color: var(--palette-text-primary);
@mixin heading1;
}
.heading2 {
font-size: calc(20rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(22em / 20);
letter-spacing: calc(0.2em / 20);
color: var(--palette-text-primary);
@mixin heading2;
}
.heading3 {
font-size: calc(18rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(20em / 18);
letter-spacing: calc(0.2em / 18);
color: var(--palette-text-primary);
@mixin heading3;
}
.heading4 {
font-size: calc(16rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(18em / 16);
letter-spacing: calc(0.2em / 16);
color: var(--palette-text-primary);
@mixin heading4;
}
.heading5 {
font-size: calc(14rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(16em / 16);
letter-spacing: calc(0.2em / 16);
color: var(--palette-text-primary);
@mixin heading5;
}
.bodyCopy {
font-size: calc(16rem / var(--rem-base));
font-weight: var(--font-weight-regular);
font-family: var(--font-family-sans-serif);
line-height: calc(20em / 16);
letter-spacing: calc(0.2em / 16);
color: var(--palette-text-primary);
@mixin bodyCopy;
}
.button {
+52
View File
@@ -0,0 +1,52 @@
@define-mixin bodyCopy {
font-size: calc(16rem / var(--rem-base));
font-weight: var(--font-weight-regular);
font-family: var(--font-family-sans-serif);
line-height: calc(20em / 16);
letter-spacing: calc(0.2em / 16);
color: var(--palette-text-primary);
}
@define-mixin heading1 {
font-size: calc(24rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(26em / 24);
letter-spacing: calc(0.2em / 24);
color: var(--palette-text-primary);
}
@define-mixin heading2 {
font-size: calc(20rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(22em / 20);
letter-spacing: calc(0.2em / 20);
color: var(--palette-text-primary);
}
@define-mixin heading3 {
font-size: calc(18rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(20em / 18);
letter-spacing: calc(0.2em / 18);
color: var(--palette-text-primary);
}
@define-mixin heading4 {
font-size: calc(16rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(18em / 16);
letter-spacing: calc(0.2em / 16);
color: var(--palette-text-primary);
}
@define-mixin heading5 {
font-size: calc(14rem / var(--rem-base));
font-weight: var(--font-weight-medium);
font-family: var(--font-family-serif);
line-height: calc(16em / 16);
letter-spacing: calc(0.2em / 16);
color: var(--palette-text-primary);
}
@@ -821,6 +821,22 @@ type ReactionConfiguration {
color: String
}
################################################################################
## CommunityGuidelines
################################################################################
type CommunityGuidelines {
"""
enable set to true will show the guidelines above the question box.
"""
enabled: Boolean!
"""
content of the guidelines.
"""
content: String
}
################################################################################
## Settings
################################################################################
@@ -870,14 +886,9 @@ type Settings {
requireEmailConfirmation: Boolean!
"""
communityGuidelinesEnable will show the guidelines above the question box.
communityGuidelines will be shown in the comments stream.
"""
communityGuidelinesEnable: Boolean!
"""
communityGuidelines is the content of the guidelines.
"""
communityGuidelines: String
communityGuidelines: CommunityGuidelines!
"""
questionBoxEnable will enable the Question Box's content to be visible above
@@ -2085,6 +2096,18 @@ input SettingsKarmaInput {
thresholds: SettingsKarmaThresholdsInput
}
input SettingsCommunityGuidelinesInput {
"""
enable set to true will show the guidelines above the question box.
"""
enabled: Boolean
"""
content of the guidelines.
"""
content: String
}
input SettingsCharCountInput {
"""
enabled when true, enables the character count moderation phase.
@@ -2122,15 +2145,9 @@ input SettingsInput {
requireEmailConfirmation: Boolean
"""
communityGuidelinesEnable will enable the Info Box content visible above the question
box.
communityGuidelines will be shown in the comments stream.
"""
communityGuidelinesEnable: Boolean
"""
communityGuidelines is the content of the Info Box.
"""
communityGuidelines: String
communityGuidelines: SettingsCommunityGuidelinesInput
"""
questionBoxEnable will enable the Question Box's content to be visible above
+4 -2
View File
@@ -18,8 +18,10 @@ import {
export interface ModerationSettings {
moderation: GQLMODERATION_MODE;
requireEmailConfirmation: boolean;
communityGuidelinesEnable: boolean;
communityGuidelines?: string;
communityGuidelines: {
enabled: boolean;
content?: string;
};
questionBoxEnable: boolean;
questionBoxIcon?: string;
questionBoxContent?: string;
+4 -1
View File
@@ -85,7 +85,10 @@ export async function createTenant(mongo: Db, input: CreateTenantInput) {
// Email confirmation is default off.
requireEmailConfirmation: false,
communityGuidelinesEnable: false,
communityGuidelines: {
enabled: false,
content: "",
},
questionBoxEnable: false,
premodLinksEnable: false,
autoCloseStream: false,
+5 -5
View File
@@ -28,10 +28,10 @@ import {
} from "talk-framework/lib/relay";
commitLocalUpdate(environment, s => {
const root = s.getRoot();
// Create the Local Record which is the Root for the client states.
const localRecord = createAndRetain(environment, s, LOCAL_ID, LOCAL_TYPE);
root.setLinkedRecord(localRecord, "local");
const root = s.getRoot();
// Create the Local Record which is the Root for the client states.
const localRecord = createAndRetain(environment, s, LOCAL_ID, LOCAL_TYPE);
root.setLinkedRecord(localRecord, "local");
});
```
@@ -46,7 +46,7 @@ export type ContainerProps {
}
const enhance = compose<InnerProps, ContainerProps>(
const enhance = compose<Props, ContainerProps>(
withLocalStateContainer(…),
withFragmentContainer(…)
);