feat(folders): nested folder tree (max depth 2) + id-based mutations
- new storeDb.ts: DB+FS layer (folders w/ parent_id, videos w/ global id)
- depth cap: sub-folder cannot have children (enforced in createFolder)
- video id: editable anytime (changeVideoId), uniqueness via PK
- routes:
- public /folder/:topName[/:subName], /video/:topName[/:subName]/:videoId
- admin /op/folder/:topName[/:subName], id-based /op/folders/:id/*
and /op/videos/:id/* (rename/changeId/delete/save + idAvailable check)
- views: breadcrumb + subFolder grid; 플레이리스트 추가 button shows at 2단계
- client JS: id-based mutation endpoints, share URL data attribute,
in-site player pushes share URL to address bar
- store.ts slimmed to Account + readAccounts (FS layer moved to storeDb)
- pickIntId accepts numeric JSON bodies
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
(function () {
|
||||
var overlay = document.getElementById('playerOverlay')
|
||||
if (!overlay) return
|
||||
var closeBtn = document.getElementById('playerClose')
|
||||
var video = document.getElementById('playerVideo')
|
||||
var titleEl = document.getElementById('playerTitle')
|
||||
|
||||
function openPlayer(videoId, title) {
|
||||
// 스펙: /player/:videoId 로 이동한 것처럼 동작하면서 내부 팝업으로 띄운다.
|
||||
// pushState 로 URL 만 바꿔, 새로고침/직접접근 시 player.ejs 가 응답한다.
|
||||
history.pushState({ player: true, videoId: videoId }, '', '/player/' + encodeURIComponent(videoId))
|
||||
function openPlayer(videoId, title, shareUrl) {
|
||||
// 사이트 내 재생도 share URL 을 주소창에 보이도록 pushState.
|
||||
// share URL 이 없으면 단순한 /file/video/:id 로 폴백.
|
||||
var url = shareUrl || ('/file/video/' + encodeURIComponent(videoId))
|
||||
history.pushState({ player: true, videoId: videoId }, '', url)
|
||||
titleEl.textContent = title || ''
|
||||
video.src = '/api/video/' + encodeURIComponent(videoId) + '/file'
|
||||
overlay.hidden = false
|
||||
@@ -19,17 +21,19 @@
|
||||
video.pause()
|
||||
video.removeAttribute('src')
|
||||
video.load()
|
||||
// 폴더 페이지로 되돌리기
|
||||
if (history.state && history.state.player) {
|
||||
history.back()
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.videoCard').forEach(function (card) {
|
||||
// <a> 태그면 클릭 시 share URL 로 풀 페이지 이동하도록 두고, 모달은 띄우지 않는다.
|
||||
if (card.tagName && card.tagName.toLowerCase() === 'a') return
|
||||
card.addEventListener('click', function () {
|
||||
var id = card.getAttribute('data-video-id')
|
||||
var title = card.querySelector('.videoTitle')
|
||||
openPlayer(id, title ? title.textContent : '')
|
||||
var titleNode = card.querySelector('.videoTitle')
|
||||
var shareUrl = card.getAttribute('data-share-url')
|
||||
openPlayer(id, titleNode ? titleNode.textContent : '', shareUrl)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user