Skip to content

Commit

Permalink
feat(project): add static page
Browse files Browse the repository at this point in the history
  • Loading branch information
RCVZ authored and ChristiaanScheermeijer committed Oct 3, 2022
1 parent 159d135 commit 84d21bf
Show file tree
Hide file tree
Showing 15 changed files with 806 additions and 151 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-i18next": "^11.10.0",
"react-markdown": "^8.0.3",
"react-query": "^3.13.10",
"react-router-dom": "^6.4.0",
"react-virtualized": "^9.22.3",
Expand Down
76 changes: 76 additions & 0 deletions src/components/MarkdownComponent/MarkdownComponent.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@use '../../styles/variables';
@use '../../styles/theme';

.markdown {
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0 0 1em;
font-weight: bold;
line-height: 1.33;
}

h1 {
padding-bottom: 0.3em;
font-size: 2em;
border-bottom: 1px solid rgba(variables.$white, 0.12);
}

h2 {
padding-bottom: 0.3em;
font-size: 1.5em;
border-bottom: 1px solid rgba(variables.$white, 0.12);
}

h3 {
font-size: 1.25em;
}

h4 {
font-size: 1em;
}

h5 {
font-size: 0.875em;
}

h6 {
font-size: 0.85em;
}

hr {
box-sizing: content-box;
height: 0.25em;
margin: 24px 0;
padding: 0;
overflow: hidden;
background: transparent;
background-color: rgba(variables.$white, 0.12);
border: 0;
}

img {
box-sizing: content-box;
max-width: 100%;
background-color: theme.$secondary-color;
}

a,
a:visited {
color: theme.$link-color;
text-decoration: none;

&:hover {
text-decoration: underline;
}
}

ul,
ol,
p {
margin: 1.2em 0;
}
}
52 changes: 26 additions & 26 deletions src/components/MarkdownComponent/MarkdownComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
import classNames from 'classnames';
import React from 'react';
import ReactMarkdown from 'react-markdown';

const MARKDOWN_LINK_REGEX = /\[([^[]+)]\(((https?:\/\/|www\.)?[^)]+)\)/gi;
const MARKDOWN_ITALIC_REGEX = /(?:\*|_)(\S[\s\S]*?)(?:\*|_)/gi;
const MARKDOWN_STRONG_REGEX = /(?:\*{2}|_{2})(\S[\s\S]*?)(?:\*{2}|_{2})/gi;
const MARKDOWN_ITALIC_STRONG_REGEX = /(?:\*{3}|_{3})(\S[\s\S]*?)(?:\*{3}|_{3})/gi;
const MARKDOWN_HEADERS_REGEX = /^(#{1,6})(.*)$/gm;
const LINEBREAK_REGEX = /(?:\r\n|\r|\n)/g;
import styles from './MarkdownComponent.module.scss';

type Props = {
markdownString: string;
className?: string;
disallowedElements?: string[];
};

const parseMarkdown = (value: string): string =>
value
.replace(/<[^>]+>/gm, '') // remove html should run first
.replace(MARKDOWN_HEADERS_REGEX, (...[, header, title]) => {
return '<h' + header.length + '>' + title.trim() + '</h' + header.length + '>';
})
.replace(MARKDOWN_ITALIC_STRONG_REGEX, (...[, word]) => `<strong><em>${word}</em></strong>`)
.replace(MARKDOWN_STRONG_REGEX, (...[, word]) => `<strong>${word}</strong>`)
.replace(MARKDOWN_ITALIC_REGEX, (...[, word]) => `<em>${word}</em>`)
.replace(MARKDOWN_LINK_REGEX, (...[, word, link]) => {
const externalLink = /^(https?|www\.|\/\/)/.test(link);
const target = externalLink ? ' target="_blank"' : '';
const rel = externalLink ? ' rel="noopener"' : '';

return `<a href="${link}"${target}${rel}>${word}</a>`;
})
.replace(LINEBREAK_REGEX, '<br />'); // linebreak formatter should run last

const MarkdownComponent: React.FC<Props> = ({ markdownString, className }: Props) => {
return <div className={className} dangerouslySetInnerHTML={{ __html: parseMarkdown(markdownString) }} />;
const MarkdownComponent: React.FC<Props> = ({ markdownString, className, disallowedElements }: Props) => {
return (
<ReactMarkdown
className={classNames(styles.markdown, className)}
components={{
a: ({ node, href, children, ...props }) => {
const externalLink = /^(https?|www\.|\/\/)/.test(href || '');
const target = externalLink ? '_blank' : undefined;
const rel = externalLink ? 'noopener' : undefined;
return (
<a {...props} href={href} target={target} rel={rel}>
{children}
</a>
);
},
}}
disallowedElements={disallowedElements}
unwrapDisallowed
>
{markdownString}
</ReactMarkdown>
);
};

export default MarkdownComponent;
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

exports[`<MarkdownComponent> > renders and matches snapshot 1`] = `
<div>
<div>
This is a test markdown string with a
<a
href="https://www.example.com"
rel="noopener"
target="_blank"
>
testlink
</a>
<div
class="_markdown_e219e2"
>
<p>
This is a test markdown string with a
<a
href="https://www.example.com"
rel="noopener"
target="_blank"
>
testlink
</a>
</p>
</div>
</div>
`;
2 changes: 1 addition & 1 deletion src/containers/Layout/Layout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
flex: 1;
}

.footer {
div.footer {
padding: 20px 40px;
line-height: 18px;
letter-spacing: 0.15px;
Expand Down
6 changes: 1 addition & 5 deletions src/containers/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,7 @@ const Layout = () => {
</Sidebar>
<Outlet />
</div>
{!!footerText && (
<div className={styles.footer}>
<MarkdownComponent markdownString={footerText} />
</div>
)}
{!!footerText && <MarkdownComponent className={styles.footer} markdownString={footerText} disallowedElements={['p']} />}

{/* Config select control to improve testing experience */}
{import.meta.env.APP_INCLUDE_TEST_CONFIGS && <ConfigSelect />}
Expand Down
2 changes: 1 addition & 1 deletion src/containers/Router/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function Router({ error }: Props) {
<Route element={<Layout />}>
<Route index element={<Home />} />
<Route path="/p/:id" element={<PlaylistScreenRouter />} />
<Route path="/m/:id/:slug" element={<MediaScreenRouter />} />
<Route path="/m/:id/*" element={<MediaScreenRouter />} />
<Route path="/s/:id/:slug" element={<Series />} />
<Route path="/q/*" element={<Search />} />
<Route path="/u/*" element={<User />} />
Expand Down
29 changes: 1 addition & 28 deletions src/pages/About/About.module.scss
Original file line number Diff line number Diff line change
@@ -1,37 +1,10 @@
@use '../../styles/variables';
@use '../../styles/theme';

.about {
div.about {
max-width: 960px;
margin: 24px auto;
padding: 16px;
font-size: 16px;
line-height: 1.4em;
background-color: rgba(variables.$white, 0.1);

h1, h2, h3, h4, h5, h6 {
font-weight: bold;
}

h1 {
font-size: 24px;
}

h2 {
font-size: 20px;
}

h3 {
font-size: 18px;
}

a,
a:visited {
color: theme.$link-color;
text-decoration: none;

&:hover {
text-decoration: underline;
}
}
}
9 changes: 3 additions & 6 deletions src/pages/About/About.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import styles from './About.module.scss';

const About = () => {
const markdownPage = `# About JW OTT Webapp
JW OTT Webapp is an open-source, dynamically generated video website built around JW Player and JW Platform services. It enables you to easily publish your JW Player-hosted video content with no coding and minimal configuration.
JW OTT Webapp is an open-source, dynamically generated video website built around JW Player and JW Platform services. It enables you to easily publish your JW Player-hosted video content with no coding and minimal configuration.
To see an example of JW OTT Webapp in action, see [https://jw-ott-webapp.netlify.app/](https://jw-ott-webapp.netlify.app/).
Expand All @@ -31,11 +32,7 @@ To see an example of JW OTT Webapp in action, see [https://jw-ott-webapp.netlify
- Security-related features (encrypted HLS, DRM, signed URLs)
- Self-hosted JW Players`;

return (
<div className={styles.about}>
<MarkdownComponent markdownString={markdownPage} />
</div>
);
return <MarkdownComponent className={styles.about} markdownString={markdownPage} />;
};

export default About;
Loading

0 comments on commit 84d21bf

Please sign in to comment.