mirror of
https://github.com/timmypidashev/web.git
synced 2026-04-14 02:53:51 +00:00
Fix code block formatting on mobile devices
This commit is contained in:
@@ -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
931
src/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user