Fix code block formatting on mobile devices

This commit is contained in:
2025-09-15 10:04:35 -07:00
parent f355373ba1
commit 5117218a1a
5 changed files with 632 additions and 605 deletions

View File

@@ -8,22 +8,23 @@
"preview": "astro preview"
},
"devDependencies": {
"@astrojs/react": "^4.3.0",
"@astrojs/react": "^4.3.1",
"@astrojs/tailwind": "^6.0.2",
"@tailwindcss/typography": "^0.5.16",
"@types/react": "^18.3.20",
"@types/react-dom": "^18.3.6",
"astro": "^5.13.2",
"astro": "^5.13.7",
"tailwindcss": "^3.4.17"
},
"dependencies": {
"@astrojs/mdx": "^4.3.4",
"@astrojs/node": "^9.4.2",
"@astrojs/mdx": "^4.3.5",
"@astrojs/node": "^9.4.3",
"@astrojs/rss": "^4.0.12",
"@astrojs/sitemap": "^3.5.0",
"@astrojs/sitemap": "^3.5.1",
"@giscus/react": "^3.1.0",
"@pilcrowjs/object-parser": "^0.0.4",
"@react-hook/intersection-observer": "^3.1.2",
"@rehype-pretty/transformers": "^0.13.2",
"arctic": "^3.6.0",
"lucide-react": "^0.468.0",
"marked": "^15.0.8",
@@ -35,6 +36,7 @@
"rehype-pretty-code": "^0.14.1",
"rehype-slug": "^6.0.0",
"schema-dts": "^1.1.5",
"shiki": "^3.12.2",
"typewriter-effect": "^2.21.0",
"unist-util-visit": "^5.0.0"
}

931
src/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,161 +0,0 @@
import React, { useState } from 'react';
import { Copy, Check } from 'lucide-react';
import {
SiJavascript,
SiTypescript,
SiPython,
SiRust,
SiGo,
SiC,
SiCplusplus,
SiHtml5,
SiCss3,
SiPhp,
SiRuby,
SiSwift,
SiKotlin,
SiLua,
SiJson,
SiMarkdown,
} from 'react-icons/si';
import { RxTextAlignLeft } from 'react-icons/rx';
interface CodeBlockProps {
children: React.ReactNode;
className?: string;
'data-language'?: string;
'data-theme'?: string;
raw?: string;
}
const getLanguageIcon = (language: string) => {
// Normalize the language name
const normalizedLang = language.toLowerCase().replace(/^\s+|\s+$/g, '');
// Map language names to icons
switch (normalizedLang) {
case 'js':
case 'javascript':
return <SiJavascript className="text-yellow-bright" />;
case 'ts':
case 'typescript':
return <SiTypescript className="text-blue-bright" />;
case 'py':
case 'python':
return <SiPython className="text-blue-bright" />;
case 'rs':
case 'rust':
return <SiRust className="text-orange-bright" />;
case 'go':
case 'golang':
return <SiGo className="text-blue-bright" />;
case 'c':
return <SiC className="text-blue-bright" />;
case 'cpp':
case 'c++':
return <SiCplusplus className="text-blue-bright" />;
case 'html':
return <SiHtml5 className="text-orange-bright" />;
case 'css':
return <SiCss3 className="text-blue-bright" />;
case 'php':
return <SiPhp className="text-purple-bright" />;
case 'rb':
case 'ruby':
return <SiRuby className="text-red-bright" />;
case 'swift':
return <SiSwift className="text-orange-bright" />;
case 'kt':
case 'kotlin':
return <SiKotlin className="text-purple-bright" />;
case 'lua':
return <SiLua className="text-blue-bright" />;
case 'json':
return <SiJson className="text-yellow-bright" />;
case 'md':
case 'markdown':
return <SiMarkdown className="text-blue-bright" />;
default:
return <RxTextAlignLeft className="text-yellow-bright" />;
}
};
export const CodeBlock: React.FC<CodeBlockProps> = ({
children,
className,
'data-language': language = 'text',
'data-theme': theme,
raw
}) => {
const [copied, setCopied] = useState(false);
const languageIcon = getLanguageIcon(language);
const handleCopy = () => {
// If raw content is provided, use that, otherwise try to extract text from children
const textToCopy = raw || (
typeof children === 'string'
? children
: (
React.Children.toArray(children)
.map(child =>
typeof child === 'string'
? child
: child && typeof child === 'object' && 'props' in child && typeof child.props.children === 'string'
? child.props.children
: ''
)
.join('')
)
);
navigator.clipboard.writeText(textToCopy)
.then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
})
.catch(err => {
console.error('Failed to copy: ', err);
});
};
return (
<div className="w-full rounded-md overflow-hidden border border-foreground/20 bg-background my-4" style={{ maxWidth: '95vw' }}>
{/* Header with Language Icon and Copy Button */}
<div className="bg-background border-b border-foreground/20 text-foreground p-2 flex items-center justify-between">
<div className="flex items-center">
<span className="mr-2 text-xl">
{languageIcon}
</span>
<div className="text-sm font-comic-code">
{language || "Code"}
</div>
</div>
<button
onClick={handleCopy}
className="bg-background hover:bg-foreground/10 text-foreground text-xs px-2 py-1 rounded flex items-center"
>
{copied ? (
<>
<Check size={14} className="mr-1 text-green-bright" />
<span>Copied</span>
</>
) : (
<>
<Copy size={14} className="mr-1 text-foreground/70" />
<span>Copy</span>
</>
)}
</button>
</div>
{/* Code Display */}
<div className="text-foreground overflow-x-auto">
<pre className={className}>
<code>{children}</code>
</pre>
</div>
</div>
);
};
export default CodeBlock;

View File

@@ -27,3 +27,38 @@
body {
font-family: "ComicRegular";
}
code[data-line-numbers] {
counter-reset: line;
}
code[data-line-numbers] > [data-line]::before {
counter-increment: line;
content: counter(line);
/* Other styling */
display: inline-block;
width: 0.75rem;
margin-right: 2rem;
text-align: right;
color: gray;
}
code[data-line-numbers-max-digits="2"] > [data-line]::before {
width: 1.25rem;
}
code[data-line-numbers-max-digits="3"] > [data-line]::before {
width: 1.75rem;
}
code[data-line-numbers-max-digits="4"] > [data-line]::before {
width: 2.25rem;
}
code {
overflow-x: scroll !important;
max-width: calc(82vw - 2rem) !important;
width: 100% !important;
}

View File

@@ -96,6 +96,56 @@ module.exports = {
transition: "all 0.2s ease-in-out",
},
// Code
'code:not([data-language])': {
color: theme('colors.purple.bright'),
backgroundColor: '#282828',
padding: '0',
borderRadius: '0.25rem',
fontFamily: 'Comic Code, monospace',
fontWeight: '400',
fontSize: 'inherit', // Match the parent text size
'&::before': { content: 'none' },
'&::after': { content: 'none' },
},
'pre': {
backgroundColor: '#282828',
color: theme("colors.foreground"),
borderRadius: '0.5rem',
overflow: 'visible', // This allows the copy button to be positioned outside
position: 'relative', // For the copy button positioning
marginTop: '1.5rem', // Space for the copy button and language label
fontSize: 'inherit', // Match the parent font size
},
'pre code': {
display: 'block',
fontFamily: 'Comic Code, monospace',
fontSize: '1em', // This will inherit from the prose-lg setting
padding: '0',
overflow: 'auto', // Enable horizontal scrolling
whiteSpace: 'pre',
'&::before': { content: 'none' },
'&::after': { content: 'none' },
},
'[data-rehype-pretty-code-fragment]:nth-of-type(2) pre': {
'[data-line]::before': {
content: 'counter(line)',
counterIncrement: 'line',
display: 'inline-block',
width: '1rem',
marginRight: '1rem',
textAlign: 'right',
color: '#86e1fc',
},
'[data-highlighted-line]::before': {
color: '#86e1fc',
},
},
// Bold
strong: {
color: theme("colors.orange.bright"),
@@ -123,54 +173,6 @@ module.exports = {
},
},
// Code
'code:not([data-language])': {
color: theme('colors.purple.bright'),
backgroundColor: '#282828',
padding: '0.2em 0.4em',
borderRadius: '0.25rem',
fontFamily: 'Comic Code, monospace',
fontWeight: '400',
fontSize: 'inherit', // Match the parent text size
'&::before': { content: 'none' },
'&::after': { content: 'none' },
},
'pre': {
backgroundColor: '#282828',
color: theme("colors.foreground"),
borderRadius: '0.5rem',
overflow: 'visible', // This allows the copy button to be positioned outside
position: 'relative', // For the copy button positioning
marginTop: '1.5rem', // Space for the copy button and language label
fontSize: 'inherit', // Match the parent font size
},
'pre code': {
display: 'block',
fontFamily: 'Comic Code, monospace',
fontSize: '1em', // This will inherit from the prose-lg setting
padding: '1.25rem',
overflow: 'auto', // Enable horizontal scrolling
whiteSpace: 'pre',
'&::before': { content: 'none' },
'&::after': { content: 'none' },
},
'.highlighted': {
backgroundColor: theme('colors.foreground/5'),
paddingLeft: '1rem',
paddingRight: '1rem',
marginLeft: '-1rem',
marginRight: '-1rem',
},
'.word': {
backgroundColor: theme('colors.foreground/20'),
padding: '0.2em',
borderRadius: '0.25rem',
},
// Horizontal rules
hr: {
borderColor: theme("colors.foreground"),