Skip to content

Commit

Permalink
feat(embed): render html content for snippet not found
Browse files Browse the repository at this point in the history
  • Loading branch information
tericcabrel committed Oct 17, 2022
1 parent 403a6dd commit 381ea53
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 40 deletions.
2 changes: 1 addition & 1 deletion packages/embed/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ save. The URL follows this pattern: `http:https://localhost:7502/snippets/:id`.

Run the command below:
```shell
yarn preview
yarn iframe:preview
```
Navigate to the URL `http:https://localhost:7503` to see the result.

Expand Down
2 changes: 1 addition & 1 deletion packages/embed/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"clean": "rm -rf .turbo dist build",
"dev": "nodemon --watch \"*.ts\" --exec \"ts-node\" ./src/server/index.ts",
"lint": "eslint src",
"preview": "serve ./src/server/static -l 7503",
"iframe:preview": "serve ./src/server/static -l 7503",
"push": "cp package.publish.json build/package.json && cd build && npm publish --access=public",
"test": "jest"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/embed/package.publish.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sharingan-embed",
"version": "1.0.2",
"version": "1.1.0",
"repository": "https://github.com/tericcabrel/sharingan.git",
"author": "Eric Cabrel TIOGO <[email protected]>",
"license": "MIT"
Expand Down
41 changes: 41 additions & 0 deletions packages/embed/src/renderer/content/html-generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Snippet } from '@sharingan/database';
import { Lang } from 'shiki';

import { Shiki } from '../types';
import { addWhitespaceForEmptyLine, generateLineHighlightOptions } from './utils';

export const generateNoSnippetHtmlContent = (webAppUrl: string) => {
return `<div class="no-content">
<h3>Oops! Snippet not found!</h3>
<div>Go to <a href="${webAppUrl}" target="_blank">Sharingan</a> to ensure it exists and is accessible</div>
</div>`;
};

export const generateSnippetHtmlContent = async ({ shiki, snippet }: { shiki: Shiki; snippet: Snippet }) => {
const highlighter = await shiki.getHighlighter({
langs: [snippet.language] as Lang[],
theme: snippet.theme,
themes: [snippet.theme],
});

const snippetCodeHtml = highlighter.codeToHtml(snippet.content.trim(), {
lang: snippet.language,
lineOptions: generateLineHighlightOptions(snippet.lineHighlight),
});

const backgroundColor = highlighter.getBackgroundColor();

const html = snippetCodeHtml
.replace(/<pre class="shiki" style="background-color: \#[\w]{6}">/, '')
.replace('</pre>', '')
.split('\n')
.map((line: string, i: number) => {
return `<span class='line-number'>${i + 1}</span>${addWhitespaceForEmptyLine(line)}`;
})
.join('\n');

return {
backgroundColor,
html,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,22 @@ type Args = {
scriptUrl?: string;
styleUrl: string;
title: string;
webAppUrl: string;
};

const DEFAULT_COLOR = '#22272e';

export const generateHtmlPreview = ({ code, color = DEFAULT_COLOR, rawCode, scriptUrl, styleUrl, title }: Args) => {
export const generateHTMLPreview = ({
code,
color = DEFAULT_COLOR,
rawCode,
scriptUrl,
styleUrl,
title,
webAppUrl,
}: Args) => {
const id = generateRandomString(6);
const isEmpty = !rawCode;

return `
<!DOCTYPE html>
Expand All @@ -28,22 +38,22 @@ export const generateHtmlPreview = ({ code, color = DEFAULT_COLOR, rawCode, scri
<div class="ctner">
<div class="ctner-header">
<div>${title}</div>
<div>view on <a href="">Sharingan</a></div>
<div>view on <a href="${webAppUrl}" target="_blank">Sharingan</a></div>
</div>
<textarea id="raw-code-${id}" class="hidden" rows="1" cols="1">${rawCode}</textarea>
<div class="code-editor-container" id="code-${id}" style="border: solid 1px ${color}; background-color: ${color}">
<button id="btn-copy-${id}" class="btn-copy hidden">
<button id="btn-copy-${id}" class="btn-copy hidden" style="${isEmpty ? 'display: none' : ''}">
<svg class="ic show" id="ic-copy-${id}" fill="none" stroke="#fff" viewBox="0 0 24 24" xmlns="http:https://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
</svg>
<svg class="ic hidden" id="ic-copied-${id}" fill="none" stroke="#10B981" viewBox="0 0 24 24" xmlns="http:https://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
</button>
<pre>${code}</pre>
${isEmpty ? `${code}` : `<pre>${code}</pre>`}
</div>
</div>
${scriptUrl ? `<script type="text/javascript" src="${scriptUrl}"></script>` : ''}
${scriptUrl && !isEmpty ? `<script type="text/javascript" src="${scriptUrl}"></script>` : ''}
</body>
</html>
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ export const generateLineHighlightOptions = (lineHighlight: string | null) => {
return lines.map(([key, value]) => ({ classes: [`line-diff line-diff-${value}`], line: key }));
};

/**
* Adding two spaces in an empty span makes it counted as a code line
*
* Convert <span class="line"></span> to <span class="line"> </span>
* Convert <span class="line line-diff-add"></span> to <span class="line line-diff-add"> </span>
*
* @param line
*/
export const addWhitespaceForEmptyLine = (line: string) => {
if (/<span class="line (line-diff-?[a-z ]*)*"><\/span>/.test(line)) {
const [openingBracket] = line.split('</span>');
Expand Down
44 changes: 12 additions & 32 deletions packages/embed/src/renderer/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { Snippet } from '@sharingan/database';
import { Highlighter, HighlighterOptions, Lang } from 'shiki';

import { generateHtmlPreview } from './html-preview';
import { addWhitespaceForEmptyLine, generateLineHighlightOptions } from './utils';

type Shiki = {
getHighlighter: (options: HighlighterOptions) => Promise<Highlighter>;
};
import { generateNoSnippetHtmlContent, generateSnippetHtmlContent } from './content/html-generator';
import { generateHTMLPreview } from './content/preview-template';
import { Shiki } from './types';

type Args = {
options: {
scriptUrl: string;
styleUrl: string;
webAppUrl: string;
};
shiki: Shiki;
snippet: Snippet | null;
Expand All @@ -20,47 +17,30 @@ type Args = {
export const renderSnippetToHtml = async ({ options, shiki, snippet }: Args): Promise<string> => {
const STYLE_URL = options.styleUrl;
const SCRIPT_URL = options.scriptUrl;
const WEBAPP_URL = options.webAppUrl;

if (!snippet) {
const code = 'No content';
const code = generateNoSnippetHtmlContent(WEBAPP_URL);

return generateHtmlPreview({
return generateHTMLPreview({
code,
rawCode: 'No content',
rawCode: '',
scriptUrl: SCRIPT_URL,
styleUrl: STYLE_URL,
title: 'Not found',
webAppUrl: WEBAPP_URL,
});
}

const highlighter = await shiki.getHighlighter({
langs: [snippet.language] as Lang[],
theme: snippet.theme,
themes: [snippet.theme],
});

const snippetCodeHtml = highlighter.codeToHtml(snippet.content.trim(), {
lang: snippet.language,
lineOptions: generateLineHighlightOptions(snippet.lineHighlight),
});

const backgroundColor = highlighter.getBackgroundColor();

const html = snippetCodeHtml
.replace(/<pre class="shiki" style="background-color: \#[\w]{6}">/, '')
.replace('</pre>', '')
.split('\n')
.map((line: string, i: number) => {
return `<span class='line-number'>${i + 1}</span>${addWhitespaceForEmptyLine(line)}`;
})
.join('\n');
const { backgroundColor, html } = await generateSnippetHtmlContent({ shiki, snippet });

return generateHtmlPreview({
return generateHTMLPreview({
code: html,
color: backgroundColor,
rawCode: snippet.content,
scriptUrl: SCRIPT_URL,
styleUrl: STYLE_URL,
title: snippet.name,
webAppUrl: WEBAPP_URL,
});
};
5 changes: 5 additions & 0 deletions packages/embed/src/renderer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Highlighter, HighlighterOptions } from 'shiki';

export type Shiki = {
getHighlighter: (options: HighlighterOptions) => Promise<Highlighter>;
};
1 change: 1 addition & 0 deletions packages/embed/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const startServer = async () => {
options: {
scriptUrl: process.env.EMBED_JS_URL,
styleUrl: process.env.EMBED_STYLE_URL,
webAppUrl: process.env.WEB_APP_URL,
},
shiki,
snippet,
Expand Down
13 changes: 13 additions & 0 deletions packages/embed/src/styles/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,16 @@
.show {
display: block;
}
.no-content {
font-family: 'Inter', monospace !important;
display: flex;
flex-direction: column;
align-items: center;
color: white;
margin-top: 15px;
margin-bottom: 40px;
}
.no-content a {
text-decoration: none;
color: aquamarine;
}

0 comments on commit 381ea53

Please sign in to comment.