-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add required npm packages * implement tutorials * add tutorial to preview route * change default tutorials links * handle not found tutorial case * fix linter * use better example tutorial * small refactor
- Loading branch information
1 parent
440bb96
commit 8944566
Showing
14 changed files
with
682 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
packages/backend/src/api/controllers/TutorialController.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { renderTutorialPage } from '@explorer/frontend' | ||
import { UserDetails } from '@explorer/shared' | ||
|
||
import { PageContextService } from '../../core/PageContextService' | ||
import { getHtmlFromMarkdown } from '../../utils/markdown/getHtmlFromMarkdown' | ||
import { ControllerResult } from './ControllerResult' | ||
|
||
export class TutorialController { | ||
constructor(private readonly pageContextService: PageContextService) {} | ||
|
||
async getTutorialPage( | ||
givenUser: Partial<UserDetails>, | ||
slug: string | ||
): Promise<ControllerResult> { | ||
const context = await this.pageContextService.getPageContext(givenUser) | ||
let articleContent: string | ||
try { | ||
const path = this.getTutorialPath(slug) | ||
articleContent = getHtmlFromMarkdown(path) | ||
} catch { | ||
return { | ||
type: 'not found', | ||
message: 'The tutorial you were looking for does not exist', | ||
} | ||
} | ||
|
||
return { | ||
type: 'success', | ||
content: renderTutorialPage({ | ||
context, | ||
articleContent: articleContent, | ||
slug, | ||
}), | ||
} | ||
} | ||
|
||
private getTutorialPath(slug: string): string { | ||
return `src/content/tutorials/${slug}.md` | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
<!-- THIS FILE SHOULD BE DELETED AS SOON AS WE ADD REAL TUTORIALS --> | ||
|
||
# h1 Heading | ||
|
||
## h2 Heading | ||
|
||
### h3 Heading | ||
|
||
#### h4 Heading | ||
|
||
##### h5 Heading | ||
|
||
###### h6 Heading | ||
|
||
## Horizontal Rules | ||
|
||
--- | ||
|
||
--- | ||
|
||
--- | ||
|
||
## Emphasis | ||
|
||
**This is bold text** | ||
|
||
**This is bold text** | ||
|
||
_This is italic text_ | ||
|
||
_This is italic text_ | ||
|
||
~~Strikethrough~~ | ||
|
||
## Blockquotes | ||
|
||
> Blockquotes can also be nested... | ||
> | ||
> > ...by using additional greater-than signs right next to each other... | ||
> > | ||
> > > ...or with spaces between arrows. | ||
## Lists | ||
|
||
Unordered | ||
|
||
- Create a list by starting a line with `+`, `-`, or `*` | ||
- Sub-lists are made by indenting 2 spaces: | ||
- Marker character change forces new list start: | ||
- Ac tristique libero volutpat at | ||
* Facilisis in pretium nisl aliquet | ||
- Nulla volutpat aliquam velit | ||
- Very easy! | ||
|
||
Ordered | ||
|
||
1. Lorem ipsum dolor sit amet | ||
2. Consectetur adipiscing elit | ||
3. Integer molestie lorem at massa | ||
|
||
4. You can use sequential numbers... | ||
5. ...or keep all the numbers as `1.` | ||
|
||
Start numbering with offset: | ||
|
||
57. foo | ||
1. bar | ||
|
||
## Code | ||
|
||
Inline `code` | ||
|
||
Indented code | ||
|
||
// Some comments | ||
line 1 of code | ||
line 2 of code | ||
line 3 of code | ||
|
||
Block code "fences" | ||
|
||
``` | ||
Sample text here... | ||
``` | ||
|
||
## Tables | ||
|
||
| Option | Description | | ||
| ------ | ------------------------------------------------------------------------- | | ||
| data | path to data files to supply the data that will be passed into templates. | | ||
| engine | engine to be used for processing templates. Handlebars is the default. | | ||
| ext | extension to be used for dest files. | | ||
|
||
Right aligned columns | ||
|
||
| Option | Description | | ||
| -----: | ------------------------------------------------------------------------: | | ||
| data | path to data files to supply the data that will be passed into templates. | | ||
| engine | engine to be used for processing templates. Handlebars is the default. | | ||
| ext | extension to be used for dest files. | | ||
|
||
## Links | ||
|
||
[link text](http://dev.nodeca.com) | ||
|
||
[link with title](http://nodeca.github.io/pica/demo/ 'title text!') | ||
|
||
Autoconverted link https://github.com/nodeca/pica (enable linkify to see) | ||
|
||
## Images | ||
|
||
![Minion](https://octodex.github.com/images/minion.png) |
40 changes: 40 additions & 0 deletions
40
packages/backend/src/utils/markdown/getHtmlFromMarkdown.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Cheerio, Element, load } from 'cheerio' | ||
import fsx from 'fs-extra' | ||
import MarkdownIt from 'markdown-it' | ||
|
||
import { renderHeading } from './renderHeading' | ||
|
||
export function getHtmlFromMarkdown(filePath: string) { | ||
const markdown = MarkdownIt({ html: true }) | ||
const file = fsx.readFileSync(filePath, 'utf-8') | ||
const rendered = markdown.render(file) | ||
const $ = load(rendered) | ||
$('a').each(function () { | ||
const $el = $(this) | ||
$el.attr('rel', 'noopener noreferrer') | ||
$el.attr('target', '_blank') | ||
}) | ||
$('h1, h2, h3, h4, h5, h6').each(function () { | ||
const $el = $(this) | ||
const html = renderHeading( | ||
//eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
parseInt(this.tagName[1]!), | ||
$el.html(), | ||
getId($el) | ||
) | ||
$el.replaceWith($(html)) | ||
}) | ||
return $('body').html() ?? '' | ||
} | ||
|
||
function getId($el: Cheerio<Element>) { | ||
return ( | ||
$el.attr('id') ?? | ||
$el | ||
.text() | ||
.toLowerCase() | ||
.replace(/[^a-z\d]/g, '-') | ||
.replace(/-+/g, '-') | ||
.replace(/^-+|-+$/g, '') | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import React, { createElement, HTMLAttributes } from 'react' | ||
import { renderToStaticMarkup } from 'react-dom/server' | ||
|
||
export function renderHeading( | ||
level: number, | ||
content: string | null, | ||
id: string | ||
) { | ||
if (content === null) { | ||
return | ||
} | ||
|
||
return renderToStaticMarkup( | ||
<Hx level={level} id={id}> | ||
<a | ||
className="Heading-Title" | ||
href={`#${id}`} | ||
dangerouslySetInnerHTML={{ __html: content }} | ||
/> | ||
</Hx> | ||
) | ||
} | ||
|
||
function Hx({ | ||
level, | ||
...props | ||
}: HTMLAttributes<HTMLHeadingElement> & { level: number }) { | ||
return createElement(`h${level}`, props) | ||
} |
Oops, something went wrong.