Forcing inputStyle to contenteditable (previous commit) didn't fix it on iPhone, confirming this is CodeMirror 5's own long-standing weakness with CJK IME composition on iOS WebKit, not just the iPad desktop-UA detection issue. There's no reliable fix short of dropping CodeMirror for the journal content field, so EasyMDE is removed entirely and the textarea goes back to a native, uncontrolled <textarea> — nothing intercepts/re-renders it during composition, so iOS's IME just works. The markdown toolbar buttons (bold/italic/heading/quote/lists/code/link) now manipulate the textarea's selection directly via a small JournalEditor JS API instead of calling EasyMDE/CodeMirror commands, and image paste tracks its upload placeholder by a unique text marker instead of a CodeMirror bookmark. Also drops the vendored easymde.min.js/css (no longer referenced) and bumps the service worker CACHE_NAME so stale cached copies of the old vendor files get evicted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
82 lines
4.7 KiB
HTML
82 lines
4.7 KiB
HTML
<!doctype html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
<title>{% block title %}해빗랩{% endblock %}</title>
|
|
{# 구글 OAuth 브랜딩 심사는 홈페이지에서 앱 이름과 목적을 확인한다 — 설명 메타 태그가 없으면 "앱의 목적에 관한 설명이 없다"로 반려된다. #}
|
|
<meta name="description" content="{% block meta_description %}HabitLab (해빗랩) is a habit tracking web app. 해빗랩은 만들고 싶은 습관과 끊고 싶은 습관을 요일 단위로 관리하는 습관 기록 앱입니다.{% endblock %}" />
|
|
|
|
<link rel="manifest" href="/static/manifest.json" />
|
|
<meta name="theme-color" content="#d97757" media="(prefers-color-scheme: light)" />
|
|
<meta name="theme-color" content="#e08962" media="(prefers-color-scheme: dark)" />
|
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
|
<meta name="apple-mobile-web-app-title" content="해빗랩" />
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/static/icons/icon-apple-180.png" />
|
|
<link rel="apple-touch-icon" href="/static/icons/icon-192.png" />
|
|
<link rel="icon" href="/static/icons/icon-192.png" />
|
|
|
|
<link rel="stylesheet" href="/static/css/style.css" />
|
|
<script src="/static/js/vendor/htmx.min.js" defer></script>
|
|
<script src="/static/js/push-register.js" defer></script>
|
|
<script src="/static/js/vendor/sortable.min.js" defer></script>
|
|
<script src="/static/js/habit-reorder.js" defer></script>
|
|
<script src="/static/js/journal-category-reorder.js" defer></script>
|
|
<script src="/static/js/journal-editor.js" defer></script>
|
|
<script src="/static/js/vendor/alpine.min.js" defer></script>
|
|
<script src="/static/js/app.js" defer></script>
|
|
</head>
|
|
<body>
|
|
<div class="app-shell{% block shell_class %}{% endblock %}">
|
|
{% if logged_in %}
|
|
<div id="ios-install-banner" class="ios-install-banner">
|
|
<span>홈 화면에 추가하면 알림도 받을 수 있어요. 공유 버튼 → ‘홈 화면에 추가’를 눌러보세요.</span>
|
|
<button type="button" onclick="dismissIosInstallBanner()" aria-label="닫기">×</button>
|
|
</div>
|
|
<nav class="top-nav">
|
|
<span class="brand">해빗랩</span>
|
|
<div class="nav-links">
|
|
<a href="/today" class="{% block nav_today %}{% endblock %}">오늘</a>
|
|
<a href="/habits" class="{% block nav_habits %}{% endblock %}">습관 관리</a>
|
|
<a href="/history" class="{% block nav_history %}{% endblock %}">기록</a>
|
|
<a href="/journal" class="{% block nav_journal %}{% endblock %}">일기</a>
|
|
</div>
|
|
{% if current_user %}
|
|
<div class="nav-user">
|
|
{% if account_level %}<span class="nav-level-pill">Lv.{{ account_level.level }}</span>{% endif %}
|
|
<a href="/account">{{ current_user.name or current_user.email }}</a>
|
|
<form method="post" action="/auth/logout">
|
|
<button type="submit" class="btn-link">로그아웃</button>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
</nav>
|
|
<nav class="bottom-tab-bar">
|
|
<a href="/today" class="tab-item {{ self.nav_today() }}">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" /><path d="M8 12l3 3 5-6" /></svg>
|
|
<span>오늘</span>
|
|
</a>
|
|
<a href="/habits" class="tab-item {{ self.nav_habits() }}">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="6" x2="20" y2="6" /><line x1="4" y1="12" x2="20" y2="12" /><line x1="4" y1="18" x2="20" y2="18" /></svg>
|
|
<span>습관 관리</span>
|
|
</a>
|
|
<a href="/history" class="tab-item {{ self.nav_history() }}">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="16" rx="2" /><line x1="3" y1="10" x2="21" y2="10" /><line x1="8" y1="3" x2="8" y2="7" /><line x1="16" y1="3" x2="16" y2="7" /></svg>
|
|
<span>기록</span>
|
|
</a>
|
|
<a href="/journal" class="tab-item {{ self.nav_journal() }}">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" /><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" /></svg>
|
|
<span>일기</span>
|
|
</a>
|
|
</nav>
|
|
{% endif %}
|
|
{% block content %}{% endblock %}
|
|
<footer class="app-footer">
|
|
<a href="/privacy">개인정보처리방침</a>
|
|
<a href="/terms">서비스 약관</a>
|
|
</footer>
|
|
</div>
|
|
</body>
|
|
</html>
|