Skip to content

Commit

Permalink
feat(footer): add footer markdown render
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed Aug 3, 2023
1 parent 84ba4a8 commit ff572f6
Show file tree
Hide file tree
Showing 49 changed files with 234 additions and 178 deletions.
4 changes: 2 additions & 2 deletions src/GZCTF/ClientApp/src/components/ActionIconWithConfirm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ export const ActionIconWithConfirm: FC<ActionIconWithConfirmProps> = (props) =>
<Stack align="center" spacing={6}>
<Text
size="sm"
weight="bold"
fw="bold"
h="auto"
ta="center"
style={{
whiteSpace: 'pre-wrap',
textAlign: 'center',
}}
>
{props.message}
Expand Down
17 changes: 7 additions & 10 deletions src/GZCTF/ClientApp/src/components/AppFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,29 @@ import { Text, Stack, Divider, Anchor, Center } from '@mantine/core'
import MainIcon from '@Components/icon/MainIcon'
import { useFooterStyles, useIsMobile, useLogoStyles } from '@Utils/ThemeOverride'
import { useConfig } from '@Utils/useConfig'
import FooterRender from './FooterRender'

const AppFooter: FC = () => {
const { config } = useConfig()
const isMobile = useIsMobile()
const { classes } = useFooterStyles()
const { classes, theme } = useFooterStyles()
const { classes: logoClasses } = useLogoStyles()

const copyright = (
<Text
size="xs"
align="center"
weight={500}
fw={500}
color="dimmed"
sx={(theme) => ({ fontFamily: theme.fontFamilyMonospace })}
ff={theme.fontFamilyMonospace}
>
Copyright&nbsp;©&nbsp;2022-now&nbsp;
{isMobile && <br />}
<Anchor
href="https://github.com/GZTimeWalker"
color="dimmed"
size="sm"
weight={500}
fw={500}
sx={{ lineHeight: 1 }}
>
@GZTimeWalker
Expand All @@ -42,7 +43,7 @@ const AppFooter: FC = () => {
<Stack w="100%" align="center" spacing={2}>
<MainIcon style={{ maxWidth: isMobile ? 45 : 50, height: 'auto' }} />

<Text weight="bold" size={isMobile ? 28 : 36}>
<Text fw="bold" size={isMobile ? 28 : 36}>
GZ<span className={logoClasses.brand}>::</span>CTF
</Text>
</Stack>
Expand All @@ -56,11 +57,7 @@ const AppFooter: FC = () => {
<Divider label={copyright} labelPosition="center" />
)}

{config.footerInfo && (
<Text align="center" size="sm" color="dimmed">
{config.footerInfo}
</Text>
)}
{config.footerInfo && <FooterRender source={config.footerInfo} />}
</Stack>
</Center>
</div>
Expand Down
12 changes: 5 additions & 7 deletions src/GZCTF/ClientApp/src/components/ChallengeCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,22 @@ const ChallengeCard: FC<ChallengeCardProps> = (props: ChallengeCardProps) => {
>
<Stack spacing="sm" pos="relative" style={{ zIndex: 99 }}>
<Group noWrap position="apart" spacing="xs">
<Text lineClamp={1} weight={700} size={theme.fontSizes.lg}>
<Text lineClamp={1} fw={700} size={theme.fontSizes.lg}>
{challenge.title}
</Text>
{solved && <Icon path={mdiFlag} size={1} color={colorStr} />}
</Group>
<Divider />
<Group noWrap position="apart" align="start">
<Group noWrap position="center">
<Text align="center" weight={700} size={18} ff={theme.fontFamilyMonospace}>
<Text align="center" fw={700} size={18} ff={theme.fontFamilyMonospace}>
{challenge.score} pts
</Text>
</Group>
<Stack spacing="xs">
<Title order={6} align="center" mt={`calc(${theme.spacing.xs} / 2)`}>
{`${challenge.solved} `}
<Text color="dimmed" size="xs" inherit span>
<Text c="dimmed" size="xs" inherit span>
支队伍攻克
</Text>
</Title>
Expand All @@ -102,10 +102,8 @@ const ChallengeCard: FC<ChallengeCardProps> = (props: ChallengeCardProps) => {
classNames={tooltipClasses}
label={
<Stack spacing={0}>
<Text color={theme.colorScheme === 'dark' ? '' : 'dark'}>
{blood?.name}
</Text>
<Text size="xs" color="dimmed">
<Text c={theme.colorScheme === 'dark' ? '' : 'dark'}>{blood?.name}</Text>
<Text size="xs" c="dimmed">
{dayjs(blood?.submitTimeUTC).format('YY/MM/DD HH:mm:ss')}
</Text>
</Stack>
Expand Down
8 changes: 4 additions & 4 deletions src/GZCTF/ClientApp/src/components/ChallengeDetailModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const Countdown: FC<{ time: string }> = ({ time }) => {

return (
<Card w="5rem" p="0px 4px" ta="center">
<Text size="sm" weight={700}>
<Text size="sm" fw={700}>
{countdown.asSeconds() > 0 ? countdown.format('HH:mm:ss') : '00:00:00'}
</Text>
</Card>
Expand Down Expand Up @@ -323,7 +323,7 @@ const ChallengeDetailModal: FC<ChallengeDetailModalProps> = (props) => {
)}
<Title order={4}>{challenge?.title ?? title}</Title>
</Group>
<Text weight={700} sx={(theme) => ({ fontFamily: theme.fontFamilyMonospace })}>
<Text fw={700} ff={theme.fontFamilyMonospace}>
{challenge?.score ?? score} pts
</Text>
</Group>
Expand Down Expand Up @@ -403,7 +403,7 @@ const ChallengeDetailModal: FC<ChallengeDetailModalProps> = (props) => {
{isDynamic && challenge?.context?.instanceEntry && (
<Stack align="center">
<Group>
<Text size="sm" weight={600}>
<Text size="sm" fw={600}>
实例访问入口:
<Tooltip label="点击复制" withArrow classNames={tooltipClasses}>
<Code
Expand Down Expand Up @@ -440,7 +440,7 @@ const ChallengeDetailModal: FC<ChallengeDetailModalProps> = (props) => {
</Stack>
<Divider />
{solved ? (
<Text align="center" weight={700}>
<Text align="center" fw={700}>
该题目已被解出
</Text>
) : (
Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/ClientApp/src/components/ChallengePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const ChallengePanel: FC = () => {
checked={hideSolved}
onChange={(e) => setHideSolved(e.target.checked)}
label={
<Text size="md" weight={700}>
<Text size="md" fw={700}>
隐藏已解出
</Text>
}
Expand Down
81 changes: 81 additions & 0 deletions src/GZCTF/ClientApp/src/components/FooterRender.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { marked } from 'marked'
import { forwardRef } from 'react'
import { Sx, TypographyStylesProvider, createStyles } from '@mantine/core'
import { useIsMobile } from '@Utils/ThemeOverride'

interface MarkdownProps extends React.ComponentPropsWithoutRef<'div'> {
source: string
sx?: Sx | (Sx | undefined)[]
}

const useFooterStyles = createStyles((theme) => {
const sc = (dark: any, light: any) => (theme.colorScheme === 'dark' ? dark : light)
const cs = theme.colors

return {
root: {
overflowX: 'auto',
textAlign: 'center',
fontSize: theme.fontSizes.sm,
color: theme.fn.dimmed(),

'& p': {
wordBreak: 'break-word',
wordWrap: 'break-word',
overflow: 'hidden',
marginBottom: theme.spacing.xs,
},

'& :not(pre) > code': {
color: theme.fn.dimmed(),
whiteSpace: 'normal',
fontSize: '0.95em',
backgroundColor: 'transparent',
padding: `1px calc(${theme.spacing.xs} / 2)`,
border: 'none',
},

'& strong': {
color: cs.brand[sc(6, 7)],
},

'& a': {
color: theme.fn.dimmed(),
textDecoration: 'none',
transition: 'all 0.2s ease-in-out',
},

'& a:hover': {
textDecoration: 'none',
},
},
}
})

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

const isMobile = useIsMobile()

// replace `<mbr/>` with `<br />` for mobile
const mdSource = source.replace(/<mbr\/>/g, isMobile ? '<br />' : '')

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

export default FooterRender
2 changes: 1 addition & 1 deletion src/GZCTF/ClientApp/src/components/GameCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const GameCard: FC<GameCardProps> = ({ game, ...others }) => {
</Badge>
</Group>
</Group>
<Text weight={500} size="sm" lineClamp={3}>
<Text fw={500} size="sm" lineClamp={3}>
{summary}
</Text>
</Stack>
Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/ClientApp/src/components/GameNoticePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ const GameNoticePanel: FC = () => {
{filteredNotices.map((notice) => (
<List.Item key={notice.id} icon={iconMap.get(notice.type)}>
<Stack spacing={1}>
<Text size="xs" weight={700} color="dimmed">
<Text size="xs" fw={700} c="dimmed">
{dayjs(notice.time).format('YY/MM/DD HH:mm:ss')}
</Text>
<Text>{notice.content}</Text>
Expand Down
6 changes: 3 additions & 3 deletions src/GZCTF/ClientApp/src/components/MobilePostCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const MobilePostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
<Stack spacing="xs">
<Box onClick={() => navigate(`/posts/${post.id}`)}>
<Title order={3} pb={4}>
<Text span color="brand">
<Text span c="brand">
{post.isPinned ? '[置顶] ' : '>>> '}
</Text>
{post.title}
Expand All @@ -31,7 +31,7 @@ const MobilePostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
{post.tags && (
<Group position="left">
{post.tags.map((tag, idx) => (
<Text key={idx} size="sm" weight={700} span color="brand">
<Text key={idx} size="sm" fw={700} span c="brand">
{`#${tag}`}
</Text>
))}
Expand All @@ -58,7 +58,7 @@ const MobilePostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
<Avatar alt="avatar" src={post.authorAvatar} size="sm">
{post.authorName?.slice(0, 1) ?? 'A'}
</Avatar>
<Text weight={500} size="sm">
<Text fw={500} size="sm">
{post.authorName ?? 'Anonym'} 发布于 {dayjs(post.time).format('HH:mm, YY/MM/DD')}
</Text>
</Group>
Expand Down
10 changes: 5 additions & 5 deletions src/GZCTF/ClientApp/src/components/MobileScoreboardItemModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,27 +98,27 @@ const MobileScoreboardItemModal: FC<MobileScoreboardItemModalProps> = (props) =>
</Center>
<Group grow ta="center">
<Stack spacing={1}>
<Text weight={700} size="sm" className={classes.mono}>
<Text fw={700} size="sm" className={classes.mono}>
{item?.rank}
</Text>
<Text size="xs">总排名</Text>
</Stack>
{item?.organization && (
<Stack spacing={1}>
<Text weight={700} size="sm" className={classes.mono}>
<Text fw={700} size="sm" className={classes.mono}>
{item?.organizationRank}
</Text>
<Text size="xs">排名</Text>
</Stack>
)}
<Stack spacing={1}>
<Text weight={700} size="sm" className={classes.mono}>
<Text fw={700} size="sm" className={classes.mono}>
{item?.score}
</Text>
<Text size="xs">得分</Text>
</Stack>
<Stack spacing={1}>
<Text weight={700} size="sm" className={classes.mono}>
<Text fw={700} size="sm" className={classes.mono}>
{item?.solvedCount}
</Text>
<Text size="xs">攻克数量</Text>
Expand Down Expand Up @@ -185,7 +185,7 @@ const MobileScoreboardItemModal: FC<MobileScoreboardItemModalProps> = (props) =>
</Table>
</ScrollArea>
) : (
<Text py="1rem" weight={700}>
<Text py="1rem" fw={700}>
Ouch! 这支队伍还没有解出题目呢……
</Text>
)}
Expand Down
10 changes: 5 additions & 5 deletions src/GZCTF/ClientApp/src/components/PostCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ const PostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
<Avatar alt="avatar" src={post.authorAvatar} size="sm">
{post.authorName?.slice(0, 1) ?? 'A'}
</Avatar>
<Text weight={700}>
<Text fw={700}>
{post.authorName ?? 'Anonym'} 发布于 {dayjs(post.time).format('HH:mm, YY/MM/DD')}
</Text>
</Group>
<Text align="right">
<Anchor component={Link} to={`/posts/${post.id}`}>
<Text span weight={500} size="sm">
<Text span fw={500} size="sm">
查看详情 &gt;&gt;&gt;
</Text>
</Anchor>
Expand All @@ -60,7 +60,7 @@ const PostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
<Group position="apart">
<Title order={3}>
{post.isPinned && (
<Text span color="brand">
<Text span c="brand">
{'[置顶] '}
</Text>
)}
Expand All @@ -84,7 +84,7 @@ const PostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
) : (
<Title order={3}>
{post.isPinned && (
<Text span color="brand">
<Text span c="brand">
{'[置顶] '}
</Text>
)}
Expand All @@ -95,7 +95,7 @@ const PostCard: FC<PostCardProps> = ({ post, onTogglePinned }) => {
{post.tags && (
<Group>
{post.tags.map((tag, idx) => (
<Text key={idx} size="sm" weight={700} span color="brand">
<Text key={idx} size="sm" fw={700} span c="brand">
{`#${tag}`}
</Text>
))}
Expand Down
4 changes: 2 additions & 2 deletions src/GZCTF/ClientApp/src/components/RecentGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const RecentGame: FC<RecentGameProps> = ({ game, ...others }) => {

<Stack spacing={0} mt={16}>
<Group noWrap spacing={0} position="apart">
<Text size="sm" weight={700}>
<Text size="sm" fw={700}>
{status === GameStatus.Coming ? '开始于' : '结束于'}
</Text>
<Badge size="xs" color={color} variant="light">
Expand All @@ -103,7 +103,7 @@ const RecentGame: FC<RecentGameProps> = ({ game, ...others }) => {
</Badge>
</Group>
<Group noWrap spacing={0} position="apart">
<Text size="sm" weight={700}>
<Text size="sm" fw={700}>
{status === GameStatus.OnGoing ? '剩余时间' : '持续时间'}
</Text>
<Badge size="xs" color={color} variant="light">
Expand Down
Loading

0 comments on commit ff572f6

Please sign in to comment.