Skip to content

Commit

Permalink
feat: add fetchLeetCodeQuestionData function to LinkCard (#439)
Browse files Browse the repository at this point in the history
* fix: location reload not working (#431)

* fix(deps): update all non-major dependencies (patch) (#427)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat: add fetchLeetCodeQuestionData function to LinkCard

* refactor: optimize fetchLeetCodeQuestionData function in LinkCard

* refactor: optimize fetchLeetCodeQuestionData function in LinkCard

feat: batch request of leetcode
refactor: optimize fetchLeetCodeQuestionData function in LinkCard and add BlockLinkRenderer  imp

* refactor: optimize fetchLeetCodeQuestionData function in LinkCard and update API_URL

* fix:TMDB api had changed
ref:https://developer.themoviedb.org/docs/append-to-response

---------

Co-authored-by: Suemor <suemor233@outlook.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
3 people authored and Innei committed Aug 23, 2024
1 parent 7d82c00 commit 3ce4bc8
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 3 deletions.
4 changes: 3 additions & 1 deletion src/app/api/tmdb/[...all]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ export const GET = async (req: NextRequest) => {
const searchString = query.toString()

const url = `https://api.themoviedb.org/3/${pathname.join('/')}${
searchString ? `?${searchString}` : ''
searchString
? `?${searchString}&api_key=${process.env.TMDB_API_KEY}`
: `?api_key=${process.env.TMDB_API_KEY}`
}`

const headers = new Headers()
Expand Down
4 changes: 3 additions & 1 deletion src/app/global-error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export default function GlobalError({
<h1 className="mb-4">禁止访问或者 API 服务出现问题</h1>
<div className="flex justify-center">
<LazyMotion features={domAnimation}>
<StyledButton onClick={location.reload}>重试</StyledButton>
<StyledButton onClick={() => location.reload()}>
重试
</StyledButton>
</LazyMotion>
</div>
</NormalContainer>
Expand Down
113 changes: 113 additions & 0 deletions src/components/ui/link-card/LinkCard.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable unicorn/switch-case-braces */
import { simpleCamelcaseKeys as camelcaseKeys } from '@mx-space/api-client'
import { m, useMotionTemplate, useMotionValue } from 'framer-motion'
import Link from 'next/link'
Expand All @@ -11,6 +12,7 @@ import uniqolor from 'uniqolor'
import { LazyLoad } from '~/components/common/Lazyload'
import { MingcuteStarHalfFill } from '~/components/icons/star'
import { usePeek } from '~/components/modules/peek/usePeek'
import { API_URL } from '~/constants/env'
import { LanguageToColorMap } from '~/constants/language'
import { useIsClientTransition } from '~/hooks/common/use-is-client'
import useIsCommandOrControlPressed from '~/hooks/common/use-is-command-or-control-pressed'
Expand Down Expand Up @@ -93,6 +95,7 @@ const LinkCardImpl: FC<LinkCardProps> = (props) => {
[LinkCardSource.GHCommit]: fetchGitHubCommitData,
[LinkCardSource.GHPr]: fetchGitHubPRData,
[LinkCardSource.Self]: fetchMxSpaceData,
[LinkCardSource.LEETCODE]: fetchLeetCodeQuestionData,
} as Record<LinkCardSource, FetchObject>
if (tmdbEnabled)
fetchDataFunctions[LinkCardSource.TMDB] = fetchTheMovieDBData
Expand Down Expand Up @@ -508,3 +511,113 @@ const fetchTheMovieDBData: FetchObject = {
json.homepage && setFullUrl(json.homepage)
},
}

const fetchLeetCodeQuestionData: FetchObject = {
isValid: (id) => {
// 检查 titleSlug 是否是一个有效的字符串
return typeof id === 'string' && id.length > 0
},
fetch: async (id, setCardInfo, setFullUrl) => {
try {
//获取题目信息
const body = {
query: `query questionData($titleSlug: String!) {\n question(titleSlug: $titleSlug) {translatedTitle\n difficulty\n likes\n topicTags { translatedName\n }\n stats\n }\n}\n`,
variables: { titleSlug: id },
}
const questionData = await fetch(`${API_URL}/fn/leetcode/shiro`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
}).then(async (res) => {
if (!res.ok) {
throw new Error('Failed to fetch LeetCode question title')
}
return res.json()
})
const questionTitleData = camelcaseKeys(questionData.data.question)
const stats = JSON.parse(questionTitleData.stats)
// 设置卡片信息
setCardInfo({
title: (
<>
<span className="flex items-center gap-2">
<span className="flex-1">
{questionTitleData.translatedTitle}
</span>
<span className="shrink-0 self-end justify-self-end">
{questionTitleData.likes > 0 && (
<span className="inline-flex shrink-0 items-center gap-1 self-center text-sm text-orange-400 dark:text-yellow-500">
<i className="icon-[mingcute--thumb-up-line]" />
<span className="font-sans font-medium">
{questionTitleData.likes}
</span>
</span>
)}
</span>
</span>
</>
),
desc: (
<>
<span
className={`mr-4 font-bold ${getDifficultyColorClass(questionTitleData.difficulty)}`}
>
{questionTitleData.difficulty}
</span>
<span className="overflow-hidden">
{questionTitleData.topicTags
.map((tag: any) => tag.translatedName)
.join(' / ')}
</span>
<span className="float-right overflow-hidden">
AR: {stats.acRate}
</span>
</>
),
image:
'https://upload.wikimedia.org/wikipedia/commons/1/19/LeetCode_logo_black.png',
color: getDifficultyColor(questionTitleData.difficulty),
})

setFullUrl(`https://leetcode.cn/problems/${id}/description`)
} catch (err) {
console.error('Error fetching LeetCode question data:', err)
throw err
}
},
}

// 映射难度到颜色的函数
function getDifficultyColor(difficulty: string) {
switch (difficulty) {
case 'Easy':
return '#00BFA5'
case 'Medium':
return '#FFA726'
case 'Hard':
return '#F44336'
default:
return '#757575'
}
}

// 难度字体颜色className
function getDifficultyColorClass(difficulty: string) {
switch (difficulty) {
case 'Easy':
return 'text-green-500'
case 'Medium':
return 'text-yellow-500'
case 'Hard':
return 'text-red-500'
default:
return 'text-gray-500'
}
}

interface LeetCodeResponse {
query: string
variables: Record<string, any>
}
1 change: 1 addition & 0 deletions src/components/ui/link-card/enums.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export enum LinkCardSource {
GHCommit = 'gh-commit',
GHPr = 'gh-pr',
TMDB = 'tmdb',
LEETCODE = 'leetcode',
}
12 changes: 12 additions & 0 deletions src/components/ui/markdown/renderers/LinkRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
isGithubPrUrl,
isGithubRepoUrl,
isGithubUrl,
isLeetCodeUrl,
isSelfArticleUrl,
isSelfThinkingUrl,
isTMDBUrl,
Expand Down Expand Up @@ -144,6 +145,17 @@ export const BlockLinkRenderer = ({

return fallbackElement
}

case isLeetCodeUrl(url): {
return (
<LinkCard
fallbackUrl={url.toString()}
source={LinkCardSource.LEETCODE}
id={url.pathname.split('/')[2]}
/>
)
}

case isBilibiliVideoUrl(url): {
const { id } = parseBilibiliVideoUrl(url)

Expand Down
4 changes: 3 additions & 1 deletion src/lib/link-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { isClientSide, isDev } from './env'
export const getTweetId = (url: URL) => url.pathname.split('/').pop()!

const GITHUB_HOST = 'github.com'

export const isLeetCodeUrl = (url: URL) => {
return url.hostname === 'leetcode.cn' || url.hostname === 'leetcode.com'
}
export const isGithubRepoUrl = (url: URL) =>
url.hostname === GITHUB_HOST &&
url.pathname.startsWith('/') &&
Expand Down

0 comments on commit 3ce4bc8

Please sign in to comment.