mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-07-03 16:46:39 -04:00
switch to shiki for syntax highlighting
This commit is contained in:
@ -2,5 +2,5 @@
|
||||
margin-left: 0;
|
||||
padding-left: 1.25em;
|
||||
border-left: 0.25em solid var(--colors-link);
|
||||
color: var(--colors-mediumDark);
|
||||
color: var(--colors-medium-dark);
|
||||
}
|
||||
|
85
components/Code/Code.module.css
Normal file
85
components/Code/Code.module.css
Normal file
@ -0,0 +1,85 @@
|
||||
figure:has(.highlighted) {
|
||||
margin: 1em auto;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background-color: var(--colors-background-header);
|
||||
}
|
||||
|
||||
.highlighted {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
font-size: 0.9em;
|
||||
tab-size: 2px;
|
||||
border: 1px solid var(--colors-kinda-light);
|
||||
border-radius: 0.6em;
|
||||
}
|
||||
|
||||
.highlighted span {
|
||||
color: var(--shiki-light);
|
||||
font-style: var(--shiki-light-font-style);
|
||||
font-weight: var(--shiki-light-font-weight);
|
||||
text-decoration: var(--shiki-light-text-decoration);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .highlighted span {
|
||||
color: var(--shiki-dark);
|
||||
font-style: var(--shiki-dark-font-style);
|
||||
font-weight: var(--shiki-dark-font-weight);
|
||||
text-decoration: var(--shiki-dark-text-decoration);
|
||||
}
|
||||
|
||||
.highlighted[data-line-numbers] {
|
||||
counter-reset: line;
|
||||
}
|
||||
|
||||
.highlighted[data-line-numbers] > [data-line]::before {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-right: 1.5em;
|
||||
text-align: right;
|
||||
color: var(--colors-medium-light);
|
||||
counter-increment: line;
|
||||
content: counter(line);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.highlighted[data-line-numbers-max-digits="2"] > [data-line]::before {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.highlighted[data-line-numbers-max-digits="3"] > [data-line]::before {
|
||||
width: 1.75rem;
|
||||
}
|
||||
|
||||
.inline {
|
||||
padding: 0.2em 0.3em;
|
||||
font-size: 0.925em;
|
||||
page-break-inside: avoid;
|
||||
background-color: var(--colors-background-outer);
|
||||
border: 1px solid var(--colors-kinda-light);
|
||||
border-radius: 0.6em;
|
||||
}
|
||||
|
||||
.copyButton {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 3em;
|
||||
width: 3em;
|
||||
color: var(--colors-medium-dark);
|
||||
border: 1px solid var(--colors-kinda-light);
|
||||
border-top-right-radius: 0.6em;
|
||||
border-bottom-left-radius: 0.6em;
|
||||
background-color: var(--colors-background-header);
|
||||
backdrop-filter: saturate(180%) blur(5px);
|
||||
}
|
||||
|
||||
.copyButton > svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.copyButton:hover,
|
||||
.copyButton:focus-visible {
|
||||
color: var(--colors-link);
|
||||
}
|
@ -1,38 +1,41 @@
|
||||
import CodeBlock from "../CodeBlock";
|
||||
import CodeInline from "../CodeInline";
|
||||
import clsx from "clsx";
|
||||
import CopyButton from "../CopyButton";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import styles from "./Code.module.css";
|
||||
|
||||
export type CodeProps = ComponentPropsWithoutRef<"code"> & {
|
||||
forceBlock?: boolean;
|
||||
"data-language"?: string;
|
||||
"data-theme"?: string;
|
||||
};
|
||||
|
||||
// a simple wrapper component that "intelligently" picks between inline code and code blocks (w/ optional syntax
|
||||
// highlighting & a clipboard button)
|
||||
const Code = ({ forceBlock, className, children, ...rest }: CodeProps) => {
|
||||
// detect if this input has already been touched by prism.js via rehype
|
||||
const classNames = className?.split(" ");
|
||||
const prismEnabled = classNames?.includes("code-highlight");
|
||||
|
||||
if (prismEnabled || forceBlock) {
|
||||
const Code = ({
|
||||
"data-language": dataLanguage,
|
||||
"data-theme": dataTheme, // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
}: CodeProps) => {
|
||||
// detect if this input has already been touched by shiki via rehype-pretty-code
|
||||
if (dataLanguage) {
|
||||
// full multi-line code blocks with copy-to-clipboard button
|
||||
// automatic if highlighted by prism, otherwise can be forced (rather than inlined) with `forceBlock={true}`
|
||||
return (
|
||||
<CodeBlock
|
||||
highlight={prismEnabled && !classNames?.includes("language-plaintext")}
|
||||
withCopyButton
|
||||
className={className}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</CodeBlock>
|
||||
<>
|
||||
<CopyButton className={styles.copyButton} source={children} />
|
||||
<code className={clsx(styles.highlighted, className)} {...rest}>
|
||||
{children}
|
||||
</code>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// simple inline code in paragraphs, headings, etc. (never highlighted)
|
||||
return (
|
||||
<CodeInline className={className} {...rest}>
|
||||
<code className={clsx(styles.inline, className)} {...rest}>
|
||||
{children}
|
||||
</CodeInline>
|
||||
</code>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,122 +0,0 @@
|
||||
.codeBlock {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 1em auto;
|
||||
color: var(--colors-codeText);
|
||||
}
|
||||
|
||||
.codeBlock .code {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
font-size: 0.9em;
|
||||
tab-size: 2px;
|
||||
background-color: var(--colors-codeBackground);
|
||||
border: 1px solid var(--colors-kindaLight);
|
||||
border-radius: 0.6em;
|
||||
}
|
||||
|
||||
.codeBlock :global(.line-number)::before {
|
||||
display: inline-block;
|
||||
width: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
text-align: right;
|
||||
color: var(--colors-codeComment);
|
||||
content: attr(line);
|
||||
font-variant-numeric: tabular-nums;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.codeBlock :global(.code-line):first-of-type {
|
||||
margin-right: 3em;
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.comment),
|
||||
.codeBlock.highlight :global(.token.prolog),
|
||||
.codeBlock.highlight :global(.token.cdata) {
|
||||
color: var(--colors-codeComment);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.delimiter),
|
||||
.codeBlock.highlight :global(.token.boolean),
|
||||
.codeBlock.highlight :global(.token.keyword),
|
||||
.codeBlock.highlight :global(.token.selector),
|
||||
.codeBlock.highlight :global(.token.important),
|
||||
.codeBlock.highlight :global(.token.doctype),
|
||||
.codeBlock.highlight :global(.token.atrule),
|
||||
.codeBlock.highlight :global(.token.url) {
|
||||
color: var(--colors-codeKeyword);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.tag),
|
||||
.codeBlock.highlight :global(.token.builtin),
|
||||
.codeBlock.highlight :global(.token.regex) {
|
||||
color: var(--colors-codeNamespace);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.property),
|
||||
.codeBlock.highlight :global(.token.constant),
|
||||
.codeBlock.highlight :global(.token.variable),
|
||||
.codeBlock.highlight :global(.token.attr-value),
|
||||
.codeBlock.highlight :global(.token.class-name),
|
||||
.codeBlock.highlight :global(.token.string),
|
||||
.codeBlock.highlight :global(.token.char) {
|
||||
color: var(--colors-codeVariable);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.literal-property),
|
||||
.codeBlock.highlight :global(.token.attr-name) {
|
||||
color: var(--colors-codeAttribute);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.function) {
|
||||
color: var(--colors-codeLiteral);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.tag .punctuation),
|
||||
.codeBlock.highlight :global(.token.attr-value .punctuation) {
|
||||
color: var(--colors-codePunctuation);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.inserted) {
|
||||
color: var(--colors-codeAddition);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.deleted) {
|
||||
color: var(--colors-codeDeletion);
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.url) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.bold) {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.codeBlock.highlight :global(.token.italic) {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.cornerCopyButton {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 3em;
|
||||
width: 3em;
|
||||
color: var(--colors-mediumDark);
|
||||
border: 1px solid var(--colors-kindaLight);
|
||||
border-top-right-radius: 0.6em;
|
||||
border-bottom-left-radius: 0.6em;
|
||||
background-color: var(--colors-backgroundHeader);
|
||||
backdrop-filter: saturate(180%) blur(5px);
|
||||
}
|
||||
|
||||
.cornerCopyButton > svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.cornerCopyButton:hover,
|
||||
.cornerCopyButton:focus-visible {
|
||||
color: var(--colors-link);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import clsx from "clsx";
|
||||
import CopyButton from "../CopyButton";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import styles from "./CodeBlock.module.css";
|
||||
|
||||
export type CodeBlockProps = ComponentPropsWithoutRef<"div"> & {
|
||||
highlight?: boolean;
|
||||
withCopyButton?: boolean;
|
||||
};
|
||||
|
||||
const CodeBlock = ({ highlight, withCopyButton, className, children, ...rest }: CodeBlockProps) => {
|
||||
return (
|
||||
<div className={clsx(styles.codeBlock, highlight && styles.highlight)}>
|
||||
{withCopyButton && <CopyButton className={styles.cornerCopyButton} source={children} />}
|
||||
<code className={clsx(styles.code, className)} {...rest}>
|
||||
{children}
|
||||
</code>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CodeBlock;
|
@ -1,2 +0,0 @@
|
||||
export * from "./CodeBlock";
|
||||
export { default } from "./CodeBlock";
|
@ -1,8 +0,0 @@
|
||||
.codeInline {
|
||||
padding: 0.175em 0.3em;
|
||||
font-size: 0.925em;
|
||||
page-break-inside: avoid;
|
||||
background-color: var(--colors-codeBackground);
|
||||
border: 1px solid var(--colors-kindaLight);
|
||||
border-radius: 0.6em;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import clsx from "clsx";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import styles from "./CodeInline.module.css";
|
||||
|
||||
export type CodeInlineProps = ComponentPropsWithoutRef<"code">;
|
||||
|
||||
const CodeInline = ({ className, ...rest }: CodeInlineProps) => (
|
||||
<code className={clsx(styles.codeInline, className)} {...rest} />
|
||||
);
|
||||
|
||||
export default CodeInline;
|
@ -1,2 +0,0 @@
|
||||
export * from "./CodeInline";
|
||||
export { default } from "./CodeInline";
|
@ -2,9 +2,9 @@
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding: 1.25em 1.5em;
|
||||
border-top: 1px solid var(--colors-kindaLight);
|
||||
background-color: var(--colors-backgroundOuter);
|
||||
color: var(--colors-mediumDark);
|
||||
border-top: 1px solid var(--colors-kinda-light);
|
||||
background-color: var(--colors-background-outer);
|
||||
color: var(--colors-medium-dark);
|
||||
}
|
||||
|
||||
.row {
|
||||
@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
.link {
|
||||
color: var(--colors-mediumDark) !important;
|
||||
color: var(--colors-medium-dark) !important;
|
||||
}
|
||||
|
||||
.link:has(.icon):hover,
|
||||
@ -32,7 +32,7 @@
|
||||
|
||||
.link.underline:hover,
|
||||
.link.underline:focus-visible {
|
||||
border-bottom-color: var(--colors-kindaLight);
|
||||
border-bottom-color: var(--colors-kinda-light);
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
@ -2,8 +2,8 @@
|
||||
width: 100%;
|
||||
height: 4.5em;
|
||||
padding: 0.7em 1.5em;
|
||||
border-bottom: 1px solid var(--colors-kindaLight);
|
||||
background-color: var(--colors-backgroundHeader);
|
||||
border-bottom: 1px solid var(--colors-kinda-light);
|
||||
background-color: var(--colors-background-header);
|
||||
|
||||
/* make sticky */
|
||||
position: sticky;
|
||||
@ -25,7 +25,7 @@
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
color: var(--colors-mediumDark) !important;
|
||||
color: var(--colors-medium-dark) !important;
|
||||
}
|
||||
|
||||
.homeLink:hover,
|
||||
@ -63,7 +63,7 @@
|
||||
|
||||
.homeLink:hover .homeImage,
|
||||
.homeLink:focus-visible .homeImage {
|
||||
border-color: var(--colors-linkUnderline);
|
||||
border-color: var(--colors-link-underline);
|
||||
}
|
||||
|
||||
.name {
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
.h.divider {
|
||||
padding-bottom: 0.25em;
|
||||
border-bottom: 1px solid var(--colors-kindaLight);
|
||||
border-bottom: 1px solid var(--colors-kinda-light);
|
||||
}
|
||||
|
||||
.anchor {
|
||||
|
@ -3,7 +3,7 @@
|
||||
text-decoration: none;
|
||||
|
||||
/* fancy underline */
|
||||
background-image: linear-gradient(var(--colors-linkUnderline), var(--colors-linkUnderline));
|
||||
background-image: linear-gradient(var(--colors-link-underline), var(--colors-link-underline));
|
||||
background-position: 0% 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 0% 2px;
|
||||
|
@ -7,7 +7,7 @@
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
animation: loading 1.5s infinite ease-in-out both;
|
||||
background-color: var(--colors-mediumLight);
|
||||
background-color: var(--colors-medium-light);
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
|
@ -1,19 +1,19 @@
|
||||
.link {
|
||||
display: inline-block;
|
||||
color: var(--colors-mediumDark) !important;
|
||||
color: var(--colors-medium-dark) !important;
|
||||
padding: 0.6em;
|
||||
}
|
||||
|
||||
/* indicate active page/section */
|
||||
.link.current {
|
||||
margin-bottom: -0.2em;
|
||||
border-bottom: 0.2em solid var(--colors-linkUnderline);
|
||||
border-bottom: 0.2em solid var(--colors-link-underline);
|
||||
}
|
||||
|
||||
.link:not(.current):hover,
|
||||
.link:not(.current):focus-visible {
|
||||
margin-bottom: -0.2em;
|
||||
border-bottom: 0.2em solid var(--colors-kindaLight);
|
||||
border-bottom: 0.2em solid var(--colors-kinda-light);
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
@ -9,6 +9,6 @@
|
||||
.slug::before {
|
||||
content: "\002E\002F"; /* "./" */
|
||||
letter-spacing: 0.1em;
|
||||
color: var(--colors-mediumLight);
|
||||
color: var(--colors-medium-light);
|
||||
margin-right: -0.1em;
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ https://github.com/reach/reach-ui/blob/main/packages/skip-nav/styles.css */
|
||||
width: auto;
|
||||
height: auto;
|
||||
clip: auto;
|
||||
background: var(--colors-superDuperLight);
|
||||
background: var(--colors-super-duper-light);
|
||||
color: var(--colors-link);
|
||||
border: 2px solid var(--colors-kindaLight);
|
||||
border: 2px solid var(--colors-kinda-light);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
margin-right: -0.6em;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
color: var(--colors-mediumDark);
|
||||
color: var(--colors-medium-dark);
|
||||
}
|
||||
|
||||
.toggle:hover,
|
||||
|
Reference in New Issue
Block a user