no message

This commit is contained in:
2025-09-26 14:56:56 +09:00
parent 74e88d7d89
commit d2a1f37f39
15 changed files with 399 additions and 385 deletions
@@ -41,6 +41,24 @@
</div>
<div class="write_option btn-example controlbox-location" id="location_field"></div>
</div>
<div class="manual-input-section" style="margin-bottom: 2em; padding: 1.5em; border: 1px solid #ddd; border-radius: 4px; background-color: #f9f9f9;">
<h4 style="margin-bottom: 1em; font-size: 1.1em; color: #333;"><i class="icon solid fa-cog" style="margin-right: 0.5em;"></i>수동 설정</h4>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1.5em;">
<div>
<label for="manual_date" style="font-weight: bold; margin-bottom: 0.5em; display: block;">작성일</label>
<input type="datetime-local" id="manual_date" style="width:100%; box-sizing: border-box;">
</div>
<div>
<label for="manual_lat" style="font-weight: bold; margin-bottom: 0.5em; display: block;">위도 (Latitude)</label>
<input type="number" id="manual_lat" step="any" placeholder="예: 37.5665" style="width:100%; box-sizing: border-box;">
</div>
<div>
<label for="manual_lon" style="font-weight: bold; margin-bottom: 0.5em; display: block;">경도 (Longitude)</label>
<input type="number" id="manual_lon" step="any" placeholder="예: 126.9780" style="width:100%; box-sizing: border-box;">
</div>
</div>
<p style="font-size: 0.8em; color: #777; margin-top: 1em;">* 작성일이나 좌표를 직접 입력하면 자동으로 측정된 GPS 정보 대신 입력된 값이 저장됩니다.</p>
</div>
</div>
</th:block>
</section>
+17 -10
View File
@@ -34,21 +34,12 @@
<!-- </section>-->
<section class="wrapper style1">
<div class="container" style="text-align:center;">
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9504446465764716" data-ad-slot="1234567890" data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
<div class="container">
<div class="row">
<div class="col-12">
<div id="content_inner">
<article>
<section th:each="post : ${Posts}">
<section th:each="post , iterStat : ${Posts}">
<div class="box post" th:id="${post.id}" onclick="goToViewer(this)" style="cursor: pointer;">
<span class="image left">
<img th:src="${post.thumb != null and not #strings.isEmpty(post.thumb)} ? ${apiBaseUrl + post.thumb} : @{/images/pic01.jpg}" alt="Post Thumbnail" />
@@ -66,6 +57,22 @@
<p th:text="${#strings.abbreviate(post.html, 80)}" class="ellipsis"></p>
</div>
</div>
<th:block th:if="${iterStat.count % 3 == 0}">
<section>
<div class="box ad-container" style="padding: 2em; text-align: center;">
<p style="margin-bottom: 1em; color: #888;">- Advertisement -</p>
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9504446465764716"
data-ad-slot="5334609005"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
</section>
</th:block>
</section>
</article>
</div>
@@ -16,6 +16,10 @@
<div class="col-12">
<div id="content_inner">
<article>
<header class="major" th:if="${filterTitle}">
<h2 th:text="${filterTitle}">필터링된 게시물</h2>
<p><a th:href="@{/blog/posts}">모든 글 보기</a></p>
</header>
<th:block th:each="post, iterStat : ${postsPage.content}">
<section th:id="'post-section-' + ${post.id}">
<div class="box post" th:id="${post.id}">
@@ -48,12 +52,12 @@
<th:block th:if="${iterStat.count % 3 == 0}">
<section>
<div class="box" style="padding: 2em; text-align: center;">
<div class="box ad-container" style="padding: 2em; text-align: center;">
<p style="margin-bottom: 1em; color: #888;">- Advertisement -</p>
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"
data-ad-slot="yyyyyyyyyy"
data-ad-client="ca-pub-9504446465764716"
data-ad-slot="5334609005"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
@@ -68,21 +72,21 @@
<nav aria-label="Page navigation" th:if="${postsPage.totalPages > 1}" style="text-align: center; margin-top: 2.5em; font-size: 0.9em;">
<ul class="pagination" style="display: inline-block; padding-left: 0; list-style: none; border-radius: 5px; border: 1px solid #e0e0e0; overflow: hidden;">
<li th:styleappend="${postsPage.isFirst()} ? 'opacity: 0.5; pointer-events: none;' : ''" style="display: inline; float: left;">
<a th:href="${postsPage.isFirst()} ? '#' : @{/blog/posts(page=${postsPage.number - 1})}"
<a th:href="${postsPage.isFirst()} ? '#' : @{/blog/posts(page=${postsPage.number - 1}, category=${currentCategory}, tag=${currentTag})}"
class="button alt small" style="border-radius:0; margin:0; border-right: 1px solid #e0e0e0;">
&laquo; Prev
</a>
</li>
<li th:each="pageNum : ${#numbers.sequence(0, postsPage.totalPages - 1)}"
style="display: inline; float: left; border-right: 1px solid #e0e0e0;">
<a th:href="@{/blog/posts(page=${pageNum})}"
<a th:href="@{/blog/posts(page=${pageNum}, category=${currentCategory}, tag=${currentTag})}"
th:text="${pageNum + 1}"
th:class="${pageNum == postsPage.number} ? 'button small' : 'button alt small'"
style="border-radius:0; margin:0;">
</a>
</li>
<li th:styleappend="${postsPage.isLast()} ? 'opacity: 0.5; pointer-events: none;'" style="display: inline; float: left;">
<a th:href="${postsPage.isLast()} ? '#' : @{/blog/posts(page=${postsPage.number + 1})}"
<a th:href="${postsPage.isLast()} ? '#' : @{/blog/posts(page=${postsPage.number + 1}, category=${currentCategory}, tag=${currentTag})}"
class="button alt small" style="border-radius:0; margin:0;">
Next &raquo;
</a>
@@ -164,7 +164,9 @@
<div class="container" style="text-align:center;">
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9504446465764716" data-ad-slot="1234567890" data-ad-format="auto"
data-ad-client="ca-pub-9504446465764716"
data-ad-slot="5334609005"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
@@ -328,7 +328,9 @@
<div class="container" style="text-align:center;">
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9504446465764716" data-ad-slot="1234567890" data-ad-format="auto"
data-ad-client="ca-pub-9504446465764716"
data-ad-slot="5334609005"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
@@ -409,11 +409,38 @@
canvas.addEventListener('mouseup', handlePointerUp);
canvas.addEventListener('dblclick', handleDoubleClick);
// ▼▼▼ [추가] 터치 이벤트 리스너 등록 ▼▼▼
canvas.addEventListener('touchstart', handlePointerDown);
canvas.addEventListener('touchmove', (e) => {
e.preventDefault(); // 모바일에서 드래그 시 화면이 스크롤되는 것을 방지
handlePointerMove(e);
});
canvas.addEventListener('touchend', handlePointerUp);
function getCanvasCoordinates(event) {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width, scaleY = canvas.height / rect.height;
const clientX = event.touches ? event.touches[0].clientX : event.clientX;
const clientY = event.touches ? event.touches[0].clientY : event.clientY;
// 터치 이벤트와 마우스 이벤트를 모두 처리하기 위한 좌표 변수
let clientX, clientY;
if (event.touches && event.touches.length > 0) {
// 'touchstart', 'touchmove' 이벤트 처리
clientX = event.touches[0].clientX;
clientY = event.touches[0].clientY;
} else if (event.changedTouches && event.changedTouches.length > 0) {
// 'touchend' 이벤트 처리
clientX = event.changedTouches[0].clientX;
clientY = event.changedTouches[0].clientY;
} else {
// 마우스 이벤트 처리 ('mousedown', 'mousemove', 'mouseup')
clientX = event.clientX;
clientY = event.clientY;
}
// clientX 또는 clientY가 undefined인 경우 오류 방지
if (typeof clientX === 'undefined' || typeof clientY === 'undefined') return null;
return { x: (clientX - rect.left) * scaleX / dpr, y: (clientY - rect.top) * scaleY / dpr };
}
@@ -456,6 +483,10 @@
// =======================================
function handlePointerDown(event) {
if (isProcessing || isAnimatingCompletion) return;
if (event.type.startsWith('touch')) {
event.preventDefault();
}
const coords = getCanvasCoordinates(event);
const element = findElementAt(coords.x, coords.y);
if (!element) return;
@@ -506,6 +537,11 @@
if (!isDragging) { draggedCards = []; return; }
const coords = getCanvasCoordinates(event);
if (!coords) { // coords가 null일 경우를 대비한 방어 코드
isDragging = false;
draggedCards = [];
return;
}
const dropTargetStackId = findStackAt(coords.x, coords.y);
const sourceStackIndex = draggedCards.sourceStackIndex;
@@ -827,7 +863,9 @@
<div class="container" style="text-align:center;">
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9504446465764716" data-ad-slot="1234567890" data-ad-format="auto"
data-ad-client="ca-pub-9504446465764716"
data-ad-slot="5334609005"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
@@ -300,7 +300,9 @@
<div class="container" style="text-align:center;">
<ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-9504446465764716" data-ad-slot="1234567890" data-ad-format="auto"
data-ad-client="ca-pub-9504446465764716"
data-ad-slot="5334609005"
data-ad-format="auto"
data-full-width-responsive="true"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
@@ -10,15 +10,14 @@
<th:block layout:fragment="content" id="content">
<section class="wrapper style2">
<div class="container"
th:with="isAdmin=${#authorization.expression('hasRole(''ADMIN'')')}, isWriter=${#authentication.name == srcPost.writer}"
th:attr="
onclick=${(isAdmin or isWriter) ? 'loadEditor()' : ''},
style=${(isAdmin or isWriter) ? 'cursor: pointer;' : ''},
title=${(isAdmin or isWriter) ? '클릭하여 수정하기' : ''}
"
sec:authorize="isAuthenticated()">
<header class="major">
<div class="container" sec:authorize="isAuthenticated()">
<header class="major"
th:with="isAdmin=${#authorization.expression('hasRole(''ADMIN'')')}, isWriter=${#authentication.name == srcPost.writer}"
th:attr="
onclick=${(isAdmin or isWriter) ? 'loadEditor()' : ''},
style=${(isAdmin or isWriter) ? 'cursor: pointer;' : ''},
title=${(isAdmin or isWriter) ? '클릭하여 수정하기' : ''}
">
<h2 id="title_layer">
<span th:text="${srcPost.title}">게시물 제목이 여기에 표시됩니다</span>
<span style="font-size: 0.8em; color: #888; font-weight: normal; margin-left: 0.5em;">
@@ -41,8 +40,8 @@
</div>
</div>
<div class="container open-login-popup" sec:authorize="isAnonymous()" to="#loginPopup" style="cursor: pointer;">
<header class="major">
<div class="container" sec:authorize="isAnonymous()">
<header class="major open-login-popup" to="#loginPopup" style="cursor: pointer;">
<h2 id="title_layer_anon">
<span th:text="${srcPost.title}">게시물 제목이 여기에 표시됩니다</span>
<span style="font-size: 0.8em; color: #888; font-weight: normal; margin-left: 0.5em;">