fix mobile scroll, weird padding box, improve <code> styles

This commit is contained in:
Michael Freno
2026-01-04 01:32:59 -05:00
parent a3ee392e51
commit afefb8fc5b
3 changed files with 124 additions and 99 deletions

View File

@@ -103,22 +103,47 @@ export default function PostBodyClient(props: PostBodyClientProps) {
codeBlocks.forEach((codeBlock) => {
const pre = codeBlock.parentElement;
if (!pre || pre.querySelector(".copy-button")) return;
if (!pre) return;
// Check if already processed (has header with copy button)
const existingHeader = pre.previousElementSibling;
if (
existingHeader?.classList.contains("language-header") &&
existingHeader.querySelector(".copy-button")
) {
return;
}
// Set off-black background for code block
pre.style.backgroundColor = "#1a1a1a";
// Extract language from code block classes
const classes = Array.from(codeBlock.classList);
const languageClass = classes.find((cls) => cls.startsWith("language-"));
const language = languageClass?.replace("language-", "") || "";
// Create language header if language is detected and not already present
if (
language &&
pre.previousElementSibling?.classList.contains("language-header") ===
false
) {
// Create language header if language is detected
if (language) {
const languageHeader = document.createElement("div");
languageHeader.className = "language-header";
languageHeader.textContent = language;
languageHeader.style.backgroundColor = "#1a1a1a";
// Add language label
const languageLabel = document.createElement("span");
languageLabel.textContent = language;
languageHeader.appendChild(languageLabel);
// Create copy button in header
const copyButton = document.createElement("button");
copyButton.className = "copy-button";
copyButton.textContent = "Copy";
copyButton.dataset.codeBlock = "true";
// Store reference to the code block for copying
copyButton.dataset.codeBlockId = `code-${Math.random().toString(36).substr(2, 9)}`;
codeBlock.dataset.codeBlockId = copyButton.dataset.codeBlockId;
languageHeader.appendChild(copyButton);
// Insert header before pre element
pre.parentElement?.insertBefore(languageHeader, pre);
@@ -144,14 +169,6 @@ export default function PostBodyClient(props: PostBodyClientProps) {
pre.appendChild(lineNumbers);
}
// Create copy button
const copyButton = document.createElement("button");
copyButton.className = "copy-button";
copyButton.textContent = "Copy";
copyButton.dataset.codeBlock = "true";
pre.appendChild(copyButton);
});
};
@@ -340,8 +357,14 @@ export default function PostBodyClient(props: PostBodyClientProps) {
// Handle click
if (e.type === "click" && target.classList.contains("copy-button")) {
const pre = target.parentElement;
const codeBlock = pre?.querySelector("code");
// Find the code block using the stored ID
const codeBlockId = target.dataset.codeBlockId;
const codeBlock = codeBlockId
? contentRef?.querySelector(
`code[data-code-block-id="${codeBlockId}"]`
)
: null;
if (!codeBlock) return;
const code = codeBlock.textContent || "";

View File

@@ -300,77 +300,73 @@ export default function PostPage() {
};
return (
<Show
when={data()}
fallback={
<div class="flex h-screen items-center justify-center">
<Spinner size="xl" />
</div>
}
>
{(loadedData) => {
// Handle redirect for by-id route
if ("redirect" in loadedData()) {
return <Navigate href={(loadedData() as any).redirect} />;
<CustomScrollbar autoHide={true} autoHideDelay={1500} rightOffset={250}>
<Show
when={data()}
fallback={
<div class="flex h-screen items-center justify-center">
<Spinner size="xl" />
</div>
}
>
{(loadedData) => {
// Handle redirect for by-id route
if ("redirect" in loadedData()) {
return <Navigate href={(loadedData() as any).redirect} />;
}
return (
<Show
when={loadedData().post as Post}
fallback={<Navigate href="/404" />}
>
{(p) => {
const postData = loadedData();
return (
<Show
when={loadedData().post as Post}
fallback={<Navigate href="/404" />}
>
{(p) => {
const postData = loadedData();
// Convert arrays back to Maps for component
const userCommentMap = new Map<UserPublicData, number[]>(
postData.userCommentArray || []
);
const reactionMap = new Map<number, CommentReaction[]>(
postData.reactionArray || []
);
// Convert arrays back to Maps for component
const userCommentMap = new Map<UserPublicData, number[]>(
postData.userCommentArray || []
);
const reactionMap = new Map<number, CommentReaction[]>(
postData.reactionArray || []
);
return (
<>
<Title>
{p().title.replaceAll("_", " ")} | Michael Freno
</Title>
<Meta
name="description"
content={
p().subtitle ||
`Read ${p().title.replaceAll("_", " ")} by Michael Freno on the freno.me blog.`
}
/>
return (
<>
<Title>
{p().title.replaceAll("_", " ")} | Michael Freno
</Title>
<Meta
name="description"
content={
p().subtitle ||
`Read ${p().title.replaceAll("_", " ")} by Michael Freno on the freno.me blog.`
}
/>
<div class="blog-overide relative -mt-16 overflow-x-hidden">
{/* Fixed banner image background */}
<div class="fixed inset-0 top-0 left-0 z-0 aspect-auto max-h-3/4 w-full overflow-hidden brightness-75 md:ml-62.5 md:max-h-[50vh] md:w-[calc(100vw-500px)]">
<img
src={p().banner_photo || "/blueprint.jpg"}
alt="post-cover"
class="h-full w-full object-cover select-none"
style={{
"pointer-events": "none"
}}
/>
<div class="fixed top-24 z-50 m-auto w-full px-4 text-center tracking-widest text-white backdrop-blur-md select-text text-shadow-lg backdrop:brightness-50 sm:top-36 md:top-[20vh] md:w-[calc(100vw-500px)]">
<div class="py-8 text-3xl font-semibold tracking-widest">
{p().title.replaceAll("_", " ")}
<Show when={p().subtitle}>
<div class="py-8 text-xl font-light tracking-widest">
{p().subtitle}
</div>
</Show>
<div class="blog-overide relative -mt-16 overflow-x-hidden">
{/* Fixed banner image background */}
<div class="fixed inset-0 top-0 left-0 z-0 aspect-auto max-h-3/4 w-full overflow-hidden brightness-75 md:ml-62.5 md:max-h-[50vh] md:w-[calc(100vw-500px)]">
<img
src={p().banner_photo || "/blueprint.jpg"}
alt="post-cover"
class="h-full w-full object-cover select-none"
style={{
"pointer-events": "none"
}}
/>
<div class="fixed top-24 z-50 m-auto w-full px-4 text-center tracking-widest text-white backdrop-blur-md select-text text-shadow-lg backdrop:brightness-50 sm:top-36 md:top-[20vh] md:w-[calc(100vw-500px)]">
<div class="py-8 text-3xl font-semibold tracking-widest">
{p().title.replaceAll("_", " ")}
<Show when={p().subtitle}>
<div class="py-8 text-xl font-light tracking-widest">
{p().subtitle}
</div>
</Show>
</div>
</div>
</div>
</div>
<CustomScrollbar
autoHide={true}
autoHideDelay={1500}
rightOffset={250}
>
<div class="z-10 pt-80 backdrop-blur-[0.01px] sm:pt-96 md:pt-[50vh]">
{/* Content that slides over the fixed image */}
<div class="bg-base relative pb-24">
@@ -506,14 +502,14 @@ export default function PostPage() {
</div>
</div>
</div>
</CustomScrollbar>
</div>
</>
);
}}
</Show>
);
}}
</Show>
</div>
</>
);
}}
</Show>
);
}}
</Show>
</CustomScrollbar>
);
}

View File

@@ -692,7 +692,7 @@ button:active,
position: relative;
overflow: auto;
max-height: 60vh;
background-color: var(--color-crust);
background-color: #1a1a1a;
color: #fff;
font-family: "Source Code Pro", monospace;
border-radius: 0.5rem;
@@ -711,12 +711,16 @@ button:active,
/* Language header */
#post-content-body .language-header {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5rem 1rem;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
background-color: var(--color-mantle);
background-color: #1a1a1a;
color: var(--color-subtext1);
border-bottom: 1px solid var(--color-surface0);
border-top-left-radius: 0.375rem;
@@ -741,7 +745,7 @@ button:active,
text-align: right;
user-select: none;
pointer-events: none;
background-color: var(--color-crust);
background-color: #1a1a1a;
border-right: 1px solid var(--color-surface0);
color: var(--color-overlay0);
font-size: 0.875rem;
@@ -755,13 +759,13 @@ button:active,
padding-left: 4rem;
}
/* Copy button */
/* Copy button - now in header */
#post-content-body .copy-button {
position: absolute;
top: 0.5rem;
right: 0.5rem;
padding: 0.375rem 0.75rem;
font-size: 0.75rem;
position: relative;
top: unset;
right: unset;
padding: 0.25rem 0.625rem;
font-size: 0.625rem;
font-weight: 500;
border-radius: 0.25rem;
transition: all 0.2s;
@@ -770,6 +774,8 @@ button:active,
color: var(--color-text);
border: 1px solid var(--color-overlay0);
cursor: pointer;
text-transform: none;
letter-spacing: normal;
}
#post-content-body .copy-button:hover {