Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: inline code style to hide backticks #426

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/backend/src/seed/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async function createSeedPosts(strapi) {
title: "Styled Post",
author: { connect: [userIds[0]] },
tags: { connect: tagIds.slice(0, 3) },
body: '<p><strong>Bold</strong></p>\n\n<p><em>Italic</em></p>\n\n<p><s>Strike</s></p>\n\n<p><code>Code</code></p>\n\n<blockquote>"Quote"</blockquote>\n\n<h1>H1</h1>\n\n<h2>H2</h2>\n\n<h3>H3</h3>\n\n<ul>\n<li>Bullet</li>\n</ul>\n\n<ol>\n<li>Ordered</li>\n\n<li>Ordered</li>\n</ol>',
body: '<p><strong>Bold</strong></p>\n\n<p><em>Italic</em></p>\n\n<p><s>Strike</s></p>\n\n<p><code>Inline Code</code></p>\n\n<pre><code>console.log("Code Block");</code></pre>\n\n<blockquote>"Quote"</blockquote>\n\n<h1>H1</h1>\n\n<h2>H2</h2>\n\n<h3>H3</h3>\n\n<ul>\n<li>Bullet</li>\n</ul>\n\n<ol>\n<li>Ordered</li>\n\n<li>Ordered</li>\n</ol>',
publishedAt: new Date(),
},
});
Expand Down
45 changes: 36 additions & 9 deletions apps/frontend/src/components/tiptap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { lowlight } from "lowlight";

import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
import CharacterCount from "@tiptap/extension-character-count";
import Code from "@tiptap/extension-code";

function ToolBar({ editor, user }) {
const addYoutubeEmbed = () => {
Expand All @@ -56,6 +57,20 @@ function ToolBar({ editor, user }) {
}
};

const checkAndToggleInlineCode = () => {
if (editor.isActive("codeBlock")) {
editor.commands.toggleCodeBlock();
}
editor.commands.toggleCode();
};

const checkAndToggleCodeBlock = () => {
if (!editor.isActive("code")) {
editor.commands.unsetCode();
}
editor.commands.toggleCodeBlock();
};

const handleImageSubmit = async (event) => {
event.preventDefault();

Expand Down Expand Up @@ -123,15 +138,26 @@ function ToolBar({ editor, user }) {
leftIcon={<FontAwesomeIcon icon={faStrikethrough} />}
onClick={() => editor.chain().focus().toggleStrike().run()}
/>
<Button
variant="ghost"
iconSpacing={0}
p={2}
title="Add code"
aria-label="Add code"
leftIcon={<FontAwesomeIcon icon={faCode} />}
onClick={() => editor.commands.toggleCodeBlock()}
/>
<Menu>
<MenuButton
as={Button}
variant="ghost"
title="Select code"
aria-label="Select code"
iconSpacing={0}
p={2}
leftIcon={<FontAwesomeIcon icon={faCode} />}
/>
<MenuList>
<MenuItem onClick={() => checkAndToggleInlineCode()}>
Toggle inline code
</MenuItem>

<MenuItem onClick={() => checkAndToggleCodeBlock()}>
Toggle code block
</MenuItem>
</MenuList>
</Menu>
<Button
variant="ghost"
iconSpacing={0}
Expand Down Expand Up @@ -304,6 +330,7 @@ const Tiptap = ({ handleContentChange, user, content }) => {
defaultLanguage: "javascript",
lowlight,
}),
Code.configure({}),
CharacterCount.configure({}),
],
content: content ? content : "",
Expand Down
11 changes: 11 additions & 0 deletions apps/frontend/src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,17 @@
font-weight: 700;
}
}

:not(pre) code {
background-color: #e2e8f0;
border: 1px solid #cbd5e0;
padding: 0 2px;
}

code::before,
code::after {
display: none;
}
}

.dark-border pre {
Expand Down
162 changes: 141 additions & 21 deletions e2e/editor.spec.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,152 @@
import { test, expect } from "@playwright/test";

test.beforeEach(async ({ page }) => {
await page.goto("/posts/2");
});
test.describe("Using Lorem Post 1", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/posts/2"); // Lorem Post 1
});

test("it should be possible to type in the editor", async ({ page }) => {
const textToType = "Hello World";
await page.getByTestId("editor").fill(textToType);
test("it should be possible to type in the editor", async ({ page }) => {
const textToType = "Hello World";
await page.getByTestId("editor").fill(textToType);

const wordCount = await page.getByTestId("word-count").innerText();
expect(wordCount).toBe(textToType.split(" ").length.toString() + " words");
});
const wordCount = await page.getByTestId("word-count").innerText();
expect(wordCount).toBe(textToType.split(" ").length.toString() + " words");
});

test("it should have eleven buttons in the toolbar", async ({ page }) => {
const buttons = page.locator("#toolbar > button");
expect(await buttons.count()).toBe(10);

const addImageButton = page.locator("#toolbar > label > button");
expect(await addImageButton.count()).toBe(1);
});

test("it should have eleven buttons in the toolbar", async ({ page }) => {
const buttons = page.locator("#toolbar > button");
expect(await buttons.count()).toBe(10);
test("it should be possible to edit the title", async ({ page }) => {
await page.getByTestId("post-title").click();

const addImageButton = page.locator("#toolbar > label > button");
expect(await addImageButton.count()).toBe(1);
const titleField = page.getByTestId("post-title-field");
await titleField.fill("New Title");
await page.keyboard.press("Enter");

const newTitle = await page.getByTestId("post-title").innerText();
expect(newTitle).toBe("New Title");
});
});

test("it should be possible to edit the title", async ({ page }) => {
await page.getByTestId("post-title").click();
test.describe("Using Styled Post", () => {
test.beforeEach(async ({ page }) => {
await page.goto("/posts/1"); // Styled Post
});

test("it should toggle inline code", async ({ page }) => {
// Select the text currently set as inline code
await page.getByTestId("editor").getByText("Inline Code").click();
await page.getByTestId("editor").press("Home");
await page.getByTestId("editor").press("Shift+End");
// Remove inline code
await page.getByLabel("Select code").click();
await page.getByRole("menuitem", { name: "Toggle inline code" }).click();

// Check that the text was converted to a paragraph
await expect(
page.getByTestId("editor").getByRole("code").getByText("Inline Code"),
).not.toBeVisible();
await expect(
page
.getByTestId("editor")
.getByRole("paragraph")
.getByText("Inline Code"),
).toBeVisible();

// Toggle back to inline code
await page.getByTestId("editor").getByText("Inline Code").click();
await page.getByTestId("editor").press("Home");
await page.getByTestId("editor").press("Shift+End");
await page.getByLabel("Select code").click();
await page.getByRole("menuitem", { name: "Toggle inline code" }).click();

// Check that the text was converted to inline code
await expect(
page.getByTestId("editor").getByRole("code").getByText("Inline Code"),
).toBeVisible();
});

test("it should toggle code block", async ({ page }) => {
// Select the text currently set as code block
await page.getByText('"Code Block"').click();
await page.getByTestId("editor").press("Home");
await page.getByTestId("editor").press("Shift+End");
// Remove code block
await page.getByLabel("Select code").click();
await page.getByRole("menuitem", { name: "Toggle code block" }).click();

// Check that the text was converted to a paragraph
await expect(
page
.getByTestId("editor")
.getByRole("code")
.getByText('console.log("Code Block");'),
).not.toBeVisible();
await expect(
page
.getByTestId("editor")
.getByRole("paragraph")
.getByText('console.log("Code Block");'),
).toBeVisible();

// Toggle back to code block
await page.getByText('"Code Block"').click();
await page.getByTestId("editor").press("Home");
await page.getByTestId("editor").press("Shift+End");
await page.getByLabel("Select code").click();
await page.getByRole("menuitem", { name: "Toggle code block" }).click();

// Check that the text was converted to a code block
await expect(
page
.getByTestId("editor")
.getByRole("code")
.getByText('console.log("Code Block");'),
).toBeVisible();
await expect(
page.getByTestId("editor").getByRole("code").getByText("Code Block"),
).toHaveClass("hljs-string");
});

test("inline code and code block should be mutually exclusive", async ({
page,
}) => {
// Select the text currently set as inline code
await page.getByTestId("editor").getByText("Inline Code").click();
await page.getByTestId("editor").press("Home");
await page.getByTestId("editor").press("Shift+End");
// Change it to code block
await page.getByLabel("Select code").click();
await page.getByRole("menuitem", { name: "Toggle code block" }).click();

// Should be converted to code block
await expect(
page.getByTestId("editor").getByRole("code").getByText("Inline Code"),
).toBeVisible();
// Check that the class specific to code block is present
await expect(
page.getByTestId("editor").getByRole("code").getByText("Inline"),
).toHaveClass(/hljs-.*/);

const titleField = page.getByTestId("post-title-field");
await titleField.fill("New Title");
await page.keyboard.press("Enter");
// Select the text currently set as code block
await page.getByTestId("editor").getByText("Inline Code").click();
await page.getByTestId("editor").press("Home");
await page.getByTestId("editor").press("Shift+End");
// Change it to inline code
await page.getByLabel("Select code").click();
await page.getByRole("menuitem", { name: "Toggle inline code" }).click();

const newTitle = await page.getByTestId("post-title").innerText();
expect(newTitle).toBe("New Title");
// Should be converted to inline code
await expect(
page.getByTestId("editor").getByRole("code").getByText("Inline Code"),
).toBeVisible();
await expect(
page.getByTestId("editor").getByRole("code").getByText("Inline"),
).not.toHaveClass(/hljs-.*/);
});
});
Loading