오늘 작업
- 포스트 개수에 대한 등급을 만들고 싶음
- 움직이는 이미지로 보여주기를 원함
- 새싹 → 묘목 → 나무(여기서 특정 개수에 따라 사과를 추가하고 사과가 3개가 되면)
- → 거목 → 다음은 구상중
등급 디자인
SVG 선 그리기 (가지가 자라나기)
<svg viewBox="0 0 100 120" style="width: 100px; height: 120px; overflow: visible;">
<ellipse cx="50" cy="115" rx="7" ry="5" fill="#8d6e63" />
<path class="plant-path stem" d="M50,115 Q40,60 50,15" fill="none"
stroke="var(--brand-accent-green)" stroke-width="5" stroke-linecap="round"/>
</svg>
/* 모든 선(path)에 공통으로 적용되는 코드입니다. */
.plant-path {
/* 1. 선을 점선(dash)으로 만드는데, 점선 하나의 길이를 150(선 전체 길이보다 길게)으로 설정합니다. */
stroke-dasharray: 150;
/* 2. 그 점선의 시작 위치를 150만큼 뒤로 밀어버립니다. (결과: 화면에서 선이 아예 안 보임!) */
stroke-dashoffset: 150;
/* 3. stroke-dashoffset 값이 변할 때 1.5초 동안 스르륵 변하게 만듭니다. (부드러운 가속도 추가) */
transition: stroke-dashoffset 1.5s cubic-bezier(0.4, 0, 0.2, 1);
}
/* JS에서 컨테이너에 'level-1' 클래스를 달아주면 아래 CSS가 발동합니다. */
.level-1 .stem {
/* 밀어냈던 시작 위치를 90까지만 당겨옵니다. (결과: 선이 중간까지만 스르륵 그려짐) */
stroke-dashoffset: 90;
}
/* 'level-2' 클래스가 달리면 발동합니다. */
.level-2 .stem {
/* 시작 위치를 0으로(원래 위치로) 완전히 당겨옵니다. (결과: 줄기가 끝까지 다 그려짐) */
stroke-dashoffset: 0;
}
깃허브 스타일 잔디 심기
<div id="heatmap-grid" class="d-grid gap-1" style="grid-template-columns: repeat(7, 1fr);">
</div>
/* 잔디밭 한 칸의 기본 디자인입니다. */
.heatmap-box {
aspect-ratio: 1; /* 가로세로 비율을 1:1 완벽한 정사각형으로 고정합니다. */
background-color:
}
/* 글을 쓴 날(active)에 적용될 디자인입니다. */
.heatmap-box.active {
background-color: var(--brand-accent-green); /* 브랜드 포인트 컬러(초록색)로 칠합니다. */
}
JavaScript 부분: 28일치 날짜 계산 및 색칠하기
function renderHeatmap(posts) {
const heatmapGrid = document.getElementById('heatmap-grid');
heatmapGrid.innerHTML = ''; // 함수가 실행될 때마다 기존 잔디를 싹 밀고 새로 심습니다.
// 1. 내가 쓴 글들의 날짜 데이터만 깔끔하게 '년-월-일' 문자열 배열로 바꿉니다.
// 예: ["2026-2-20", "2026-2-19", "2026-2-15"]
const postDates = posts.map(p => {
const d = new Date(p.created_at);
return `${d.getFullYear()}-${d.getMonth()+1}-${d.getDate()}`;
});
const totalDays = 28; // 화면에 보여줄 총 날짜 수입니다. (7칸 x 4줄)
const today = new Date(); // 오늘 날짜를 기준으로 잡습니다.
// 2. 27일 전부터 0일 전(오늘)까지 총 28번 반복문을 돌립니다.
for (let i = totalDays - 1; i >= 0; i--) {
// targetDate를 오늘 날짜로 초기화합니다.
const targetDate = new Date(today);
// 오늘 날짜에서 i만큼 일을 뺍니다. (예: i가 27이면 27일 전 날짜가 됨)
targetDate.setDate(today.getDate() - i);
// 계산된 과거나 오늘 날짜를 '년-월-일' 형태의 문자열로 만듭니다.
const dateString = `${targetDate.getFullYear()}-${targetDate.getMonth()+1}-${targetDate.getDate()}`;
// 3. ✨핵심✨: 방금 만든 날짜(dateString)가 내가 글 쓴 날짜 배열(postDates)에 들어있는지 확인합니다.
// includes()는 들어있으면 true, 없으면 false를 반환합니다.
const isPosted = postDates.includes(dateString);
// 잔디 칸을 담당할 div 태그를 메모리상에 하나 만듭니다.
const box = document.createElement('div');
// isPosted가 true면 'heatmap-box active' 클래스를, false면 'heatmap-box ' 클래스를 줍니다.
// 이 삼항 연산자 덕분에 글을 쓴 날에만 초록색 불(active)이 켜집니다.
box.className = 'heatmap-box ' + (isPosted ? 'active' : '');
// 만들어진 네모 칸을 실제 화면(heatmapGrid)에 끼워 넣습니다.
heatmapGrid.appendChild(box);
}
}
테스트
묘목 테스트
from apps.user.models import User
from apps.post.models import Post
from django.utils import timezone
import datetime
user = User.objects.first()
print(f"✅ [{user.nickname}] 님의 계정으로 나무 키우기를 시작합니다...")
created_posts = []
for i in range(1, 31):
post = Post.objects.create(
user=user,
title=f"🌳 성장하는 정원 테스트 게시글 {i}",
content="나무가 자라나는지 확인하기 위한 더미 데이터입니다. 씨앗에서 숲까지! 🌱 -> 🌲",
is_temp=False,
visibility="PUBLIC"
)
created_posts.append(post)
today = timezone.now()
for i, post in enumerate(created_posts):
days_ago = i % 28
past_date = today - datetime.timedelta(days=days_ago)
Post.objects.filter(id=post.id).update(created_at=past_date)
print("🎉 성공! 30개의 포스트가 생성되고 날짜가 분산되었습니다.")

깃 형식 전환
28일 → 365일
