Skip to content

Commit

Permalink
add code block group
Browse files Browse the repository at this point in the history
  • Loading branch information
Nickid2018 committed Sep 9, 2023
1 parent 76b40e1 commit 9bccc16
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 50 deletions.
39 changes: 37 additions & 2 deletions src/app/blog/[...slug]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,50 @@ import Toc from "./toc";
export default function Layout({ children }: { children: ReactNode }) {
useEffect(() => {
const buttons = document.getElementsByClassName("copy-content");
for (let i = 0; i < buttons.length; i++) {
for (let i = 0; i < buttons.length; i++)
buttons[i].addEventListener("click", () => {
const button = buttons[i] as HTMLButtonElement;
navigator.clipboard.writeText(button.value).then(r => {
button.innerText = "inventory";
setTimeout(() => (button.innerText = "content_paste"), 1000);
});
});
}
const codeGroupTabs = document.getElementsByClassName("code-group-tab");
for (let i = 0; i < codeGroupTabs.length; i++)
codeGroupTabs[i].addEventListener("click", () => {
const tab = codeGroupTabs[i] as HTMLSpanElement;
const tabId = tab.id;
const tabIdSplit = tabId.split("-");
const renderUniqueString = tabIdSplit[2];
const index = parseInt(tabIdSplit[3]);
const codeGroup = document.getElementById(`code-group-blocks-${renderUniqueString}`);
console.log(codeGroup);
if (codeGroup) {
const codeBlocks = codeGroup.getElementsByClassName("code-group-block");
for (let j = 0; j < codeBlocks.length; j++) {
if (j == index) {
const tab = document.getElementById(`code-block-${renderUniqueString}-${j}`);
if (tab) tab.classList.add("code-block-active");
} else {
const tab = document.getElementById(`code-block-${renderUniqueString}-${j}`);
if (tab) tab.classList.remove("code-block-active");
}
}
}
const tabGroup = document.getElementById(`code-group-tabs-${renderUniqueString}`);
if (tabGroup) {
const tabs = tabGroup.getElementsByClassName("code-group-tab");
for (let j = 0; j < tabs.length; j++) {
if (j == index) {
const tab = document.getElementById(`code-tab-${renderUniqueString}-${j}`);
if (tab) tab.classList.add("code-tab-active");
} else {
const tab = document.getElementById(`code-tab-${renderUniqueString}-${j}`);
if (tab) tab.classList.remove("code-tab-active");
}
}
}
});
}, []);
return (
<div className="relative top-[60px] flex h-full w-full justify-center font-sans">
Expand Down
129 changes: 106 additions & 23 deletions src/app/blog/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,32 +35,42 @@ function escape(html: string, encode: boolean) {
return html;
}

const markedRenderer = {
code(code: string, language: string | undefined, escaped: boolean) {
if (!language) return `<pre>${code}</pre>`;
const langData = language.split(" ");
let lang = langData[0].toLowerCase();
const flags = langData.slice(1);
if (!Prism.languages[lang]) {
require(`prismjs/components/prism-${lang}.js`);
if (!Prism.languages[lang]) lang = "plaintext";
}
const rendered = Prism.highlight(code, Prism.languages[lang], lang);
const classAttr = ` class="prism language-${escape(lang, false)}"`;
const buttonCopy = `
function loadLanguage(lang: string) {
lang = lang.toLowerCase();
console.log(lang);
if (!Prism.languages[lang]) {
require(`prismjs/components/prism-${lang}.js`);
if (!Prism.languages[lang]) lang = "plaintext";
}
return lang;
}

function makeCodeBlock(code: string, lang: string, flags: string[]) {
const rendered = Prism.highlight(code, Prism.languages[lang], lang);
const classAttr = ` class="prism language-${escape(lang, false)}"`;
const buttonCopy = `
<button class="copy-content" value="${encodeHTML(code)}">
<span>content_paste</span>
</button>`;
const langText = flags.includes("no-copy")
? `<span class="lang-text-static">${escape(lang, false)}</span>`
: `<span class="lang-text">${escape(lang, false)}</span>`;
return `
const langText = flags.includes("no-copy")
? `<span class="lang-text-static">${escape(lang, false)}</span>`
: `<span class="lang-text">${escape(lang, false)}</span>`;
return `
<div class="code-container">
${langText}
${flags.includes("no-copy") ? "" : buttonCopy}
<pre><code${classAttr}>${rendered}</code></pre>
</div>
`;
}

const markedRenderer = {
code(code: string, language: string | undefined, escaped: boolean) {
if (!language) return `<pre>${code}</pre>`;
const langData = language.split(" ");
let lang = loadLanguage(langData[0]);
const flags = langData.slice(1);
return makeCodeBlock(code, lang, flags);
},
heading(text: string, level: number, raw: string) {
const linkHref = slug(text);
Expand Down Expand Up @@ -102,6 +112,82 @@ const markedHooks = {
}
};

function blockContainerCodeGroup(content: string[]) {
let inCodeBlock = false;
const codeBlocks = [];
let currentCodeBlock = [] as string[];
for (let i = 0; i < content.length; i++) {
const line = content[i];
if (line.startsWith("```")) {
if (inCodeBlock) {
codeBlocks[codeBlocks.length - 1].content = currentCodeBlock.join("\n");
currentCodeBlock = [];
inCodeBlock = false;
} else {
inCodeBlock = true;
const lineSplit = line.substring(3).split(" ");
let language = "plaintext";
let fileName = "Unnamed File";
const flags = [];
if (lineSplit) {
language = lineSplit[0];
for (let j = 1; j < lineSplit.length; j++) {
const part = lineSplit[j];
if (part.startsWith("[") && part.endsWith("]")) fileName = part.substring(1, part.length - 1);
else flags.push(part);
}
}
codeBlocks.push({
lang: language,
fileName: fileName,
content: "",
flags: flags
});
}
} else if (inCodeBlock) currentCodeBlock.push(line);
}
const codeBlocksRendered = codeBlocks.map(block => {
const lang = loadLanguage(block.lang);
const rendered = makeCodeBlock(block.content, lang, block.flags);
return {
fileName: block.fileName,
rendered: rendered
};
});
const tabs = [];
const blocks = [];
const renderUniqueString = Math.random().toString(36).substring(4);
for (let i = 0; i < codeBlocksRendered.length; i++) {
const block = codeBlocksRendered[i];
const tab =
i == 0
? `<span class="code-group-tab code-tab-active" id="code-tab-${renderUniqueString}-${i}">${block.fileName}</span>`
: `<span class="code-group-tab" id="code-tab-${renderUniqueString}-${i}">${block.fileName}</span>`;
const blockRendered =
i == 0
? `<div class="code-group-block code-block-active" id="code-block-${renderUniqueString}-${i}">${block.rendered}</div>`
: `<div class="code-group-block" id="code-block-${renderUniqueString}-${i}">${block.rendered}</div>`;
tabs.push(tab);
blocks.push(blockRendered);
}
return `
<div class="block-code-group">
<div class="code-group-tabs" id="code-group-tabs-${renderUniqueString}">${tabs.join("\n")}</div>
<div class="code-group-blocks" id="code-group-blocks-${renderUniqueString}">${blocks.join("\n")}</div>
</div>
`;
}

function blockContainerPlain(headerSplit: string[], content: string) {
const title = headerSplit.length === 1 ? headerSplit[0].toUpperCase() : headerSplit.slice(1).join(" ");
return `
<div class="block-container-${headerSplit[0].toLowerCase()}">
<p class="block-container-title">${title}</p>
${markdownRendererWithoutContainer.parse(content)}
</div>
`;
}

const blockContainerExtension = {
name: "blockContainer",
level: "block",
Expand All @@ -123,12 +209,9 @@ const blockContainerExtension = {
renderer(token: Tokens.Generic) {
const header = token.text[0];
const headerSplit = header.split(" ");
const content = token.text.slice(1).join("\n");
const title = headerSplit.length === 1 ? headerSplit[0].toUpperCase() : headerSplit.slice(1).join(" ");
return `<div class="block-container-${headerSplit[0].toLowerCase()}">
<p class="block-container-title">${title}</p>
${markdownRendererWithoutContainer.parse(content)}
</div>`;
const content = token.text.slice(1);
if (headerSplit[0] === "code-group") return blockContainerCodeGroup(content);
else return blockContainerPlain(headerSplit, content.join("\n"));
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const notoSans = Noto_Sans({
subsets: ["latin"],
style: ["normal", "italic"],
display: "auto",
weight: ["400", "700"],
weight: ["400", "500", "700"],
variable: "--font-noto-sans"
});

Expand Down
72 changes: 64 additions & 8 deletions src/app/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,67 @@
overflow: auto;
font-size: 80%;
line-height: 1.45;
background-color: var(--color-pre-background);
background-color: var(--color-background-pre);
border-radius: 6px;
scrollbar-width: thin;
}

.markdown-content .code-group-tabs {
margin-left: 0;
margin-right: 0;
border-radius: 6px 6px 0 0;
background-color: var(--color-background-pre);
position: relative;
padding: 0 12px;
overflow: auto hidden;
border-bottom: 1px solid var(--color-border);
}

.markdown-content .code-group-tabs span {
position: relative;
padding: .75em 12px calc(.75em - 2px);
line-height: 2.5rem;
font-weight: 500;
font-size: 90%;
cursor: pointer;
white-space: nowrap;
transition: color .25s;
color: var(--color-text-inactive);
}

.markdown-content .code-group-tabs span:hover,
.markdown-content .code-group-tabs span.code-tab-active {
color: var(--color-text);
}

.markdown-content .code-group-tabs span::after {
position: absolute;
right: 8px;
bottom: -1px;
left: 8px;
height: 2px;
content: "";
background-color: transparent;
transition: background-color .25s;
z-index: 1;
}

.markdown-content .code-group-tabs span.code-tab-active::after {
background-color: var(--color-text-link);
}

.markdown-content .code-group-blocks pre {
border-radius: 0 0 6px 6px;
}

.markdown-content .code-group-block {
display: none;
}

.markdown-content .code-group-block.code-block-active {
display: block;
}

.markdown-content pre::-webkit-scrollbar {
height: 8px;
background-color: #f0f0f0;
Expand Down Expand Up @@ -151,7 +207,7 @@
border: 1px solid var(--color-border);
border-radius: 4px;
opacity: 0;
background-color: var(--color-pre-background);
background-color: var(--color-background-pre);
transition: opacity 0.6s cubic-bezier(.06, .72, 0, 1.02);
z-index: 3;
}
Expand All @@ -161,7 +217,7 @@
}

.markdown-content a {
color: var(--color-link-text);
color: var(--color-text-link);
background-color: transparent;
text-decoration: none;
}
Expand All @@ -176,7 +232,7 @@
font-size: 85%;
font-weight: 400;
white-space: break-spaces;
background-color: var(--color-code-background);
background-color: var(--color-background-code);
border-radius: 6px;
}

Expand Down Expand Up @@ -314,19 +370,19 @@
}

.markdown-content div.block-container-info {
background-color: var(--color-info-background);
background-color: var(--color-background-info);
}

.markdown-content div.block-container-tip {
background-color: var(--color-tip-background);
background-color: var(--color-background-tip);
}

.markdown-content div.block-container-warning {
background-color: var(--color-warning-background);
background-color: var(--color-background-warning);
}

.markdown-content div.block-container-danger {
background-color: var(--color-danger-background);
background-color: var(--color-background-danger);
}

.markdown-content li.task-list-item {
Expand Down
20 changes: 12 additions & 8 deletions src/app/styles/markdown-dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

@layer base {
:root[class~="dark"] {
--color-text: #fff;
--color-text-link: theme('colors.primary.600');
--color-text-inactive: theme('colors.neutral.500');
--color-text-secondary: theme('colors.neutral.400');

--color-border: theme('colors.neutral.200');
--color-pre-background: theme('colors.neutral.100');
--color-code-background: theme('colors.neutral.200');
--color-link-text: theme('colors.primary.600');

--color-background-pre: theme('colors.neutral.100');
--color-background-code: theme('colors.neutral.200');
--color-background-secondary: theme('colors.neutral.100');
--color-text-secondary: theme('colors.neutral.300');
--color-info-background: theme('colors.neutral.100');
--color-tip-background: theme('colors.primary.100');
--color-warning-background: theme('colors.warning.100');
--color-danger-background: theme('colors.danger.100');
--color-background-info: theme('colors.neutral.100');
--color-background-tip: theme('colors.primary.100');
--color-background-warning: theme('colors.warning.100');
--color-background-danger: theme('colors.danger.100');
}
}
20 changes: 12 additions & 8 deletions src/app/styles/markdown-light.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

@layer base {
:root:not([class~="dark"]) {
--color-text: #000;
--color-text-link: theme('colors.primary.600');
--color-text-inactive: theme('colors.neutral.500');
--color-text-secondary: theme('colors.neutral.400');

--color-border: theme('colors.neutral.200');
--color-pre-background: theme('colors.neutral.100');
--color-code-background: theme('colors.neutral.200');
--color-link-text: theme('colors.primary.600');

--color-background-pre: theme('colors.neutral.100');
--color-background-code: theme('colors.neutral.200');
--color-background-secondary: theme('colors.neutral.100');
--color-text-secondary: theme('colors.neutral.400');
--color-info-background: theme('colors.neutral.100');
--color-tip-background: theme('colors.primary.100');
--color-warning-background: theme('colors.warning.100');
--color-danger-background: theme('colors.danger.100');
--color-background-info: theme('colors.neutral.100');
--color-background-tip: theme('colors.primary.100');
--color-background-warning: theme('colors.warning.100');
--color-background-danger: theme('colors.danger.100');
}
}

0 comments on commit 9bccc16

Please sign in to comment.