diff --git a/README.md b/README.md index 081c603..1a3180c 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,19 @@ python3 -m http.server 8000 --bind 127.0.0.1 이후 `http://127.0.0.1:8000`에 접속합니다. +## 문의 영역 + +- `index.html#contact`: 이메일 주소와 복사 버튼을 제공하는 문의 영역입니다. 스타일은 `contact-email.css`, 복사 및 결과 안내는 `contact-email.js`에 있습니다. +- `index-form.html#contact`: 기존 문의 폼형을 그대로 보존한 페이지입니다. 이름·회사명·이메일·연락처·문의내용·파일첨부를 받으며, 필수 입력 확인, 글자 수 표시, 첨부파일 선택·삭제·드래그와 전송 완료 안내 모달을 지원합니다. 모달은 확인 버튼·닫기 버튼·Esc·바깥 영역 클릭으로 닫습니다. +- 문의 스타일은 `contact-form.css`, 폼 동작은 `contact-form.js`에 있습니다. +- 현재는 전송 완료 화면까지만 구현되어 있으며 입력 내용과 파일을 전송하거나 저장하지 않습니다. 실제 접수에는 서버 연동이 필요합니다. 첨부는 최대 5개, 합계 20MB까지 선택할 수 있습니다. + +메인 페이지의 ‘프로젝트 문의’ 버튼은 이메일 문의 영역으로 이동합니다. + ## 파일 -- `index.html`: 회사 소개, 사업 영역, 프로젝트 8개, 연혁, 문의 정보 +- `index.html`: 회사 소개, 사업 영역, 프로젝트 8개, 연혁, 이메일 문의 +- `index-form.html`: 기존 문의 폼을 포함한 회사 홈페이지 - `styles.css`: 색상, 타이포그래피, 반응형 레이아웃 및 모션 - `company.css`: 회사 개요·대표이사·조직도를 통합한 패널과 특허 영역. 기존 사업영역의 스타일과 동작은 유지합니다. - `script.js`: Canvas 입체 그래픽, 프로젝트 필터, 연혁 탭, 메뉴, 스크롤 효과 @@ -27,17 +37,6 @@ python3 -m http.server 8000 --bind 127.0.0.1 - `assets/images/archive/`: 현재 화면에서 사용하지 않는 합본 이미지와 이전 버전. 원본 보관용이며 갤러리에 연결하지 않습니다. - `docs/`: 원본 회사소개서, 소개서 다운로드 링크의 대상 -## 연락처 교체 - -사용자 요청에 따라 아래 연락처는 **임시 정보**입니다. 실제 인물에게 연결되지 않도록 예약된 `.example` 이메일을 사용했습니다. - -- 이메일: `hello@tront.example` -- 전화번호: `053-000-0000` - -`script.js` 상단 `CONTACT`의 `email`, `phone`을 실제 정보로 바꾸고 `temporary`를 `false`로 변경합니다. JavaScript 비활성 환경에서도 같은 정보를 표시하도록 `index.html`의 이메일, 전화번호, `mailto:`, `tel:`도 함께 수정합니다. 실제 정보로 교체한 뒤 `.contact-placeholder`의 임시 연락처 문구를 삭제할 수 있습니다. - -문의 버튼은 메일 앱을 엽니다. 이메일 주소 복사는 보안 환경(HTTPS 또는 localhost)에서 작동하며, 사용할 수 없으면 주소를 선택해 수동 복사를 안내합니다. 서버가 없는 정적 사이트이므로 문의 접수나 이메일 발송을 수행하지 않습니다. - ## 콘텐츠 기준 - 설립일: 2008년 12월 1일 @@ -91,4 +90,4 @@ python3 -m http.server 8000 --bind 127.0.0.1 - Canvas는 화면 밖이나 다른 탭에서 렌더링을 중지합니다. - 본문 바로가기, 포커스 표시, 이미지 대체 텍스트, 의미 있는 HTML 구조 -외부 CDN이나 폰트 라이브러리를 사용하지 않아 다운로드한 파일만으로 홈페이지 화면을 확인할 수 있습니다. 지도 모달은 외부 지도 서비스를 불러오며 이메일/전화 링크는 기기 앱으로 연결됩니다. +외부 CDN이나 폰트 라이브러리를 사용하지 않아 다운로드한 파일만으로 홈페이지 화면을 확인할 수 있습니다. 지도 모달은 외부 지도 서비스를 불러옵니다. diff --git a/assets/icons/content_copy.svg b/assets/icons/content_copy.svg new file mode 100644 index 0000000..ffcc814 --- /dev/null +++ b/assets/icons/content_copy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/patent-liquid-dispenser.png b/assets/images/patent-liquid-dispenser.png index 58d6dc9..36f0b8c 100644 Binary files a/assets/images/patent-liquid-dispenser.png and b/assets/images/patent-liquid-dispenser.png differ diff --git a/assets/images/patent-virtual-image.png b/assets/images/patent-virtual-image.png index 4b0f546..d4ddb94 100644 Binary files a/assets/images/patent-virtual-image.png and b/assets/images/patent-virtual-image.png differ diff --git a/contact-email.css b/contact-email.css new file mode 100644 index 0000000..3fed95b --- /dev/null +++ b/contact-email.css @@ -0,0 +1,49 @@ +/* A direct connection: editorial typography and a detachable copy tab. */ +.contact-email-section::before { display: none; } +.contact-email-section .wrap { position: relative; } +.email-intro { display: flex; align-items: flex-end; justify-content: space-between; gap: 40px; } +.email-intro h2 { font-size: clamp(36px, 4.1vw, 62px); font-weight: 600; line-height: 1.3; letter-spacing: -.055em; } +.email-intro h2 em { color: var(--lime); font-style: normal; } +.email-intro > p { color: #d4defc; font-size: 13px; line-height: 1.95; padding-bottom: 5px; } +.email-channel { position: relative; margin-top: 72px; border-top: 1px solid #ffffff65; } +.email-channel::before { content: ''; position: absolute; top: -4px; left: 0; width: 7px; height: 7px; background: var(--lime); } +.email-channel-meta, .email-channel-footer { display: flex; justify-content: space-between; align-items: center; gap: 24px; } +.email-channel-meta { padding-top: 20px; color: #c9d6ff; font: 10px/1.5 monospace; letter-spacing: 1.1px; } +.email-address-row { display: flex; align-items: center; gap: 24px; padding: 40px 0 44px; } +.email-route { font: 44px/1 Arial, sans-serif; color: var(--lime); align-self: flex-start; margin-top: 12px; } +.email-address { font: 500 clamp(30px, 5.4vw, 82px)/1.15 Arial, sans-serif; letter-spacing: -.055em; min-width: 0; overflow-wrap: anywhere; word-break: normal; user-select: all; } +.email-copy { position: relative; flex: none; margin-left: auto; width: 116px; min-height: 116px; padding: 22px 20px 18px; background: var(--lime); color: var(--ink); display: flex; flex-direction: column; align-items: flex-start; gap: 19px; border-radius: 0; transform: rotate(-5deg); transition: transform .25s var(--ease), background .25s; } +.email-copy::before { content: ''; position: absolute; left: -7px; top: 0; bottom: 0; border-left: 1px dashed #d5ee8190; } +.email-copy img { width: 26px; height: 26px; } +.email-copy-label { font-size: 12px; font-weight: 700; } +.email-copy-index { position: absolute; top: 17px; right: 15px; font-size: 17px; } +.email-copy:hover, .email-copy:focus-visible { transform: rotate(0deg) translateY(-4px); background: #e3f7ac; } +.email-copy.is-copied { transform: rotate(0deg); background: var(--paper); } +.email-channel-footer { border-top: 1px solid #ffffff40; padding-top: 22px; } +.email-channel-note { color: #e2e9ff; font-size: 12px; } +.email-copy-status { color: #c9d6ff; font: 9px/1.7 monospace; letter-spacing: .65px; text-align: right; } +.email-copy-status.is-feedback { color: var(--lime); font-family: var(--font); letter-spacing: 0; font-size: 12px; } +.email-noscript { font-size: 12px; margin-top: 20px; } +@media (max-width: 1000px) { + .email-intro { align-items: flex-start; } + .email-intro > p { font-size: 12px; } + .email-address-row { gap: 16px; } + .email-copy { width: 96px; min-height: 104px; padding: 18px 15px; } + .email-route { font-size: 32px; margin-top: 8px; } +} +@media (max-width: 600px) { + .email-intro { flex-direction: column; gap: 22px; } + .email-intro h2 { font-size: clamp(30px, 8vw, 46px); } + .email-channel { margin-top: 42px; } + .email-channel-meta { font-size: 8px; letter-spacing: .5px; gap: 16px; } + .email-channel-meta > span:last-child { text-align: right; max-width: 115px; } + .email-address-row { flex-wrap: wrap; gap: 18px; padding: 32px 0 28px; } + .email-route { display: none; } + .email-address { flex-basis: 100%; font-size: clamp(27px, 7.5vw, 44px); } + .email-copy { margin: 8px 3px 0 auto; width: auto; min-height: 0; flex-direction: row; align-items: center; gap: 12px; padding: 15px 19px; transform: rotate(-3deg); } + .email-copy img { width: 21px; height: 21px; } + .email-copy-index { position: static; margin-left: 15px; } + .email-channel-footer { align-items: flex-start; flex-direction: column; gap: 12px; } + .email-channel-note { font-size: 11px; } + .email-copy-status { font-size: 8px; text-align: left; } +} diff --git a/contact-email.js b/contact-email.js new file mode 100644 index 0000000..2679277 --- /dev/null +++ b/contact-email.js @@ -0,0 +1,52 @@ +(() => { + 'use strict'; + const button = document.querySelector('.email-copy'); + const address = document.querySelector('.email-address'); + const status = document.querySelector('.email-copy-status'); + if (!button || !address || !status) return; + const label = button.querySelector('.email-copy-label'); + const initialStatus = status.textContent; + let resetTimer; + + function copyFallback(value) { + const field = document.createElement('textarea'); + field.value = value; + field.setAttribute('readonly', ''); + field.style.cssText = 'position:fixed;left:-9999px;top:0;opacity:0'; + document.body.append(field); + field.select(); + try { + if (!document.execCommand('copy')) throw new Error('Copy failed'); + } finally { + field.remove(); + button.focus({ preventScroll: true }); + } + } + + button.addEventListener('click', async () => { + clearTimeout(resetTimer); + const value = address.textContent.trim(); + try { + try { + if (!navigator.clipboard?.writeText) throw new Error('Clipboard unavailable'); + await navigator.clipboard.writeText(value); + } catch { + copyFallback(value); + } + label.textContent = '복사 완료'; + button.classList.add('is-copied'); + status.textContent = '이메일 주소를 복사했습니다. 메일의 받는 사람에 붙여넣어 주세요.'; + } catch { + label.textContent = '다시 복사'; + button.classList.remove('is-copied'); + status.textContent = '복사하지 못했습니다. 이메일 주소를 선택해 직접 복사해 주세요.'; + } + status.classList.add('is-feedback'); + resetTimer = setTimeout(() => { + label.textContent = '주소 복사'; + button.classList.remove('is-copied'); + status.classList.remove('is-feedback'); + status.textContent = initialStatus; + }, 6000); + }); +})(); diff --git a/contact-form.css b/contact-form.css new file mode 100644 index 0000000..115432f --- /dev/null +++ b/contact-form.css @@ -0,0 +1,111 @@ +/* Contact section, inquiry form, and completion dialog. */ +.contact-form-section .wrap { position: relative; } +.contact-form-section .section-top { align-items: center; gap: 24px; } +.contact-form-section h2 { font-size: clamp(38px, 4.4vw, 64px); font-weight: 600; line-height: 1.3; letter-spacing: -.055em; } +.contact-form-section h2 em { color: var(--lime); font-style: normal; } + +/* Introduction and inquiry form. */ +.contact-form-layout { display: grid; grid-template-columns: .85fr 1.15fr; gap: 80px; align-items: start; } +.contact-form-intro { padding-top: 15px; } +.contact-form-intro h2 { font-size: clamp(36px, 3.3vw, 49px); } +.contact-form-intro > p { color: #d9e3ff; font-size: 14px; line-height: 1.95; margin-top: 27px; } +.contact-form-topics { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 29px; } +.contact-form-topics span { border: 1px solid #ffffff40; border-radius: 30px; font-size: 10px; padding: 9px 13px; color: #e1e8ff; } +.contact-form-art { position: relative; display: flex; align-items: center; justify-content: center; width: 230px; height: 215px; margin: 60px 0 0 12px; color: var(--lime); } +.contact-form-art::before, .contact-form-art::after { content: ""; position: absolute; width: 175px; height: 175px; border: 1px solid #d5ee8166; border-radius: 26px; transform: rotate(-20deg); } +.contact-form-art::after { transform: rotate(16deg); border-color: #d5ee8133; width: 200px; height: 200px; } +.contact-form-art .arrow-icon { width: 94px; height: 94px; } +.contact-form-caption { margin-top: 34px; color: #cbd7ff; font-size: 9px; font-family: monospace; letter-spacing: 1.4px; } +.inquiry-form { background: var(--paper); color: var(--ink); border-radius: 7px; padding: 36px 38px; min-width: 0; } +.inquiry-heading { display: flex; justify-content: space-between; align-items: center; gap: 20px; margin-bottom: 29px; } +.inquiry-heading h3 { font-size: 21px; font-weight: 600; letter-spacing: -.65px; } +.inquiry-heading p { font-size: 10px; color: #697269; } +.inquiry-required { color: var(--blue); } +.inquiry-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 23px 22px; } +.inquiry-field { min-width: 0; } +.inquiry-field--wide { grid-column: 1 / -1; } +.inquiry-field label, .inquiry-attachment-label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 10px; } +.inquiry-field label > span, .inquiry-attachment-label > span { font-size: 10px; font-weight: 400; color: #7a8477; margin-left: 5px; } +.inquiry-field label .inquiry-required { color: var(--blue); } +.inquiry-field input, .inquiry-field textarea { display: block; width: 100%; border: 1px solid #d2d8cb; border-radius: 4px; background: #fff9; color: var(--ink); font: inherit; font-size: 13px; line-height: 1.5; padding: 13px 14px; transition: border-color .2s, box-shadow .2s; } +.inquiry-field input::placeholder, .inquiry-field textarea::placeholder { color: #8a9286; } +.inquiry-form :is(input, textarea):focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; } +.inquiry-field textarea { resize: vertical; min-height: 137px; } +.inquiry-counter { margin-top: 7px; text-align: right; font: 10px monospace; color: #798474; } +.inquiry-upload { position: relative; display: flex; align-items: center; justify-content: center; gap: 15px; padding: 21px 17px; border: 1px dashed #aebca1; border-radius: 4px; background: #e9eddf; transition: background .2s, border-color .2s; } +.inquiry-upload:hover, .inquiry-upload.is-dragging { background: #e0e8d2; border-color: var(--blue); } +.inquiry-upload:focus-within { outline: 2px solid var(--blue); outline-offset: 3px; } +.inquiry-upload > svg { width: 24px; height: 24px; color: #617557; flex: none; } +.inquiry-upload strong { display: block; font-size: 12px; font-weight: 500; line-height: 1.6; } +.inquiry-upload small { display: block; font-size: 10px; color: #73816a; margin-top: 3px; line-height: 1.7; } +.inquiry-upload input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; } +.inquiry-files { margin: 0; padding: 0; list-style: none; } +.inquiry-files li { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--line); font-size: 11px; } +.inquiry-file-name { flex: 1; min-width: 0; overflow-wrap: anywhere; } +.inquiry-file-size { font: 10px monospace; color: #697564; white-space: nowrap; } +.inquiry-file-remove { display: grid; place-items: center; flex: none; width: 30px; height: 30px; font-size: 19px; background: #e4e9dc; border-radius: 50%; color: #4c5e44; } +.inquiry-form button:focus-visible { outline-color: var(--blue); outline-offset: 3px; } +.inquiry-upload-status { margin-top: 8px; font-size: 11px; line-height: 1.7; color: #53664c; } +.inquiry-upload-status:empty { display: none; } +.inquiry-upload-status.is-error { color: #a03827; } +.inquiry-submit { display: flex; align-items: center; justify-content: space-between; gap: 20px; width: 100%; padding: 18px 20px; background: var(--ink); color: var(--paper); border-radius: 4px; margin-top: 27px; font-size: 13px; font-weight: 600; transition: background .2s; } +.inquiry-submit:hover { background: var(--blue); } +.inquiry-submit:disabled { opacity: .55; cursor: not-allowed; } +.inquiry-submit .arrow-icon { width: 22px; height: 22px; } +.inquiry-noscript-note { color: #77816e; font-size: 10px; line-height: 1.7; text-align: center; margin-top: 13px; } +html.inquiry-success-open { overflow: hidden; } +.inquiry-dialog { width: min(460px, calc(100% - 32px)); max-width: none; max-height: calc(100dvh - 32px); margin: auto; padding: 48px 32px 25px; border: 1px solid var(--line); border-radius: 12px; background: var(--paper); color: var(--ink); text-align: center; box-shadow: 0 28px 90px #101e2440; overflow: auto; } +.inquiry-dialog::backdrop { background: #101e2499; backdrop-filter: blur(5px); } +.inquiry-dialog-close { position: absolute; top: 10px; right: 10px; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: transparent; color: #677269; font-size: 27px; line-height: 1; } +.inquiry-dialog-close:hover { background: #e4e9dc; } +.inquiry-success-mark { display: grid; place-items: center; width: 72px; height: 72px; margin: 0 auto 26px; border-radius: 50%; background: #e2ebff; color: var(--blue); } +.inquiry-success-mark svg { width: 38px; height: 38px; } +.inquiry-success-label { color: var(--blue); font-size: 8px; font-weight: 600; letter-spacing: 1.2px; margin-bottom: 12px; } +.inquiry-dialog h2 { font-size: 27px; font-weight: 600; line-height: 1.4; letter-spacing: -1.2px; } +#inquiry-success-description { color: #65715e; font-size: 13px; line-height: 1.9; margin-top: 17px; } +.inquiry-dialog-confirm { display: block; width: 100%; min-height: 48px; margin-top: 30px; border-radius: 4px; background: var(--blue); color: white; font-size: 13px; font-weight: 600; transition: background .2s; } +.inquiry-dialog-confirm:hover { background: #1c43b7; } +@media (max-width: 400px) { + .inquiry-dialog { padding: 43px 20px 23px; } + .inquiry-dialog h2 { font-size: 23px; letter-spacing: -.8px; } + #inquiry-success-description { font-size: 12px; } +} + +@media (max-width: 1150px) { + .contact-form-layout { grid-template-columns: .8fr 1.2fr; gap: 40px; } + .inquiry-form { padding: 29px 27px; } + .contact-form-intro h2 { font-size: 36px; } + .contact-form-intro > p { font-size: 12px; } + .contact-form-intro > p br { display: none; } +} +@media (max-width: 850px) { + .contact-form-section .section-top { margin-bottom: 42px; } + .contact-form-layout { grid-template-columns: 1fr; gap: 35px; } + .contact-form-intro { padding-top: 0; position: relative; padding-right: 140px; } + .contact-form-intro > p { max-width: 420px; margin-top: 20px; } + .contact-form-art { position: absolute; right: 0; top: 10px; width: 100px; height: 130px; margin: 0 12px 0 0; } + .contact-form-art::before { width: 90px; height: 90px; border-radius: 14px; } + .contact-form-art::after { width: 110px; height: 110px; border-radius: 14px; } + .contact-form-art .arrow-icon { width: 50px; height: 50px; } + .contact-form-topics { margin-top: 20px; } + .contact-form-caption { display: none; } + .inquiry-form { padding: 32px; } +} +@media (max-width: 600px) { + .contact-form-section .section-top { align-items: flex-start; flex-direction: column; gap: 21px; margin-bottom: 37px; } + .contact-form-section h2 { font-size: clamp(31px, 8.1vw, 44px); } + .contact-form-intro { padding-right: 0; } + .contact-form-art { display: none; } + .contact-form-intro > p { font-size: 12px; max-width: 320px; } + .contact-form-topics span { font-size: 9px; padding: 8px 11px; } + .inquiry-form { padding: 26px 20px; } + .inquiry-heading { margin-bottom: 26px; gap: 10px; } + .inquiry-heading h3 { font-size: 20px; } + .inquiry-heading p { font-size: 9px; } + .inquiry-fields { grid-template-columns: 1fr; gap: 21px; } + .inquiry-field input, .inquiry-field textarea { font-size: 16px; padding: 12px; } + .inquiry-upload { padding: 20px 12px; gap: 10px; } + .inquiry-upload strong { font-size: 11px; } + .inquiry-upload small { font-size: 9px; } + .inquiry-noscript-note { font-size: 9px; } +} diff --git a/contact-form.js b/contact-form.js new file mode 100644 index 0000000..54e2d33 --- /dev/null +++ b/contact-form.js @@ -0,0 +1,129 @@ +/* Local interaction preview: no requests, uploads, or storage. */ +(() => { + 'use strict'; + const form = document.querySelector('.inquiry-form'); + if (!form) return; + + const message = form.elements.message; + const counter = form.querySelector('[data-message-count]'); + const input = form.elements.attachments; + const dropzone = form.querySelector('.inquiry-upload'); + const list = form.querySelector('.inquiry-files'); + const uploadStatus = form.querySelector('.inquiry-upload-status'); + const dialog = document.querySelector('#inquiry-success-dialog'); + const submitButton = form.querySelector('.inquiry-submit'); + submitButton.disabled = false; + const maxFiles = 5; + const maxBytes = 20 * 1024 * 1024; + let files = []; + let dragDepth = 0; + + function formatSize(size) { + return size >= 1024 * 1024 ? `${(size / 1024 / 1024).toFixed(1)} MB` : `${Math.max(1, Math.ceil(size / 1024))} KB`; + } + + function showFiles() { + list.replaceChildren(); + files.forEach((file, index) => { + const item = document.createElement('li'); + const name = document.createElement('span'); + name.className = 'inquiry-file-name'; + name.textContent = file.name; + const size = document.createElement('span'); + size.className = 'inquiry-file-size'; + size.textContent = formatSize(file.size); + const remove = document.createElement('button'); + remove.type = 'button'; + remove.className = 'inquiry-file-remove'; + remove.textContent = '×'; + remove.setAttribute('aria-label', `${file.name} 삭제`); + remove.addEventListener('click', () => { + files.splice(index, 1); + showFiles(); + const next = list.querySelectorAll('button')[Math.min(index, files.length - 1)]; + (next || input).focus(); + }); + item.append(name, size, remove); + list.append(item); + }); + uploadStatus.classList.remove('is-error'); + uploadStatus.textContent = files.length ? `${files.length}개 선택 · 총 ${formatSize(files.reduce((sum, file) => sum + file.size, 0))}` : ''; + } + + function addFiles(selection) { + const next = [...files]; + for (const file of selection) { + if (!next.some(existing => existing.name === file.name && existing.size === file.size && existing.lastModified === file.lastModified)) next.push(file); + } + let error = ''; + if (next.length > maxFiles) error = '파일은 최대 5개까지 첨부할 수 있습니다.'; + else if (next.reduce((sum, file) => sum + file.size, 0) > maxBytes) error = '첨부파일의 총 용량은 20MB 이하여야 합니다.'; + input.value = ''; + if (error) { + uploadStatus.textContent = error; + uploadStatus.classList.add('is-error'); + return; + } + files = next; + showFiles(); + } + + input.addEventListener('change', () => addFiles([...input.files])); + dropzone.addEventListener('dragenter', event => { + event.preventDefault(); + dragDepth++; + dropzone.classList.add('is-dragging'); + }); + dropzone.addEventListener('dragover', event => { + event.preventDefault(); + event.dataTransfer.dropEffect = 'copy'; + }); + dropzone.addEventListener('dragleave', () => { + if (--dragDepth <= 0) dropzone.classList.remove('is-dragging'); + }); + dropzone.addEventListener('drop', event => { + event.preventDefault(); + dragDepth = 0; + dropzone.classList.remove('is-dragging'); + addFiles([...event.dataTransfer.files]); + }); + // Avoid navigating away if a file is dropped just outside the attachment area. + for (const type of ['dragover', 'drop']) { + form.addEventListener(type, event => { + if ([...event.dataTransfer.types].includes('Files')) event.preventDefault(); + }); + } + + form.addEventListener('input', event => { + if (event.target.matches('input, textarea')) event.target.setCustomValidity(''); + counter.textContent = message.value.length.toLocaleString('ko-KR'); + }); + dialog.querySelectorAll('[data-close-inquiry]').forEach(button => { + button.addEventListener('click', () => dialog.close()); + }); + let backdropPressed = false; + function isBackdrop(event) { + const bounds = dialog.getBoundingClientRect(); + return event.target === dialog && (event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom); + } + dialog.addEventListener('pointerdown', event => { backdropPressed = isBackdrop(event); }); + dialog.addEventListener('click', event => { + if (backdropPressed && isBackdrop(event)) dialog.close(); + backdropPressed = false; + }); + dialog.addEventListener('close', () => { + document.documentElement.classList.remove('inquiry-success-open'); + submitButton.focus({ preventScroll: true }); + }); + form.addEventListener('submit', event => { + event.preventDefault(); + for (const field of [form.elements.name, message]) { + field.setCustomValidity(field.value.trim() ? '' : '공백을 제외한 내용을 입력해 주세요.'); + } + if (!form.reportValidity()) return; + if (!dialog.open) { + dialog.showModal(); + document.documentElement.classList.add('inquiry-success-open'); + } + }); +})(); diff --git a/index-form.html b/index-form.html new file mode 100644 index 0000000..5685abf --- /dev/null +++ b/index-form.html @@ -0,0 +1,385 @@ + + + + + + + + + + + + + + + + TRONT — 기술로 연결하고, 가능성을 확장하다 + + + + + + + + + + + + + + + + + + + + + +
+
+
+

CONNECTING IDEAS. CREATING IMPACT.

+

기술로 연결하고,
가능성을 확장하다.

+

모빌리티부터 디지털 플랫폼까지.
비즈니스의 다음을 함께 만드는 기술 파트너, 트론트.

+ +
INNOVATION SINCE2008경험은 깊게.
시선은 더 멀리.
+
+ + SCROLL TO EXPLORE + +
+ + + +
+
기술에 대한 깊이, 사람을 향한 방향
+
+

복잡한 기술을
의미 있는 경험으로.

+

트론트는 모바일, 웹, 애플리케이션을 넘어 산업과 일상을 연결하는 IT 솔루션 전문 기업입니다. 2008년의 첫걸음부터 다양한 산업 현장에서 쌓아온 경험으로, 고객의 아이디어를 작동하는 서비스로 만듭니다.

지능형 관제, 디지털 플랫폼, 미래 모빌리티까지.
기술의 경계를 넘나들며 비즈니스에 필요한 연결을 설계합니다.

트론트 회사소개서 PDF · 9.2 MB
+
+
+
+

COMPANY AT A GLANCE

+

주식회사 트론트TRONT Co., Ltd.

+
+
설립일
+
사업분야
모바일 솔루션 · 웹 서비스 · 산업용 애플리케이션 개발
+
소재지
대구광역시 북구 경대로17길 47
IT융합산업빌딩 1203호
+
+ 기술 연구와 특허 살펴보기 +
+
+
+

PEOPLE & ORGANIZATION

함께 만드는 전문 조직

+
18명2025.10 기준
+
+
+
CEO · 대표이사김칠수
+
    +
  • 기술지원팀

    TECHNICAL SUPPORT

  • +
  • 개발1팀

    Web 개발
    모바일 앱 개발

  • +
  • 개발2팀

    내비게이션 개발

  • +
+
+
+
+
+ +
+
FIVE FIELDS. ONE CONNECTED VISION.
+

기술을 잇는
IT 전문가 그룹

주식회사 트론트는 스마트 모빌리티, 산업 관제, 자산 관리, SaaS 플랫폼,
디지털 인터페이스 분야에서 고객의 디지털 혁신을 이끕니다.

+
+
01
SMART MOBILITY & HMI

스마트 모빌리티 및 HMI 플랫폼

운전자와 차량 사이, 직관적인 연결을 만듭니다. 국내외 내비게이션 HMI와 차량 통신 기술을 바탕으로 새로운 이동 경험을 구현합니다.

차량 통신네비게이션 개발 연결성관제 시스템
+
02
INDUSTRIAL MONITORING & CONTROL

산업 통합 관제 및 제어 시스템

현장의 데이터를 한눈에, 복잡한 운영을 더 명확하게. 실시간 모니터링과 데이터 송수신, 원격 제어를 통합해 산업 현장의 효율과 안전을 지원합니다.

실시간 모니터링데이터 송수신 프로토콜시스템 통합(SI)원격 제어 및 안전 시스템
+
03
WEB3 & ASSET MANAGEMENT

고도화된 Web3 & Asset 관리 솔루션

자산의 흐름에 정확함을, 운영에 투명함을 더합니다. 블록체인 기반 서비스와 RFID·NFC 기술을 활용해 데이터와 실물 자산을 연결합니다.

블록체인 기반 투명성 확보RFID / NFC 등 무선 통신 기반 자산 관리금융 기술 융합
+
04
COMMUNITY & SAAS PLATFORM

전문 커뮤니티 및 SaaS 플랫폼

사람과 사람, 서비스와 일상을 연결합니다. 약국·교육·스포츠 등 도메인에 대한 이해를 바탕으로 모바일 앱, 웹, 관리자 시스템을 함께 구축합니다.

도메인 특화 Web/App 서비스GroupWareLMS 개발
+
05
FUTURE TECH & DIGITAL INTERFACE

미래 기술 및 디지털 인터페이스

새로운 기술이 자연스러운 경험이 되도록. 가상현실 기반 웹 환경, 디지털 사이니지, 영상 분석과 UX 기술로 디지털 접점을 확장합니다.

Virtual Reality기반 Web 환경SIGNAGE영상 분석 및 UX
+
+
+
+
+ +
+
아이디어가 현실이 되는 순간
+

기술로 만든
실제의 변화.

다양한 산업에서 증명해 온 실행력.
트론트가 함께 만든 프로젝트를 소개합니다.

+
8 PROJECTS
+
+ + + + + + + + + + + + + + + + +
+
+ +
+
+
IDEAS INTO INTELLECTUAL PROPERTY
+
+

기술의 깊이를
보여주는 특허.

특정 기술에 안주하지 않는 R&D 프로세스를 핵심 과정으로 삼고 있습니다.
미래 비즈니스 환경 변화에 선제적으로 대응하기 위해 지속적인 발굴 및 지식재산권 확보에 주력하고 있습니다.
특허와 인증은 당사가 미래에도 신뢰할 수 있는 파트너임을 증명하는 잠재적 능력입니다.

+ +
+
+
+ + + 객체 가상 이미지 구현 방법 특허증, 제10-0951362호 + 특허증 크게 보기 + +
+

01 VIRTUAL IMAGE

+

객체 가상 이미지 구현 방법

+

실제 객체를 기반으로 가상 이미지를 생성하고, 현실과 통합하는 기술입니다.

+
특허번호
제10-0951362호
출원일
등록일
+
+
+
+ + + 액체 세제 자동 판매 장치 특허증, 제10-1099507호 + 특허증 크게 보기 + +
+

02 DEVICE CONTROL

+

액체 세제 자동 판매 장치

+

액체 세제의 자동 판매 및 관리를 위한 기술로 효율적인 자판기 시스템 제어에 대한 특허.

+
특허번호
제10-1099507호
출원일
등록일
+
+
+
+
+
+ +
A CONTINUOUS JOURNEY OF INNOVATION

새로운 길은,
계속됩니다.

첫 서버에서 글로벌 모빌리티까지.
기술이 바뀌어도, 더 나은 답을 찾는 우리의 태도는 같습니다.

WHAT'S NEXT

더 넓은 연결, 다음의 가능성

블록체인 기반 기부 플랫폼 GivOn 관리자 개발과 소규모 기관차 관제 프로그램 개발로 기술의 쓰임을 넓혀갑니다.

Web3관제 시스템디지털 플랫폼
+ +
+
+
+
+
+

어떤 프로젝트를
생각하고 계신가요?

+

아직 구체적이지 않아도 괜찮습니다.
만들고 싶은 서비스와 해결하고 싶은 문제를 들려주세요.
아이디어의 다음 단계를 함께 고민하겠습니다.

+
프로젝트 의뢰기술 상담파트너십
+ + +
+
+

프로젝트 문의

* 필수 입력

+
+
+
+
+
+

0 / 2,000

+
+ +
+ +
파일을 선택하거나 여기에 놓아주세요소개서, 기획안 등 · 최대 5개, 총 20MB
+ +
+
    +

    +
    +
    + + +
    +
    +
    +
    +
    + + + + + + +

    THANK YOU FOR REACHING OUT

    +

    문의가 전송되었습니다.

    +

    트론트에 관심을 가져주셔서 감사합니다.
    남겨주신 내용을 확인한 후 연락드리겠습니다.

    + +
    + + +
    +

    COME FIND US

    트론트 오시는 길

    + +
    +
    +
    +

    지도를 불러오는 중입니다.

    +
    + +
    + + + diff --git a/index.html b/index.html index 0e7307d..c53f8b8 100644 --- a/index.html +++ b/index.html @@ -6,20 +6,27 @@ + + + + + TRONT — 기술로 연결하고, 가능성을 확장하다 - + - + + + @@ -32,11 +39,11 @@ - 함께 만들어가요 + 프로젝트 문의 @@ -271,8 +278,6 @@ - -

    소개서에 수록된 실제 프로젝트와 수행 기간을 기준으로 구성했습니다.

    @@ -310,17 +315,39 @@ -

    회사소개서에 수록된 특허증을 기준으로 소개합니다.

    소개서에서 보기
    A CONTINUOUS JOURNEY OF INNOVATION

    새로운 길은,
    계속됩니다.

    첫 서버에서 글로벌 모빌리티까지.
    기술이 바뀌어도, 더 나은 답을 찾는 우리의 태도는 같습니다.

    WHAT'S NEXT

    더 넓은 연결, 다음의 가능성

    블록체인 기반 기부 플랫폼 GivOn 관리자 개발과 소규모 기관차 관제 프로그램 개발로 기술의 쓰임을 넓혀갑니다.

    Web3관제 시스템디지털 플랫폼
    -
    YOUR NEXT CHAPTER STARTS HERE.

    다음의 가능성,
    함께 만들까요?

    새로운 서비스의 시작부터 복잡한 기술의 해답까지.
    트론트와 새로운 프로젝트를 함께 만들어가요.

    함께 프로젝트 만들기
    EMAIL

    이메일과 연락처 정보 없음.

    COME FIND US
    대구광역시 북구 경대로17길 47
    IT융합산업빌딩 1203호
    +
    +
    +
    YOUR IDEA. OUR NEXT CHAPTER.
    + + +
    +
    + +

    COME FIND US

    트론트 오시는 길

    @@ -333,6 +360,5 @@
    -
    diff --git a/projects/asset.html b/projects/asset.html index 09a3acc..b490c97 100644 --- a/projects/asset.html +++ b/projects/asset.html @@ -5,7 +5,7 @@ WideAsset S/W — RF 자산관리 솔루션 구축 | TRONT - + @@ -27,7 +27,7 @@
    IT ASSETS / OFFICE EQUIPMENT
    -
    PDA / WideAsset S/WPROJECT SCREENS
    +
    PDA / WideAsset S/WPROJECT SCREENS
    diff --git a/projects/bems.html b/projects/bems.html index 6804a47..7c2d59f 100644 --- a/projects/bems.html +++ b/projects/bems.html @@ -5,7 +5,7 @@ BEMS — 빌딩 에너지 통합 관리 시스템 BEMS 개발 | TRONT - + @@ -27,7 +27,7 @@
    BUILDING ENERGY MANAGEMENT
    -
    웹PROJECT SCREENS
    +
    웹PROJECT SCREENS
    diff --git a/projects/bispet.html b/projects/bispet.html index b03c82b..489f1dc 100644 --- a/projects/bispet.html +++ b/projects/bispet.html @@ -5,7 +5,7 @@ BISPET — 애견인들 위한 커뮤니티 개발 | TRONT - + @@ -27,7 +27,7 @@
    MOBILE APP / ADMIN
    -
    모바일 앱 / 관리자 화면PROJECT SCREENS
    +
    모바일 앱 / 관리자 화면PROJECT SCREENS
    diff --git a/projects/givon.html b/projects/givon.html index 6e8de5b..549f0a4 100644 --- a/projects/givon.html +++ b/projects/givon.html @@ -5,7 +5,7 @@ GivOn — 블록체인 기반 기부 플랫폼 관리자 페이지 개발 | TRONT - + @@ -27,7 +27,7 @@
    DONATION PLATFORM / ADMIN
    -
    관리자 화면PROJECT SCREENS
    +
    관리자 화면PROJECT SCREENS
    diff --git a/projects/gps-building.html b/projects/gps-building.html index 46dbd92..d9b6a2b 100644 --- a/projects/gps-building.html +++ b/projects/gps-building.html @@ -5,7 +5,7 @@ GPS 솔루션 — GPS 트래킹 기반 위치확인 시스템 개발 | TRONT - + @@ -34,7 +34,7 @@
    POSITION / DESTINATION / DIRECTION
    -
    GPS / OUTDOOR TRACKERPROJECT SCREENS
    +
    GPS / OUTDOOR TRACKERPROJECT SCREENS
    diff --git a/projects/mobility.html b/projects/mobility.html index 3976430..2c29440 100644 --- a/projects/mobility.html +++ b/projects/mobility.html @@ -5,7 +5,7 @@ 현대 오토에버 — 국내향 및 해외향 내비게이션 HMI 개발 | TRONT - + @@ -27,7 +27,7 @@
    HYUNDAI / KIA
    -
    차량용 내비게이션PROJECT SCREENS
    +
    차량용 내비게이션PROJECT SCREENS
    diff --git a/projects/pharmacy.html b/projects/pharmacy.html index f533a00..4498d86 100644 --- a/projects/pharmacy.html +++ b/projects/pharmacy.html @@ -5,7 +5,7 @@ 모두의약국 — 약사님들의 커뮤니티 개발 | TRONT - + @@ -27,7 +27,7 @@
    APP / WEB / ADMIN
    -
    모바일 앱 / 웹PROJECT SCREENS
    +
    모바일 앱 / 웹PROJECT SCREENS
    diff --git a/projects/signage.html b/projects/signage.html index 0dd3cd6..2d60700 100644 --- a/projects/signage.html +++ b/projects/signage.html @@ -5,7 +5,7 @@ Signage 솔루션 — 빌딩(건물) 영상홍보 통합안내 시스템 | TRONT - + @@ -41,7 +41,7 @@
    ONE SYSTEM / MULTIPLE SCREENS
    -
    MULTI-VISION / DIDPROJECT SCREENS
    +
    MULTI-VISION / DIDPROJECT SCREENS
    diff --git a/script.js b/script.js index a29bbb7..7628c99 100644 --- a/script.js +++ b/script.js @@ -1,27 +1,13 @@ -/* TRONT static website. Contact details below are intentionally temporary. */ +/* Shared interactions for the TRONT website. */ (() => { 'use strict'; - const CONTACT = Object.freeze({ - email: 'hello@tront.example', // Replace with the company's actual email. - phone: '053-000-0000', // Replace with the company's actual phone. - temporary: true // Set false after replacing both details. - }); const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); const $ = (selector, root = document) => root.querySelector(selector); const $$ = (selector, root = document) => [...root.querySelectorAll(selector)]; document.documentElement.classList.add('js-ready'); $('#copyright-year').textContent = new Date().getFullYear(); - $$('[data-contact-email]').forEach(link => { - link.href = `mailto:${CONTACT.email}`; - if (link.closest('.contact-row')) link.textContent = CONTACT.email; - }); - $$('[data-contact-phone]').forEach(link => { - link.href = `tel:${CONTACT.phone.replace(/[^+\d]/g, '')}`; - link.textContent = CONTACT.phone; - }); - $('.contact-placeholder').hidden = !CONTACT.temporary; // Mobile navigation is available without changing desktop navigation. const menuButton = $('.menu-toggle'); @@ -252,28 +238,6 @@ }); }); - let toastTimer; - function notify(message) { - const toast = $('.toast'); - toast.textContent = message; - toast.classList.add('is-visible'); - clearTimeout(toastTimer); - toastTimer = setTimeout(() => toast.classList.remove('is-visible'), 3200); - } - $('.copy-email').addEventListener('click', async () => { - try { - if (!navigator.clipboard?.writeText) throw new Error('Clipboard unavailable'); - await navigator.clipboard.writeText(CONTACT.email); - notify('이메일 주소를 복사했습니다.'); - } catch { - const range = document.createRange(); - range.selectNodeContents($('.contact-row [data-contact-email]')); - const selection = window.getSelection(); - selection.removeAllRanges(); selection.addRange(range); - notify('이메일 주소를 선택했습니다. 복사 단축키를 사용해 주세요.'); - } - }); - // Original Canvas artwork: an evolving, connected torus. No 3D library. const canvas = $('#connection-canvas'); const ctx = canvas.getContext('2d');