Skip to content

Commit

Permalink
Add InlineTitle component
Browse files Browse the repository at this point in the history
This new component doesn't rely on marked.js but escapes any special
characters and then replaces any backtick with a <code> HTML tag to
render any inline codeblocks in all titles.
  • Loading branch information
sebastinez committed Jul 1, 2024
1 parent 1f27466 commit 96042be
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 47 deletions.
5 changes: 1 addition & 4 deletions src/components/InlineMarkdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@
import { Renderer } from "@app/lib/markdown";
export let content: string;
export let stripEmphasizedStyling: boolean = false;
export let fontSize: "tiny" | "small" | "regular" | "medium" | "large" =
"small";
const render = (content: string): string =>
dompurify.sanitize(
markdown.parseInline(content, {
renderer: new Renderer($activeUnloadedRouteStore, {
stripEmphasizedStyling,
}),
renderer: new Renderer($activeUnloadedRouteStore),
}) as string,
);
</script>
Expand Down
4 changes: 1 addition & 3 deletions src/components/Markdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,7 @@
function render(content: string): string {
return dompurify.sanitize(
markdownWithExtensions.parse(content, {
renderer: new Renderer($activeUnloadedRouteStore, {
stripEmphasizedStyling: false,
}),
renderer: new Renderer($activeUnloadedRouteStore),
breaks,
}) as string,
);
Expand Down
17 changes: 1 addition & 16 deletions src/lib/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,14 @@ const anchorMarkedExtension = {

export class Renderer extends BaseRenderer {
#route: Route;
#stripEmphasizedStyling: boolean | undefined;

/**
* If `baseUrl` is provided, all hrefs attributes in anchor tags, except those
* starting with `#`, are resolved with respect to `baseUrl`
*/
constructor(
activeUnloadedRoute: Route,
{ stripEmphasizedStyling }: { stripEmphasizedStyling: boolean },
) {
constructor(activeUnloadedRoute: Route) {
super();
this.#route = activeUnloadedRoute;
this.#stripEmphasizedStyling = stripEmphasizedStyling;
}
// Overwrites the rendering of heading tokens.
// Since there are possible non ASCII characters in headings,
Expand All @@ -69,16 +64,6 @@ export class Renderer extends BaseRenderer {
return `<h${depth} id="${escapedText}">${text}</h${depth}>`;
}

strong({ tokens }: Tokens.Strong) {
const text = this.parser.parseInline(tokens);
return this.#stripEmphasizedStyling ? text : `<strong>${text}</strong>`;
}

em({ tokens }: Tokens.Em) {
const text = this.parser.parseInline(tokens);
return this.#stripEmphasizedStyling ? text : `<em>${text}</em>`;
}

link({ href, title, tokens }: Tokens.Link): string {
const text = this.parser.parseInline(tokens);
if (href.startsWith("#")) {
Expand Down
4 changes: 4 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export function formatLocationHash(hash: string | null): number | null {
return null;
}

export function formatInlineTitle(input: string): string {
return input.replaceAll(/`([^`]+)`/g, "<code>$1</code>");
}

export function parseNodeId(
nid: string,
): { prefix: string; pubkey: string } | undefined {
Expand Down
4 changes: 2 additions & 2 deletions src/views/projects/Cob/CobCommitTeaser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import IconButton from "@app/components/IconButton.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import InlineTitle from "@app/views/projects/components/InlineTitle.svelte";
import Link from "@app/components/Link.svelte";
export let baseUrl: BaseUrl;
Expand Down Expand Up @@ -68,7 +68,7 @@
commit: commit.id,
}}>
<div class="summary" use:twemoji>
<InlineMarkdown fontSize="small" content={commit.summary} />
<InlineTitle fontSize="small" content={commit.summary} />
</div>
</Link>
{#if commit.description}
Expand Down
7 changes: 2 additions & 5 deletions src/views/projects/Commit.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import Changeset from "@app/views/projects/Changeset.svelte";
import CommitAuthorship from "@app/views/projects/Commit/CommitAuthorship.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import InlineTitle from "@app/views/projects/components/InlineTitle.svelte";
import Layout from "./Layout.svelte";
import Link from "@app/components/Link.svelte";
import Share from "./Share.svelte";
Expand Down Expand Up @@ -50,10 +50,7 @@
<div class="header">
<div style="display:flex; flex-direction: column; gap: 0.5rem;">
<span class="title">
<InlineMarkdown
stripEmphasizedStyling
fontSize="large"
content={header.summary} />
<InlineTitle fontSize="large" content={header.summary} />
<div class="button-container">
<Link
route={{
Expand Down
4 changes: 2 additions & 2 deletions src/views/projects/Commit/CommitTeaser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import ExpandButton from "@app/components/ExpandButton.svelte";
import IconButton from "@app/components/IconButton.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import InlineTitle from "@app/views/projects/components/InlineTitle.svelte";
import Link from "@app/components/Link.svelte";
import Id from "@app/components/Id.svelte";
Expand Down Expand Up @@ -86,7 +86,7 @@
}}>
<div style="position: relative;">
<div class="summary" use:twemoji>
<InlineMarkdown fontSize="regular" content={commit.summary} />
<InlineTitle fontSize="regular" content={commit.summary} />
</div>
</div>
</Link>
Expand Down
7 changes: 2 additions & 5 deletions src/views/projects/Issue.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
import ExtendedTextarea from "@app/components/ExtendedTextarea.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import InlineTitle from "@app/views/projects/components/InlineTitle.svelte";
import LabelInput from "./Cob/LabelInput.svelte";
import Layout from "./Layout.svelte";
import Markdown from "@app/components/Markdown.svelte";
Expand Down Expand Up @@ -499,10 +499,7 @@
<span class="txt-missing">No title</span>
{:else}
<div class="title">
<InlineMarkdown
stripEmphasizedStyling
fontSize="large"
content={newTitle} />
<InlineTitle fontSize="large" content={newTitle} />
</div>
{/if}
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/views/projects/Issue/IssueTeaser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { absoluteTimestamp, formatTimestamp } from "@app/lib/utils";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import InlineTitle from "@app/views/projects/components/InlineTitle.svelte";
import Link from "@app/components/Link.svelte";
import NodeId from "@app/components/NodeId.svelte";
Expand Down Expand Up @@ -93,7 +93,7 @@
{#if !issue.title}
<span class="txt-missing">No title</span>
{:else}
<InlineMarkdown fontSize="regular" content={issue.title} />
<InlineTitle fontSize="regular" content={issue.title} />
{/if}
</Link>
</span>
Expand Down
7 changes: 2 additions & 5 deletions src/views/projects/Patch.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
import ExtendedTextarea from "@app/components/ExtendedTextarea.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import InlineTitle from "@app/views/projects/components/InlineTitle.svelte";
import LabelInput from "@app/views/projects/Cob/LabelInput.svelte";
import Layout from "@app/views/projects/Layout.svelte";
import Link from "@app/components/Link.svelte";
Expand Down Expand Up @@ -724,10 +724,7 @@
<span class="txt-missing">No title</span>
{:else}
<div class="title">
<InlineMarkdown
stripEmphasizedStyling
fontSize="large"
content={patch.title} />
<InlineTitle fontSize="large" content={patch.title} />
</div>
{/if}
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/views/projects/Patch/PatchTeaser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { absoluteTimestamp, formatTimestamp } from "@app/lib/utils";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import InlineTitle from "@app/views/projects/components/InlineTitle.svelte";
import Link from "@app/components/Link.svelte";
import NodeId from "@app/components/NodeId.svelte";
Expand Down Expand Up @@ -105,7 +105,7 @@
node: baseUrl,
patch: patch.id,
}}>
<InlineMarkdown fontSize="regular" content={patch.title} />
<InlineTitle fontSize="regular" content={patch.title} />
</Link>
{#if patch.labels.length > 0}
<span
Expand Down
28 changes: 28 additions & 0 deletions src/views/projects/components/InlineTitle.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script lang="ts">
import dompurify from "dompurify";
import escape from "lodash/escape";
import { formatInlineTitle } from "@app/lib/utils";
export let content: string;
export let fontSize: "tiny" | "small" | "regular" | "medium" | "large" =
"small";
</script>

<style>
.content :global(code) {
font-family: var(--font-family-monospace);
background-color: var(--color-fill-ghost);
border-radius: var(--border-radius-tiny);
padding: 0.125rem 0.25rem;
}
</style>

<span
class="content"
class:txt-large={fontSize === "large"}
class:txt-medium={fontSize === "medium"}
class:txt-regular={fontSize === "regular"}
class:txt-small={fontSize === "small"}
class:txt-tiny={fontSize === "tiny"}>
{@html dompurify.sanitize(formatInlineTitle(escape(content)))}
</span>
2 changes: 1 addition & 1 deletion tests/e2e/project/issue.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {

test("navigate single issue", async ({ page }) => {
await page.goto(`${cobUrl}/issues`);
await page.getByText("This title has markdown").click();
await page.getByText("This title has **markdown**").click();

await expect(page).toHaveURL(/\/issues\/[0-9a-f]{40}/);
});
Expand Down
17 changes: 17 additions & 0 deletions tests/unit/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ describe("Format functions", () => {
expect(utils.formatRepositoryId(id)).toEqual(expected);
});

test.each([
{
input: "<TR> Hello `new` world",
expected: "<TR> Hello <code>new</code> world",
},
{ input: "Hello `new` world", expected: "Hello <code>new</code> world" },
{
input: "Hello `new` world `radicle`",
expected: "Hello <code>new</code> world <code>radicle</code>",
},
{ input: "Hello `` world", expected: "Hello `` world" },
{ input: "Hello `", expected: "Hello `" },
{ input: "Hello", expected: "Hello" },
])("formatInlineTitle $input => $expected", ({ input, expected }) => {
expect(utils.formatInlineTitle(input)).toEqual(expected);
});

test.each([
{
id: "did:key:z6MkmzRwg47UWQxczLLLFfkEwpBGitjzJ1vKPE8U9ymd6fz6",
Expand Down

0 comments on commit 96042be

Please sign in to comment.