diff --git a/mon-entreprise/package.json b/mon-entreprise/package.json index 28aa60047..57cc2534b 100644 --- a/mon-entreprise/package.json +++ b/mon-entreprise/package.json @@ -30,7 +30,6 @@ "classnames": "^2.2.5", "color-convert": "^1.9.2", "core-js": "^3.2.1", - "focus-trap-react": "^3.1.2", "fuse.js": "5.2.1", "iframe-resizer": "^4.1.1", "js-yaml": "^3.13.1", diff --git a/mon-entreprise/source/components/Overlay.css b/mon-entreprise/source/components/Overlay.css deleted file mode 100644 index 5c4fb526f..000000000 --- a/mon-entreprise/source/components/Overlay.css +++ /dev/null @@ -1,32 +0,0 @@ -#overlayWrapper { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(255, 255, 255, 0.9); - overflow: auto; - z-index: 1; -} -#overlayContent { - position: absolute; - padding-bottom: 1rem; - min-height: 6em; -} -#overlayCloseButton { - position: absolute; - top: 0rem; - text-decoration: none; - font-size: 200%; - color: rgba(51, 51, 80, 0.8); - right: 0.5rem; -} -@media (min-width: 600px) { - #overlayContent { - transform: translateX(-50%); - top: 100px; - left: 50%; - width: 80%; - max-width: 40em; - } -} diff --git a/mon-entreprise/source/components/Overlay.tsx b/mon-entreprise/source/components/Overlay.tsx index 80e4837bd..45855aab6 100644 --- a/mon-entreprise/source/components/Overlay.tsx +++ b/mon-entreprise/source/components/Overlay.tsx @@ -2,7 +2,7 @@ import * as animate from 'Components/ui/animate' import { LinkButton } from 'Components/ui/Button' import FocusTrap from 'focus-trap-react' import React, { useEffect } from 'react' -import './Overlay.css' +import styled from 'styled-components' type OverlayProps = React.HTMLAttributes & { onClose?: () => void @@ -12,6 +12,7 @@ type OverlayProps = React.HTMLAttributes & { export default function Overlay({ onClose, children, + className, ...otherProps }: OverlayProps) { useEffect(() => { @@ -22,7 +23,7 @@ export default function Overlay({ } }, []) return ( -
+
{children} {onClose && ( × @@ -49,6 +49,39 @@ export default function Overlay({
-
+ ) } + +const StyledOverlayWrapper = styled.div` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.9); + overflow: auto; + z-index: 1; + .overlayContent { + position: absolute; + padding-bottom: 1rem; + min-height: 6em; + } + .overlayCloseButton { + position: absolute; + top: 0rem; + text-decoration: none; + font-size: 200%; + color: rgba(51, 51, 80, 0.8); + right: 0.5rem; + } + @media (min-width: 600px) { + .overlayContent { + transform: translateX(-50%); + top: 100px; + left: 50%; + width: 80%; + max-width: 40em; + } + } +` diff --git a/mon-entreprise/source/components/ui/PublicodeHighlighter.tsx b/mon-entreprise/source/components/ui/PublicodeHighlighter.tsx deleted file mode 100644 index 016e20e46..000000000 --- a/mon-entreprise/source/components/ui/PublicodeHighlighter.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { LinkRenderer } from 'Components/utils/markdown' -import React from 'react' -import emoji from 'react-easy-emoji' -import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter' -import yaml from 'react-syntax-highlighter/dist/esm/languages/prism/yaml' -import style from 'react-syntax-highlighter/dist/esm/styles/prism/atom-dark' - -SyntaxHighlighter.registerLanguage('yaml', yaml) - -export default ({ source }: { source: string }) => ( -
- - {source} - - - {emoji('⚡')} Lancer le calcul - -
-) diff --git a/mon-entreprise/source/components/ui/Typography.css b/mon-entreprise/source/components/ui/Typography.css index fe498dad8..170024a37 100644 --- a/mon-entreprise/source/components/ui/Typography.css +++ b/mon-entreprise/source/components/ui/Typography.css @@ -76,13 +76,8 @@ button { } p, -a, ul { line-height: 1.7rem; -} - -p, -ul { margin: 0 0 0.6rem; } diff --git a/mon-entreprise/source/components/utils/markdown.tsx b/mon-entreprise/source/components/utils/markdown.tsx index 98d38e76d..4ac6533ae 100644 --- a/mon-entreprise/source/components/utils/markdown.tsx +++ b/mon-entreprise/source/components/utils/markdown.tsx @@ -1,4 +1,4 @@ -import PublicodeHighlighter from 'Components/ui/PublicodeHighlighter' +import PublicodeHighlighter from '../../../../publicodes/source/components/PublicodeHighlighter' import React, { useContext } from 'react' import emoji from 'react-easy-emoji' import ReactMarkdown, { ReactMarkdownProps } from 'react-markdown' diff --git a/mon-entreprise/source/sites/publi.codes/Mécanismes.tsx b/mon-entreprise/source/sites/publi.codes/Mécanismes.tsx index df2206932..12d0eefd0 100644 --- a/mon-entreprise/source/sites/publi.codes/Mécanismes.tsx +++ b/mon-entreprise/source/sites/publi.codes/Mécanismes.tsx @@ -1,36 +1,11 @@ -import { Markdown } from 'Components/utils/markdown' import { ScrollToTop } from 'Components/utils/Scroll' -import mecanisms from '../../../../publicodes/source/mecanisms.yaml' import React, { useEffect } from 'react' import { useLocation } from 'react-router-dom' import { HashLink as Link } from 'react-router-hash-link' -import { capitalise0 } from '../../utils' +import mecanisms from '../../../../publicodes/docs/mecanisms.yaml' +import MecanismExplanation from '../../../../publicodes/source/components/mecanisms/Explanation' import { Header } from './Header' -type MecanismProp = { - exemples: { base: string } - description: string - name: string -} -const Mecanism = ({ name, description, exemples }: MecanismProp) => ( - -

-
{name}
-

- - {exemples && ( - <> - {Object.entries(exemples).map(([name, exemple]) => ( - -

{name === 'base' ? 'Exemple' : capitalise0(name)}

- -
- ))}{' '} - - )} - Retour à la liste -
-) export default function Landing() { const { pathname } = useLocation() useEffect(() => { @@ -59,7 +34,10 @@ export default function Landing() { ))} {Object.entries(mecanisms).map(([name, data]) => ( - + + + Retour à la liste + ))} ) diff --git a/mon-entreprise/tsconfig.json b/mon-entreprise/tsconfig.json index 1aa3bac10..694e9bf83 100644 --- a/mon-entreprise/tsconfig.json +++ b/mon-entreprise/tsconfig.json @@ -15,5 +15,9 @@ }, "noEmit": true }, - "include": ["types", "source"] + "include": [ + "types", + "source", + "../publicodes/source/components/PublicodeHighlighter.tsx" + ] } diff --git a/mon-entreprise/webpack.common.js b/mon-entreprise/webpack.common.js index dab1414db..77a2666e3 100644 --- a/mon-entreprise/webpack.common.js +++ b/mon-entreprise/webpack.common.js @@ -1,9 +1,9 @@ /* eslint-env node */ const HTMLPlugin = require('html-webpack-plugin') const CopyPlugin = require('copy-webpack-plugin') -const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin') -const { EnvironmentPlugin } = require('webpack') const path = require('path') +const { EnvironmentPlugin } = require('webpack') +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin') module.exports.default = { resolve: { diff --git a/package.json b/package.json index 043c4839b..02cb00aa3 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,6 @@ "mocha": "^5.0.4", "mocha-webpack": "^2.0.0-beta.0", "mock-local-storage": "^1.0.5", - "monaco-editor-webpack-plugin": "^1.9.0", "nearley-loader": "^2.0.0", "postcss-loader": "^2.1.2", "prettier": "^1.19.1", diff --git a/publicodes/source/mecanisms.yaml b/publicodes/docs/mecanisms.yaml similarity index 100% rename from publicodes/source/mecanisms.yaml rename to publicodes/docs/mecanisms.yaml diff --git a/publicodes/package.json b/publicodes/package.json index 3c9e410cb..cff9e84eb 100644 --- a/publicodes/package.json +++ b/publicodes/package.json @@ -27,6 +27,8 @@ "react-easy-emoji": "^1.4.0", "react-i18next": "^11.4.0", "react-markdown": "^4.3.1", + "focus-trap-react": "^3.1.2", + "react-syntax-highlighter": "^12.2.1", "styled-components": "^5.1.0", "yaml": "^1.9.2" }, @@ -38,7 +40,7 @@ "scripts": { "prepublishOnly": "yarn test && yarn run build", "clean": "rimraf dist node_modules", - "prepare": "yarn run clean && yarn run build", + "prepare": "rimraf dist && yarn run build", "build": "tsc && yarn run webpack --config webpack.config.js", "test:file": "yarn mocha-webpack --webpack-config ./webpack.test.js --include test/setupIntl.js", "test": "yarn test:file \"./{,!(node_modules)/**/}!(webpack).test.js\"" diff --git a/publicodes/source/components/Markdown.tsx b/publicodes/source/components/Markdown.tsx index 19c50bc85..3dfc6909e 100644 --- a/publicodes/source/components/Markdown.tsx +++ b/publicodes/source/components/Markdown.tsx @@ -4,12 +4,7 @@ import ReactMarkdown, { ReactMarkdownProps } from 'react-markdown' import { HashLink as Link } from 'react-router-hash-link' import { EngineContext } from './contexts' import { RuleLinkWithContext } from './RuleLink' - -const internalURLs = { - 'mon-entreprise.fr': 'mon-entreprise', - 'mycompanyinfrance.fr': 'infrance', - 'publi.codes': 'publicodes' -} as const +import PublicodeHighlighter from './PublicodeHighlighter' export function LinkRenderer({ href, @@ -44,6 +39,14 @@ export function LinkRenderer({ ) } + +const CodeBlock = ({ value, language }: { value: string; language: string }) => + language === 'yaml' ? ( + + ) : ( + {value} + ) + const TextRenderer = ({ children }: { children: string }) => ( <>{emoji(children)} ) @@ -65,6 +68,7 @@ export const Markdown = ({ renderers={{ link: LinkRenderer, text: TextRenderer, + code: CodeBlock, ...renderers }} {...otherProps} diff --git a/publicodes/source/components/Modal.tsx b/publicodes/source/components/Modal.tsx new file mode 100644 index 000000000..4d87cd798 --- /dev/null +++ b/publicodes/source/components/Modal.tsx @@ -0,0 +1,97 @@ +import FocusTrap from 'focus-trap-react' +import React, { useEffect } from 'react' +import styled from 'styled-components' + +type ModalProps = React.HTMLAttributes & { + onClose?: () => void + children: React.ReactNode +} + +export default function Modal({ + onClose, + children, + className, + ...otherProps +}: ModalProps) { + useEffect(() => { + const body = document.getElementsByTagName('body')[0] + body.classList.add('no-scroll') + return () => { + body.classList.remove('no-scroll') + } + }, []) + return ( + + +
+ {children} + {onClose && ( + + )} +
+
+
+ ) +} + +const StyledModalWrapper = styled.div` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.9); + overflow: auto; + z-index: 1; + + .overlayContent { + position: absolute; + padding-bottom: 1rem; + min-height: 6em; + } + .overlayContent > * { + animation: fromBottom 0.4s; + } + .overlayCloseButton { + position: absolute; + top: 0rem; + text-decoration: none; + font-size: 200%; + color: rgba(51, 51, 80, 0.8); + right: 0.5rem; + } + @media (min-width: 600px) { + .overlayContent { + transform: translateX(-50%); + top: 100px; + left: 50%; + width: 80%; + max-width: 40em; + } + } + @keyframes fromBottom { + from { + transform: translateY(-10px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } + } +` diff --git a/publicodes/source/components/PublicodeHighlighter.tsx b/publicodes/source/components/PublicodeHighlighter.tsx new file mode 100644 index 000000000..3f7ac5146 --- /dev/null +++ b/publicodes/source/components/PublicodeHighlighter.tsx @@ -0,0 +1,24 @@ +import React from 'react' +import emoji from 'react-easy-emoji' +import { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter' +import yaml from 'react-syntax-highlighter/dist/esm/languages/prism/yaml' +import style from 'react-syntax-highlighter/dist/esm/styles/prism/atom-dark' + +SyntaxHighlighter.registerLanguage('yaml', yaml) + +export default function PublicodeHighlighter({ source }: { source: string }) { + return ( + + ) +} diff --git a/mon-entreprise/source/components/RuleSource.tsx b/publicodes/source/components/RuleSource.tsx similarity index 59% rename from mon-entreprise/source/components/RuleSource.tsx rename to publicodes/source/components/RuleSource.tsx index 9d4d14593..983bacc82 100644 --- a/mon-entreprise/source/components/RuleSource.tsx +++ b/publicodes/source/components/RuleSource.tsx @@ -1,14 +1,17 @@ -import { ParsedRule } from 'publicodes' import yaml from 'yaml' import React from 'react' -import rules from 'Rules' -import PublicodeHighlighter from './ui/PublicodeHighlighter' - -type RuleSourceProps = Pick - -export default function RuleSource({ dottedName }: RuleSourceProps) { - const source = rules[dottedName] +import Engine from '../index' +import PublicodeHighlighter from './PublicodeHighlighter' +type Props = { dottedName: Rules; engine: Engine } +export default function RuleSource({ + engine, + dottedName +}: Props) { + const source = engine.getRules()[dottedName] + if (!source) { + return + } return (

Source publicode

diff --git a/publicodes/source/components/mecanisms/Explanation.tsx b/publicodes/source/components/mecanisms/Explanation.tsx new file mode 100644 index 000000000..30b25989e --- /dev/null +++ b/publicodes/source/components/mecanisms/Explanation.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import { capitalise0 } from '../../utils' +import { Markdown } from '../Markdown' + +type MecanismProp = { + exemples: { base: string } + description: string + name: string +} + +export default function MecanismExplanation({ + name, + description, + exemples +}: MecanismProp) { + return ( + <> + {!!name && ( +

+
{name}
+

+ )} + + {exemples && ( + <> + {Object.entries(exemples).map(([name, exemple]) => ( + +

{name === 'base' ? 'Exemple' : capitalise0(name)}

+ +
+ ))}{' '} + + )} + + ) +} diff --git a/publicodes/source/components/mecanisms/Somme.js b/publicodes/source/components/mecanisms/Somme.js index c855208cc..92d9df13d 100644 --- a/publicodes/source/components/mecanisms/Somme.js +++ b/publicodes/source/components/mecanisms/Somme.js @@ -86,7 +86,7 @@ const StyledRow = styled.div` display: flex; align-items: center; flex-flow: row nowrap; - + line-height: 1.7rem; :nth-child(2n) { background-color: var(--lightestColor); } diff --git a/publicodes/source/components/mecanisms/common.tsx b/publicodes/source/components/mecanisms/common.tsx index 5301c1740..d1c7b506f 100644 --- a/publicodes/source/components/mecanisms/common.tsx +++ b/publicodes/source/components/mecanisms/common.tsx @@ -1,5 +1,5 @@ import classnames from 'classnames' -import React from 'react' +import React, { useState, useEffect } from 'react' import { Trans } from 'react-i18next' import styled from 'styled-components' import { formatValue } from '../../format' @@ -7,8 +7,10 @@ import { Evaluation, ParsedRule, Types, Unit, EvaluatedNode } from '../../types' import { capitalise0 } from '../../utils' import { RuleLinkWithContext } from '../RuleLink' import mecanismColors from './colors' +import Modal from '../Modal' import { makeJsx } from '../../evaluation' - +import MecanismExplanation from './Explanation' +import mecanismsDoc from '../../../docs/mecanisms.yaml' type NodeValuePointerProps = { data: Evaluation unit: Unit @@ -65,9 +67,9 @@ export function Mecanism({ return ( {displayName && ( - + {name} - + )} <> {children} @@ -100,6 +102,7 @@ export const InfixMecanism = ({
{ return ( - + {name} - + + ) +} + +const MecanismName = ({ + name, + inline = false, + children +}: { + name: string + inline?: boolean + children: React.ReactNode +}) => { + const [showExplanation, setShowExplanation] = useState(false) + + return ( + <> + setShowExplanation(true)} + > + {children} + + {showExplanation && ( + setShowExplanation(false)}> + + + )} + ) } const StyledOperation = styled.span` + line-height: 1.7rem; + ::before { content: '('; } diff --git a/publicodes/source/components/rule/Rule.tsx b/publicodes/source/components/rule/Rule.tsx index fbcbc6001..5e1b0a397 100644 --- a/publicodes/source/components/rule/Rule.tsx +++ b/publicodes/source/components/rule/Rule.tsx @@ -24,7 +24,7 @@ export default function Rule({ const { description, question } = rule return ( -
+
diff --git a/publicodes/source/mecanisms/encadrement.tsx b/publicodes/source/mecanisms/encadrement.tsx index 0ad5ede13..a7ab07aa2 100644 --- a/publicodes/source/mecanisms/encadrement.tsx +++ b/publicodes/source/mecanisms/encadrement.tsx @@ -16,7 +16,7 @@ function MecanismEncadrement({ nodeValue, explanation }) { <>