Skip to content

Commit

Permalink
feat: code highlight
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Sep 5, 2022
1 parent 0b09a1b commit 083a989
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 56 deletions.
7 changes: 6 additions & 1 deletion GZCTF/ClientApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"echarts": "^5.3.3",
"echarts-for-react": "^3.0.2",
"marked": "^4.1.0",
"prismjs": "^1.29.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^6.3.0",
Expand All @@ -42,20 +43,24 @@
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
"@types/marked": "^4.0.6",
"@types/node": "18.7.15",
"@types/prismjs": "^1.26.0",
"@types/react": "^18.0.18",
"@types/react-dom": "^18.0.6",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"@vitejs/plugin-react": "^2.1.0",
"axios": "^0.27.2",
"babel-plugin-prismjs": "^2.1.0",
"eslint": "8.23.0",
"form-data": "~4.0.0",
"lodash": "^4.17.21",
"prettier": "~2.7.1",
"rollup": "^2.79.0",
"swagger-typescript-api": "^10.0.1",
"tslib": "^2.4.0",
"typescript": "4.8.2",
"vite": "^3.1.0",
"vite-plugin-pages": "^0.26.0"
"vite-plugin-pages": "^0.26.0",
"vite-plugin-prismjs": "^0.0.8"
}
}
45 changes: 45 additions & 0 deletions GZCTF/ClientApp/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions GZCTF/ClientApp/src/components/ChallengeDetailModal.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import { marked } from 'marked'
import { FC, useEffect, useState } from 'react'
import React from 'react'
import {
ActionIcon,
Box,
Button,
Card,
Code,
Expand All @@ -18,16 +18,16 @@ import {
Text,
TextInput,
Title,
TypographyStylesProvider,
} from '@mantine/core'
import { useClipboard, useDisclosure, useInputState } from '@mantine/hooks'
import { showNotification, updateNotification } from '@mantine/notifications'
import { mdiCheck, mdiClose, mdiDownload, mdiLightbulbOnOutline, mdiLoading } from '@mdi/js'
import { Icon } from '@mdi/react'
import { showErrorNotification } from '@Utils/ApiErrorHandler'
import { useTypographyStyles } from '@Utils/ThemeOverride'
import { useTypographyStyles } from '@Utils/useTypographyStyles'
import api, { AnswerResult, ChallengeType } from '@Api'
import { ChallengeTagItemProps } from '../utils/ChallengeItem'
import MarkdownRender from './MarkdownRender'

interface ChallengeDetailModalProps extends ModalProps {
gameId: number
Expand Down Expand Up @@ -271,7 +271,7 @@ const ChallengeDetailModal: FC<ChallengeDetailModalProps> = (props) => {
<Stack justify="space-between" style={{ position: 'relative', minHeight: '20vh' }}>
<LoadingOverlay visible={!challenge} />
<Group grow noWrap position="right" align="flex-start" spacing={2}>
<TypographyStylesProvider className={classes.root} style={{ minHeight: '4rem' }}>
<Box className={classes.root} style={{ minHeight: '4rem' }}>
{challenge?.context?.url && (
<Popover
opened={downloadOpened}
Expand Down Expand Up @@ -305,8 +305,8 @@ const ChallengeDetailModal: FC<ChallengeDetailModalProps> = (props) => {
</Popover.Dropdown>
</Popover>
)}
<div dangerouslySetInnerHTML={{ __html: marked(challenge?.content ?? '') }} />
</TypographyStylesProvider>
<MarkdownRender source={challenge?.content ?? ''} />
</Box>
</Group>
{challenge?.hints && challenge.hints.length > 0 && (
<Stack spacing={2}>
Expand Down
36 changes: 36 additions & 0 deletions GZCTF/ClientApp/src/components/MarkdownRender.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { marked } from 'marked'
import Prism from 'prismjs'
import { forwardRef } from 'react'
import { TypographyStylesProvider } from '@mantine/core'
import { useTypographyStyles } from '@Utils/useTypographyStyles'

interface MarkdownProps extends React.ComponentPropsWithoutRef<'div'> {
source: string
}

export const MarkdownRender = forwardRef<HTMLDivElement, MarkdownProps>((props, ref) => {
const { classes, cx } = useTypographyStyles()
const { source, ...others } = props

marked.setOptions({
highlight(code, lang) {
if (Prism.languages[lang]) {
return Prism.highlight(code, Prism.languages[lang], lang)
} else {
return code
}
},
})

return (
<TypographyStylesProvider
ref={ref}
className={others.className ? cx(classes.root, others.className) : classes.root}
{...others}
>
<div dangerouslySetInnerHTML={{ __html: marked.parse(source) }} />
</TypographyStylesProvider>
)
})

export default MarkdownRender
11 changes: 4 additions & 7 deletions GZCTF/ClientApp/src/components/PostCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import dayjs from 'dayjs'
import { marked } from 'marked'
import { FC, useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import {
Expand All @@ -9,16 +8,16 @@ import {
Title,
Text,
Stack,
TypographyStylesProvider,
Avatar,
Anchor,
ActionIcon,
useMantineTheme,
} from '@mantine/core'
import { mdiPencilOutline, mdiPinOffOutline, mdiPinOutline } from '@mdi/js'
import { Icon } from '@mdi/react'
import { useTypographyStyles } from '@Utils/ThemeOverride'
import { useUserRole } from '@Utils/useUser'
import { PostInfoModel, Role } from '@Api'
import MarkdownRender from './MarkdownRender'
import { RequireRole } from './WithRole'

interface PostCardProps {
Expand All @@ -27,7 +26,7 @@ interface PostCardProps {
}

const PostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
const { classes, theme } = useTypographyStyles()
const theme = useMantineTheme()
const navigate = useNavigate()
const { role } = useUserRole()
const [disabled, setDisabled] = useState(false)
Expand Down Expand Up @@ -92,9 +91,7 @@ const PostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
{post.title}
</Title>
)}
<TypographyStylesProvider className={classes.root}>
<div dangerouslySetInnerHTML={{ __html: marked(post.summary) }} />
</TypographyStylesProvider>
<MarkdownRender source={post.summary} />
{post.tags && (
<Group>
{post.tags.map((tag) => (
Expand Down
11 changes: 4 additions & 7 deletions GZCTF/ClientApp/src/components/admin/PostEditCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { marked } from 'marked'
import { FC } from 'react'
import {
ActionIcon,
Expand All @@ -7,12 +6,12 @@ import {
Badge,
Card,
Title,
TypographyStylesProvider,
PaperProps,
useMantineTheme,
} from '@mantine/core'
import { mdiPinOffOutline, mdiPinOutline, mdiDeleteOutline, mdiPencilOutline } from '@mdi/js'
import { Icon } from '@mdi/react'
import { useTypographyStyles } from '@Utils/ThemeOverride'
import MarkdownRender from '@Components/MarkdownRender'
import { PostInfoModel } from '@Api'

interface PostEditCardProps extends PaperProps {
Expand All @@ -23,7 +22,7 @@ interface PostEditCardProps extends PaperProps {
}

const PostEditCard: FC<PostEditCardProps> = ({ post, onDelete, onEdit, onPin, ...props }) => {
const { classes, theme } = useTypographyStyles()
const theme = useMantineTheme()
return (
<Card shadow="sm" p="lg" {...props}>
<Stack>
Expand All @@ -50,9 +49,7 @@ const PostEditCard: FC<PostEditCardProps> = ({ post, onDelete, onEdit, onPin, ..
</ActionIcon>
</Group>
</Group>
<TypographyStylesProvider className={classes.root}>
<div dangerouslySetInnerHTML={{ __html: marked(post.summary) }} />
</TypographyStylesProvider>
<MarkdownRender source={post.summary} />
<Group position="right">
<Badge color="brand" variant="light">
{new Date(post.time).toLocaleString()}
Expand Down
10 changes: 3 additions & 7 deletions GZCTF/ClientApp/src/pages/games/[id]/Index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import dayjs from 'dayjs'
import { marked } from 'marked'
import { FC, useEffect, useState } from 'react'
import { Link, useNavigate, useParams } from 'react-router-dom'
import {
Expand All @@ -9,7 +8,6 @@ import {
Stack,
Text,
Title,
TypographyStylesProvider,
Center,
Alert,
Badge,
Expand All @@ -23,9 +21,10 @@ import { mdiAlertCircle, mdiCheck, mdiFlagOutline, mdiTimerSand } from '@mdi/js'
import { Icon } from '@mdi/react'
import CustomProgress from '@Components/CustomProgress'
import GameJoinModal from '@Components/GameJoinModal'
import MarkdownRender from '@Components/MarkdownRender'
import WithNavBar from '@Components/WithNavbar'
import { showErrorNotification } from '@Utils/ApiErrorHandler'
import { useBannerStyles, useTypographyStyles } from '@Utils/ThemeOverride'
import { useBannerStyles } from '@Utils/ThemeOverride'
import { usePageTitle } from '@Utils/usePageTitle'
import { useUser } from '@Utils/useUser'
import api, { GameJoinModel, ParticipationStatus } from '@Api'
Expand Down Expand Up @@ -97,7 +96,6 @@ const GameDetail: FC = () => {
})

const { classes, theme } = useBannerStyles()
const { classes: typographyClasses } = useTypographyStyles()

const startTime = dayjs(game?.start) ?? dayjs()
const endTime = dayjs(game?.end) ?? dayjs()
Expand Down Expand Up @@ -266,9 +264,7 @@ const GameDetail: FC = () => {
当前激活队伍已经成功报名,请耐心等待比赛开始。
</Alert>
)}
<TypographyStylesProvider className={typographyClasses.root}>
<div dangerouslySetInnerHTML={{ __html: marked(game?.content ?? '') }} />
</TypographyStylesProvider>
<MarkdownRender source={game?.content ?? ''} />
</Stack>
<GameJoinModal
title="补全报名信息"
Expand Down
Loading

0 comments on commit 083a989

Please sign in to comment.