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"
|
"preview": "astro preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@astrojs/react": "^4.3.0",
|
"@astrojs/react": "^4.3.1",
|
||||||
"@astrojs/tailwind": "^6.0.2",
|
"@astrojs/tailwind": "^6.0.2",
|
||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@types/react": "^18.3.20",
|
"@types/react": "^18.3.20",
|
||||||
"@types/react-dom": "^18.3.6",
|
"@types/react-dom": "^18.3.6",
|
||||||
"astro": "^5.13.2",
|
"astro": "^5.13.7",
|
||||||
"tailwindcss": "^3.4.17"
|
"tailwindcss": "^3.4.17"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^4.3.4",
|
"@astrojs/mdx": "^4.3.5",
|
||||||
"@astrojs/node": "^9.4.2",
|
"@astrojs/node": "^9.4.3",
|
||||||
"@astrojs/rss": "^4.0.12",
|
"@astrojs/rss": "^4.0.12",
|
||||||
"@astrojs/sitemap": "^3.5.0",
|
"@astrojs/sitemap": "^3.5.1",
|
||||||
"@giscus/react": "^3.1.0",
|
"@giscus/react": "^3.1.0",
|
||||||
"@pilcrowjs/object-parser": "^0.0.4",
|
"@pilcrowjs/object-parser": "^0.0.4",
|
||||||
"@react-hook/intersection-observer": "^3.1.2",
|
"@react-hook/intersection-observer": "^3.1.2",
|
||||||
|
"@rehype-pretty/transformers": "^0.13.2",
|
||||||
"arctic": "^3.6.0",
|
"arctic": "^3.6.0",
|
||||||
"lucide-react": "^0.468.0",
|
"lucide-react": "^0.468.0",
|
||||||
"marked": "^15.0.8",
|
"marked": "^15.0.8",
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
"rehype-pretty-code": "^0.14.1",
|
"rehype-pretty-code": "^0.14.1",
|
||||||
"rehype-slug": "^6.0.0",
|
"rehype-slug": "^6.0.0",
|
||||||
"schema-dts": "^1.1.5",
|
"schema-dts": "^1.1.5",
|
||||||
|
"shiki": "^3.12.2",
|
||||||
"typewriter-effect": "^2.21.0",
|
"typewriter-effect": "^2.21.0",
|
||||||
"unist-util-visit": "^5.0.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 {
|
body {
|
||||||
font-family: "ComicRegular";
|
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",
|
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
|
// Bold
|
||||||
strong: {
|
strong: {
|
||||||
color: theme("colors.orange.bright"),
|
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
|
// Horizontal rules
|
||||||
hr: {
|
hr: {
|
||||||
borderColor: theme("colors.foreground"),
|
borderColor: theme("colors.foreground"),
|
||||||
|
|||||||
Reference in New Issue
Block a user