diff --git a/content/posts/JOURNAL/2025-recap.mdx b/content/posts/JOURNAL/2025-recap.mdx index cb89006..9696a05 100644 --- a/content/posts/JOURNAL/2025-recap.mdx +++ b/content/posts/JOURNAL/2025-recap.mdx @@ -241,16 +241,26 @@ draft: false caption="팀 프로젝트" /> - - COMMA : 오락실 감성을 담은 미니게임과 커뮤니티로 ‘잠깐의 쉼표’를 제공하는 - 플랫폼 `Vue`, `Kaplay` - - RoomE : 몰입감 있는 3D 공간에서 ‘나’를 표현하고, 취향 - 기반으로 연결되는 힐링 커뮤니티 플랫폼 `React` `R3F` - - RoomE-BO : RoomE의 - 백오피스, GA를 통한 데이터 수집 후 시각화 통계 자료 제공 `React` , `Recharts` - - Slice : 오늘의 할 일을 작은 조각으로 나누어 가볍게 완성해가는 Todo 서비스 - `Next`, `Storybook` , `Tanstak` + + +• COMMA : 오락실 감성을 담은 미니게임과 커뮤니티로 ‘잠깐의 쉼표’를 제공하는 플랫폼{" "} +COMMA + + +• RoomE : 몰입감 있는 3D 공간에서 ‘나’를 표현하고 취향 기반으로 연결되는 힐링 커뮤니티 플랫폼{" "} +RoomE + + +• RoomE-BO : RoomE의 백오피스, 데이터 수집 및 시각화 제공{" "} +RoomE-BO + + +• Slice : 오늘의 할 일을 작은 조각으로 나누어 완성해가는 Todo 서비스{" "} +Slice + +
- - MediaWave : 지금 뜨는 영화·시리즈를 한눈에, 취향 맞춤 추천과 솔직한 리뷰로 - 즐기는 커뮤니티 `Firebase`, `Redux` - - RoomE 리팩토링 : 기존 2D로 제작되었던 - 음악 페이지를 `R3F` + `Three.js` 도입하여 3D로 리팩토링 진행 - - B-log : 개인 - 기술 블로그 `Next` , `Supabase` , `Velite` + + +• MediaWave : 지금 뜨는 영화·시리즈를 한눈에, 취향 맞춤 추천과 솔직한 리뷰로 즐기는 커뮤니티{" "} +MediaWave + + +• RoomE 리팩토링 : 기존 2D로 제작되었던 음악 페이지를 3D 기술을 도입하여 리팩토링 진행 {" "} +RoomE + + +• B-log : 개인 기술 블로그{" "} +B-log --- diff --git a/package.json b/package.json index c13df27..2f2bbf7 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "react-dom": "19.2.0", "react-icons": "^5.5.0", "rehype-autolink-headings": "^7.1.0", - "rehype-slug": "^6.0.0" + "rehype-slug": "^6.0.0", + "remark-link-card-plus": "^0.7.3" }, "devDependencies": { "@svgr/webpack": "^8.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d978830..93f059f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: rehype-slug: specifier: ^6.0.0 version: 6.0.0 + remark-link-card-plus: + specifier: ^0.7.3 + version: 0.7.3 devDependencies: '@svgr/webpack': specifier: ^8.1.0 @@ -767,6 +770,9 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@borewit/text-codec@0.2.1': + resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -1818,6 +1824,13 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -2384,6 +2397,16 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.1.2: + resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} + engines: {node: '>=20.18.1'} + ci-info@4.3.1: resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} @@ -2640,6 +2663,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} @@ -2911,6 +2937,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-type@21.3.0: + resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} + engines: {node: '>=20'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -3138,6 +3168,12 @@ packages: html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + htmlparser2@10.0.0: + resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -3159,6 +3195,13 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -3292,6 +3335,10 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -4050,6 +4097,10 @@ packages: oniguruma-to-es@4.3.4: resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + open-graph-scraper@6.11.0: + resolution: {integrity: sha512-KkO3qMMzJj9KYGtCl19dRtncb+RuBiG/P9BgukcAG4p2w9wSAWTE90vL6/xqth1K9ThkYF/+xfTGrVvU79TJtQ==} + engines: {node: '>=20.0.0'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -4099,6 +4150,15 @@ packages: parse-numeric-range@1.3.0: resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==} + parse-srcset@1.0.2: + resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} + + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} @@ -4336,6 +4396,10 @@ packages: remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-link-card-plus@0.7.3: + resolution: {integrity: sha512-abWy0PeihkWYvQP2rPSORdXviJrpn/v7K1P7PQyhqz6JIQs55Jwb0QHcnykCmjIdLYKUL2UmTGfva2yB8iakUw==} + engines: {node: '>=20'} + remark-mdx@3.1.1: resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} @@ -4401,6 +4465,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sanitize-html@2.17.0: + resolution: {integrity: sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==} + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -4607,6 +4674,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strtok3@10.3.4: + resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + engines: {node: '>=18'} + style-to-js@1.1.19: resolution: {integrity: sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ==} @@ -4691,6 +4762,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + tough-cookie@5.1.2: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} @@ -4807,6 +4882,10 @@ packages: engines: {node: '>=0.8.0'} hasBin: true + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -4814,6 +4893,10 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@7.18.2: + resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} + engines: {node: '>=20.18.1'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -5861,6 +5944,8 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@borewit/text-codec@0.2.1': {} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -6902,6 +6987,15 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + '@trysound/sax@0.2.0': {} '@tsconfig/node10@1.0.11': {} @@ -7496,6 +7590,31 @@ snapshots: character-reference-invalid@2.0.1: {} + chardet@2.1.1: {} + + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.1.2: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.0.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.18.2 + whatwg-mimetype: 4.0.0 + ci-info@4.3.1: {} cjs-module-lexer@2.1.1: {} @@ -7734,6 +7853,11 @@ snapshots: emoji-regex@9.2.2: {} + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 @@ -8202,6 +8326,15 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-type@21.3.0: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.4 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -8494,6 +8627,20 @@ snapshots: html-void-elements@3.0.0: {} + htmlparser2@10.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 6.0.1 + + htmlparser2@8.0.2: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 4.5.0 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -8516,6 +8663,12 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.5: {} @@ -8641,6 +8794,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-plain-object@5.0.0: {} + is-potential-custom-element-name@1.0.1: {} is-regex@1.2.1: @@ -9856,6 +10011,13 @@ snapshots: regex: 6.1.0 regex-recursion: 6.0.2 + open-graph-scraper@6.11.0: + dependencies: + chardet: 2.1.1 + cheerio: 1.1.2 + iconv-lite: 0.7.2 + undici: 7.18.2 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -9919,6 +10081,17 @@ snapshots: parse-numeric-range@1.3.0: {} + parse-srcset@1.0.2: {} + + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + parse5@7.3.0: dependencies: entities: 6.0.1 @@ -10194,6 +10367,16 @@ snapshots: transitivePeerDependencies: - supports-color + remark-link-card-plus@0.7.3: + dependencies: + file-type: 21.3.0 + open-graph-scraper: 6.11.0 + sanitize-html: 2.17.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + transitivePeerDependencies: + - supports-color + remark-mdx@3.1.1: dependencies: mdast-util-mdx: 3.0.0 @@ -10277,6 +10460,15 @@ snapshots: safer-buffer@2.1.2: {} + sanitize-html@2.17.0: + dependencies: + deepmerge: 4.3.1 + escape-string-regexp: 4.0.0 + htmlparser2: 8.0.2 + is-plain-object: 5.0.0 + parse-srcset: 1.0.2 + postcss: 8.5.6 + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -10550,6 +10742,10 @@ snapshots: strip-json-comments@3.1.1: {} + strtok3@10.3.4: + dependencies: + '@tokenizer/token': 0.3.0 + style-to-js@1.1.19: dependencies: style-to-object: 1.0.12 @@ -10631,6 +10827,12 @@ snapshots: dependencies: is-number: 7.0.0 + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + tough-cookie@5.1.2: dependencies: tldts: 6.1.86 @@ -10753,6 +10955,8 @@ snapshots: uglify-js@3.19.3: optional: true + uint8array-extras@1.5.0: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -10762,6 +10966,8 @@ snapshots: undici-types@6.21.0: {} + undici@7.18.2: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: diff --git a/src/components/mdx/LinkBadge.tsx b/src/components/mdx/LinkBadge.tsx new file mode 100644 index 0000000..402bfc3 --- /dev/null +++ b/src/components/mdx/LinkBadge.tsx @@ -0,0 +1,47 @@ +import { ArrowUpRight } from "lucide-react"; +import Link from "next/link"; +import { ReactNode } from "react"; +import { FaGithub } from "react-icons/fa"; +import { PiRocketLaunchFill } from "react-icons/pi"; +import { SiVelog } from "react-icons/si"; + +type LinkBadgeProps = { + href: string; + children: ReactNode; + icon?: "github" | "deploy" | "velog"; + variant?: "default" | "blue" | "green"; +}; + +export default function LinkBadge({ + href, + children, + icon, + variant = "default", +}: LinkBadgeProps) { + const icons = { + github: , + deploy: , + velog: , + }; + + const variantClass = { + default: + "border-neutral-300/70 text-neutral-800 bg-white dark:bg-neutral-900 dark:text-neutral-200 dark:border-neutral-700", + blue: "border-blue-300/70 text-blue-700 bg-blue-50 dark:text-blue-300 dark:bg-blue-900/30 dark:border-blue-700", + green: + "border-emerald-300/70 text-emerald-700 bg-emerald-50 dark:text-emerald-300 dark:bg-emerald-900/30 dark:border-emerald-700", + }[variant]; + + return ( + + {icon && {icons[icon]}} + {children} + + + ); +} diff --git a/src/components/mdx/PostMention.tsx b/src/components/mdx/PostMention.tsx new file mode 100644 index 0000000..59f139c --- /dev/null +++ b/src/components/mdx/PostMention.tsx @@ -0,0 +1,30 @@ +import { velitePosts } from "@/lib/posts"; +import Link from "next/link"; + +type Props = { + slug: string; +}; + +export default function PostMention({ slug }: Props) { + const post = velitePosts.find((p) => p.slug === slug); + + if (!post) { + return ( + + @{slug} + + ); + } + + return ( + + {post.title} + + {post.category} · {post.date} + + + ); +} diff --git a/src/components/mdx/index.ts b/src/components/mdx/index.ts index 3f038ed..78a34bc 100644 --- a/src/components/mdx/index.ts +++ b/src/components/mdx/index.ts @@ -1,4 +1,6 @@ export { default as Callout } from "./Callout"; +export { default as CodeBlockFigure } from "./CodeBlock"; export { default as Figure } from "./Figure"; +export { default as LinkBadge } from "./LinkBadge"; +export { default as PostMention } from "./PostMention"; export { default as Quote } from "./Quote"; -export { default as CodeBlockFigure } from "./CodeBlock"; diff --git a/src/styles/mdx.css b/src/styles/mdx.css index 9d2605c..68fa566 100644 --- a/src/styles/mdx.css +++ b/src/styles/mdx.css @@ -107,3 +107,7 @@ Inline code .prose :where(code):not(:where(pre code)) { white-space: normal; } + +.prose a.no-underline { + text-decoration: none !important; +} \ No newline at end of file diff --git a/velite.config.ts b/velite.config.ts index d41964e..05d5f0f 100644 --- a/velite.config.ts +++ b/velite.config.ts @@ -3,6 +3,7 @@ import rehypeAutolinkHeadings from "rehype-autolink-headings"; import rehypePrettyCode from "rehype-pretty-code"; import rehypeSlug from "rehype-slug"; import remarkGfm from "remark-gfm"; +import remarkLinkCard from "remark-link-card-plus"; import { defineCollection, defineConfig, s } from "velite"; const capitalizeFirst = (v: string) => { @@ -57,7 +58,15 @@ export default defineConfig({ }), }, mdx: { - remarkPlugins: [remarkGfm], + remarkPlugins: [ + remarkGfm, + [ + remarkLinkCard, + { + className: "link-card", + }, + ], + ], rehypePlugins: [ rehypeSlug, [