This commit is contained in:
monoid 2025-04-07 22:53:01 +09:00
parent 4203f06af0
commit e3eb8934ef
6 changed files with 688 additions and 135 deletions

View file

@ -16,7 +16,8 @@
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"tailwind-merge": "^3.0.2", "tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.17" "tailwindcss": "^4.0.17",
"wouter": "^3.6.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.17.0", "@eslint/js": "^9.17.0",

35
pnpm-lock.yaml generated
View file

@ -29,6 +29,9 @@ importers:
tailwindcss: tailwindcss:
specifier: ^4.0.17 specifier: ^4.0.17
version: 4.0.17 version: 4.0.17
wouter:
specifier: ^3.6.0
version: 3.6.0(react@18.3.1)
devDependencies: devDependencies:
'@eslint/js': '@eslint/js':
specifier: ^9.17.0 specifier: ^9.17.0
@ -956,6 +959,9 @@ packages:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
ms@2.1.3: ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@ -1022,6 +1028,10 @@ packages:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
regexparam@3.0.0:
resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==}
engines: {node: '>=8'}
resolve-from@4.0.0: resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -1105,6 +1115,11 @@ packages:
uri-js@4.4.1: uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
use-sync-external-store@1.5.0:
resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
vite@6.0.9: vite@6.0.9:
resolution: {integrity: sha512-MSgUxHcaXLtnBPktkbUSoQUANApKYuxZ6DrbVENlIorbhL2dZydTLaZ01tjUoE3szeFzlFk9ANOKk0xurh4MKA==} resolution: {integrity: sha512-MSgUxHcaXLtnBPktkbUSoQUANApKYuxZ6DrbVENlIorbhL2dZydTLaZ01tjUoE3szeFzlFk9ANOKk0xurh4MKA==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
@ -1154,6 +1169,11 @@ packages:
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
wouter@3.6.0:
resolution: {integrity: sha512-l11eR4urCc+CbY8+pV8HKFHxEqMgffss9aVB1XwiSkLDtH3cI6XpCa50cOzREzL0KwQqrwCVE5dCyeNcCgFpPg==}
peerDependencies:
react: '>=16.8.0'
yocto-queue@0.1.0: yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -1922,6 +1942,8 @@ snapshots:
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
mitt@3.0.1: {}
ms@2.1.3: {} ms@2.1.3: {}
nanoid@3.3.8: {} nanoid@3.3.8: {}
@ -1979,6 +2001,8 @@ snapshots:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
regexparam@3.0.0: {}
resolve-from@4.0.0: {} resolve-from@4.0.0: {}
reusify@1.0.4: {} reusify@1.0.4: {}
@ -2066,6 +2090,10 @@ snapshots:
dependencies: dependencies:
punycode: 2.3.1 punycode: 2.3.1
use-sync-external-store@1.5.0(react@18.3.1):
dependencies:
react: 18.3.1
vite@6.0.9(jiti@2.4.2)(lightningcss@1.29.2): vite@6.0.9(jiti@2.4.2)(lightningcss@1.29.2):
dependencies: dependencies:
esbuild: 0.24.2 esbuild: 0.24.2
@ -2082,4 +2110,11 @@ snapshots:
word-wrap@1.2.5: {} word-wrap@1.2.5: {}
wouter@3.6.0(react@18.3.1):
dependencies:
mitt: 3.0.1
react: 18.3.1
regexparam: 3.0.0
use-sync-external-store: 1.5.0(react@18.3.1)
yocto-queue@0.1.0: {} yocto-queue@0.1.0: {}

View file

@ -8,6 +8,8 @@ import { GalleryTitleHeader } from './GalleryTitleHeader';
import { GlobalNavigationBar, Header, VisitHistory } from './Header'; import { GlobalNavigationBar, Header, VisitHistory } from './Header';
import { LoginBox } from './Sidebar'; import { LoginBox } from './Sidebar';
import { GalleryTable, TableRowData } from './table'; import { GalleryTable, TableRowData } from './table';
import { articles } from './data/article';
import { Route, Switch } from 'wouter';
const tableData: TableRowData[] = [ const tableData: TableRowData[] = [
@ -37,22 +39,6 @@ const tableData: TableRowData[] = [
recommendations: "-", recommendations: "-",
isAdOrSurvey: true, isAdOrSurvey: true,
}, },
{ // Notice Example 1
id: 1012381,
category: "공지",
titleText: "3월 5주차 주던",
commentCount: 7,
variant: "icon_notice",
author: {
type: "nickname",
nickname: "보배단",
userType: "manager", // Optional, if applicable
},
date: "25.03.27",
views: 3178,
recommendations: 12,
isNotice: true,
},
{ // Notice Example 2 { // Notice Example 2
id: 784571, id: 784571,
category: "공지", category: "공지",
@ -69,34 +55,28 @@ const tableData: TableRowData[] = [
recommendations: 6, recommendations: 6,
isNotice: true, isNotice: true,
}, },
{ // Normal Row Example 1 ...articles.map((item) => ({
id: 1040045, id: item.id, // Random ID for each article
category: "일반", category: "일반",
titleText: "버서커 헬 졸업해도되는데 태초한번도 안떠서 계속 돌림", titleText: item.Title,
variant: "icon_pic", variant: "icon_pic",
commentCount: 2, date: `25.04.02`,
author: { views: parseInt(item.View),
type: "nickname", commentCount: item.comments.length,
nickname: "븜구리", author: item.Author.match(/ㅇㅇ \(\d+\.\d+\)/) ? {
userType: "manager", // Optional, if applicable
},
date: "21:58",
views: 4,
recommendations: 0,
},
{ // Normal Row Example 2 (IP Author)
id: 1040043,
category: "일반",
titleText: "혹시 엘마가 진각무기압타 빗자루 쓸 수 있음?",
variant: "icon_txt",
author: {
type: "IP", type: "IP",
ip: "1.248", ip: item.Author.split(" ")[1],
} : item.Author === "ㅇㅇ" ? {
type: "semi-nickname",
nickname: item.Author,
} : {
type: "nickname",
nickname: item.Author,
}, },
date: "21:58", titleLinkUrl: `/${item.id}`,
views: 1, recommendations: Math.floor(Math.random() * 50), // Random number for recommendations
recommendations: 0, isNews: false,
}, } satisfies TableRowData)),
// ... Add all other rows from the original HTML here // ... Add all other rows from the original HTML here
{ // News Row Example { // News Row Example
id: '', // No ID id: '', // No ID
@ -110,59 +90,75 @@ const tableData: TableRowData[] = [
}, },
]; ];
function GalleryMain() {
return <AnnoymousNickNameProvider value="썬갤러">
<Header />
<GlobalNavigationBar />
<VisitHistory recentVisits={[
{
id: 1,
name: "워썬더",
isMinor: true,
},
{
id: 2,
name: "배틀그라운드",
isMinor: false,
},
{
id: 3,
name: "리그오브레전드",
isMinor: false,
},
{
id: 4,
name: "발로란트",
isMinor: false,
},
{
id: 5,
name: "오버워치",
isMinor: true,
}
]} />
<div className='relative w-[1450px] mx-auto'>
<main
className='w-[1160px] m-[20px_auto_0]'
>
<section className='' >
<div className='flex justify-between'>
<div style={{
width: "840px",
}}>
<GalleryTitleHeader title='워썬더 갤러리' />
<div
className='border-custom-blue-dark border w-[840px]'
/>
<PostListControls owner />
<GalleryTable data={tableData} />
<PostListControls />
</div>
<div style={{
width: "300px",
}}>
<LoginBox />
</div>
</div>
</section>
</main>
</div>
<Footer />
</AnnoymousNickNameProvider>
}
// Sample data - replace with your actual data source/props function GalleryDetail(params: { id: string }) {
const comments: SubCommentData[] = [ const { id } = params;
{ const idNumber = parseInt(id);
id: 1, const article = articles.find((item) => item.id === idNumber);
author: { type: 'IP', ip: '222.116' }, // Assuming author is an object with type and name if (!article) {
text: '너 지금 상현이햄을 ■■라고', return <div>Article not found</div>;
timestamp: '03.31 17:44:25', }
showDelete: true,
},
{
id: 2,
author: { type: "IP", ip: "218.144" },
text: '미국인들도 저사람 얘기할때마다 동양인이 어쩌고랑 엮는데 왤케화남ㅋㅋ',
timestamp: '03.31 18:16:45',
showDelete: true,
},
{
id: 3,
author: { type: "IP", ip: "183.96" },
text: '다른 나라랑 다르게 미국에선 ~계 미국인이라는 정체성이 확고하고 사회적인 인식도 그럼',
timestamp: '03.31 18:18:40',
showDelete: true,
},
{
id: 4,
author: { type: "semi-nickname", nickname: "ㅇㅇ" },
text: '이새낀 미국을 모르노 ㅋㅋㅋㅋ',
timestamp: '03.31 20:34:54',
showDelete: false, // No delete button in this example
},
{
id: 5,
author: { type: "semi-nickname", nickname: "ㅇㅇ" },
text: '어어 내려놔라',
timestamp: '03.31 21:16:46',
showDelete: false,
},
{
id: 6,
author: { type: "nickname", nickname: '티르칸쟈카' },
text: '원종원종아...',
timestamp: '03.31 21:23:59',
showDelete: false,
},
// Add more comment objects as needed
];
function App() {
return ( return (
<AnnoymousNickNameProvider value="썬갤러"> <AnnoymousNickNameProvider value="썬갤러">
<div> <div>
@ -205,41 +201,48 @@ function App() {
className='border-custom-blue-dark border w-[1158px]' className='border-custom-blue-dark border w-[1158px]'
/> />
<GalleryContentHeader kind='일반' <GalleryContentHeader kind='일반'
title={'아 e글 유파들이 고도 왜 안올리는지 알았다'} title={article.Title}
author={{ author={article.Author === "ㅇㅇ" ? {
type: "semi-nickname",
nickname: article.Author,
} : article.Author.match(/ㅇㅇ \(\d+\)/) ? {
type: "IP", type: "IP",
ip: "183.96", ip: article.Author.split(" ")[1],
} : {
type: "nickname",
nickname: article.Author,
}} }}
date='2025.02.04 21:32:47' date='2025.02.04 21:32:47'
views={1234} views={parseInt(article.View)}
recommendations={12} recommendations={Math.floor(Math.random() * 50)}
commentCount={9} commentCount={article.comments.length}
/> />
<GalleryContent /> <GalleryContent
coverImage={`https://placehold.co/840x480?text=${encodeURIComponent(article.imageTitle)}`}
coverImageAlt={`${article.imageTitle} (${article.imageDescription})`}
>
{article.body}
</GalleryContent>
<CommentHeader commentCount={9} /> <CommentHeader commentCount={9} />
<CommentListContainer> <CommentListContainer>
<CommentItem comment={{ {article.comments.map((comment, index) => (<CommentItem
id: 1, key={index}
author: { type: "nickname", nickname: "동아리망했다" }, comment={{
text: '너 지금 상현이햄을 ■■라고', id: index,
timestamp: '03.31 17:44:25', author: comment.nickname.match(/ㅇㅇ \(\d+\)/) ? {
showDelete: true, type: "IP",
}} /> ip: comment.nickname.split(" ")[1],
<CommentItem comment={{ } : comment.nickname === "ㅇㅇ" ? {
id: 2, type: "semi-nickname",
author: { type: "IP", ip: "218.144" }, nickname: comment.nickname,
text: '그냥 미국인인데 조센징들은 왜 조선계라고 못 넣어서 안달일까', } : {
timestamp: '03.31 18:16:45', type: "nickname",
showDelete: true, nickname: comment.nickname,
subComments: comments, },
}} /> text: comment.content,
<CommentItem comment={{ timestamp: comment.date,
id: 3, }}
author: { type: "IP", ip: "123.245" }, />))}
text: 'aaa',
timestamp: '03.31 18:16:45',
showDelete: true,
}} />
</CommentListContainer> </CommentListContainer>
<CommentPagination currentPage={1} maxPage={2} /> <CommentPagination currentPage={1} maxPage={2} />
<CommentInput /> <CommentInput />
@ -266,4 +269,11 @@ function App() {
) )
} }
function App() {
return <Switch>
<Route path="/" component={GalleryMain} />
<Route path="/:id" component={(params) => <GalleryDetail id={params.params.id} />} />
</Switch>
}
export default App export default App

View file

@ -275,7 +275,25 @@ function SilbechuButton() {
</button>; </button>;
} }
export function GalleryContent() { interface GalleryContentProps {
coverImage?: string;
coverImageAlt?: string;
children?: React.ReactNode;
recommendCount?: number;
fixedNickCount?: number;
downvoteCount?: number;
}
export function GalleryContent({
coverImage,
children,
recommendCount = 0,
fixedNickCount = 0,
downvoteCount = 0,
coverImageAlt = "cover image",
}: GalleryContentProps) {
return <article return <article
className="text-custom-gray-dark text-[13px] font-apple" className="text-custom-gray-dark text-[13px] font-apple"
> >
@ -290,7 +308,8 @@ export function GalleryContent() {
width: "550px", width: "550px",
height: "350px", height: "350px",
}} }}
alt="alt" alt={coverImageAlt}
src={coverImage}
/> />
</span> </span>
</div> </div>
@ -300,21 +319,15 @@ export function GalleryContent() {
width: "900px", width: "900px",
}} }}
> >
<p> {children}
s텀
</p>
<p>
</p>
</div> </div>
</div> </div>
</div> </div>
<div className="relative"> <div className="relative">
<GalleryRecommendation <GalleryRecommendation
recommendCount={2} recommendCount={recommendCount}
fixedNickCount={1} fixedNickCount={fixedNickCount}
downvoteCount={downvoteCount}
/> />
</div> </div>
<div <div

492
src/data/article.ts Normal file
View file

@ -0,0 +1,492 @@
const contents = [
{
"body": "아니 진짜 T-80BVM 이거 너무 심한 거 아니냐? 정면은 거의 뚫리지도 않는데 기동성까지 좋아서 다 씹어먹고 다니네. 약점이라고 있는 것도 존나 작아서 맞추기도 힘들고. 이거 때문에 탑방 밸런스 개판된 지가 언젠데 아직도 너프 소식이 없냐? 가이진 진짜 일 안 하냐? 솔직히 이거 하나 때문에 겜 하기 싫어질 때 많음. 유저들이 그렇게 징징대는데 콧방귀도 안 뀌는 거 보면 진짜 대단하다 싶다. 다른 나라 탱크들은 다 너프 쳐먹이면서 왜 얘만 무적임?",
"imageTitle": "T-80BVM OP",
"imageDescription": "War Thunder T-80BVM tank dominating a battlefield, dramatic lighting, smoke",
"comments": [
{
"nickname": "레오파르트오너",
"date": "25.01.13 10:15:02",
"content": "ㄹㅇㅋㅋ 어제도 BVM 3대한테 혼자 다 털림"
},
{
"nickname": "ㅇㅇ(112.158)",
"date": "25.01.13 10:16:35",
"content": "꼬우면 너도 소련 타라 이 말이야~"
},
{
"nickname": "전차장김씨",
"date": "25.01.13 10:18:11",
"content": "차체 하단 쏘면 잘 뚫리던데? 손 문제 아님?"
},
{
"nickname": "에이브람스탄다",
"date": "25.01.13 10:20:55",
"content": "하단이고 포탑링이고 다 쏘는데도 도탄만 오지게 남 ㅅㅂ"
},
{
"nickname": "ㅇㅇ(223.38)",
"date": "25.01.13 10:22:01",
"content": "BVM 너프하면 소련 접는다 ㅅㄱ"
},
{
"nickname": "폭탄받아라",
"date": "25.01.13 10:25:48",
"content": "그래도 챌린저2보다는 양반임 ㅋㅋㅋ ㅠㅠ"
},
{
"nickname": "뉴비조아",
"date": "25.01.13 10:30:17",
"content": "BVM 진짜 문제긴 함. 기동성, 방호력, 화력 다 좋은데 약점은 너무 작고, 특히 렐릭트 ERA 때문에 HEAT탄이나 미사일은 거의 씨알도 안 먹히고 날탄도 숭숭 튕겨냄. 포수 조준경 쪽이나 차체 하단 정중앙 아니면 사실상 정면에서 안정적으로 격파하기가 너무 어려움. 측면도 공간장갑이랑 연료탱크가 탄 다 쳐먹고. 솔직히 다른 탑티어 MBT들이랑 비교했을 때 너무 독보적인 성능임. 가이진이 밸런스 잡을 생각이 있다면 다음 메이저 업데이트 때 BR을 올리든가 장갑 모델링을 수정하든가 뭔가 조치가 있어야 한다고 봄. 이대로 가면 진짜 탑방은 BVM 온라인 될 듯."
},
{
"nickname": "ㅇㅇ(175.223)",
"date": "25.01.13 10:33:40",
"content": "<img title=\"빡침\" description=\"분노콘\" />"
},
{
"nickname": "슈투카",
"date": "25.01.13 10:35:12",
"content": "비행기로 잡으면 쉬운데? ㅋㅋ"
},
{
"nickname": "지상만함",
"date": "25.01.13 10:37:05",
"content": "ㄴ 지상전 하러 왔지 비행기 타러 왔냐고 아 ㅋㅋ"
},
{
"nickname": "ㅇㅇ(121.167)",
"date": "25.01.13 10:40:29",
"content": "스웨덴이 더 사기 아님? Strv 122 시리즈가 ㄹㅇ 벽인데"
},
{
"nickname": "썬더하는틀딱",
"date": "25.01.13 10:42:51",
"content": "라떼는 마우스가 짱이었어..."
},
{
"nickname": "ㅇㅇ(118.235)",
"date": "25.01.13 10:45:11",
"content": "가이진: 꼬우면 골탱 사서 빨리 BVM 뚫어라 ㅎㅎ"
}
]
},
{
"body": "진짜 지상 리얼 좀 하려고 하면 하늘에서 미사일 날아오고 폭탄 떨어지고 정신을 못 차리겠다. 겜 시작하고 좀 몰아보려고 하면 바로 CAS 쳐맞고 뒤지고, 스폰하면 또 날아와서 죽이고... 이게 탱크 게임이냐 비행기 게임이냐? 스폰 보호는 장식이냐고. 대공포는 있긴 한데 그걸로 다 막을 수도 없고 너무 스트레스 받는다 진짜. 특히 Su-25나 A-10 같은 애들 뜨면 그냥 게임 터졌다고 봐야 함. SP 요구량 좀 더 올리거나 대공 효율 좀 높여줘야 하는 거 아니냐?",
"imageTitle": "CAS Hell",
"imageDescription": "Overhead view of a tank exploding from an aircraft bomb in War Thunder, intense explosion, ground battle chaos",
"comments": [
{
"nickname": "지상만함",
"date": "25.01.13 11:05:44",
"content": "ㄹㅇ 지상전 하러 왔는데 하늘만 쳐다봐야 함"
},
{
"nickname": "폭탄받아라",
"date": "25.01.13 11:07:19",
"content": "꼬우면 너도 CAS 타든가 ㅋㅋㅋ"
},
{
"nickname": "ㅇㅇ(211.36)",
"date": "25.01.13 11:08:50",
"content": "대공 좀 해라 징징대지 말고. 판처게파르트 같은 거 타면 다 잡는데?"
},
{
"nickname": "레오파르트오너",
"date": "25.01.13 11:10:22",
"content": "ㄴ 대공 타면 점수 못 먹어서 탱크 못 뽑는다고 아 ㅋㅋ"
},
{
"nickname": "ㅇㅇ(175.198)",
"date": "25.01.13 11:12:05",
"content": "스폰킬이 제일 문제임. 스폰하자마자 날아오는 건 막을 방법이 없음. 스폰 보호 시간 늘리거나 스폰 지역 대공 방어라도 강화해야 함."
},
{
"nickname": "슈투카",
"date": "25.01.13 11:15:37",
"content": "솔직히 지상 리얼에서 CAS가 너무 강력한 건 팩트임. 지상 장비로 어느 정도 성과를 내야 CAS를 뽑을 수 있는 구조인데, 초반에 한두 대만 떠도 게임 흐름이 확 넘어가 버림. 특히 유도 무기 가진 제트기들은 저고도 대공포 사거리 밖에서 안전하게 공격할 수 있어서 더 문제임. 그렇다고 대공 미사일 차량들은 가격도 비싸고 운용 난이도도 높은 편이라 모든 유저가 쉽게 쓸 수 있는 것도 아니고. 가이진이 진짜 고민해봐야 할 문제임. SP 조절만으로는 한계가 있고, 맵 디자인이나 대공 시스템 자체에 대한 근본적인 개선이 필요하다고 생각함. 아니면 아예 CAS 없는 지상전 모드를 따로 만들어주든가."
},
{
"nickname": "ㅇㅇ(119.201)",
"date": "25.01.13 11:18:49",
"content": "<img title=\"징징\" description=\"우는콘\" />"
},
{
"nickname": "뉴비조아",
"date": "25.01.13 11:20:11",
"content": "카미카제 하는 놈들 진짜 극혐임"
},
{
"nickname": "ㅇㅇ(123.456)",
"date": "25.01.13 11:22:38",
"content": "그래서 요즘 겜 잘 안 함. 스트레스만 받음."
},
{
"nickname": "에이브람스탄다",
"date": "25.01.13 11:25:03",
"content": "미국 A-10이랑 소련 Su-25가 제일 악질임. 미사일 너무 많아."
},
{
"nickname": "전차장김씨",
"date": "25.01.13 11:27:55",
"content": "차라리 아케이드처럼 비행기 슬롯 제한 두는 게 나을지도?"
},
{
"nickname": "ㅇㅇ(110.70)",
"date": "25.01.13 11:30:10",
"content": "워썬더가 원래 공중전 게임이었어서 그럼 (아님)"
},
{
"nickname": "썬더하는틀딱",
"date": "25.01.13 11:32:48",
"content": "옛날엔 폭격기 맞추는 맛이라도 있었는데 요즘 미사일은 답도 없다~"
},
{
"nickname": "ㅇㅇ(223.62)",
"date": "25.01.13 11:35:00",
"content": "헬기는 더 심함 ㅅㄱ"
}
]
},
{
"body": "아니 진짜 어이가 없네 ㅋㅋㅋ 분명히 제대로 조준해서 쐈는데 그냥 적 탱크 통과하고 아무 일 없다는 듯이 지나가는 거 뭐냐? 이게 한두 번도 아니고 대체 언제 고칠 거냐 가이진아? 결정적인 순간에 이러면 진짜 키보드 부순다 ㅅㅂ. 몇 년째 이 버그 방치하는 거 레전드네. 특히 구축 몰 때 고스트쉘 나면 혈압 오름. 방금도 E-100 옆구리에 APDS 쐈는데 그냥 통과함 ㅋㅋㅋㅋㅋ 아오",
"imageTitle": "Ghost Shell WTF",
"imageDescription": "War Thunder gameplay screenshot showing a tank shell passing harmlessly through an enemy tank, glitch effect, frustration expression",
"comments": [
{
"nickname": "폭탄받아라",
"date": "25.01.13 14:20:11",
"content": "나만 그런 게 아니었네 ㅋㅋㅋㅋㅋㅋ 어제 나도 당함"
},
{
"nickname": "ㅇㅇ(118.235)",
"date": "25.01.13 14:21:45",
"content": "서버렉 아니냐? 핑 높으면 자주 그럼"
},
{
"nickname": "지상만함",
"date": "25.01.13 14:23:02",
"content": "핑 30대인데도 그럼 ㅅㄱ 이건 그냥 버그임"
},
{
"nickname": "레오파르트오너",
"date": "25.01.13 14:25:33",
"content": "워썬더 하루이틀 함? ㅋㅋ 그러려니 해야지"
},
{
"nickname": "ㅇㅇ(223.38)",
"date": "25.01.13 14:27:18",
"content": "<img title=\"샷건\" description=\"분노콘\" />"
},
{
"nickname": "전차장김씨",
"date": "25.01.13 14:29:50",
"content": "가끔 패킷 로스 뜨면서 그럴 때 있던데 서버 문제일 가능성이 높음. 특히 유럽 서버나 북미 서버에서 자주 겪는 듯. 근데 아시아 서버에서도 가끔 발생하는 거 보면 그냥 게임 자체 엔진 문제거나 서버 동기화 문제일 수도 있음. 예전부터 꾸준히 제기된 문제인데 가이진이 '고쳤다'고 발표한 적은 몇 번 있지만 실제로 완전히 사라진 적은 없는 것 같음. 특히 빠른 속도로 기동하는 목표물을 맞추거나, 특정 각도에서 특정 장갑 부위를 맞출 때 더 자주 발생하는 느낌적인 느낌? 그냥 운이 없었다고 생각하고 넘기는 게 정신 건강에 이로움..."
},
{
"nickname": "ㅇㅇ(121.167)",
"date": "25.01.13 14:32:07",
"content": "니 에임 문제 아님? ㅋㅋ 리플 돌려봐라"
},
{
"nickname": "뉴비조아",
"date": "25.01.13 14:34:15",
"content": "그래서 중요한 순간엔 그냥 기도하면서 쏨"
},
{
"nickname": "ㅇㅇ(175.223)",
"date": "25.01.13 14:36:40",
"content": "가이진 일해라!!!!!!!!!!!"
},
{
"nickname": "에이브람스탄다",
"date": "25.01.13 14:38:51",
"content": "고폭탄으로 궤도 쏠 때도 가끔 고스트쉘 남"
},
{
"nickname": "슈투카",
"date": "25.01.13 14:40:28",
"content": "비행기는 고스트쉘 없어서 좋음 ㅎ"
},
{
"nickname": "ㅇㅇ(112.158)",
"date": "25.01.13 14:42:19",
"content": "응 안고쳐줘~"
},
{
"nickname": "썬더하는틀딱",
"date": "25.01.13 14:45:05",
"content": "워썬더의 신비 중 하나지... 받아들여라..."
}
]
},
{
"body": "워썬더 시작한 지 얼마 안 된 뉴비입니다. 국가도 많고 테크트리도 복잡해서 뭐부터 연구해야 할지 감이 안 오네요 ㅠㅠㅠ 주로 지상전 위주로 하고 싶은데, 초보자가 하기 쉽고 괜찮은 국가나 테크트리 추천 좀 부탁드립니다! 현질은 조금 할 생각 있습니다. 어떤 나라가 좀 무난하고 연구 뚫는 재미도 있을까요?",
"imageTitle": "Newbie Needs Help",
"imageDescription": "Confused anime character looking at the vast War Thunder tech tree screen, question marks floating around",
"comments": [
{
"nickname": "전차장김씨",
"date": "25.01.13 09:50:10",
"content": "근본 국룰 3대장 (미국, 독일, 소련) 중에 하나 하세요. 제일 무난함."
},
{
"nickname": "ㅇㅇ(118.235)",
"date": "25.01.13 09:51:33",
"content": "미국 추천. 초반엔 좀 약해도 뒤로 갈수록 좋고 공중 지원도 빵빵함."
},
{
"nickname": "레오파르트오너",
"date": "25.01.13 09:52:58",
"content": "독일 ㄱㄱ. 초반 4호 전차 라인 펀치력 좋고 나중에 레오파르트 간지남."
},
{
"nickname": "에이브람스탄다",
"date": "25.01.13 09:54:05",
"content": "소련이 뉴비한테 제일 좋음. 튼튼하고 주포도 쎄고 T-34 시리즈가 국밥임."
},
{
"nickname": "ㅇㅇ(211.36)",
"date": "25.01.13 09:56:11",
"content": "프랑스, 이탈리아, 스웨덴 같은 마이너 국가는 나중에 하셈. 초반에 하면 고통받음."
},
{
"nickname": "슈투카",
"date": "25.01.13 09:58:42",
"content": "개인적으로 뉴비면 소련이나 독일 추천함. 미국은 초반 셔먼이 좀 애매할 수 있음. 소련은 T-34 라인이 진짜 든든하고 KV 시리즈도 좋음. 장갑이 어느 정도 있어서 실수해도 좀 버텨주고 주포 위력도 괜찮아서 맞추면 한 방에 가는 경우가 많음. 독일은 4호 전차 F2 이후부터 주포 성능이 확 좋아져서 저격하는 맛이 있음. 판터나 티거 같은 유명한 전차들도 탈 수 있고. 근데 둘 다 장단점이 명확함. 소련은 부각이 안 좋고 후진 속도가 느린 경우가 많고, 독일은 측면 장갑이 약한 편임. 그래도 이 두 국가가 연구할 장비도 많고 성능도 전체적으로 준수해서 뉴비가 적응하기 제일 좋다고 생각함. 현질할 생각 있으면 각 국가 3~4랭크 골탱 하나 사서 연구 부스팅하면 편함."
},
{
"nickname": "폭탄받아라",
"date": "25.01.13 10:01:20",
"content": "<img title=\"환영\" description=\"응원콘\" /> 어서와! 고통받는 썬더의 세계로!"
},
{
"nickname": "지상만함",
"date": "25.01.13 10:03:05",
"content": "지상만 팔 거면 소련이나 독일, 나중에 CAS도 같이 할 거면 미국 추천."
},
{
"nickname": "ㅇㅇ(123.456)",
"date": "25.01.13 10:05:18",
"content": "영국은 하지 마셈 제발... 고통뿐임..."
},
{
"nickname": "썬더하는틀딱",
"date": "25.01.13 10:07:44",
"content": "골탱 살 거면 TURMS나 레오파르트 L/44 같은 거 사면 됨. 근데 바로 탑방 가면 썰리니까 비추."
},
{
"nickname": "ㅇㅇ(175.198)",
"date": "25.01.13 10:09:59",
"content": "뱅기도 같이 뚫어야 나중에 편함. 지상만 하면 CAS에 맨날 털림."
},
{
"nickname": "뉴비조아",
"date": "25.01.13 10:11:31",
"content": "저는 미국으로 시작했는데 재밌게 하고 있어요! M4 셔먼 좋아요!"
},
{
"nickname": "ㅇㅇ(110.70)",
"date": "25.01.13 10:13:00",
"content": "그냥 꼴리는 거 타셈. 어차피 다 고통임 ㅋㅋ"
}
]
},
{
"body": "슬슬 다음 메이저 업데이트 나올 때 되지 않았냐? 보통 몇 달 주기로 나오던데 이번엔 언제쯤일까? 이번엔 또 어떤 신기한 장비들 나올지 궁금하네. 개인적으로는 F-15나 Su-27 같은 거 기대하는데 가능성 있으려나? 아니면 새로운 국가나 시스템 추가될 수도 있고. 다들 뭐 예상함? 데브 서버는 언제 열릴까?",
"imageTitle": "Update Hype?",
"imageDescription": "War Thunder logo with futuristic background, question marks, speculation bubbles showing new tanks/planes",
"comments": [
{
"nickname": "뉴비조아",
"date": "25.01.13 15:01:22",
"content": "다음달 중순쯤 나오지 않을까? 보통 3월, 6월, 9월, 12월 이랬던 거 같은데"
},
{
"nickname": "ㅇㅇ(121.167)",
"date": "25.01.13 15:03:01",
"content": "F-15 존버한다 제발..."
},
{
"nickname": "레오파르트오너",
"date": "25.01.13 15:04:48",
"content": "Su-27 나와야 밸런스 맞지 ㄹㅇ"
},
{
"nickname": "ㅇㅇ(112.158)",
"date": "25.01.13 15:06:15",
"content": "버그나 고치고 업뎃해라 좀"
},
{
"nickname": "폭탄받아라",
"date": "25.01.13 15:08:30",
"content": "경제 개편 소식은 없나? 실버 너무 안 벌림"
},
{
"nickname": "ㅇㅇ(223.62)",
"date": "25.01.13 15:10:55",
"content": "유출 보니까 프랑스 신규 전차랑 일본 신규 전투기 나온다던데? 찌라시일 수도 있음."
},
{
"nickname": "전차장김씨",
"date": "25.01.13 15:13:07",
"content": "보통 메이저 업데이트는 분기별로 한 번씩 하니까 다음 달이나 다다음달 초쯤으로 예상해볼 수 있음. F-15나 Su-27 같은 4.5세대 전투기는 이번에 바로 나오기보다는 F-16 후기형이나 Mig-29 SMT 같은 게 먼저 나오고 그 다음이나 다다음 업뎃쯤에 나올 가능성이 높다고 봄. 지상 쪽은 아마 각 국가별로 비어있는 BR대 채워주는 장비나 기존 장비 파생형 추가될 것 같고, 해상전은... 뭐 항상 그랬듯이 소소하게 추가될 듯? 개인적인 희망 사항으로는 제발 경제 시스템 좀 개편하고 고질적인 버그들 (고스트쉘, 서버렉 등) 좀 확실하게 잡아줬으면 좋겠음. 신규 장비 추가도 좋지만 게임 플레이 환경 개선이 더 시급하다고 생각함."
},
{
"nickname": "슈투카",
"date": "25.01.13 15:16:11",
"content": "<img title=\"기대\" description=\"팝콘콘\" /> 뭐든 좋으니 빨리 나왔으면 ㅋㅋ"
},
{
"nickname": "ㅇㅇ(119.201)",
"date": "25.01.13 15:18:39",
"content": "또 소련 OP 장비 추가하고 다른 나라는 너프하겠지 뭐 ㅋㅋ"
},
{
"nickname": "지상만함",
"date": "25.01.13 15:20:04",
"content": "해상전 개편 좀 해줘라 진짜... 하는 사람이 없다고 ㅠㅠ"
},
{
"nickname": "에이브람스탄다",
"date": "25.01.13 15:22:17",
"content": "신규 국가 추가는 당분간 없을 듯. 기존 국가 채우기도 바빠 보임."
},
{
"nickname": "ㅇㅇ(175.223)",
"date": "25.01.13 15:24:50",
"content": "데브 서버 열리면 바로 달려간다 ㅋㅋ"
},
{
"nickname": "썬더하는틀딱",
"date": "25.01.13 15:27:00",
"content": "새 장비 나와봤자 연구 언제 다 하냐... 현타 온다..."
}
]
},
{
"body": "아니 진짜 어이가 없네 ㅋㅋㅋ 분명히 제대로 조준해서 쐈는데 그냥 적 탱크 통과하고 아무 일 없다는 듯이 지나가는 거 뭐냐? 이게 한두 번도 아니고 대체 언제 고칠 거냐 가이진아? 결정적인 순간에 이러면 진짜 키보드 부순다 ㅅㅂ. 몇 년째 이 버그 방치하는 거 레전드네. 특히 구축 몰 때 고스트쉘 나면 혈압 오름. 방금도 적 경전차 옆구리 정중앙에 APFSDS 박았는데 그냥 통과하고 뒤에 벽에 처맞더라 ㅋㅋㅋㅋㅋ 아오 진짜 게임 삭제 마렵다.",
"imageTitle": "Ghost Shell WTF",
"imageDescription": "War Thunder gameplay screenshot showing a tank shell passing harmlessly through an enemy tank, glitch effect, frustration expression",
"comments": [
{
"nickname": "폭탄받아라",
"date": "25.01.13 14:20:11",
"content": "나만 그런 게 아니었네 ㅋㅋㅋㅋㅋㅋ 어제 나도 당함 개빡쳤는데"
},
{
"nickname": "ㅇㅇ(118.235)",
"date": "25.01.13 14:21:45",
"content": "그거 서버렉 아니냐? 핑 높거나 패킷 로스 뜨면 자주 그럼. 니 회선 문제일 수도 있음."
},
{
"nickname": "지상만함",
"date": "25.01.13 14:23:02",
"content": "ㄴㄴ 핑 30대 유지하고 패킷로스 0%인데도 그럼 ㅅㄱ 이건 그냥 버그임. 클라이언트에서는 맞았다고 나오는데 서버에서 판정 안 나는 거."
},
{
"nickname": "레오파르트오너",
"date": "25.01.13 14:25:33",
"content": "워썬더 하루이틀 함? ㅋㅋ 그러려니 하고 넘겨야 정신건강에 이로움. 고친다고 말만 하고 몇 년째 그대로잖아."
},
{
"nickname": "ㅇㅇ(223.38)",
"date": "25.01.13 14:27:18",
"content": "<img title=\"샷건\" description=\"분노콘\" /> 진짜 이거 때문에 진 판이 몇 판이냐."
},
{
"nickname": "전차장김씨",
"date": "25.01.13 14:29:50",
"content": "고스트쉘 문제는 진짜 오래된 고질병이지... 이게 단순히 핑이나 패킷 로스 문제만은 아님. 물론 네트워크 상태가 안 좋으면 더 자주 발생할 수는 있지만, 최상의 네트워크 환경에서도 종종 발생함. 서버-클라이언트 간의 동기화 문제일 가능성이 가장 크다고 봄. 내 컴퓨터 화면(클라이언트)에서는 명중한 걸로 보이지만, 실제 서버에서는 약간의 시간차나 위치 오차 때문에 빗나갔거나 다른 곳에 맞은 걸로 처리되는 거지. 특히 고속 기동 중인 목표물을 맞추거나, 특정 각도에서 특정 부위를 노릴 때, 혹은 서버 부하가 심할 때 더 자주 발생하는 것 같다는 체감이 있음. 가이진이 몇 번이나 '개선했다', '수정했다'고 패치노트에 적었지만, 근본적인 해결은 아직 못한 듯. 그냥 워썬더를 계속 하려면 어느 정도 감수해야 하는 불편함 같은 게 되어버렸음. 리플레이 돌려보면 가끔 진짜 황당하게 빗나간 걸로 나올 때도 있고...",
},
{
"nickname": "ㅇㅇ(121.167)",
"date": "25.01.13 14:32:07",
"content": "혹시 니 에임이 살짝 빗나간 거 아님? ㅋㅋ 리플 돌려보고 와라. 가끔 착각일 때도 있음."
},
{
"nickname": "뉴비조아",
"date": "25.01.13 14:34:15",
"content": "그래서 중요한 순간엔 그냥 기도하면서 쏨... 제발 맞아라 하고 ㅠㅠ"
},
{
"nickname": "ㅇㅇ(175.223)",
"date": "25.01.13 14:36:40",
"content": "가이진 일해라!!!!!!!!!!! 버그 좀 고쳐!!!!!!"
},
{
"nickname": "에이브람스탄다",
"date": "25.01.13 14:38:51",
"content": "ㄹㅇㅋㅋ 특히 작고 빠른 애들 쏠 때 심함. 이탈리아 경전차 같은 애들."
},
{
"nickname": "슈투카",
"date": "25.01.13 14:40:28",
"content": "비행기는 고스트쉘 없어서 좋음 ㅎ 지상 접고 공중 ㄱㄱ"
},
{
"nickname": "ㅇㅇ(112.158)",
"date": "25.01.13 14:42:19",
"content": "응 안고쳐줘~ 니들이 뭘 할 수 있는데 ㅋㅋ 꼬우면 골탱 사~"
},
{
"nickname": "썬더하는틀딱",
"date": "25.01.13 14:45:05",
"content": "워썬더의 7대 불가사의 중 하나지... 받아들여라 젊은이..."
},
{
"nickname": "워린이",
"date": "25.01.13 14:47:12",
"content": "<img title=\"징징\" description=\"우는콘\" /> 저만 그런 게 아니었군요 ㅠㅠ 전 제가 잘못 쏜 줄 알았어요."
}
]
}
];
const headers = [
{
"Title": "T-80BVM 이거 진짜 너프 안하냐?",
"Author": "ㅇㅇ",
"Summary": "T-80BVM 너무 강해서 게임 밸런스가 무너짐. 정면 약점도 없고 기동성도 좋음.",
"View": "1250"
},
{
"Title": "지상 리얼인데 CAS 때문에 게임을 못하겠다",
"Author": "ㅇㅇ",
"Summary": "지상 리얼리스틱 전투에서 CAS(근접항공지원)가 너무 강력해서 지상 장비 플레이 경험이 심각하게 저해됨. 스폰 보호도 없음.",
"View": "1530"
},
{
"Title": "워썬더식 명중 ㅋㅋㅋㅋㅋ",
"Author": "폭탄받아라",
"Summary": "분명히 조준하고 쐈는데도 탄이 이상한 곳으로 빗나가거나 적에게 피해를 주지 못하는 '워썬더식 명중' 현상 움짤/영상.",
"View": "1120"
},
{
"Title": "뉴비인데 뭐부터 연구해야 할까요?",
"Author": "워린이",
"Summary": "워썬더를 처음 시작하는 플레이어가 어떤 국가와 테크트리를 선택하고 연구해야 할지 조언을 구하는 글. 추천 트리 질문.",
"View": "720"
},
{
"Title": "다음 메이저 업뎃 언제쯤 나올 거 같냐?",
"Author": "뉴비조아",
"Summary": "다음 메이저 업데이트 시기 예측 및 기대되는 신규 장비/기능 토론.",
"View": "880"
},
{
"Title": "고스트쉘 버그 아직도 있네 ㅅㅂ",
"Author": "지상만함",
"Summary": "포탄이 적 전차를 통과하거나 명중 판정이 나지 않는 '고스트쉘' 버그가 여전히 발생하고 있음을 지적하며 불만 제기.",
"View": "990"
}
]
export const articles = headers.map((header, index) => {
const content = contents[index];
return {
id: 984970 - index,
...header,
...content,
}
});

View file

@ -1,3 +1,4 @@
import { Link } from 'wouter';
import { AuthorData, NickName } from './AuthorData'; import { AuthorData, NickName } from './AuthorData';
import { cn } from './util/cn'; import { cn } from './util/cn';
@ -74,7 +75,8 @@ export function TableRow({ rowData }: TableRowProps) {
(isAdOrSurvey || isNotice) && 'font-bold', // Conditional bold (isAdOrSurvey || isNotice) && 'font-bold', // Conditional bold
)}>{category}</td> )}>{category}</td>
<td className={cn(tdBaseClasses, "text-left text-[13px] h-[29px]")}> <td className={cn(tdBaseClasses, "text-left text-[13px] h-[29px]")}>
<a href={titleLinkUrl} className={cn( <Link href={titleLinkUrl}
className={cn(
'text-custom-gray-dark inline-block max-w-[82%] align-middle text-ellipsis whitespace-nowrap overflow-hidden pt-[1px] leading-tight', // Approximates titleLinkStyle 'text-custom-gray-dark inline-block max-w-[82%] align-middle text-ellipsis whitespace-nowrap overflow-hidden pt-[1px] leading-tight', // Approximates titleLinkStyle
"hover:underline", "hover:underline",
isNews && '!text-custom-green', // News specific color override isNews && '!text-custom-green', // News specific color override
@ -88,7 +90,7 @@ export function TableRow({ rowData }: TableRowProps) {
)} )}
{/* Title text - boldness handled by titleLinkClasses */} {/* Title text - boldness handled by titleLinkClasses */}
{titleText} {titleText}
</a> </Link>
{commentCount !== undefined && commentCount > 0 && ( {commentCount !== undefined && commentCount > 0 && (
<span className="text-xs text-custom-gray-medium ml-1 align-middle tracking-[-0.05em]"> <span className="text-xs text-custom-gray-medium ml-1 align-middle tracking-[-0.05em]">
[{commentCount}] [{commentCount}]