앱 설정에서 세로 모드 지원을 비활성화하고, HTML 파일에 화면 방향을 가로로 설정하는 메타 태그를 추가했습니다. 또한, PDF 목록 JSON 파일을 업데이트하여 새로운 폴더 구조와 파일을 추가했습니다.
This commit is contained in:
parent
2fa420494a
commit
81bd98885b
Binary file not shown.
|
|
@ -8,5 +8,5 @@
|
|||
"icon": "icon.png",
|
||||
"largeIcon": "largeIcon.png",
|
||||
"supportTouchMode": "full",
|
||||
"supportPortraitMode": "true"
|
||||
"supportPortraitMode": "false"
|
||||
}
|
||||
|
|
@ -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.
Binary file not shown.
Binary file not shown.
|
|
@ -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 로드 ----------
|
||||
|
|
|
|||
Loading…
Reference in New Issue