feat(blog): 모바일 반응형 — FAB + 풀다운 리프레시 + 칩 필터
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -758,4 +758,19 @@
|
||||
align-self: stretch;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 태그/카테고리 필터 가로 스크롤 */
|
||||
.blog-categories,
|
||||
.blog-category-list {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
flex-wrap: nowrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.blog-categories > *,
|
||||
.blog-category-list > * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import {
|
||||
updateBlogPost,
|
||||
deleteBlogPost,
|
||||
} from '../../api';
|
||||
import { useIsMobile } from '../../hooks/useIsMobile';
|
||||
import PullToRefresh from '../../components/PullToRefresh';
|
||||
import FAB from '../../components/FAB';
|
||||
import './Blog.css';
|
||||
|
||||
// ── 마크다운 렌더러 ──────────────────────────────────────────────────────────
|
||||
@@ -353,15 +356,15 @@ const BlogEditor = ({ post, onSave, onClose }) => {
|
||||
// ── 메인 Blog 컴포넌트 ───────────────────────────────────────────────────────
|
||||
|
||||
const Blog = () => {
|
||||
const isMobile = useIsMobile();
|
||||
const staticPosts = useMemo(() => getBlogPosts(), []);
|
||||
const [apiPosts, setApiPosts] = useState([]);
|
||||
const [apiError, setApiError] = useState(false);
|
||||
const [editorPost, setEditorPost] = useState(null); // null=닫힘, {}=새글, post=수정
|
||||
const [isEditorOpen, setIsEditorOpen] = useState(false);
|
||||
|
||||
// API 글 불러오기
|
||||
useEffect(() => {
|
||||
getBlogPostsApi()
|
||||
const fetchPosts = useCallback(() => {
|
||||
return getBlogPostsApi()
|
||||
.then((data) => {
|
||||
const posts = Array.isArray(data) ? data : (data?.posts ?? []);
|
||||
setApiPosts(posts.map((p) => ({ ...p, slug: `api-${p.id}` })));
|
||||
@@ -369,6 +372,11 @@ const Blog = () => {
|
||||
.catch(() => setApiError(true));
|
||||
}, []);
|
||||
|
||||
// API 글 불러오기
|
||||
useEffect(() => {
|
||||
fetchPosts();
|
||||
}, [fetchPosts]);
|
||||
|
||||
// 정적 + API 글 병합 (API 글이 앞에 표시)
|
||||
const allPosts = useMemo(() => {
|
||||
const combined = [...apiPosts, ...staticPosts];
|
||||
@@ -450,6 +458,7 @@ const Blog = () => {
|
||||
const closeEditor = useCallback(() => { setIsEditorOpen(false); setEditorPost(null); }, []);
|
||||
|
||||
return (
|
||||
<PullToRefresh onRefresh={fetchPosts}>
|
||||
<div className="blog">
|
||||
<header className="blog-header">
|
||||
<div>
|
||||
@@ -651,7 +660,10 @@ const Blog = () => {
|
||||
onClose={closeEditor}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FAB onClick={openNewEditor} label="글 쓰기" />
|
||||
</div>
|
||||
</PullToRefresh>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user