Skip to content

Commit

Permalink
feat: add code block
Browse files Browse the repository at this point in the history
  • Loading branch information
CaliCastle committed Jun 9, 2023
1 parent 6983e29 commit 05fc03a
Show file tree
Hide file tree
Showing 16 changed files with 835 additions and 127 deletions.
3 changes: 2 additions & 1 deletion app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import '~/app/globals.css'
import './globals.css'
import './clerk.css'
import './prism.css'

import { ClerkProvider } from '@clerk/nextjs'
import { type Metadata } from 'next'
Expand Down
151 changes: 151 additions & 0 deletions app/prism.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
.prismjs {
--tw-prose-pre-bg: rgba(245, 245, 245, .05);
--tw-prose-pre-code: theme('colors.zinc.600');
background: linear-gradient(to top, rgba(235, 235, 235, .3) 0%, rgba(255, 255, 255, 0.1) 100%);
}

.dark {
.prismjs {
--tw-prose-pre-bg: rgba(5, 5, 5, .05);
--tw-prose-pre-code: theme('colors.zinc.300');
background: linear-gradient(to bottom, rgba(35, 35, 35, .4) 0%, rgba(0, 0, 0, 0.2) 100%);
}
}

.token.tag,
.token.class-name,
.token.selector,
.token.selector .class,
.token.selector.class,
.token.function {
@apply text-blue-700;
}

.token.attr-name,
.token.keyword,
.token.module,
.token.rule,
.token.pseudo-class,
.token.important {
@apply text-orange-700;
}

.token.attr-value,
.token.class,
.token.string {
@apply text-sky-700;
}

.token.attr-value * {
@apply text-sky-700;
}

.token.property {
@apply text-sky-700;
}

.token.unit {
@apply text-teal-800;
}

.language-css .token.function {
@apply text-teal-800;
}

.dark {
.token.tag,
.token.class-name,
.token.selector,
.token.selector .class,
.token.selector.class,
.token.function {
@apply text-blue-300;
}

.token.attr-name,
.token.keyword,
.token.module,
.token.rule,
.token.pseudo-class,
.token.important {
@apply text-orange-300;
}

.token.attr-value,
.token.class,
.token.string {
@apply text-sky-300;
}

.token.attr-value * {
@apply text-sky-300;
}

.token.property {
@apply text-sky-300;
}

.token.unit {
@apply text-teal-200;
}

.language-css .token.function {
@apply text-teal-200;
}
}

.token.punctuation,
.token.attr-equals {
@apply text-zinc-500;
}

.token.attr-value .attr-equals,
.token.attr-value .attr-equals + .punctuation,
.token.attr-value > .punctuation:last-child {
@apply text-zinc-500;
}

.language-shell .token:not(.comment),
.token.atapply .token:not(.rule):not(.important):not(.punctuation) {
color: inherit;
}

.token.comment,
.token.operator,
.token.combinator {
@apply text-zinc-400;
}

.token.unchanged {
@apply block;
}

.token.deleted,
.token.inserted {
@apply block relative -mx-9 pl-8 pr-5 border-l-4 before:absolute before:top-0 before:left-4;
}

.token.inserted {
@apply bg-teal-400/[0.15] border-teal-400 before:content-['+'] before:text-teal-400;
}

.token.deleted {
@apply bg-rose-500/[0.15] border-rose-400 before:content-['-'] before:text-rose-400;
}

pre[class^='language-diff-'] {
@apply flex px-9;
}

pre[class^='language-diff-'] > code {
@apply flex-none min-w-full;
}

/* targets the `­` in a code example */
span.code-highlight.bg-code-highlight:has(> span[title*="\AD"]) {
@apply bg-pink-500/10 text-pink-400 mx-[1px];
}

.comment.linenumber {
@apply opacity-40;
}
22 changes: 22 additions & 0 deletions assets/icons/ClipboardCheckIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { type IconProps } from '~/assets'

export function ClipboardCheckIcon(props: IconProps = {}) {
return (
<svg
width="1em"
height="1em"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M16 4.03837C16 4.02576 16 4.01297 16 4C16 3.53501 16 3.30252 15.9489 3.11177C15.8102 2.59413 15.4059 2.18981 14.8882 2.05111C14.6975 2 14.465 2 14 2H10C9.53501 2 9.30252 2 9.11177 2.05111C8.59413 2.18981 8.18981 2.59413 8.05111 3.11177C8 3.30252 8 3.53501 8 4C8 4.01297 8 4.02576 8 4.03838M16 4.03837C16 4.47792 15.9986 4.7028 15.9489 4.88823C15.8102 5.40587 15.4059 5.81019 14.8882 5.94889C14.6975 6 14.465 6 14 6H10C9.53501 6 9.30252 6 9.11177 5.94889C8.59413 5.81019 8.18981 5.40587 8.05111 4.88823C8.00143 4.7028 8.00004 4.47793 8 4.03838M16 4.03837C16.7844 4.08627 17.3409 4.19394 17.816 4.43597C18.5686 4.81947 19.1805 5.43139 19.564 6.18404C20 7.03969 20 8.15979 20 10.4V15.6C20 17.8402 20 18.9603 19.564 19.816C19.1805 20.5686 18.5686 21.1805 17.816 21.564C16.9603 22 15.8402 22 13.6 22H10.4C8.15979 22 7.03968 22 6.18404 21.564C5.43139 21.1805 4.81947 20.5686 4.43597 19.816C4 18.9603 4 17.8402 4 15.6V10.4C4 8.15979 4 7.03969 4.43597 6.18404C4.81947 5.43139 5.43139 4.81947 6.18404 4.43597C6.65905 4.19394 7.21558 4.08627 8 4.03838M9 13.6663L11.3412 16.005C12.4672 14.0361 14.0256 12.3484 15.8987 11.0693"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
24 changes: 24 additions & 0 deletions assets/icons/ClipboardDataIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react'

import { type IconProps } from '~/assets'

export function ClipboardDataIcon(props: IconProps = {}) {
return (
<svg
width="1em"
height="1em"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M16 4.03837C16 4.02576 16 4.01297 16 4C16 3.53501 16 3.30252 15.9489 3.11177C15.8102 2.59413 15.4059 2.18981 14.8882 2.05111C14.6975 2 14.465 2 14 2H10C9.53501 2 9.30252 2 9.11177 2.05111C8.59413 2.18981 8.18981 2.59413 8.05111 3.11177C8 3.30252 8 3.53501 8 4C8 4.01297 8 4.02576 8 4.03838M16 4.03837C16 4.47792 15.9986 4.7028 15.9489 4.88823C15.8102 5.40587 15.4059 5.81019 14.8882 5.94889C14.6975 6 14.465 6 14 6H10C9.53501 6 9.30252 6 9.11177 5.94889C8.59413 5.81019 8.18981 5.40587 8.05111 4.88823C8.00143 4.7028 8.00004 4.47793 8 4.03838M16 4.03837C16.7844 4.08627 17.3409 4.19394 17.816 4.43597C18.5686 4.81947 19.1805 5.43139 19.564 6.18404C20 7.03969 20 8.15979 20 10.4V15.6C20 17.8402 20 18.9603 19.564 19.816C19.1805 20.5686 18.5686 21.1805 17.816 21.564C16.9603 22 15.8402 22 13.6 22H10.4C8.15979 22 7.03968 22 6.18404 21.564C5.43139 21.1805 4.81947 20.5686 4.43597 19.816C4 18.9603 4 17.8402 4 15.6V10.4C4 8.15979 4 7.03969 4.43597 6.18404C4.81947 5.43139 5.43139 4.81947 6.18404 4.43597C6.65905 4.19394 7.21558 4.08627 8 4.03838M8 11H8.001M8 16H8.001M11 11H16M11 16H16"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
2 changes: 2 additions & 0 deletions assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export { BilibiliIcon } from './icons/BilibiliIcon'
export { BriefcaseIcon } from './icons/BriefcaseIcon'
export { CalendarIcon } from './icons/CalendarIcon'
export { CheckDoubleTickIcon } from './icons/CheckDoubleTickIcon'
export { ClipboardCheckIcon } from './icons/ClipboardCheckIcon'
export { ClipboardDataIcon } from './icons/ClipboardDataIcon'
export { CloudIcon } from './icons/CloudIcon'
export { CursorClickIcon } from './icons/CursorClickIcon'
export { CursorIcon } from './icons/CursorIcon'
Expand Down
135 changes: 22 additions & 113 deletions components/PostPortableText.tsx
Original file line number Diff line number Diff line change
@@ -1,127 +1,36 @@
'use client'

import { PortableText, type PortableTextComponents } from '@portabletext/react'
import Image from 'next/image'
import React from 'react'
import { Tweet } from 'react-tweet'

import { ClientOnly } from '~/components/ClientOnly'
import { Commentable } from '~/components/Commentable'
import { PeekabooLink } from '~/components/links/PeekabooLink'
import {
PortableTextBlocksBlockquote,
PortableTextBlocksH1,
PortableTextBlocksH2,
PortableTextBlocksH3,
PortableTextBlocksH4,
PortableTextBlocksListItem,
PortableTextBlocksNormal,
} from '~/components/portable-text/PortableTextBlocks'
import { PortableTextCodeBlock } from '~/components/portable-text/PortableTextCodeBlock'
import { PortableTextImage } from '~/components/portable-text/PortableTextImage'
import { PortableTextTweet } from '~/components/portable-text/PortableTextTweet'

const components: PortableTextComponents = {
block: {
normal: ({ value, children }) => {
const isEmpty = !Boolean(
value.children
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
.map((child) => ('text' in child ? child.text : ''))
.join('')
)

return (
<p
data-blockid={isEmpty ? undefined : value._key}
className="group relative"
>
{!isEmpty && (
<ClientOnly>
<Commentable blockId={value._key} />
</ClientOnly>
)}
{children}
</p>
)
},
h1: ({ value, children }) => {
return (
<h1 data-blockid={value._key} className="group relative">
<ClientOnly>
<Commentable blockId={value._key} />
</ClientOnly>
{children}
</h1>
)
},
h2: ({ value, children }) => {
return (
<h2 data-blockid={value._key} className="group relative">
<ClientOnly>
<Commentable blockId={value._key} />
</ClientOnly>
{children}
</h2>
)
},
h3: ({ value, children }) => {
return (
<h3 data-blockid={value._key} className="group relative">
<ClientOnly>
<Commentable blockId={value._key} />
</ClientOnly>
{children}
</h3>
)
},
h4: ({ value, children }) => {
return (
<h4 data-blockid={value._key} className="group relative">
<ClientOnly>
<Commentable blockId={value._key} />
</ClientOnly>
{children}
</h4>
)
},
blockquote: ({ value, children }) => {
return (
<blockquote data-blockid={value._key} className="group relative">
<ClientOnly>
<Commentable blockId={value._key} />
</ClientOnly>
{children}
</blockquote>
)
},
},
listItem: ({ value, children }) => {
return (
<li data-blockid={value._key} className="group relative">
<ClientOnly>
<Commentable className="mr-5" blockId={value._key} />
</ClientOnly>
{children}
</li>
)
normal: PortableTextBlocksNormal,
h1: PortableTextBlocksH1,
h2: PortableTextBlocksH2,
h3: PortableTextBlocksH3,
h4: PortableTextBlocksH4,
blockquote: PortableTextBlocksBlockquote,
},
listItem: PortableTextBlocksListItem,
types: {
image: ({ value }) => {
return (
<div data-blockid={value._key} className="group relative">
<ClientOnly>
<Commentable blockId={value._key} />
</ClientOnly>

<Image
src={value.url}
width={value.dimensions.width}
height={value.dimensions.height}
unoptimized
placeholder={value.lqip ? 'blur' : 'empty'}
blurDataURL={value.lqip}
className="relative z-20 rounded-xl md:rounded-3xl"
alt=""
/>
</div>
)
},
tweet: ({ value }) => (
<ClientOnly>
<div className="flex justify-center">
<Tweet id={value.id} />
</div>
</ClientOnly>
),
image: PortableTextImage,
tweet: PortableTextTweet,
codeBlock: PortableTextCodeBlock,
},

marks: {
Expand Down
Loading

0 comments on commit 05fc03a

Please sign in to comment.