앱 설정에서 세로 모드 지원을 비활성화하고, HTML 파일에 화면 방향을 가로로 설정하는 메타 태그를 추가했습니다. 또한, PDF 목록 JSON 파일을 업데이트하여 새로운 폴더 구조와 파일을 추가했습니다.

This commit is contained in:
9700X_PC 2025-09-19 14:52:45 +09:00
parent 2fa420494a
commit 81bd98885b
10 changed files with 163 additions and 113 deletions

BIN
ChoiPDFv.app_1.0.1_all.ipk Normal file

Binary file not shown.

View File

@ -8,5 +8,5 @@
"icon": "icon.png",
"largeIcon": "largeIcon.png",
"supportTouchMode": "full",
"supportPortraitMode": "true"
"supportPortraitMode": "false"
}

View File

@ -1,18 +1,58 @@
[
{
"type": "folder",
"name": "도면",
"children": [
{ "type": "file", "fileName": "제동장치.pdf", "uri": "assets/pdfs/로템1단계/제동장치.pdf" },
{ "type": "file", "fileName": "18. 공기 배관(하부).pdf", "uri": "assets/pdfs/우진200/18. 공기 배관(하부).pdf" }
]
},
{
"type": "folder",
"name": "매뉴얼",
"children": [
{ "type": "file", "fileName": "사용자.pdf", "uri": "assets/manual/user.pdf" }
]
}
{
"type": "folder",
"name": "교육교재",
"children": [
{
"type": "folder",
"name": "다대선",
"children": [
{ "type": "file", "fileName": "1-1.pdf", "uri": "assets/pdfs/교육교재/다대선/1-1.pdf" },
{ "type": "file", "fileName": "1.pdf", "uri": "assets/pdfs/교육교재/다대선/1.pdf" },
{ "type": "file", "fileName": "2-1.pdf", "uri": "assets/pdfs/교육교재/다대선/2-1.pdf" },
{ "type": "file", "fileName": "2.pdf", "uri": "assets/pdfs/교육교재/다대선/2.pdf" }
]
}
]
},
{
"type": "folder",
"name": "도면",
"children": [
{
"type": "folder",
"name": "로템1단계",
"children": [
{ "type": "file", "fileName": "부산1호선_40량_컬러도면집_전기회로.pdf", "uri": "assets/pdfs/도면/로템1단계/data_db_notic_20181102_020630_부산1호선_40량_컬러도면집_전기회로.pdf" },
{ "type": "file", "fileName": "부산1호선_40량_컬러도면집_제동회로.pdf", "uri": "assets/pdfs/도면/로템1단계/data_db_notic_20181102_020754_부산1호선_40량_컬러도면집_제동회로.pdf" }
]
}
]
},
{
"type": "folder",
"name": "정비지침서",
"children": [
{
"type": "folder",
"name": "로템2단계",
"children": [
{ "type": "file", "fileName": "1-1.pdf", "uri": "assets/pdfs/정비지침서/로템2단계/1-1.pdf" },
{ "type": "file", "fileName": "1-2.pdf", "uri": "assets/pdfs/정비지침서/로템2단계/1-2.pdf" },
{ "type": "file", "fileName": "1-3.pdf", "uri": "assets/pdfs/정비지침서/로템2단계/1-3.pdf" },
{ "type": "file", "fileName": "2-1.pdf", "uri": "assets/pdfs/정비지침서/로템2단계/2-1.pdf" },
{ "type": "file", "fileName": "2-2.pdf", "uri": "assets/pdfs/정비지침서/로템2단계/2-2.pdf" }
]
},
{
"type": "folder",
"name": "우진200량",
"children": [
{ "type": "file", "fileName": "차량일반 - 1.1일반사양 및 성능.pdf", "uri": "assets/pdfs/정비지침서/우진200량/제1장 차량일반 - 1.1일반사양 및 성능.pdf" },
{ "type": "file", "fileName": "차량일반 - 1.2 주요기기 사양.pdf", "uri": "assets/pdfs/정비지침서/우진200량/제1장 차량일반 - 1.2 주요기기 사양.pdf" },
{ "type": "file", "fileName": "차량일반 - 1.3 기호 명칭 및 인통선 기능.pdf", "uri": "assets/pdfs/정비지침서/우진200량/제1장 차량일반 - 1.3 기호 명칭 및 인통선 기능.pdf" }
]
}
]
}
]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
<meta name="screen-orientation" content="landscape" />
<title>Choi PDF Viewer</title>
<!-- <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&display=swap" /> -->
<link rel="stylesheet" href="webOSTVjs-1.2.10/fontawesome/css/all.min.css">
@ -12,26 +13,100 @@
--primary-bg:#1e1e1e;--secondary-bg:#2d2d2d;--tertiary-bg:#3c3c3c;
--text-primary:#e0e0e0;--text-secondary:#a0a0a0;--accent:#0099ff;--border:#4a4a4a
}
html,body{margin:0;height:100vh;overflow:hidden;background:var(--primary-bg);color:var(--text-primary);font-family:'Pretendard', sans-serif,system-ui,Roboto,-apple-system,sans-serif;display:flex}
#file-sidebar,#page-sidebar{width:360px;background:var(--secondary-bg);display:flex;flex-direction:column}
/* webOS TV 전체 화면 설정 */
html,body{
margin:0;
padding:0;
width:100vw;
height:100vh;
min-height:100vh;
overflow:hidden;
background:var(--primary-bg);
color:var(--text-primary);
font-family:'Pretendard', sans-serif,system-ui,Roboto,-apple-system,sans-serif;
display:flex;
position:fixed;
top:0;
left:0;
right:0;
bottom:0;
}
/* webOS TV 해상도에 맞는 사이드바 크기 */
#file-sidebar,#page-sidebar{
width:420px;
max-width:25vw;
background:var(--secondary-bg);
display:flex;
flex-direction:column;
height:100vh;
}
#file-sidebar{border-right:1px solid var(--border)}
#page-sidebar{border-left:1px solid var(--border)}
main{flex:1;display:flex;flex-direction:column;position:relative}
#viewer-container{flex:1;display:flex;justify-content:center;align-items:center;background:var(--primary-bg);overflow:hidden;touch-action:none;user-select:none;position:relative}
main{
flex:1;
display:flex;
flex-direction:column;
position:relative;
height:100vh;
min-width:0;
}
#viewer-container{
flex:1;
display:flex;
justify-content:center;
align-items:center;
background:var(--primary-bg);
overflow:hidden;
touch-action:none;
user-select:none;
position:relative;
width:100%;
height:100%;
}
/* 확대 모드시 벽(좌상단) 붙이기 */
.zoomed #viewer-container{justify-content:flex-start!important;align-items:flex-start!important}
.sidebar-hidden{display:none!important}
#viewer-header,#viewer-footer{position:absolute;left:0;right:0;z-index:10;display:flex;justify-content:space-between;align-items:center;background:rgba(45,45,45,.9);backdrop-filter:blur(5px);padding:10px 16px}
#viewer-header,#viewer-footer{
position:absolute;
left:0;
right:0;
z-index:10;
display:flex;
justify-content:space-between;
align-items:center;
background:rgba(45,45,45,.9);
backdrop-filter:blur(5px);
padding:15px 20px;
font-size:1.1em;
}
#viewer-header{top:0;border-bottom:1px solid var(--border)}
#viewer-footer{bottom:0;border-top:1px solid var(--border)}
.nav-btn{background:none;border:0;color:var(--text-primary);font-size:2rem;cursor:pointer;padding:0 14px}
.nav-btn:disabled{color:#666;cursor:not-allowed}
.sidebar-header{padding:14px 16px;font-weight:700;background:var(--tertiary-bg);border-bottom:1px solid var(--border)}
.sidebar-content{flex:1;overflow:auto}
.sidebar-header{
padding:18px 20px;
font-weight:700;
font-size:1.3em;
background:var(--tertiary-bg);
border-bottom:1px solid var(--border);
}
.sidebar-content{
flex:1;
overflow:auto;
height:calc(100vh - 70px);
}
.sidebar-content ul{margin:0;padding:0;list-style:none}
.sidebar-content li{padding:20px 24px;font-size: 1.2em;min-height: 60px;border-bottom:1.5px solid var(--border);cursor:pointer}
.sidebar-content li{
padding:22px 26px;
font-size:1.3em;
min-height:70px;
border-bottom:1.5px solid var(--border);
cursor:pointer;
display:flex;
align-items:center;
}
.sidebar-content li:hover{background:#383838}
.sidebar-content li.active{background:var(--accent);font-weight: 700;color:#fff}
#file-list .folder>.row{font-weight:700}
@ -39,12 +114,15 @@
#file-list .row{display:flex;align-items:center;gap:10px}
#file-list .icon{width:18px;text-align:center;color:#9ad1ff}
body.portrait #file-sidebar,
body.portrait #page-sidebar {
max-height: 30vh; /* 세로 화면에선 높이 제한 */
}
canvas{background:#fff;box-shadow:0 10px 30px rgba(0,0,0,.35);border-radius:6px;will-change:transform}
canvas{
background:#fff;
box-shadow:0 15px 40px rgba(0,0,0,.4);
border-radius:8px;
will-change:transform;
max-width:calc(100vw - 900px);
max-height:calc(100vh - 150px);
}
</style>
</head>
<body>
@ -184,91 +262,23 @@
parent.appendChild(li);
}
});
// }
// async function loadFileList(){
// try{
// const res = await fetch('assets/pdf-list.json');
// const data = await res.json();
// fileListEl.innerHTML = '';
// // 평면 배열도 허용: {fileName,uri}[]
// const items = Array.isArray(data) ? data : [];
// // 폴더/파일 혼합 트리 렌더
// renderTree(items, fileListEl);
// }catch(e){
// console.error('파일 목록 로드 실패', e);
// fileListEl.innerHTML = '<li>파일 목록을 불러올 수 없습니다.</li>';
// }
// }
async function loadFileList() {
webOS.service.request("luna://com.webos.service.tv.storage", {
method: "listStorages",
parameters: {},
onSuccess: function (res) {
if (res.devices && res.devices.length > 0) {
const usb = res.devices.find(d => d.deviceType === "usb"); // 첫 번째 USB
if (!usb) {
console.warn("USB가 연결되지 않았습니다.");
fileListEl.innerHTML = '<li>USB를 연결하세요.</li>';
return;
}
fileListEl.innerHTML = '';
scanUsbPdfs(usb.mountPath, (files) => {
if (files.length === 0) {
fileListEl.innerHTML = '<li>PDF 파일이 없습니다.</li>';
} else {
createFileList(files, fileListEl);
}
});
} else {
fileListEl.innerHTML = '<li>USB가 감지되지 않았습니다.</li>';
}
},
onFailure: function (err) {
console.error("스토리지 조회 실패:", err);
fileListEl.innerHTML = '<li>USB 인식 오류</li>';
}
});
}
async function loadFileList(){
try{
const res = await fetch('assets/pdf-list.json');
const data = await res.json();
fileListEl.innerHTML = '';
// 평면 배열도 허용: {fileName,uri}[]
const items = Array.isArray(data) ? data : [];
// 폴더/파일 혼합 트리 렌더
renderTree(items, fileListEl);
}catch(e){
console.error('파일 목록 로드 실패', e);
fileListEl.innerHTML = '<li>파일 목록을 불러올 수 없습니다.</li>';
}
}
function scanUsbPdfs(path, callback) {
webOS.service.request("luna://com.webos.service.tv.storage", {
method: "listFiles",
parameters: { path },
onSuccess: function (res) {
let results = [];
res.files.forEach(file => {
if (file.type === "dir") {
// 재귀적으로 하위 폴더 탐색
scanUsbPdfs(file.fullPath, (sub) => {
if (sub.length > 0) {
results.push({
name: file.name,
type: "folder",
children: sub
});
}
callback(results);
});
} else if (file.type === "file" && file.name.toLowerCase().endsWith(".pdf")) {
results.push({
name: file.name,
type: "file",
uri: file.fullPath
});
}
});
callback(results);
},
onFailure: function (err) {
console.error("USB 파일 검색 실패:", err);
callback([]);
}
});
}
// ---------- PDF 로드 ----------