Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
fd26ffa
style: #54 FE1 공통 컴포넌트 CSS 구현
Aug 5, 2026
a6d049b
feat: #54 회원가입·로그인·시험기간 등록 화면 구현
Aug 5, 2026
445c1d5
feat: #54 과목 등록·가용시간 입력·시험범위 등록 화면 구현
Aug 5, 2026
fd21ed7
feat: #54 학습 작업 확인 화면 및 추가·수정 모달 구현
Aug 5, 2026
f1ae9a2
fix: #54 학습작업 수정 방식을 실제 뷰(formset 일괄저장)에 맞게 수정
Aug 5, 2026
9495610
style: #54 공통 CSS 정리 - fff 하드코딩 제거 및 화면별 스타일 통합
Aug 5, 2026
3c3b55d
fix: #54 가용시간 입력 화면 인라인 스타일 제거 및 레이아웃 정리
Aug 5, 2026
0cbeadc
fix: #54 시험범위 등록 화면 Figma 레이아웃 반영
Aug 5, 2026
17905bf
feat: #54 학습자료 상세 화면 추출·분석 자동 진행 흐름 구현
Aug 5, 2026
071841e
fix: #54 학습 작업 화면 버튼 통합 및 삭제 확인 팝업 적용
Aug 5, 2026
ae5ba8d
fix: #54 과목 등록 화면 중복 다음 버튼 제거
Aug 5, 2026
0543c34
fix: #54 템플릿 문법 오류 수정 (줄바꿈 깨짐 복구)
Aug 5, 2026
cebbb0e
Merge branch 'dev' into feature/#54-fe1-templates
Aug 5, 2026
b077121
fix: #54 학습작업 추가 화면 제목 상단 텍스트 깨짐 수정
Aug 5, 2026
82d6de9
fix: #54 가용시간 입력 화면 기존 입력값 표시(초록점) 유지되도록 수정
Aug 5, 2026
5fde07c
fix: #54 시험범위 등록 에러 표시 개선 및 추출·분석 자동 진행 로직 반영
Aug 5, 2026
5039e5e
fix: #54 학습작업 화면 좌측 과목 리스트 버튼 스타일 및 활성 표시 추가
Aug 5, 2026
11fe6bb
style: #54 회원가입·로그인 제목 크기 공통 클래스로 통일
Aug 5, 2026
b031303
style: #54 전체 제목 크기 확대 및 화면별 스타일 개선
Aug 5, 2026
f088225
fix: #54 시험기간 상세 화면 텍스트 깨짐 수정 및 전용 클래스 정리
Aug 5, 2026
4d6d4b0
style: #54 버튼·카드·인풋 스타일을 Figma 실측값 기준으로 개선
Aug 5, 2026
1f1391c
fix: 템플릿 수정
Aug 6, 2026
a380f86
Merge branch 'dev' into feature/#54-fe1-templates
Aug 6, 2026
6d043a7
fix:pr 리뷰에 따라 meterial_detail.html 수정
Aug 8, 2026
2c20358
Merge branch 'dev' into feature/#54-fe1-templates
Aug 8, 2026
014023f
feat: #54 소셜 로그인 버튼 추가 및 대소문자 버그 수정
Aug 8, 2026
08b7b8e
style: 버튼색 수정 파랑->남색
Aug 8, 2026
1302a9a
fix: #54 시험범위 등록 시 material_type 기본값 누락 버그 수정
Aug 9, 2026
bf89ad8
feat: #54 학습 작업에 PDF 페이지 출처(source_pages) 표시 추가
Aug 9, 2026
31a93e1
style:계획 가능 판정css
Aug 9, 2026
2275d09
Merge branch 'dev' into feature/#54-fe1-templates
Aug 9, 2026
281d648
fix:에러메시지 팝업처럼 뜨게 수정
Aug 9, 2026
0ef1ba4
fix:리뷰내용 수정
Aug 9, 2026
e4284f1
fix: #54 PROCESSING 좀비 상태(is_stale) 재시도 UI 반영
Aug 9, 2026
4580aeb
Merge branch 'dev' into feature/#54-fe1-templates
Aug 9, 2026
a4d96d9
fix: #54 stale 상태 진입 시 stuck 타이머·UI 잔여 노출 정리
Aug 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions accounts/templates/accounts/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{% extends "base.html" %}
{% load static %}
{% load socialaccount %}
{% block title %}
로그인 - PLAN B
{% endblock %}

{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/components.css' %}">
{% endblock %}

{% block content %}
<div class="auth-wrap">
<div class="card auth-card">
<div class="page-title-sm">다시 오셨네요</div>
<div class="page-sub">계획을 이어서 확인해보세요</div>

{% if form.non_field_errors %}
<div class="form-error-box">
{{ form.non_field_errors|striptags }}
</div>
{% endif %}

<form method="post" novalidate>
{% csrf_token %}
{% if request.GET.next %}
<input type="hidden" name="next" value="{{ request.GET.next }}">
{% endif %}

<div class="form-group">
<label class="form-label" for="{{ form.username.id_for_label }}">
{{ form.username.label }}
</label>
{{ form.username }}
</div>

<div class="form-group">
<label class="form-label" for="{{ form.password.id_for_label }}">
비밀번호
</label>
{{ form.password }}
</div>

<button type="submit" class="btn btn-brand btn-block">
로그인
</button>
</form>

<div class="auth-divider">
<span>또는</span>
</div>

<a href="{% provider_login_url 'google' process='login' %}"
class="btn btn-ghost btn-block social-btn">
구글로 로그인
</a>
<a href="{% provider_login_url 'naver' process='login' %}"
class="btn btn-ghost btn-block social-btn">
네이버로 로그인
</a>

<div class="auth-link">
계정이 없나요?
<a href="{% url 'accounts:signup' %}">회원가입</a>
</div>
</div>
</div>
{% endblock %}
99 changes: 99 additions & 0 deletions accounts/templates/accounts/signup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{% extends "base.html" %}
{% load static %}
{% load socialaccount %}
{% block title %}
회원가입 - PLAN B
{% endblock %}

{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/components.css' %}">
{% endblock %}

{% block content %}
<div class="auth-wrap">
<div class="card auth-card">
<div class="page-title-sm">PLAN B 시작하기</div>
<div class="page-sub">시험 계획을 함께 관리해요</div>

{% if form.non_field_errors %}
<div class="form-error-box">
{{ form.non_field_errors|striptags }}
</div>
{% endif %}

<form method="post" novalidate>
{% csrf_token %}

<div class="form-group">
<label class="form-label" for="{{ form.email.id_for_label }}">
이메일
</label>
{{ form.email }}
{% if form.email.errors %}
<div class="field-error">
{{ form.email.errors|striptags }}
</div>
{% endif %}
</div>

<div class="form-group">
<label class="form-label" for="{{ form.nickname.id_for_label }}">
닉네임
</label>
{{ form.nickname }}
{% if form.nickname.errors %}
<div class="field-error">
{{ form.nickname.errors|striptags }}
</div>
{% endif %}
</div>

<div class="form-group">
<label class="form-label" for="{{ form.password1.id_for_label }}">
비밀번호
</label>
{{ form.password1 }}
{% if form.password1.errors %}
<div class="field-error">
{{ form.password1.errors|striptags }}
</div>
{% endif %}
</div>

<div class="form-group">
<label class="form-label" for="{{ form.password2.id_for_label }}">
비밀번호 확인
</label>
{{ form.password2 }}
{% if form.password2.errors %}
<div class="field-error">
{{ form.password2.errors|striptags }}
</div>
{% endif %}
</div>

<button type="submit" class="btn btn-brand btn-block">
회원가입
</button>
</form>

<div class="auth-divider">
<span>또는</span>
</div>

<a href="{% provider_login_url 'google' process='login' %}"
class="btn btn-ghost btn-block social-btn">
구글로 시작하기
</a>
<a href="{% provider_login_url 'naver' process='login' %}"
class="btn btn-ghost btn-block social-btn">
네이버로 시작하기
</a>

<div class="auth-link">
이미 계정이 있나요?
<a href="{% url 'accounts:login' %}">로그인</a>
</div>
</div>
</div>
{% endblock %}
11 changes: 11 additions & 0 deletions exams/templates/exams/_topbar.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div style="display:flex; align-items:center; justify-content:space-between; padding:18px 0 26px;">
<a href="{% url 'exams:period_list' %}" style="font-weight:800; font-size:15px; color:var(--neutral11); text-decoration:none; letter-spacing:.03em;">
PLAN B
</a>
<form method="post" action="{% url 'accounts:logout' %}" style="margin:0;">
{% csrf_token %}
<button type="submit" class="btn btn-ghost" style="height:34px; padding:0 14px; font-size:12px;">
{{ request.user.nickname|default:request.user.username }} · 로그아웃
</button>
</form>
</div>
174 changes: 174 additions & 0 deletions exams/templates/exams/available_time_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
{% extends "base.html" %}
{% load static exam_extras %}
{% block title %}
가용시간 입력 - PLAN B
{% endblock %}

{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/components.css' %}">
{% endblock %}

{% block content %}
{% include "exams/_topbar.html" %}
{% get_calendar_grid period.id as calendar_days %}

<div class="container avail-wrap">
<div class="crumb-text">
<a href="{% url 'exams:period_detail' period.id %}">PLAN B</a>
&nbsp;›&nbsp; 가용시간 입력
</div>
<div class="page-title">
가용시간 입력하기
</div>
<div class="page-sub">
하루 전체에서 공부 가능한 시간을 날짜별로 입력해주세요
</div>

{% if formset.non_form_errors %}
<div class="form-error-box">
{{ formset.non_form_errors|striptags }}
</div>
{% endif %}

<form method="post" novalidate id="available-time-form">
{% csrf_token %}
{{ formset.management_form }}

<div class="formset-hidden">
{% for form in formset %}
<div data-formset-row="{{ forloop.counter0 }}">
{{ form.id }}
{{ form.date }}
{{ form.hours }}
{{ form.minutes }}
</div>
{% endfor %}
</div>

<div class="avail-body">
<div class="card avail-cal-col">
<div class="avail-cal-title">
{{ period.start_date|date:"n월 j일" }} -
{{ period.end_date|date:"n월 j일" }}
</div>

<div class="avail-cal-grid">
<div class="avail-weekday">월</div>
<div class="avail-weekday">화</div>
<div class="avail-weekday">수</div>
<div class="avail-weekday">목</div>
<div class="avail-weekday">금</div>
<div class="avail-weekday">토</div>
<div class="avail-weekday">일</div>

{% for day in calendar_days %}
{% if forloop.first %}
{% if day.is_exam_day %}
<button type="button" class="avail-day exam-day" disabled
data-date="{{ day.date|date:'Y-m-d' }}"
style="grid-column-start:{{ day.weekday }};">
{{ day.date|date:"j" }}
</button>
{% else %}
<button type="button"
class="avail-day{% if day.has_value %} has-value{% endif %}"
data-index="{{ day.formset_index }}"
data-date="{{ day.date|date:'Y-m-d' }}"
style="grid-column-start:{{ day.weekday }};">
{{ day.date|date:"j" }}
</button>
{% endif %}
{% else %}
{% if day.is_exam_day %}
<button type="button" class="avail-day exam-day" disabled
data-date="{{ day.date|date:'Y-m-d' }}">
{{ day.date|date:"j" }}
</button>
{% else %}
<button type="button"
class="avail-day{% if day.has_value %} has-value{% endif %}"
data-index="{{ day.formset_index }}"
data-date="{{ day.date|date:'Y-m-d' }}">
{{ day.date|date:"j" }}
</button>
{% endif %}
{% endif %}
{% endfor %}
</div>
</div>

<div class="card avail-side-col disabled" id="side-panel">
<div id="side-panel-date" class="avail-side-date">
날짜를 선택하세요
</div>
<div class="avail-side-caption">선택한 날짜</div>

<div class="field-label">전체 가용 시간</div>
<input type="number" min="0" step="10"
class="form-control num"
id="side-panel-minutes"
placeholder="240">
<div class="avail-side-hint">분 단위로 입력</div>

<button type="button"
class="btn btn-brand btn-block avail-save-btn"
id="side-panel-save">
저장
</button>
</div>
</div>

<button type="submit" class="btn btn-brand avail-next-btn">
다음
</button>
</form>
</div>

<script>
(function () {
var sidePanel = document.getElementById('side-panel');
var dateLabel = document.getElementById('side-panel-date');
var minutesInput = document.getElementById('side-panel-minutes');
var saveBtn = document.getElementById('side-panel-save');
var currentDay = null;

function selectDay(dayBtn) {
document.querySelectorAll('.avail-day').forEach(function (d) {
d.classList.remove('sel');
});
dayBtn.classList.add('sel');
currentDay = dayBtn;
sidePanel.classList.remove('disabled');
dateLabel.textContent = dayBtn.dataset.date;

var row = document.querySelector(
'[data-formset-row="' + dayBtn.dataset.index + '"]'
);
var hoursInput = row.querySelector('input[name$="-hours"]');
var minInput = row.querySelector('input[name$="-minutes"]');
var total = (parseInt(hoursInput.value || 0, 10) * 60) +
parseInt(minInput.value || 0, 10);
minutesInput.value = total || '';
}

document.querySelectorAll('.avail-day:not(.exam-day)').forEach(
function (btn) {
btn.addEventListener('click', function () {
selectDay(btn);
});
}
);

saveBtn.addEventListener('click', function () {
if (!currentDay) return;
var total = parseInt(minutesInput.value || 0, 10);
var row = document.querySelector(
'[data-formset-row="' + currentDay.dataset.index + '"]'
);
row.querySelector('input[name$="-hours"]').value = Math.floor(total / 60);
row.querySelector('input[name$="-minutes"]').value = total % 60;
currentDay.classList.toggle('has-value', total > 0);
});
})();
</script>
{% endblock %}
Loading