generated from ttipo/project-base
docs: 9단계(보내기 취소 · 예약 발송 · 외부 이미지 · 인쇄 · 보낸 사람 차단) 계약과 디자인
보내기 취소 · 예약 발송(엔진이 제출을 붙잡는다 — FUTURERELEASE), 외부 이미지 중계, 인쇄, 보낸 사람 차단, 보내기 · 읽기 설정의 계약(2절)을 정하고, 확정한 캔버스 보드 넷(MailReadTools · MailPrint · MailSendLater · SettingsSendRead)을 둔다. 디자인 README 에 구현하며 정한 보완을 적었다. 리뷰(화면 한 번 · 서버 두 번)로 정한 것도 함께 적었다 — 붙잡힌 메일은 취소로만 보낸편지함을 떠난다(MAIL_015 — 모든 옮기기 · 지우기 길, 확인하지 못하면 닫힌 쪽), 발송은 늘 envelope 을 직접 준다(엔진이 받지 않는 주소를 not-found 로 빼고 다시 제출 — 전에는 말없이 빠졌다), 다시 취소해도 200, 이미지 중계의 동시 수(서버 16 · 직원 6 — 받는 수가 적은 직원부터), 차단 주소는 dot-atom 만 · 다시 POST 하면 꺼진 규칙을 켠다. 엔진 사실(2026-10-29): envelope 의 거절은 제출 전체 · 첫 주소 하나, 내보내는 사본에서 Bcc 를 뗀다(개발의 Mailpit 이 보이는 Bcc 줄은 Mailpit 이 붙인다), 제출 조회의 정렬 이름은 sentAt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>인쇄 화면</title>
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<style>
|
||||
@font-face{font-family:'Pretendard';src:url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2-variations'),url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2');font-weight:45 920;font-style:normal;font-display:swap}
|
||||
body{margin:0}
|
||||
:focus-visible{outline:2px solid #0E7C86;outline-offset:2px}
|
||||
.primary{background:#0E7C86;color:#FFFFFF}
|
||||
.primary:hover{background:#0A5F67}
|
||||
.ghost{background:transparent;color:#4A5363}
|
||||
.ghost:hover{background:#F2F4F7;color:#171C26}
|
||||
</style>
|
||||
</helmet>
|
||||
<div style="width: 1440px; height: 1060px; box-sizing: border-box; padding: 48px; display: flex; flex-direction: column; gap: 28px; background: #F6F7F9; color: #171C26; font-family: Pretendard, -apple-system, 'Apple SD Gothic Neo', 'Malgun Gothic', system-ui, sans-serif; font-size: 13px; line-height: 1.5">
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 6px; max-width: 980px">
|
||||
<h1 style="margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -0.02em">인쇄 화면</h1>
|
||||
<p style="margin: 0; font-size: 13.5px; color: #4A5363">⋯ › 인쇄(또는 읽기 화면에서 Ctrl+P)는 새 탭에 메일 한 통만 담은 인쇄 화면을 열고 브라우저의 인쇄 창을 바로 띄웁니다. 앱의 레일 · 메일함 · 목록 · 도구 줄은 인쇄하지 않습니다. 긴 메일은 여러 쪽으로 이어집니다.</p>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 820px minmax(0, 1fr); gap: 28px; align-items: start">
|
||||
|
||||
<section aria-label="인쇄 화면 (새 탭)" style="display: flex; flex-direction: column; border: 1px solid #D0D5DD; border-radius: 12px; overflow: hidden; background: #E9ECEF">
|
||||
<div style="display: flex; align-items: center; gap: 8px; min-height: 52px; box-sizing: border-box; padding: 4px 16px; background: #FFFFFF; border-bottom: 1px solid #E6E8EC">
|
||||
<span style="flex: 1 1 auto; font-weight: 600; color: #344054">인쇄 화면 — 화면에만 보이는 줄</span>
|
||||
<button type="button" class="primary" style="display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 14px; border: 0; border-radius: 8px; font: inherit; font-weight: 600; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg><span>인쇄</span></button>
|
||||
<button type="button" class="ghost" style="min-height: 40px; padding: 0 12px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer">닫기</button>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: center; padding: 28px 0 32px">
|
||||
<article aria-label="A4 한 쪽" style="width: 595px; min-height: 760px; box-sizing: border-box; padding: 48px 52px; background: #FFFFFF; box-shadow: 0 4px 18px rgba(16, 24, 28, 0.12); display: flex; flex-direction: column; gap: 14px; color: #111827">
|
||||
<div style="display: flex; align-items: baseline; justify-content: space-between; padding-bottom: 8px; border-bottom: 1px solid #D0D5DD; font-size: 10.5px; color: #4A5363">
|
||||
<span>ARA SYSTEM 메일</span>
|
||||
<span>김아라 <ara.kim@arasystem.it.kr></span>
|
||||
</div>
|
||||
<h2 style="margin: 4px 0 0; font-size: 17px; line-height: 1.4; font-weight: 700">Re: 메일 서버 이전 일정 공유</h2>
|
||||
<dl style="display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: 3px 10px; margin: 0; font-size: 11.5px">
|
||||
<dt style="color: #4A5363">보낸 사람</dt><dd style="margin: 0">이도윤 <doyun.lee@arasystem.it.kr></dd>
|
||||
<dt style="color: #4A5363">받는 사람</dt><dd style="margin: 0">김아라 <ara.kim@arasystem.it.kr></dd>
|
||||
<dt style="color: #4A5363">참조</dt><dd style="margin: 0">인프라팀 <infra@arasystem.it.kr></dd>
|
||||
<dt style="color: #4A5363">날짜</dt><dd style="margin: 0">2026년 10월 26일 (월) 오전 10:42</dd>
|
||||
<dt style="color: #4A5363">첨부</dt><dd style="margin: 0">메일서버_전환_체크리스트.xlsx (48 KB)</dd>
|
||||
</dl>
|
||||
<hr style="margin: 2px 0; border: 0; border-top: 1px solid #E6E8EC">
|
||||
<div style="display: flex; flex-direction: column; gap: 10px; font-size: 12.5px; line-height: 1.75">
|
||||
<p style="margin: 0">김아라님, 안녕하세요.</p>
|
||||
<p style="margin: 0">말씀하신 대로 이번 주 금요일(10/30) 저녁 9시에 MX 레코드를 새 메일 서버로 전환하겠습니다. 전환 하루 전에 DNS TTL을 300초로 낮춰 두고, 기존 서버는 2주 동안 함께 운영합니다.</p>
|
||||
<p style="margin: 0">전환 체크리스트를 첨부했으니 확인 부탁드립니다.</p>
|
||||
<p style="margin: 0">이도윤 드림</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 20px">
|
||||
<section style="display: flex; flex-direction: column; gap: 10px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">인쇄되는 것</h2>
|
||||
<ul style="margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; color: #344054">
|
||||
<li>머리 줄 — 「ARA SYSTEM 메일」과 인쇄한 직원의 이름 · 주소</li>
|
||||
<li>제목 · 보낸 사람 · 받는 사람 · 참조 · 날짜(읽기 화면에 보이는 것과 같습니다 — 숨은참조는 넣지 않습니다)</li>
|
||||
<li>첨부 — 파일 이름과 크기만(내용은 인쇄하지 않습니다)</li>
|
||||
<li>본문 — 읽기 화면과 같은 정화를 거친 그대로. 쪽 번호 · 날짜는 브라우저의 머리글 · 바닥글 설정을 따릅니다</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section style="display: flex; flex-direction: column; gap: 10px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">이미지 · 긴 메일</h2>
|
||||
<ul style="margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; color: #344054">
|
||||
<li>외부 이미지는 읽기 화면에서 보이고 있던 대로 인쇄합니다(막혀 있었으면 인쇄에도 없습니다)</li>
|
||||
<li>본문은 인쇄할 폭(A4)에 맞춰 다시 잰 뒤 인쇄합니다 — 긴 메일은 여러 쪽으로 이어지고 끝에 빈 쪽이 생기지 않습니다</li>
|
||||
<li>인쇄 창을 닫아도 인쇄 화면 탭은 남습니다 — [인쇄]로 다시, [닫기]로 탭을 닫습니다</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section style="display: flex; flex-direction: column; gap: 10px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">못 열 때</h2>
|
||||
<p style="margin: 0; color: #344054">메일을 찾을 수 없으면 인쇄 화면에 "메일을 찾을 수 없습니다"와 [닫기], 받지 못하면 [다시 시도]가 보이고 인쇄 창은 띄우지 않습니다. 세션이 끝났으면 로그인 화면으로 갑니다.</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":1060}}'>
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,172 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>읽기 화면 — 외부 이미지 · 인쇄 · 보낸 사람 차단</title>
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<style>
|
||||
@font-face{font-family:'Pretendard';src:url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2-variations'),url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2');font-weight:45 920;font-style:normal;font-display:swap}
|
||||
body{margin:0}
|
||||
a{color:#0E7C86}a:hover{color:#0A5F67}
|
||||
:focus-visible{outline:2px solid #0E7C86;outline-offset:2px}
|
||||
.primary{background:#0E7C86;color:#FFFFFF}
|
||||
.primary:hover{background:#0A5F67}
|
||||
.ghost{background:transparent;color:#4A5363}
|
||||
.ghost:hover{background:#F2F4F7;color:#171C26}
|
||||
.danger-solid{background:#B42318;color:#FFFFFF}
|
||||
.danger-solid:hover{background:#912018}
|
||||
.tool{background:transparent;color:#344054}
|
||||
.tool:hover{background:#F2F4F7;color:#171C26}
|
||||
.notice-btn{background:#FFFFFF;color:#7A5200;border:1px solid #F0D9A8}
|
||||
.notice-btn:hover{background:#FFF1D6}
|
||||
.menu-item{background:transparent;color:#344054}
|
||||
.menu-item:hover{background:#EEF0F3}
|
||||
.toast-action{background:transparent;color:#9ED6DB}
|
||||
.toast-action:hover{background:rgba(255,255,255,0.1)}
|
||||
</style>
|
||||
</helmet>
|
||||
<div style="width: 1440px; height: 1220px; box-sizing: border-box; padding: 48px; display: flex; flex-direction: column; gap: 28px; background: #F6F7F9; color: #171C26; font-family: Pretendard, -apple-system, 'Apple SD Gothic Neo', 'Malgun Gothic', system-ui, sans-serif; font-size: 13px; line-height: 1.5">
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 6px; max-width: 980px">
|
||||
<h1 style="margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -0.02em">읽기 화면 — 외부 이미지 · 인쇄 · 보낸 사람 차단</h1>
|
||||
<p style="margin: 0; font-size: 13.5px; color: #4A5363">외부 이미지는 지금처럼 막아 두고, 원하면 그 메일만 보이게 합니다. 이미지는 사내 서버가 대신 받아 보여 주므로 보낸 사람에게 이 PC 의 주소가 드러나지 않습니다. 인쇄 · 차단은 ⋯ 메뉴에서 합니다.</p>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 860px minmax(0, 1fr); gap: 20px; align-items: start">
|
||||
|
||||
<section aria-label="읽기 화면 — 외부 이미지를 막은 메일" style="display: flex; flex-direction: column; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px; overflow: hidden">
|
||||
<div style="display: flex; align-items: center; gap: 2px; min-height: 52px; box-sizing: border-box; padding: 4px 24px; border-bottom: 1px solid #EEF0F3">
|
||||
<button type="button" class="tool" style="display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 10px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 17 4 12 9 7"></polyline><path d="M20 18v-2a4 4 0 0 0-4-4H4"></path></svg><span>답장</span></button>
|
||||
<button type="button" class="tool" style="display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 10px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer"><span>전체 답장</span></button>
|
||||
<button type="button" class="tool" style="display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 10px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 17 20 12 15 7"></polyline><path d="M4 18v-2a4 4 0 0 1 4-4h12"></path></svg><span>전달</span></button>
|
||||
<span aria-hidden="true" style="width: 1px; height: 20px; margin: 0 8px; background: #E6E8EC"></span>
|
||||
<button type="button" class="tool" style="display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 10px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg><span>스팸 신고</span></button>
|
||||
<button type="button" class="tool" style="display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 10px; border: 0; border-radius: 8px; color: #B42318; font: inherit; font-weight: 500; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg><span>삭제</span></button>
|
||||
<button type="button" class="tool" aria-label="더 보기" aria-haspopup="menu" aria-expanded="true" style="display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border: 0; border-radius: 8px; background: #EEF0F3; cursor: pointer"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="1"></circle><circle cx="19" cy="12" r="1"></circle><circle cx="5" cy="12" r="1"></circle></svg></button>
|
||||
</div>
|
||||
|
||||
<article aria-labelledby="rt-subject" style="display: flex; flex-direction: column; gap: 18px; box-sizing: border-box; padding: 20px 32px 32px">
|
||||
<h2 id="rt-subject" style="margin: 4px 0 0; font-size: 20px; line-height: 1.4; font-weight: 650; letter-spacing: -0.015em">[클라우드 브리프] 10월 넷째 주 — 서버 비용 줄이는 다섯 가지</h2>
|
||||
<div style="display: flex; align-items: flex-start; gap: 12px">
|
||||
<span aria-hidden="true" style="flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 50%; background: #E3F2F3; color: #0A5F67; font-size: 14px; font-weight: 600">클</span>
|
||||
<div style="flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px">
|
||||
<div style="display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px">
|
||||
<span style="font-size: 13.5px; font-weight: 600">클라우드 브리프</span>
|
||||
<span style="font-size: 12.5px; color: #667085">news@cloudbrief.example</span>
|
||||
<span style="margin-left: auto; font-size: 12.5px; color: #667085; white-space: nowrap; font-variant-numeric: tabular-nums">2026. 10. 29. (목) 오전 8:00</span>
|
||||
</div>
|
||||
<span style="font-size: 12.5px; color: #4A5363">받는 사람 김아라 <ara.kim@arasystem.it.kr></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 8px 8px 8px 12px; border-radius: 8px; background: #FFF7E6; color: #7A5200; font-size: 12.5px">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: 0 0 auto"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
|
||||
<span style="flex: 1 1 auto">외부 이미지를 차단했습니다. 개인정보 보호를 위해 보낸 사람 서버의 이미지는 불러오지 않습니다.</span>
|
||||
<button type="button" class="notice-btn" style="flex: 0 0 auto; min-height: 36px; padding: 0 12px; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer">이미지 보기</button>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 12px; max-width: 640px; font-size: 14px; line-height: 1.75; color: #1F2733">
|
||||
<p style="margin: 0">안녕하세요, 이번 주 클라우드 브리프입니다. 서버 비용을 줄이는 다섯 가지 방법을 정리했습니다.</p>
|
||||
<p style="margin: 0">1. 쓰지 않는 디스크 정리하기 — 스냅숏만 남기고 붙어 있지 않은 볼륨을 지우면 …</p>
|
||||
<p style="margin: 0">2. 예약 인스턴스로 바꾸기 — 1년 약정이면 …</p>
|
||||
<p style="margin: 0; color: #667085">(이미지가 있던 자리는 비어 있습니다 — 글은 그대로 읽힙니다.)</p>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 20px">
|
||||
<div role="menu" aria-label="더 보기" style="display: flex; flex-direction: column; width: 300px; padding: 6px; border: 1px solid #E6E8EC; border-radius: 10px; background: #FFFFFF; box-shadow: 0 10px 28px rgba(16, 24, 28, 0.12)">
|
||||
<button type="button" role="menuitem" class="menu-item" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; text-align: left; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 6 2 18 2 18 9"></polyline><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"></path><rect x="6" y="14" width="12" height="8"></rect></svg><span style="flex: 1 1 auto">인쇄</span><span style="font-size: 12px; color: #667085">Ctrl+P</span></button>
|
||||
<button type="button" role="menuitem" class="menu-item" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; text-align: left; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg><span>원문 내려받기 (.eml)</span></button>
|
||||
<span role="separator" style="height: 1px; margin: 4px 6px; background: #EEF0F3"></span>
|
||||
<button type="button" role="menuitem" class="menu-item" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; text-align: left; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><line x1="20" y1="8" x2="20" y2="14"></line><line x1="23" y1="11" x2="17" y2="11"></line></svg><span>보낸 사람을 주소록에 추가</span></button>
|
||||
<button type="button" role="menuitem" class="menu-item" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; text-align: left; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon></svg><span>이런 메일로 필터 만들기</span></button>
|
||||
<button type="button" role="menuitem" class="menu-item" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border: 0; border-radius: 6px; color: #B42318; font: inherit; text-align: left; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line></svg><span>보낸 사람 차단</span></button>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363; max-width: 380px">「인쇄」는 새 탭에 인쇄 화면을 열고 바로 인쇄 창을 띄웁니다(다음 보드). 읽기 화면에서 Ctrl+P 를 눌러도 같습니다. 이미 차단한 보낸 사람이면 마지막 항목이 「보낸 사람 차단 풀기」입니다. 사내 직원 · 내 주소는 차단 항목이 없습니다.</p>
|
||||
|
||||
<div role="dialog" aria-modal="true" aria-labelledby="blk-title" style="width: 400px; box-sizing: border-box; padding: 18px 20px 14px; border: 1px solid #E6E8EC; border-radius: 12px; background: #FFFFFF; box-shadow: 0 14px 36px rgba(16, 24, 28, 0.14); display: flex; flex-direction: column; gap: 14px">
|
||||
<h2 id="blk-title" style="margin: 0; font-size: 15px; font-weight: 700">보낸 사람 차단</h2>
|
||||
<p style="margin: 0; font-size: 13px; color: #344054">앞으로 오는 메일을 스팸메일함으로 보냅니다. 부재중 자동 응답도 보내지 않습니다.</p>
|
||||
<div role="radiogroup" aria-label="차단할 범위" style="display: flex; flex-direction: column; gap: 4px">
|
||||
<label style="display: flex; align-items: flex-start; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 10px 10px; border: 1px solid #0E7C86; border-radius: 8px; background: #F2FAFA; cursor: pointer">
|
||||
<input type="radio" name="blk-scope" checked style="width: 18px; height: 18px; margin: 1px 0 0; accent-color: #0E7C86">
|
||||
<span style="display: flex; flex-direction: column; line-height: 1.4"><span style="font-weight: 600">이 주소만</span><span style="font-size: 12.5px; color: #4A5363">news@cloudbrief.example</span></span>
|
||||
</label>
|
||||
<label style="display: flex; align-items: flex-start; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 10px 10px; border: 1px solid #D0D5DD; border-radius: 8px; cursor: pointer">
|
||||
<input type="radio" name="blk-scope" style="width: 18px; height: 18px; margin: 1px 0 0; accent-color: #0E7C86">
|
||||
<span style="display: flex; flex-direction: column; line-height: 1.4"><span style="font-weight: 600">이 도메인 전체</span><span style="font-size: 12.5px; color: #4A5363">@cloudbrief.example 에서 오는 메일 모두</span></span>
|
||||
</label>
|
||||
</div>
|
||||
<label style="display: flex; align-items: center; gap: 10px; min-height: 40px; cursor: pointer">
|
||||
<input type="checkbox" checked style="width: 18px; height: 18px; margin: 0; accent-color: #0E7C86">
|
||||
<span>이 메일도 스팸메일함으로 옮기기</span>
|
||||
</label>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #667085">차단한 주소는 설정 › 메일 › 차단한 주소에서 풀 수 있습니다.</p>
|
||||
<div style="display: flex; justify-content: flex-end; gap: 8px">
|
||||
<button type="button" class="primary" style="min-height: 44px; padding: 0 18px; border: 0; border-radius: 8px; font: inherit; font-weight: 600; cursor: pointer">차단</button>
|
||||
<button type="button" class="ghost" style="min-height: 44px; padding: 0 14px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer">취소</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; align-items: start">
|
||||
|
||||
<section style="display: flex; flex-direction: column; gap: 12px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 2px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">[이미지 보기]를 누른 뒤</h2>
|
||||
<p style="margin: 0; font-size: 12px; color: #667085">그 메일만 · 다시 열면 설정대로</p>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column; gap: 10px; padding: 14px; border: 1px solid #EEF0F3; border-radius: 8px">
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 120px; border-radius: 6px; background: linear-gradient(135deg, #DDEFF1, #F3E9D8); color: #4A5363; font-size: 12.5px">(받아 온 이미지)</div>
|
||||
<p style="margin: 0; font-size: 13.5px; color: #1F2733">안녕하세요, 이번 주 클라우드 브리프입니다. …</p>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363">안내 줄은 사라집니다. 이미지를 받지 못한 자리(없어진 주소 · 너무 큰 파일 · 사내망 주소)는 비어 있습니다. 메일 안의 배경 그림은 보이지 않습니다.</p>
|
||||
</section>
|
||||
|
||||
<section style="display: flex; flex-direction: column; gap: 12px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 2px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">설정에 따라 처음부터 보일 때</h2>
|
||||
<p style="margin: 0; font-size: 12px; color: #667085">설정 › 메일 › 보내기 · 읽기 › 외부 이미지</p>
|
||||
</div>
|
||||
<ul style="margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; color: #344054">
|
||||
<li><strong>늘 묻기</strong>(처음 값) — 메일마다 [이미지 보기]</li>
|
||||
<li><strong>주소록 · 사내 직원의 메일은 늘 보기</strong> — 보낸 사람이 내 주소록이나 사내 목록에 있으면 바로 보입니다. 나머지는 [이미지 보기]</li>
|
||||
<li><strong>늘 보기</strong> — 모든 메일에서 바로 보입니다</li>
|
||||
</ul>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363">스팸메일함의 메일은 설정과 상관없이 늘 묻습니다. 답장 · 전달에 인용한 본문에는 이미지가 실리지 않습니다(지금과 같음).</p>
|
||||
</section>
|
||||
|
||||
<section style="display: flex; flex-direction: column; gap: 10px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 2px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">차단한 뒤</h2>
|
||||
<p style="margin: 0; font-size: 12px; color: #667085">알림 · 스팸메일함에서 읽을 때</p>
|
||||
</div>
|
||||
<div role="status" style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 6px 6px 6px 14px; border-radius: 10px; background: #0B3640; color: #FFFFFF">
|
||||
<span style="flex: 1 1 auto; font-weight: 500">news@cloudbrief.example 을 차단하고 이 메일을 스팸메일함으로 옮겼습니다.</span>
|
||||
<button type="button" class="toast-action" style="min-height: 36px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer">되돌리기</button>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 8px 8px 8px 12px; border-radius: 8px; background: #F2F4F7; color: #344054; font-size: 12.5px">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: 0 0 auto"><circle cx="12" cy="12" r="10"></circle><line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line></svg>
|
||||
<span style="flex: 1 1 auto">차단한 보낸 사람의 메일입니다.</span>
|
||||
<button type="button" class="ghost" style="flex: 0 0 auto; min-height: 36px; padding: 0 10px; border: 1px solid #D0D5DD; border-radius: 6px; background: #FFFFFF; font: inherit; font-weight: 600; cursor: pointer">차단 풀기</button>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363">[되돌리기]는 차단을 풀고 메일을 받은편지함으로 돌려놓습니다. 「이 도메인 전체」는 gmail.com · naver.com 처럼 여러 사람이 쓰는 메일 서비스에서는 고를 수 없습니다(까닭을 칸 아래에).</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":1220}}'>
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,203 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>보내기 취소 · 예약 발송</title>
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<style>
|
||||
@font-face{font-family:'Pretendard';src:url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2-variations'),url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2');font-weight:45 920;font-style:normal;font-display:swap}
|
||||
body{margin:0}
|
||||
a{color:#0E7C86}a:hover{color:#0A5F67}
|
||||
:focus-visible{outline:2px solid #0E7C86;outline-offset:2px}
|
||||
.primary{background:#0E7C86;color:#FFFFFF}
|
||||
.primary:hover{background:#0A5F67}
|
||||
.ghost{background:transparent;color:#4A5363}
|
||||
.ghost:hover{background:#F2F4F7;color:#171C26}
|
||||
.field{box-sizing:border-box;border:1px solid #D0D5DD;border-radius:8px;background:#FFFFFF;font:inherit;color:#171C26}
|
||||
.menu-item{background:transparent;color:#344054}
|
||||
.menu-item:hover{background:#EEF0F3}
|
||||
.toast-action{background:transparent;color:#9ED6DB}
|
||||
.toast-action:hover{background:rgba(255,255,255,0.1)}
|
||||
.row:hover{background:#F6F7F9}
|
||||
</style>
|
||||
</helmet>
|
||||
<div style="width: 1440px; height: 1500px; box-sizing: border-box; padding: 48px; display: flex; flex-direction: column; gap: 28px; background: #F6F7F9; color: #171C26; font-family: Pretendard, -apple-system, 'Apple SD Gothic Neo', 'Malgun Gothic', system-ui, sans-serif; font-size: 13px; line-height: 1.5">
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 6px; max-width: 1000px">
|
||||
<h1 style="margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -0.02em">보내기 취소 · 예약 발송</h1>
|
||||
<p style="margin: 0; font-size: 13.5px; color: #4A5363">[보내기]를 누르면 메일 서버가 몇 초(설정 — 처음 10초) 기다렸다가 보냅니다. 그동안 [보내기 취소]로 쓰기 화면에 돌아옵니다. 기다리는 곳이 서버라 창을 닫아도 그대로 보내집니다. 예약 발송은 같은 방식으로 7일 안의 시각까지 기다립니다.</p>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 480px 420px minmax(0, 1fr); gap: 20px; align-items: start">
|
||||
|
||||
<section style="display: flex; flex-direction: column; gap: 12px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 2px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">쓰기 화면 — 보내기 ▾</h2>
|
||||
<p style="margin: 0; font-size: 12px; color: #667085">단추를 둘로 나눕니다 — 오른쪽 ▾ 는 메뉴</p>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 12px; min-height: 64px; box-sizing: border-box; padding: 10px 12px; border: 1px solid #EEF0F3; border-radius: 10px">
|
||||
<div style="display: inline-flex; align-items: stretch; border-radius: 8px; overflow: hidden">
|
||||
<button type="button" class="primary" style="display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px 0 18px; border: 0; font: inherit; font-weight: 600; cursor: pointer"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg><span>보내기</span></button>
|
||||
<span aria-hidden="true" style="width: 1px; background: rgba(255, 255, 255, 0.35)"></span>
|
||||
<button type="button" class="primary" aria-label="보내기 방법 더 보기" aria-haspopup="menu" aria-expanded="true" style="display: inline-flex; align-items: center; justify-content: center; width: 40px; min-height: 44px; border: 0; font: inherit; cursor: pointer; background: #0A5F67"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"></polyline></svg></button>
|
||||
</div>
|
||||
<button type="button" class="ghost" style="min-height: 44px; padding: 0 12px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer">임시 저장</button>
|
||||
<span style="margin-left: auto; font-size: 12px; color: #667085">2분 전에 저장함</span>
|
||||
</div>
|
||||
<div role="menu" aria-label="보내기 방법" style="display: flex; flex-direction: column; width: 260px; margin-top: -4px; padding: 6px; border: 1px solid #E6E8EC; border-radius: 10px; background: #FFFFFF; box-shadow: 0 10px 28px rgba(16, 24, 28, 0.12)">
|
||||
<button type="button" role="menuitem" class="menu-item" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; text-align: left; cursor: pointer"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg><span>예약 발송…</span></button>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363">메뉴는 「예약 발송…」 하나로 시작합니다. 단축키 Ctrl+Enter 는 그대로 [보내기]입니다. 보내는 중 · 저장 중 · 첨부를 올리는 중에는 두 단추가 함께 꺼집니다(지금의 [보내기]와 같은 규칙).</p>
|
||||
</section>
|
||||
|
||||
<div role="dialog" aria-modal="true" aria-labelledby="sch-title" style="box-sizing: border-box; padding: 18px 20px 14px; border: 1px solid #E6E8EC; border-radius: 12px; background: #FFFFFF; box-shadow: 0 14px 36px rgba(16, 24, 28, 0.14); display: flex; flex-direction: column; gap: 14px">
|
||||
<h2 id="sch-title" style="margin: 0; font-size: 15px; font-weight: 700">예약 발송</h2>
|
||||
<div role="radiogroup" aria-label="보낼 시각" style="display: flex; flex-direction: column; gap: 4px">
|
||||
<label style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 0 10px; border: 1px solid #0E7C86; border-radius: 8px; background: #F2FAFA; cursor: pointer">
|
||||
<input type="radio" name="sch" checked style="width: 18px; height: 18px; margin: 0; accent-color: #0E7C86">
|
||||
<span style="flex: 1 1 auto; font-weight: 600">내일 오전</span><span style="font-size: 12.5px; color: #4A5363; font-variant-numeric: tabular-nums">10월 30일 (금) 오전 9:00</span>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 0 10px; border: 1px solid #D0D5DD; border-radius: 8px; cursor: pointer">
|
||||
<input type="radio" name="sch" style="width: 18px; height: 18px; margin: 0; accent-color: #0E7C86">
|
||||
<span style="flex: 1 1 auto; font-weight: 600">내일 오후</span><span style="font-size: 12.5px; color: #4A5363; font-variant-numeric: tabular-nums">10월 30일 (금) 오후 1:00</span>
|
||||
</label>
|
||||
<label style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 0 10px; border: 1px solid #D0D5DD; border-radius: 8px; cursor: pointer">
|
||||
<input type="radio" name="sch" style="width: 18px; height: 18px; margin: 0; accent-color: #0E7C86">
|
||||
<span style="flex: 1 1 auto; font-weight: 600">다음 주 월요일</span><span style="font-size: 12.5px; color: #4A5363; font-variant-numeric: tabular-nums">11월 2일 (월) 오전 9:00</span>
|
||||
</label>
|
||||
<label style="display: flex; flex-direction: column; gap: 8px; box-sizing: border-box; padding: 10px; border: 1px solid #D0D5DD; border-radius: 8px; cursor: pointer">
|
||||
<span style="display: flex; align-items: center; gap: 10px"><input type="radio" name="sch" style="width: 18px; height: 18px; margin: 0; accent-color: #0E7C86"><span style="font-weight: 600">직접 고르기</span></span>
|
||||
<span style="display: flex; gap: 8px; padding-left: 28px">
|
||||
<input class="field" type="date" value="2026-10-30" aria-label="날짜" style="height: 40px; padding: 0 10px; flex: 1 1 auto">
|
||||
<select class="field" aria-label="시각" style="height: 40px; padding: 0 8px; flex: 0 0 130px"><option>오전 9:00</option></select>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #667085">이 PC 의 시간(한국 표준시)으로 보냅니다 · 7일 안에서 고를 수 있습니다.</p>
|
||||
<div style="display: flex; justify-content: flex-end; gap: 8px">
|
||||
<button type="button" class="primary" style="min-height: 44px; padding: 0 18px; border: 0; border-radius: 8px; font: inherit; font-weight: 600; cursor: pointer">예약</button>
|
||||
<button type="button" class="ghost" style="min-height: 44px; padding: 0 14px; border: 0; border-radius: 8px; font: inherit; font-weight: 500; cursor: pointer">취소</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section style="display: flex; flex-direction: column; gap: 10px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">예약 시각 규칙</h2>
|
||||
<ul style="margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; color: #344054">
|
||||
<li>골라 둔 시각이 이미 지났거나 5분 안이면 칸 아래 "지금부터 5분 뒤 이후의 시각을 고르세요."</li>
|
||||
<li>7일을 넘으면 "7일 안의 시각만 고를 수 있습니다." — 메일 서버의 한도입니다</li>
|
||||
<li>시각은 30분 단위로 고릅니다. 오늘 오후가 남았으면 「오늘 오후 6:00」도 첫 줄에 보입니다</li>
|
||||
<li>예약한 메일도 받는 사람 확인은 지금 합니다 — 없는 주소면 지금과 같이 칸 아래에서 막습니다</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 520px minmax(0, 1fr); gap: 20px; align-items: start">
|
||||
<section style="display: flex; flex-direction: column; gap: 10px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 2px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">보낸 뒤 알림</h2>
|
||||
<p style="margin: 0; font-size: 12px; color: #667085">[보내기 취소]는 기다리는 시간 동안만 — 그 뒤 알림은 저절로 닫힙니다</p>
|
||||
</div>
|
||||
<div role="status" style="display: flex; flex-direction: column; gap: 6px; box-sizing: border-box; padding: 8px 6px 10px 14px; border-radius: 10px; background: #0B3640; color: #FFFFFF">
|
||||
<div style="display: flex; align-items: center; gap: 10px">
|
||||
<span style="flex: 1 1 auto; font-weight: 500">메일을 보냈습니다.</span>
|
||||
<button type="button" class="toast-action" style="min-height: 36px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer">보내기 취소</button>
|
||||
</div>
|
||||
<span aria-hidden="true" style="display: block; height: 3px; margin-right: 8px; border-radius: 2px; background: rgba(255, 255, 255, 0.18)"><span style="display: block; width: 62%; height: 100%; border-radius: 2px; background: #7FD3DA"></span></span>
|
||||
</div>
|
||||
<div role="status" style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 6px 6px 6px 14px; border-radius: 10px; background: #912018; color: #FFFFFF">
|
||||
<span style="flex: 1 1 auto; font-weight: 500">보냈지만 1명은 받지 못합니다 — nobody@arasystem.it.kr (없는 주소)</span>
|
||||
<button type="button" class="toast-action" style="min-height: 36px; padding: 0 10px; border: 0; border-radius: 6px; color: #FFD8D3; font: inherit; font-weight: 600; cursor: pointer">보내기 취소</button>
|
||||
</div>
|
||||
<div role="status" style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 6px 14px; border-radius: 10px; background: #0B3640; color: #FFFFFF">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9ED6DB" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: 0 0 auto"><polyline points="20 6 9 17 4 12"></polyline></svg>
|
||||
<span style="flex: 1 1 auto; font-weight: 500">보내기를 취소했습니다. 쓰던 메일로 돌아왔습니다.</span>
|
||||
</div>
|
||||
<div role="alert" style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 6px 14px; border-radius: 10px; background: #912018; color: #FFFFFF">
|
||||
<span style="flex: 1 1 auto; font-weight: 500">이미 보낸 메일이라 취소할 수 없습니다.</span>
|
||||
</div>
|
||||
<div role="status" style="display: flex; align-items: center; gap: 10px; min-height: 44px; box-sizing: border-box; padding: 6px 6px 6px 14px; border-radius: 10px; background: #0B3640; color: #FFFFFF">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9ED6DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: 0 0 auto"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
|
||||
<span style="flex: 1 1 auto; font-weight: 500">10월 30일 (금) 오전 9:00 에 보냅니다.</span>
|
||||
<button type="button" class="toast-action" style="min-height: 36px; padding: 0 10px; border: 0; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer">예약됨 보기</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section style="display: flex; flex-direction: column; gap: 10px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">보내기 취소의 흐름</h2>
|
||||
<ol style="margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; color: #344054">
|
||||
<li>[보내기] → 쓰기 화면을 닫고 알림 "메일을 보냈습니다." + [보내기 취소] + 남은 시간 막대(설정한 초 — 마우스를 올려도 시간은 멈추지 않습니다)</li>
|
||||
<li>[보내기 취소] → 서버가 보내지 않고 그 메일을 임시보관함으로 돌려놓습니다 → 쓰기 화면이 그 메일로 다시 열립니다(받는 사람 · 제목 · 본문 · 첨부 그대로)</li>
|
||||
<li>시간이 지나면 알림이 닫히고 메일은 보낸 것입니다 — 늦게 누르면 "이미 보낸 메일이라 취소할 수 없습니다."</li>
|
||||
<li>받는 사람 확인은 [보내기]를 누른 순간에 합니다 — 일부가 받지 못하면 그 알림에도 [보내기 취소]가 있어 주소를 고쳐 다시 보낼 수 있습니다</li>
|
||||
<li>설정 › 메일 › 보내기 · 읽기에서 끔 · 5 · 10 · 20 · 30초 — 끄면 지금처럼 바로 보냅니다</li>
|
||||
</ol>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363">기다리는 동안에도 보낸편지함에 보입니다(날짜 칸에 "보내는 중"). 다른 화면으로 옮겨 다녀도 알림은 그대로입니다. 로그아웃 · 다른 계정 로그인 때는 알림을 닫습니다 — 메일은 그대로 보내집니다.</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 280px 560px minmax(0, 1fr); gap: 20px; align-items: start">
|
||||
|
||||
<section aria-label="메일함 패널 — 예약됨" style="display: flex; flex-direction: column; gap: 2px; padding: 12px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<a href="#" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border-radius: 8px; color: #344054; text-decoration: none"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline><path d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"></path></svg><span style="flex: 1 1 auto">받은편지함</span><span style="font-size: 12px; font-weight: 600; color: #344054">5</span></a>
|
||||
<a href="#" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border-radius: 8px; color: #344054; text-decoration: none"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"></line><polygon points="22 2 15 22 11 13 2 9 22 2"></polygon></svg><span style="flex: 1 1 auto">보낸편지함</span></a>
|
||||
<a href="#" aria-current="page" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border-radius: 8px; background: #E3F2F3; color: #0A5F67; font-weight: 600; text-decoration: none"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg><span style="flex: 1 1 auto">예약됨</span><span style="font-size: 12px; font-weight: 600">2</span></a>
|
||||
<a href="#" style="display: flex; align-items: center; gap: 10px; min-height: 40px; padding: 0 10px; border-radius: 8px; color: #344054; text-decoration: none"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline></svg><span style="flex: 1 1 auto">임시보관함</span></a>
|
||||
<p style="margin: 6px 4px 0; font-size: 12px; color: #667085">「예약됨」은 예약한 메일이 있을 때만 보낸편지함 아래에 보입니다. 숫자는 예약한 통 수입니다.</p>
|
||||
</section>
|
||||
|
||||
<section aria-label="예약됨 목록" style="display: flex; flex-direction: column; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px; overflow: hidden">
|
||||
<div style="display: flex; align-items: baseline; gap: 10px; padding: 14px 20px; border-bottom: 1px solid #EEF0F3">
|
||||
<h2 style="margin: 0; font-size: 16px; font-weight: 700">예약됨</h2>
|
||||
<span style="font-size: 12.5px; color: #667085">2통 · 보낼 시각 차례</span>
|
||||
</div>
|
||||
<a href="#" class="row" style="display: grid; grid-template-columns: 150px minmax(0, 1fr) 150px; align-items: center; gap: 12px; min-height: 52px; padding: 0 20px; border-bottom: 1px solid #EEF0F3; color: #171C26; text-decoration: none">
|
||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">받는 사람: 이도윤</span>
|
||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500">11월 첫 주 배포 일정 확인 부탁드립니다</span>
|
||||
<span style="text-align: right; font-size: 12.5px; color: #0A5F67; font-weight: 600; font-variant-numeric: tabular-nums">10월 30일 (금) 오전 9:00</span>
|
||||
</a>
|
||||
<a href="#" class="row" style="display: grid; grid-template-columns: 150px minmax(0, 1fr) 150px; align-items: center; gap: 12px; min-height: 52px; padding: 0 20px; color: #171C26; text-decoration: none">
|
||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">받는 사람: 인프라팀 외 2명</span>
|
||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500">[공지] 메일 서버 전환 완료 안내</span>
|
||||
<span style="text-align: right; font-size: 12.5px; color: #0A5F67; font-weight: 600; font-variant-numeric: tabular-nums">11월 2일 (월) 오전 9:00</span>
|
||||
</a>
|
||||
<p style="margin: 0; padding: 12px 20px; font-size: 12px; color: #667085; border-top: 1px solid #EEF0F3">고르는 칸 · 여러 통 처리는 없습니다(한 통씩 엽니다). 보낸 메일은 저절로 이 목록에서 빠지고 보낸편지함에 남습니다.</p>
|
||||
</section>
|
||||
|
||||
<section style="display: flex; flex-direction: column; gap: 12px; padding: 20px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 2px">
|
||||
<h2 style="margin: 0; font-size: 14px; font-weight: 700">예약한 메일을 열면</h2>
|
||||
<p style="margin: 0; font-size: 12px; color: #667085">읽기 화면 머리 아래 안내 줄</p>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 8px; padding: 8px 8px 8px 12px; border-radius: 8px; background: #E3F2F3; color: #0A5F67; font-size: 12.5px">
|
||||
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex: 0 0 auto"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
|
||||
<span style="flex: 1 1 auto; font-weight: 500">10월 30일 (금) 오전 9:00 에 보낼 메일입니다.</span>
|
||||
<button type="button" class="ghost" style="flex: 0 0 auto; min-height: 36px; padding: 0 10px; border: 1px solid #9ED6DB; border-radius: 6px; background: #FFFFFF; color: #0A5F67; font: inherit; font-weight: 600; cursor: pointer">고치기</button>
|
||||
<button type="button" class="ghost" style="flex: 0 0 auto; min-height: 36px; padding: 0 10px; border: 1px solid #9ED6DB; border-radius: 6px; background: #FFFFFF; color: #0A5F67; font: inherit; font-weight: 600; cursor: pointer">예약 취소</button>
|
||||
</div>
|
||||
<ul style="margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; color: #344054">
|
||||
<li>[예약 취소] → 보내지 않고 임시보관함으로 옮깁니다 — 알림 "예약을 취소하고 임시보관함으로 옮겼습니다." + [고치기]</li>
|
||||
<li>[고치기] → 예약을 취소하고 쓰기 화면으로 엽니다 — 다시 [보내기] 또는 「예약 발송…」</li>
|
||||
<li>답장 · 전달 · 스팸 신고 단추는 이 메일에는 없습니다. [삭제]는 예약을 취소한 뒤 휴지통으로 옮깁니다(확인 창)</li>
|
||||
</ul>
|
||||
<div style="display: grid; grid-template-columns: minmax(0, 1fr) 150px; align-items: center; gap: 12px; min-height: 48px; padding: 0 12px; border: 1px solid #EEF0F3; border-radius: 8px">
|
||||
<span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap"><span style="color: #4A5363">이도윤</span> · <span style="font-weight: 500">11월 첫 주 배포 일정 확인 부탁드립니다</span></span>
|
||||
<span style="text-align: right; font-size: 12.5px; color: #0A5F67; font-weight: 600">예약 · 10월 30일 오전 9:00</span>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12px; color: #667085">보낸편지함에서도 보입니다 — 날짜 칸이 "예약 · 보낼 시각"(보내기 취소를 기다리는 동안은 "보내는 중")입니다.</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":1500}}'>
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -466,6 +466,63 @@ API 와 서버 규칙은 계약 2절 "실시간 알림".
|
||||
- **읽기 화면 ⋯**: 둘째 묶음(「이런 메일로 필터 만들기」 위)에 「보낸 사람을 주소록에 추가」 → 이름 · 주소를 채운 연락처 추가 창. 이미 내 주소록에 있으면 「주소록에서 보기」(그 연락처를 고른 주소록).
|
||||
사내 직원의 주소도 「보낸 사람을 주소록에 추가」. 보낸 사람 주소가 없는 메일은 항목이 없고, 연락처가 3,000개면 항목을 끄고 이름 아래에 까닭 한 줄.
|
||||
|
||||
## 9단계 — 보내기 취소 · 예약 발송 · 외부 이미지 · 인쇄 · 보낸 사람 차단 (2026-10-29 확정 — `MailReadTools` · `MailPrint` · `MailSendLater` · `SettingsSendRead`)
|
||||
|
||||
작고 자주 쓰는 다섯 가지를 한 번에 더한다. 계약은 `docs/mail/api-contract.md` 2절의 9단계 절들. 새 아이콘: 인쇄(printer) · 시계(clock) · 차단(원 + 빗금).
|
||||
|
||||
### 읽기 화면 — 외부 이미지 · ⋯ 메뉴 · 차단 (`MailReadTools`)
|
||||
|
||||
- **외부 이미지 줄**: 지금의 노란 안내 줄("외부 이미지를 차단했습니다. …") 오른쪽에 [이미지 보기](36 — 밀도 예외 `--size-notice-action`). 누르면 그 메일만 이미지를 보이고 안내 줄은 사라진다.
|
||||
다시 열면 설정대로다. 받지 못한 이미지 자리는 비어 있다. 메일 안의 배경 그림은 보이지 않는다(알려진 한계).
|
||||
- **설정에 따라**(설정 › 메일 › 보내기 · 읽기 › 외부 이미지): 늘 묻기(처음 값) · 주소록과 사내 직원은 늘 보기 · 늘 보기. 처음부터 보이면 안내 줄이 없다. **스팸메일함의 메일은 늘 묻는다.**
|
||||
- **⋯ 메뉴**: 「인쇄」(Ctrl+P 표시) → 「원문 내려받기 (.eml)」 → 구분선 → 「보낸 사람을 주소록에 추가」/「주소록에서 보기」 → 「이런 메일로 필터 만들기」 → 「보낸 사람 차단」(빨간 글).
|
||||
이미 차단한 보낸 사람이면 마지막 항목이 「보낸 사람 차단 풀기」. 사내 직원 · 내 주소에는 차단 항목이 없다. 차단한 주소가 500개면 항목을 끄고 이름 아래에 까닭.
|
||||
- **차단 확인 창**(모달 400): 제목 "보낸 사람 차단", 설명 "앞으로 오는 메일을 스팸메일함으로 보냅니다. 부재중 자동 응답도 보내지 않습니다."
|
||||
고르기 둘 — 「이 주소만」(주소) · 「이 도메인 전체」(@도메인) — 여러 사람이 쓰는 메일 서비스(gmail.com · naver.com 등)는 도메인을 고를 수 없게 끄고 그 아래에 까닭.
|
||||
체크 「이 메일도 스팸메일함으로 옮기기」(처음 켜짐), 안내 "차단한 주소는 설정 › 메일 › 차단한 주소에서 풀 수 있습니다." — [차단](처음 초점 — 되돌릴 수 있는 일) [취소].
|
||||
- **차단한 뒤**: 알림 "‘주소’ 을 차단하고 이 메일을 스팸메일함으로 옮겼습니다." + [되돌리기](차단을 풀고 메일을 받은편지함으로). 스팸메일함에서 차단한 보낸 사람의 메일을 열면
|
||||
회색 안내 줄 "차단한 보낸 사람의 메일입니다." + [차단 풀기].
|
||||
|
||||
### 인쇄 화면 (`MailPrint`)
|
||||
|
||||
- ⋯ › 인쇄(또는 읽기 화면에서 Ctrl+P)는 **새 탭**에 인쇄 화면을 열고 브라우저의 인쇄 창을 바로 띄운다. 앱의 레일 · 메일함 · 목록 · 도구 줄은 인쇄하지 않는다.
|
||||
- 화면에만 보이는 위 줄: "인쇄 화면" + [인쇄](다시 띄우기) [닫기](탭 닫기). 인쇄 창을 닫아도 탭은 남는다.
|
||||
- 인쇄하는 것: 머리 줄(「ARA SYSTEM 메일」 · 인쇄한 직원의 이름 <주소>) → 제목 → 보낸 사람 · 받는 사람 · 참조 · 날짜(읽기 화면에 보이는 것 — 숨은참조는 넣지 않는다) →
|
||||
첨부(이름 · 크기만) → 가는 선 → 본문(읽기 화면과 같은 정화). 쪽 번호 · 날짜는 브라우저의 머리글 · 바닥글 설정을 따른다.
|
||||
- 외부 이미지는 읽기 화면에서 보이던 대로. 본문은 인쇄 폭(A4)에 맞춰 높이를 다시 잰 뒤 인쇄한다 — 긴 메일은 여러 쪽으로 이어지고 끝에 빈 쪽이 생기지 않는다
|
||||
(2026-10-29 확인: 지금 화면을 그대로 인쇄하면 앱 틀까지 찍히고, 화면 폭에서 잰 본문 높이 때문에 끝에 빈 쪽이 10장 생겼다).
|
||||
- 못 열 때: 메일을 찾을 수 없으면 "메일을 찾을 수 없습니다" + [닫기], 받지 못하면 [다시 시도] — 인쇄 창은 띄우지 않는다. 세션이 끝났으면 로그인 화면으로.
|
||||
|
||||
### 보내기 취소 · 예약 발송 (`MailSendLater`)
|
||||
|
||||
- **[보내기 ▾]**: 쓰기 화면의 [보내기]를 둘로 나눈다 — 왼쪽은 지금의 [보내기], 오른쪽 ▾(44 — 보드는 40, 밀도 예외를 새로 만들지 않는다)는 메뉴 「예약 발송…」(시계 아이콘). Ctrl+Enter 는 그대로 [보내기].
|
||||
보내는 중 · 저장 중 · 첨부를 올리는 중에는 두 단추를 함께 끈다(지금의 [보내기]와 같은 규칙).
|
||||
- **예약 창**(모달 400): 제목 "예약 발송". 고르기 넷 — 「내일 오전」 9:00 · 「내일 오후」 1:00 · 「다음 주 월요일」 9:00 · 「직접 고르기」(날짜 칸 + 30분 단위 시각) — 줄마다 오른쪽에 날짜 · 요일 · 시각.
|
||||
오늘 오후가 남았으면 「오늘 오후」 6:00 이 첫 줄. 안내 "이 PC 의 시간(한국 표준시)으로 보냅니다 · 7일 안에서 고를 수 있습니다." [예약] [취소].
|
||||
칸 아래 오류: "지금부터 5분 뒤 이후의 시각을 고르세요." · "7일 안의 시각만 고를 수 있습니다." 받는 사람 확인은 지금처럼 보내는 순간(없는 주소면 받는 사람 칸의 띠).
|
||||
- **보낸 뒤 알림**(오른쪽 아래): "메일을 보냈습니다." + [보내기 취소] + 아래 남은 시간 막대(설정한 초 — 마우스를 올려도 멈추지 않는다) → 시간이 지나면 저절로 닫힌다.
|
||||
일부가 받지 못하면 빨간 알림 "보냈지만 1명은 받지 못합니다 — 주소 (까닭)" + [보내기 취소](주소를 고쳐 다시 보낼 수 있게).
|
||||
[보내기 취소] → "보내기를 취소했습니다. 쓰던 메일로 돌아왔습니다." + 그 메일로 쓰기 화면(받는 사람 · 제목 · 본문 · 첨부 그대로). 늦게 누르면 "이미 보낸 메일이라 취소할 수 없습니다."
|
||||
예약 → "10월 30일 (금) 오전 9:00 에 보냅니다." + [예약됨 보기]. 로그아웃 · 다른 계정 로그인 때 알림은 닫는다 — 메일은 그대로 보내진다.
|
||||
- **「예약됨」**: 메일함 패널의 보낸편지함 아래(예약한 메일이 있을 때만, 시계 아이콘, 오른쪽에 통 수). 목록은 받는 사람 · 제목 · 보낼 시각(청록 글 — "10월 30일 (금) 오전 9:00") 차례,
|
||||
고르는 칸 · 여러 통 처리는 없다. 보낸 메일은 저절로 빠지고 보낸편지함에 남는다.
|
||||
- **예약한 메일을 열면**: 머리 아래 청록 안내 줄 "10월 30일 (금) 오전 9:00 에 보낼 메일입니다." + [고치기](예약을 취소하고 쓰기 화면으로) [예약 취소](보내지 않고 임시보관함으로 —
|
||||
알림 "예약을 취소하고 임시보관함으로 옮겼습니다." + [고치기]). 답장 · 전달 · 스팸 신고 단추는 없다. [삭제]는 예약을 취소한 뒤 휴지통으로(확인 창).
|
||||
- **보낸편지함**: 아직 보내지 않은 메일은 날짜 칸이 "예약 · 10월 30일 오전 9:00"(청록) — 보내기 취소를 기다리는 동안은 "보내는 중".
|
||||
|
||||
### 설정 · 보내기 · 읽기 · 차단한 주소 (`SettingsSendRead`)
|
||||
|
||||
- **메뉴**: 메일 묶음에 「보내기 · 읽기」(필터 아래) · 「차단한 주소」를 더한다 — 서명 · 부재중 자동 응답 · 필터 · 보내기 · 읽기 · 차단한 주소 · 알림.
|
||||
- **보내기 · 읽기**: 고르는 대로 저장한다(저장 단추 없음 — 머리 오른쪽에 "저장했습니다"). 서버에 저장되어 어느 PC 에서나 같다.
|
||||
- 「보내기 취소」 — 눌림 전환(36 — `.segmented`) 끔 · 5초 · 10초(처음) · 20초 · 30초 + "[보내기]를 누른 뒤 이 시간 동안 [보내기 취소]로 되돌릴 수 있습니다. 그동안 메일은 메일 서버에서 기다리므로 창을 닫아도 보내집니다."
|
||||
- 「외부 이미지」 — 라디오 셋(늘 묻기 · 주소록 · 사내 직원의 메일은 늘 보기 · 늘 보기, 줄마다 아래 설명) + 회색 상자
|
||||
"외부 이미지는 사내 메일 서버가 대신 받아 보여 줍니다 — 보낸 사람에게 이 PC 의 주소는 드러나지 않습니다. 다만 이미지를 받으면 보낸 사람은 메일을 열어 본 것을 알 수 있습니다."
|
||||
- **차단한 주소**: 머리 "차단한 주소" + "3 / 500" + 설명 "이 주소에서 오는 메일은 스팸메일함으로 갑니다. 부재중 자동 응답도 보내지 않습니다. 「@도메인」은 그 도메인에서 오는 메일 모두입니다."
|
||||
- 더하기 줄: 칸 "차단할 주소"(placeholder "kim@example.com 또는 @example.com") + [차단]. 칸 아래 오류: "메일 주소나 @도메인 형식으로 써 주세요." · "이미 차단한 주소입니다." ·
|
||||
"내 주소 · 사내 도메인은 차단할 수 없습니다." · "gmail.com 처럼 여러 사람이 쓰는 메일 서비스는 도메인으로 막을 수 없습니다 — 주소로 막아 주세요." · "500개까지 차단할 수 있습니다."
|
||||
- 목록: 줄마다 주소(굵게) + 아래 작은 글 "10월 29일 차단"(도메인은 "도메인 전체 · …") + [차단 풀기](36). 누르면 바로 풀고 알림 "‘주소’ 차단을 풀었습니다." + [되돌리기].
|
||||
이미 받은 메일은 옮기지 않는다. 비었으면 "차단한 주소가 없습니다. 메일의 ⋯ › 보낸 사람 차단으로도 막을 수 있습니다."
|
||||
|
||||
## 구현하며 정한 보완 (2026-10-26 — 캔버스에는 아직 없다)
|
||||
|
||||
- 찾지 못한 첨부(보관 시간이 지난 업로드·지워진 원본)는 실패로 표시하고, 전달 원본에는 "빼기"만 둔다(다시 올릴 수 없다).
|
||||
@@ -692,3 +749,55 @@ API 와 서버 규칙은 계약 2절 "실시간 알림".
|
||||
- **창의 자리**: 주소록의 연락처 · 그룹 · 구성원 창은 주소록 화면의 틀에 둔다 — 주소록 안에서 옮겨 다녀도 닫히지 않고, 주소록을 떠나면 나가기 확인을 묻고, 세션이 바뀌면 닫는다(메일 화면의 창도 같다).
|
||||
- **서버 쪽에서 생긴 한계**(계약 3절): 엔진이 만든 뒤 uid 를 바꾸지 못하게 해서 다른 프로그램이 uid 없이 만든 카드는 그룹에 넣을 수 없다 — 고치기 창에서 그 저장은 창 안 사전 문구.
|
||||
다른 프로그램이 넣은 값이 우리 규칙 밖이면 그 칸을 고칠 때만 그 값도 규칙에 맞춰야 한다(다른 칸은 그대로 고칠 수 있다).
|
||||
|
||||
### 9단계 구현하며 정한 보완 (2026-10-29 — 캔버스에는 아직 없다)
|
||||
|
||||
- **외부 이미지**: [이미지 보기]는 받는 동안 꺼진다(`aria-disabled` · `aria-busy`). 받지 못하면 인터셉터가 알리고 줄은 그대로다. 그 메일의 본문 칸만 바꾸고(받는 사이 다른 메일을 열었으면 버린다),
|
||||
줄이 사라져 초점을 잃으면 본문 틀로 옮긴다. 본문 틀의 CSP 는 보일 때만 그림에 우리 출처의 중계 경로(`/api/mail-images/`)를 연다 — 경로까지 좁힌다(2026-10-29 리뷰).
|
||||
중계 주소로 인정하는 모양은 `/api/mail-images/<base64url 한 칸>` 뿐이다(짝: backend `TOKEN_PATTERN`). 답장 · 전달 인용에는 중계 그림도 실리지 않는다.
|
||||
- **인쇄**: 라우트 `mail-print`(앱 틀 없음 · 로그인 필요), 탭 제목은 메일 제목(인쇄 머리글 · PDF 이름으로 쓰인다). `window.open` 은 누름 처리 안에서 바로 부른다(팝업 차단을 피하려고).
|
||||
- Ctrl+P(⌘P)는 메일이 다 열려 있을 때만 가로챈다 — 본문 틀 안에서 눌러도 같고, 한글 조합 중 · 다른 수식키 · 불러오는 중이면 브라우저 인쇄 그대로다. 라틴 글자가 아닌 배열은 `code === 'KeyP'` 로도 잡는다.
|
||||
- 종이 210mm · 여백 16mm 15mm 는 @page 와 같은 값이다(둘을 함께 고친다). 본문 틀의 load(그림까지) · 글꼴 준비 · 한 프레임 뒤에 인쇄 창을 한 번만 띄운다 —
|
||||
그사이 다시 받기 시작했으면 띄우지 않고, [인쇄]는 다 잰 뒤에만 눌린다. [닫기]로 닫히지 않는 탭(주소로 바로 들어온 탭)은 메일 화면으로 간다.
|
||||
- 첨부는 목록에 보이는 것만 "이름 (크기)", 날짜는 "2026년 10월 26일 (월) 오전 10:42". 받기 실패는 화면이 그린다(알림 없음). 문구: "(제목 없음)" · "(보낸 사람 없음)" · 받는 중 "메일을 불러오는 중".
|
||||
- **보내기 취소 알림**: 마감은 설정한 초를 알면 "지금 + 그 초 − 1초", 모르면 min(sendAt, 지금 + 30초)이다(설정은 메일 화면에 들어올 때 받아 둔다 — 아는 값이 0 인데 서버가 붙잡았으면 sendAt).
|
||||
이 PC 시계로 이미 지났으면 지금처럼 [보낸편지함 보기] 알림이다. 마감이 있는 알림은 마우스 · 초점으로 멈추지 않고, 알림이 넘쳐도 먼저 닫히지 않는다. 막대는 `<progress>`(aria-hidden)다.
|
||||
- 알림 단추는 한 번만 돈다(닫히는 전환 중에 두 번 눌러도 — `takeAction`). 같은 메일의 취소는 요청 하나로 묶는다. 초점이 든 알림이 닫히면 알림에 들어오기 전 요소로(없으면 본문 영역) 돌려준다.
|
||||
- 쓰기 화면으로 가지 못하면(그 화면의 나가기 확인에서 머묾 등) 그 자리에 두고 "보내기를 취소하고 임시보관함으로 옮겼습니다." + [고치기].
|
||||
- 일부 거절 문장은 붙잡은 발송이면 "받지 못합니다"(현재형)다. 예약에서 일부 거절: "예약했지만 N명은 받지 못합니다 — 주소 (까닭)" + [예약됨 보기].
|
||||
- **[보내기 ▾]**: ▾ 이름 "보내기 방법 더 보기", 메뉴 이름 "보내기 방법". 메뉴는 아래가 모자라면 위로 연다(`usePopupPlacement` — 메일함 ⋯ 과 같은 규칙). 「예약 발송…」은 [보내기]와 같은 사전 검사를 먼저 한다(걸리면 창을 열지 않고 그 칸으로).
|
||||
- **예약 창**: 「오늘 오후」 6:00 은 5분 뒤 이후일 때만, 「다음 주 월요일」은 오늘 다음의 첫 월요일(오늘이 월요일이면 7일 뒤)이다. 예약할 수 없는 시각은 빼고, 같은 시각이 겹치면 앞의 것만 둔다.
|
||||
직접 고르기는 오늘 ~ 7일 뒤 · 30분 단위, 처음 값은 내일 오전 9:00, 검사는 [예약]을 누를 때(role=alert). 시간대 이름을 모르면 "이 PC 의 시간으로 보냅니다 · 7일 안에서 고를 수 있습니다.".
|
||||
창이 열린 동안 보낼 수 없게 되거나 세션이 바뀌면 닫는다. 서버가 `sendAt` 을 `VAL_001` 로 거절하면 창을 다시 열어 그 시각을 「직접 고르기」에 채우고 까닭(5분 · 7일 문구)을 보인다 —
|
||||
이 화면의 검사로는 맞는 시각(PC 시계가 어긋남)이면 가까운 한도로 본다. 쓰기 화면을 이미 떠났으면 알림으로.
|
||||
- **「예약됨」**: 수는 `GET /scheduled-messages?limit=1` 의 total 이다 — 메일 화면에 들어올 때 · 예약하거나 취소한 뒤 · 새 메일 확인이나 실시간 알림이 바뀜을 알릴 때 다시 묻는다.
|
||||
예약됨을 보는 동안은 0통이어도 패널 줄을 남긴다(숫자 없이). 패널 줄은 보낸편지함(과 그 하위) 바로 아래이고 ⋯ 는 없다.
|
||||
- 목록: 분할 보기 2줄(받는 사람 · 시각 / 제목), 목록 보기 한 줄 세 칸(받는 사람 150 · 제목 · 보낼 시각 150). 고르는 칸 · 별 · 여러 통 처리 · 비우기 · 알림 권하기 줄은 없다.
|
||||
빈 상태 "예약한 메일이 없습니다" / "쓰기 화면의 [보내기 ▾] › 예약 발송…으로 보낼 시각을 정할 수 있습니다.".
|
||||
- [고치기] · [예약 취소]는 하는 동안 두 단추를 함께 막고, 성공해 줄이 사라지면 초점을 옮긴다. [고치기] 뒤 "예약을 취소했습니다. 고친 뒤 다시 보내 주세요." —
|
||||
쓰기 화면으로 가지 못하면 "예약을 취소하고 임시보관함으로 옮겼습니다." + [고치기]. [예약 취소] 뒤에는 삭제처럼 다음 메일(분할) · 목록(목록 보기)으로.
|
||||
- **엔진이 발송을 풀 때**: 새 메일 확인 · 실시간 알림의 상태는 바뀌지 않으므로(계약 2절) 보이는 목록 · 열린 메일 · 가장 이른 예약의 시각 + 2초에 셋을 알림 없이 다시 받고,
|
||||
시각이 지난 채 남으면 5초마다 3번 더 본다(`usePendingSendRefresh`). 검색 결과는 기다리는 메일이 보일 때만, 열린 메일은 `pendingSend` 만 고친다. `MAIL_014` 를 받아도 바로 같은 셋을 다시 받는다.
|
||||
- **붙잡힌 메일(보내는 중 · 예약)** — 취소로만 보낸편지함을 떠난다(2026-10-29 리뷰, 계약 2절 `MAIL_015`):
|
||||
- 목록(분할 · 표 · 검색)의 고르기 칸은 꺼지고(`aria-disabled`) title 이 "보내기를 기다리는 메일은 고를 수 없습니다 — 열어서 취소하거나 삭제해 주세요." — 하나 · 범위 · 모두 고르기가 건너뛰고
|
||||
여러 통 처리에도 들지 않는다(고른 뒤 붙잡히면 고른 것에서 뺀다). 보낸편지함 표의 날짜 칸은 title 에도 같은 글.
|
||||
- 읽기 화면은 두 종류 모두 스팸 신고 · 이동 · ⋯ 의 차단 항목이 없다. [삭제]는 확인 "보내지 않은 메일을 삭제할까요?" / "보내지 않고 휴지통으로 옮깁니다." [삭제] [취소](처음 초점 「취소」) →
|
||||
발송 취소 → 휴지통 → "보내지 않고 휴지통으로 옮겼습니다.". 창을 연 채 발송이 풀리면 창을 닫는다(보낸 메일의 영구 삭제 확인으로 바뀌지 않게).
|
||||
- 서버도 막는다(`MAIL_015` — 화면이 막지 못한 때만 보인다): 여러 통 처리는 그 메일만 남기고(`failedIds` · `skippedIds` — 지금처럼), 메일함 지우기 · 비우기는 붙잡힌 메일만 남으면
|
||||
진행 알림이 멈추고 인터셉터 알림 "보내기를 기다리는 메일은 옮기거나 지울 수 없습니다. 먼저 보내기를 취소해 주세요."(IMAP 으로 옮긴 메일에서만 생긴다 — 4단계 처리의 실패와 같은 모양).
|
||||
- **기다린 뒤 다음 메일로**: 삭제 · 스팸 · 차단 · 예약 취소처럼 응답을 기다린 뒤 옮기는 일은 그사이에도 같은 목록 · 같은 메일을 보고 있을 때만 한다(3 · 4단계의 단추도 함께 고쳤다 — 2026-10-29 리뷰).
|
||||
- **차단**:
|
||||
- 항목이 없는 때: 보낸 사람이 없을 때 · 내 주소 · 사내 도메인(그 하위 포함). 차단 목록은 메일 화면에 들어올 때 알림 없이 받고, 못 받았으면 ⋯ 를 열 때 다시 받는다(모르는 동안은 「보낸 사람 차단」).
|
||||
500개면 항목을 끄고(`aria-disabled`) "차단한 주소는 500개까지 둘 수 있습니다. 쓰지 않는 차단을 풀어 주세요.".
|
||||
- 창: 고르기 묶음 이름 "차단할 범위", 도메인을 고를 수 없는 까닭 "여러 사람이 쓰는 메일 서비스라 도메인으로 막을 수 없습니다.". 「이 메일도 스팸메일함으로 옮기기」는 이미 스팸메일함이면 숨긴다.
|
||||
- 옮겼으면 삭제처럼 다음으로 간다. [되돌리기]는 차단을 풀고 **원래 메일함**으로 되돌린다(보드의 "받은편지함" 대신 — 받은편지함 밖에서 막았을 수 있다).
|
||||
도메인으로 막힌 보낸 사람의 「차단 풀기」는 그 도메인 차단을 푼다. 풀기가 404 면(이미 풀림) 알림 없이 푼 것으로 본다. 차단 · 풀기 뒤 세션이 바뀌었으면 옮기기 · 알림을 하지 않는다.
|
||||
- 조사는 `objectParticle` 로 — 영문 주소는 "을(를)", 따옴표 뒤에 붙여 쓴다(보드의 "‘주소’ 을" 과 다르다). 문구: 옮기지 않은 차단 "‘주소’을(를) 차단했습니다." ·
|
||||
되돌리기 뒤 "‘주소’ 차단을 풀고 메일을 되돌렸습니다."(옮기지 않았던 차단이면 "‘주소’ 차단을 풀었습니다.") · 풀기의 되돌리기 뒤 "‘주소’을(를) 다시 차단했습니다.".
|
||||
- **설정 › 보내기 · 읽기**: 머리 설명 "고르는 대로 저장합니다. 이 설정은 어느 PC 에서나 같습니다.", "저장했습니다"는 머리 오른쪽(`SettingsPageFrame` 의 `title-aside` 슬롯).
|
||||
칸마다 저장은 한 번에 하나 — 보내는 동안 고른 값은 기억했다가 앞 저장이 끝난 뒤 보낸 값 · 서버의 답과 다르면 보낸다. "저장했습니다"는 다 끝나고 마지막이 성공했을 때. 끝내 실패하면 서버가 확인한 값으로 되돌린다.
|
||||
- **설정 › 차단한 주소**: 검사 차례는 형식 → 내 주소 · 사내 도메인 → 메일 서비스 도메인 → 이미 차단 → 500개. 서버 거절(`VAL_001` · `MAIL_013`)은 칸 아래 사전 문구(알림 없음).
|
||||
성공하면 칸을 비우고 칸 아래에 "‘…’을(를) 차단했습니다."(`role=status` — 비어 있어도 영역은 늘 둔다). Enter 는 [차단]과 같다(`isImeComposing`). 줄을 풀면 초점은 다음 줄 → 앞 줄 → 칸.
|
||||
엔진 규칙이 꺼져 있으면(`isActive: false`) 머리 아래 노란 줄(단추 없음) "지금은 차단이 동작하지 않습니다. 메일 서버의 규칙이 다른 곳에서 바뀌었습니다 — 주소를 차단하거나 풀면 다시 켜집니다." —
|
||||
차단 · 풀기가 성공하면 켜진 것으로 본다(서버가 다시 켠다 — 계약 2절).
|
||||
- **새 토큰 · 아이콘**: `--color-on-brand-track` · `--color-on-brand-progress` · `--color-on-brand-divider` · `--color-warning-border`, 아이콘 printer · clock · block(원 + 빗금).
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>설정 · 보내기 · 읽기 · 차단한 주소</title>
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<style>
|
||||
@font-face{font-family:'Pretendard';src:url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2-variations'),url('/_blob/16067b9aa5137abf808e3dbef30c42e0') format('woff2');font-weight:45 920;font-style:normal;font-display:swap}
|
||||
body{margin:0}
|
||||
a{color:#0E7C86}a:hover{color:#0A5F67}
|
||||
:focus-visible{outline:2px solid #0E7C86;outline-offset:2px}
|
||||
.primary{background:#0E7C86;color:#FFFFFF}
|
||||
.primary:hover{background:#0A5F67}
|
||||
.ghost{background:transparent;color:#4A5363}
|
||||
.ghost:hover{background:#F2F4F7;color:#171C26}
|
||||
.field{box-sizing:border-box;border:1px solid #D0D5DD;border-radius:8px;background:#FFFFFF;font:inherit;color:#171C26}
|
||||
.field:focus{outline:none;border-color:#0E7C86;box-shadow:0 0 0 1px #0E7C86}
|
||||
.field.is-error{border-color:#B42318}
|
||||
.nav-item{color:#344054}
|
||||
.nav-item:hover{background:#F2F4F7}
|
||||
.seg{background:transparent;color:#344054}
|
||||
.seg:hover{background:#F2F4F7}
|
||||
.unblock{background:#FFFFFF;color:#344054;border:1px solid #D0D5DD}
|
||||
.unblock:hover{background:#F2F4F7}
|
||||
</style>
|
||||
</helmet>
|
||||
<div style="width: 1440px; height: 1000px; box-sizing: border-box; padding: 48px; display: flex; flex-direction: column; gap: 28px; background: #F6F7F9; color: #171C26; font-family: Pretendard, -apple-system, 'Apple SD Gothic Neo', 'Malgun Gothic', system-ui, sans-serif; font-size: 13px; line-height: 1.5">
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 6px; max-width: 1000px">
|
||||
<h1 style="margin: 0; font-size: 24px; font-weight: 700; letter-spacing: -0.02em">설정 · 보내기 · 읽기 · 차단한 주소</h1>
|
||||
<p style="margin: 0; font-size: 13.5px; color: #4A5363">메일 묶음에 두 화면을 더합니다. 「보내기 · 읽기」는 고르는 대로 저장합니다(저장 단추 없음 — 알림 설정과 같은 결). 이 설정은 서버에 저장되어 어느 PC 에서나 같습니다.</p>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 220px 560px minmax(0, 1fr); gap: 20px; align-items: start">
|
||||
|
||||
<nav aria-label="설정" style="display: flex; flex-direction: column; gap: 2px; padding: 12px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<span style="padding: 6px 10px 2px; font-size: 12px; font-weight: 600; color: #667085">계정</span>
|
||||
<a href="#" class="nav-item" style="display: flex; align-items: center; min-height: 40px; padding: 0 10px; border-radius: 8px; text-decoration: none">비밀번호</a>
|
||||
<span style="padding: 10px 10px 2px; font-size: 12px; font-weight: 600; color: #667085">메일</span>
|
||||
<a href="#" class="nav-item" style="display: flex; align-items: center; min-height: 40px; padding: 0 10px; border-radius: 8px; text-decoration: none">서명</a>
|
||||
<a href="#" class="nav-item" style="display: flex; align-items: center; min-height: 40px; padding: 0 10px; border-radius: 8px; text-decoration: none">부재중 자동 응답</a>
|
||||
<a href="#" class="nav-item" style="display: flex; align-items: center; min-height: 40px; padding: 0 10px; border-radius: 8px; text-decoration: none">필터</a>
|
||||
<a href="#" aria-current="page" style="display: flex; align-items: center; min-height: 40px; padding: 0 10px; border-radius: 8px; background: #E3F2F3; color: #0A5F67; font-weight: 600; text-decoration: none">보내기 · 읽기</a>
|
||||
<a href="#" class="nav-item" style="display: flex; align-items: center; min-height: 40px; padding: 0 10px; border-radius: 8px; text-decoration: none">차단한 주소</a>
|
||||
<a href="#" class="nav-item" style="display: flex; align-items: center; min-height: 40px; padding: 0 10px; border-radius: 8px; text-decoration: none">알림</a>
|
||||
</nav>
|
||||
|
||||
<section aria-labelledby="sr-title" style="display: flex; flex-direction: column; gap: 22px; padding: 24px 28px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; align-items: baseline; gap: 12px">
|
||||
<h2 id="sr-title" style="margin: 0; font-size: 18px; font-weight: 700; letter-spacing: -0.01em">보내기 · 읽기</h2>
|
||||
<span role="status" style="margin-left: auto; display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: #067647"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"></polyline></svg>저장했습니다</span>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 10px">
|
||||
<h3 id="undo-label" style="margin: 0; font-size: 14px; font-weight: 700">보내기 취소</h3>
|
||||
<div role="radiogroup" aria-labelledby="undo-label" style="display: inline-flex; align-self: flex-start; gap: 2px; padding: 2px; border: 1px solid #D0D5DD; border-radius: 8px">
|
||||
<button type="button" role="radio" aria-checked="false" class="seg" style="min-height: 36px; padding: 0 14px; border: 0; border-radius: 6px; font: inherit; font-weight: 500; cursor: pointer">끔</button>
|
||||
<button type="button" role="radio" aria-checked="false" class="seg" style="min-height: 36px; padding: 0 14px; border: 0; border-radius: 6px; font: inherit; font-weight: 500; cursor: pointer">5초</button>
|
||||
<button type="button" role="radio" aria-checked="true" style="min-height: 36px; padding: 0 14px; border: 0; border-radius: 6px; background: #E3F2F3; color: #0A5F67; font: inherit; font-weight: 600; cursor: pointer">10초</button>
|
||||
<button type="button" role="radio" aria-checked="false" class="seg" style="min-height: 36px; padding: 0 14px; border: 0; border-radius: 6px; font: inherit; font-weight: 500; cursor: pointer">20초</button>
|
||||
<button type="button" role="radio" aria-checked="false" class="seg" style="min-height: 36px; padding: 0 14px; border: 0; border-radius: 6px; font: inherit; font-weight: 500; cursor: pointer">30초</button>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363">[보내기]를 누른 뒤 이 시간 동안 [보내기 취소]로 되돌릴 수 있습니다. 그동안 메일은 메일 서버에서 기다리므로 창을 닫아도 보내집니다.</p>
|
||||
</div>
|
||||
|
||||
<hr style="margin: 0; border: 0; border-top: 1px solid #EEF0F3">
|
||||
|
||||
<fieldset style="display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; border: 0">
|
||||
<legend style="margin: 0 0 6px; padding: 0; font-size: 14px; font-weight: 700">외부 이미지</legend>
|
||||
<label style="display: flex; align-items: flex-start; gap: 10px; min-height: 40px; padding: 8px 0; cursor: pointer">
|
||||
<input type="radio" name="img" checked style="width: 18px; height: 18px; margin: 1px 0 0; accent-color: #0E7C86">
|
||||
<span style="display: flex; flex-direction: column"><span style="font-weight: 600">늘 묻기</span><span style="font-size: 12.5px; color: #4A5363">메일마다 [이미지 보기]를 눌러 봅니다</span></span>
|
||||
</label>
|
||||
<label style="display: flex; align-items: flex-start; gap: 10px; min-height: 40px; padding: 8px 0; cursor: pointer">
|
||||
<input type="radio" name="img" style="width: 18px; height: 18px; margin: 1px 0 0; accent-color: #0E7C86">
|
||||
<span style="display: flex; flex-direction: column"><span style="font-weight: 600">주소록 · 사내 직원의 메일은 늘 보기</span><span style="font-size: 12.5px; color: #4A5363">보낸 사람이 내 주소록이나 사내 목록에 있으면 바로 보입니다</span></span>
|
||||
</label>
|
||||
<label style="display: flex; align-items: flex-start; gap: 10px; min-height: 40px; padding: 8px 0; cursor: pointer">
|
||||
<input type="radio" name="img" style="width: 18px; height: 18px; margin: 1px 0 0; accent-color: #0E7C86">
|
||||
<span style="display: flex; flex-direction: column"><span style="font-weight: 600">늘 보기</span><span style="font-size: 12.5px; color: #4A5363">스팸메일함의 메일은 이 설정과 상관없이 묻습니다</span></span>
|
||||
</label>
|
||||
<p style="margin: 4px 0 0; padding: 10px 12px; border-radius: 8px; background: #F6F7F9; font-size: 12.5px; color: #4A5363">외부 이미지는 사내 메일 서버가 대신 받아 보여 줍니다 — 보낸 사람에게 이 PC 의 주소는 드러나지 않습니다. 다만 이미지를 받으면 보낸 사람은 메일을 열어 본 것을 알 수 있습니다.</p>
|
||||
</fieldset>
|
||||
</section>
|
||||
|
||||
<section aria-labelledby="bl-title" style="display: flex; flex-direction: column; gap: 16px; padding: 24px 28px; background: #FFFFFF; border: 1px solid #E6E8EC; border-radius: 12px">
|
||||
<div style="display: flex; flex-direction: column; gap: 4px">
|
||||
<div style="display: flex; align-items: baseline; gap: 10px">
|
||||
<h2 id="bl-title" style="margin: 0; font-size: 18px; font-weight: 700; letter-spacing: -0.01em">차단한 주소</h2>
|
||||
<span style="font-size: 12.5px; color: #667085">3 / 500</span>
|
||||
</div>
|
||||
<p style="margin: 0; font-size: 12.5px; color: #4A5363">이 주소에서 오는 메일은 스팸메일함으로 갑니다. 부재중 자동 응답도 보내지 않습니다. 「@도메인」은 그 도메인에서 오는 메일 모두입니다.</p>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 6px">
|
||||
<label for="bl-add" style="font-size: 12.5px; font-weight: 600; color: #4A5363">차단할 주소</label>
|
||||
<div style="display: flex; gap: 8px">
|
||||
<input id="bl-add" class="field is-error" type="text" inputmode="email" value="kim@" placeholder="kim@example.com 또는 @example.com" aria-invalid="true" aria-describedby="bl-add-err" style="flex: 1 1 auto; height: 44px; padding: 0 12px">
|
||||
<button type="button" class="primary" style="min-height: 44px; padding: 0 18px; border: 0; border-radius: 8px; font: inherit; font-weight: 600; cursor: pointer">차단</button>
|
||||
</div>
|
||||
<p id="bl-add-err" style="margin: 0; font-size: 12.5px; color: #B42318">메일 주소나 @도메인 형식으로 써 주세요.</p>
|
||||
</div>
|
||||
|
||||
<ul style="list-style: none; margin: 0; padding: 0; border: 1px solid #EEF0F3; border-radius: 8px">
|
||||
<li style="display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 0 8px 0 14px; border-bottom: 1px solid #EEF0F3">
|
||||
<span style="flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.35"><span style="font-weight: 600; overflow: hidden; text-overflow: ellipsis">news@cloudbrief.example</span><span style="font-size: 12px; color: #667085">10월 29일 차단</span></span>
|
||||
<button type="button" class="unblock" style="flex: 0 0 auto; min-height: 36px; padding: 0 12px; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer">차단 풀기</button>
|
||||
</li>
|
||||
<li style="display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 0 8px 0 14px; border-bottom: 1px solid #EEF0F3">
|
||||
<span style="flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.35"><span style="font-weight: 600">@promo-mail.example</span><span style="font-size: 12px; color: #667085">도메인 전체 · 10월 21일 차단</span></span>
|
||||
<button type="button" class="unblock" style="flex: 0 0 auto; min-height: 36px; padding: 0 12px; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer">차단 풀기</button>
|
||||
</li>
|
||||
<li style="display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 0 8px 0 14px">
|
||||
<span style="flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.35"><span style="font-weight: 600">sales@unknown-shop.example</span><span style="font-size: 12px; color: #667085">10월 18일 차단</span></span>
|
||||
<button type="button" class="unblock" style="flex: 0 0 auto; min-height: 36px; padding: 0 12px; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer">차단 풀기</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border-radius: 8px; background: #F6F7F9; color: #4A5363; font-size: 12.5px">
|
||||
<span>칸 아래 안내(보드에 없던 경우): "이미 차단한 주소입니다." · "내 주소 · 사내 도메인은 차단할 수 없습니다." · "gmail.com 처럼 여러 사람이 쓰는 메일 서비스는 도메인으로 막을 수 없습니다 — 주소로 막아 주세요." · "500개까지 차단할 수 있습니다."</span>
|
||||
<span>[차단 풀기]는 바로 풀고 알림 "‘news@cloudbrief.example’ 차단을 풀었습니다." + [되돌리기]. 이미 받은 메일은 옮기지 않습니다.</span>
|
||||
<span>차단한 주소가 없으면 목록 자리에 "차단한 주소가 없습니다. 메일의 ⋯ › 보낸 사람 차단으로도 막을 수 있습니다."</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props='{"$preview":{"width":1440,"height":1000}}'>
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -29,9 +29,13 @@
|
||||
"MailFilterApplyStates.dc.html": { "x": 1520, "y": 12700, "w": 1440, "h": 1280, "title": "필터 적용 진행 · 결과 · 나가기 확인 · 부재중 안내" },
|
||||
"Contacts.dc.html": { "x": 0, "y": 14580, "w": 1440, "h": 900, "title": "주소록 · 내 연락처 · 그룹 · 사내", "expand": "fill", "is_interactive": true },
|
||||
"ContactsEdit.dc.html": { "x": 1520, "y": 14580, "w": 1440, "h": 1640, "title": "연락처 추가 · 고치기 · 그룹 · 상태" },
|
||||
"ContactsMail.dc.html": { "x": 3040, "y": 14580, "w": 1440, "h": 1180, "title": "메일과 함께 — 받는 사람 추천 · 주소록에 추가" }
|
||||
"ContactsMail.dc.html": { "x": 3040, "y": 14580, "w": 1440, "h": 1180, "title": "메일과 함께 — 받는 사람 추천 · 주소록에 추가" },
|
||||
"MailReadTools.dc.html": { "x": 0, "y": 16820, "w": 1440, "h": 1220, "title": "읽기 화면 — 외부 이미지 · 인쇄 · 보낸 사람 차단" },
|
||||
"MailPrint.dc.html": { "x": 1520, "y": 16820, "w": 1440, "h": 1060, "title": "인쇄 화면" },
|
||||
"MailSendLater.dc.html": { "x": 3040, "y": 16820, "w": 1440, "h": 1500, "title": "보내기 취소 · 예약 발송" },
|
||||
"SettingsSendRead.dc.html": { "x": 4560, "y": 16820, "w": 1440, "h": 1000, "title": "설정 · 보내기 · 읽기 · 차단한 주소" }
|
||||
},
|
||||
"order": ["Main.dc.html", "Login.dc.html", "Compose.dc.html", "States.dc.html", "MainList.dc.html", "MainListRead.dc.html", "ComposeEditor.dc.html", "Settings.dc.html", "ComposeAssist.dc.html", "Search.dc.html", "BulkSelect.dc.html", "ListStates.dc.html", "SettingsAccount.dc.html", "SettingsVacation.dc.html", "MailboxManage.dc.html", "MailActions4.dc.html", "SettingsNotify.dc.html", "MailRealtime.dc.html", "SettingsFilter.dc.html", "MailFilterStates.dc.html", "MailFilterApply.dc.html", "MailFilterApplyStates.dc.html", "Contacts.dc.html", "ContactsEdit.dc.html", "ContactsMail.dc.html"],
|
||||
"order": ["Main.dc.html", "Login.dc.html", "Compose.dc.html", "States.dc.html", "MainList.dc.html", "MainListRead.dc.html", "ComposeEditor.dc.html", "Settings.dc.html", "ComposeAssist.dc.html", "Search.dc.html", "BulkSelect.dc.html", "ListStates.dc.html", "SettingsAccount.dc.html", "SettingsVacation.dc.html", "MailboxManage.dc.html", "MailActions4.dc.html", "SettingsNotify.dc.html", "MailRealtime.dc.html", "SettingsFilter.dc.html", "MailFilterStates.dc.html", "MailFilterApply.dc.html", "MailFilterApplyStates.dc.html", "Contacts.dc.html", "ContactsEdit.dc.html", "ContactsMail.dc.html", "MailReadTools.dc.html", "MailPrint.dc.html", "MailSendLater.dc.html", "SettingsSendRead.dc.html"],
|
||||
"notes": {
|
||||
"flow": { "x": 0, "y": -300, "text": "arasystem 웹메일 — 1단계 화면 (로그인 → 메일함 → 쓰기)", "kind": "title1", "maxW": 4480 },
|
||||
"phase2": { "x": 0, "y": 2180, "text": "2단계 화면 — 임시 저장 · 받는 사람 자동 완성 · 서명 (2026-10-27 확정)", "kind": "title1", "maxW": 2960 },
|
||||
@@ -40,7 +44,8 @@
|
||||
"phase5": { "x": 0, "y": 8260, "text": "5단계 화면 — 실시간 새 메일 · 바탕화면 알림 — 2026-10-28 확정", "kind": "title1", "maxW": 2960 },
|
||||
"phase6": { "x": 0, "y": 10380, "text": "6단계 화면 — 메일 필터 (설정 › 메일 › 필터 · 읽기 화면 ⋯ 「이런 메일로 필터 만들기」) — 2026-10-28 확정", "kind": "title1", "maxW": 2960 },
|
||||
"phase7": { "x": 0, "y": 12400, "text": "7단계 화면 — 이미 받은 메일에 필터 적용 · 필터 창 나가기 확인 · 부재중 안내 — 2026-10-29 확정", "kind": "title1", "maxW": 2960 },
|
||||
"phase8": { "x": 0, "y": 14280, "text": "8단계 화면 — 주소록 (내 연락처 · 그룹 · 사내 목록 · 메일에서 쓰기) — 2026-10-29 확정", "kind": "title1", "maxW": 4480 }
|
||||
"phase8": { "x": 0, "y": 14280, "text": "8단계 화면 — 주소록 (내 연락처 · 그룹 · 사내 목록 · 메일에서 쓰기) — 2026-10-29 확정", "kind": "title1", "maxW": 4480 },
|
||||
"phase9": { "x": 0, "y": 16520, "text": "9단계 화면 — 보내기 취소 · 예약 발송 · 외부 이미지 보기 · 인쇄 · 보낸 사람 차단 — 2026-10-29 확정", "kind": "title1", "maxW": 6000 }
|
||||
},
|
||||
"designSystems": []
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user