-
Researching
-
-
Writing
-
-
Recording
-
-
Editing
-
-
Published
+
@@ -373,6 +391,7 @@
Untitled Video
Your Projects
Manage your upcoming and past videos.
+
diff --git a/js/app.js b/js/app.js
index a073a53..4d1b664 100644
--- a/js/app.js
+++ b/js/app.js
@@ -9,7 +9,7 @@
THEME_KEY: 'ui_theme',
SEARCH_HISTORY_KEY: 'search_history',
PROGRESS_KEY: 'watch_progress',
- ITEMS_PER_PAGE: 12,
+ ITEMS_PER_PAGE: 15,
API_CONFIG: { timeout: 1e4, retries: 3, backoff: 1.5, delay: 500 },
},
a = [
@@ -82,7 +82,7 @@
continueRow: r('continue-row'),
emptyHistory: r('empty-history'),
clearFilters: r('clearFilters'),
- studioToggleBtn: r('studioToggleBtn'),
+ modeSwitcher: r('modeSwitcher'), modeBtns: document.querySelectorAll('.mode-btn'), studioBreadcrumbs: r('studioBreadcrumbs'),
appRoot: r('app-root'),
studioRoot: r('studio-root'),
heroSection: r('hero'),
@@ -112,6 +112,8 @@
searchHistory: JSON.parse(localStorage.getItem(i.SEARCH_HISTORY_KEY) || '[]'),
progress: JSON.parse(localStorage.getItem(i.PROGRESS_KEY) || '{}'),
ytPlayer: null,
+ isPlaying: false,
+ isMuted: false,
},
l = {
sanitize: (e) =>
@@ -153,31 +155,60 @@
function d(e) {
return n.progress[e] || null;
}
+ function updateBreadcrumbs(path) {
+ if (!s.studioBreadcrumbs) return;
+ const parts = path.split(' > ');
+ s.studioBreadcrumbs.innerHTML = parts.map((p, i) =>
+ i === parts.length - 1 ? `
${p}` : `
${p}`
+ ).join('
');
+ }
+ let currentView = 'list';
+ function renderKanban(projects) {
+ const grid = document.getElementById("studioProjectsList");
+ if (!grid) return;
+ const columns = ['Research', 'Writing', 'Editing', 'Published'];
+ grid.className = 'kanban-grid';
+ grid.innerHTML = columns.map(col => {
+ const colProjects = projects.filter(p => p.status === col || (col === 'Research' && p.status === 'Researching'));
+ return `
${col} ${colProjects.length}
${colProjects.map(p => `
${p.title}
${p.progress}%${p.date}
`).join("")}
`;
+ }).join("");
+ grid.querySelectorAll(".resume-project-btn").forEach(btn => {
+ btn.addEventListener("click", (e) => {
+ const id = e.currentTarget.dataset.id;
+ const project = projects.find(p => p.id === id);
+ if (project) {
+ s.studioViews.forEach(v => v.style.display = "none");
+ if (s.activeProjectView) s.activeProjectView.style.display = "block";
+ if (r("current-project-title")) r("current-project-title").textContent = project.title;
+ updateBreadcrumbs('Studio > Projects > ' + project.title);
+ if (s.projectTabBtns[0]) s.projectTabBtns[0].click();
+ }
+ });
+ });
+ }
function renderProjects() {
const grid = document.getElementById("studioProjectsList");
if (!grid) return;
const saved = localStorage.getItem(i.PROJECTS_KEY);
const projects = saved ? JSON.parse(saved) : [
{ id: "p1", title: "The Fall of the Abbasids", status: "Writing", progress: 65, date: "2024-05-10" },
- { id: "p2", title: "Prophecy & Modernity", status: "Research", progress: 30, date: "2024-05-12" },
- { id: "p3", title: "The Silent Silk Road", status: "Editing", progress: 90, date: "2024-05-08" }
+ { id: "p2", title: "Prophecy & Modernity", status: "Researching", progress: 30, date: "2024-05-12" },
+ { id: "p3", title: "The Silent Silk Road", status: "Editing", progress: 90, date: "2024-05-08" },
+ { id: "p4", title: "The Golden Age", status: "Published", progress: 100, date: "2024-05-01" }
];
- grid.innerHTML = projects.map(p => `
-
- `).join("");
+ const listViewBtn = document.getElementById('listViewBtn');
+ const kanbanViewBtn = document.getElementById('kanbanViewBtn');
+ if (listViewBtn && !listViewBtn.hasListener) {
+ listViewBtn.addEventListener('click', () => { currentView = 'list'; listViewBtn.classList.add('active'); kanbanViewBtn.classList.remove('active'); renderProjects(); });
+ listViewBtn.hasListener = true;
+ }
+ if (kanbanViewBtn && !kanbanViewBtn.hasListener) {
+ kanbanViewBtn.addEventListener('click', () => { currentView = 'kanban'; kanbanViewBtn.classList.add('active'); listViewBtn.classList.remove('active'); renderProjects(); });
+ kanbanViewBtn.hasListener = true;
+ }
+ if (currentView === 'kanban') { renderKanban(projects); return; }
+ grid.className = 'studio-projects-grid';
+ grid.innerHTML = projects.map(p => `
`).join("");
grid.querySelectorAll(".resume-project-btn").forEach(btn => {
btn.addEventListener("click", (e) => {
const id = e.currentTarget.dataset.id;
@@ -186,6 +217,7 @@
s.studioViews.forEach(v => v.style.display = "none");
if (s.activeProjectView) s.activeProjectView.style.display = "block";
if (r("current-project-title")) r("current-project-title").textContent = project.title;
+ updateBreadcrumbs('Studio > Projects > ' + project.title);
if (s.projectTabBtns[0]) s.projectTabBtns[0].click();
}
});
@@ -238,6 +270,7 @@
},
}))),
(s.modal.style.display = 'flex'),
+ n.isPlaying = true,
s.modal.setAttribute('aria-hidden', 'false'),
(s.body.style.overflow = 'hidden'),
s.body.classList.add('modal-open'),
@@ -430,29 +463,41 @@
);
}
function k() {
- let a = n.search.toLowerCase();
- ((n.filtered = n.videos.filter((e) => {
- var t = n.categories.includes('all') || n.categories.includes(e.category),
- e = !a || e.title.toLowerCase().includes(a);
- return t && e;
- })),
- s.clearFilters && (s.clearFilters.style.display = n.categories.includes('all') ? 'none' : 'inline-flex'),
- s.resultsMeta && (s.resultsMeta.textContent = n.filtered.length + ' episode' + (1 === n.filtered.length ? '' : 's') + ' found'));
- var e = n.filtered.slice(0, i.ITEMS_PER_PAGE * (n.page + 1));
- (s.grid &&
- (0 === n.filtered.length
- ? (s.grid.innerHTML = `
-
-
-
No results found
-
Try different keywords or browse by category to find what you're looking for.
-
-
- `)
- : (s.grid.innerHTML = e.map(L).join(''))),
- s.loadMoreContainer && (s.loadMoreContainer.style.display = e.length < n.filtered.length ? 'block' : 'none'));
+ function getFuzzyScore(text, query) {
+ if (!query) return 1;
+ text = text.toLowerCase();
+ if (text.includes(query)) return 10;
+ let score = 0, qIdx = 0;
+ for (let i = 0; i < text.length && qIdx < query.length; i++) {
+ if (text[i] === query[qIdx]) { score++; qIdx++; }
+ }
+ return score / query.length;
+ }
+ const searchLower = n.search.toLowerCase();
+ n.filtered = n.videos.filter(v => {
+ const categoryMatch = n.categories.includes('all') || n.categories.includes(v.category);
+ if (!categoryMatch) return false;
+ if (!searchLower) return true;
+ return Math.max(getFuzzyScore(v.title, searchLower), getFuzzyScore(v.description || '', searchLower), v.category.includes(searchLower) ? 0.8 : 0) > 0.6;
+ });
+ if (searchLower) {
+ n.filtered.sort((a, b) => {
+ const scoreA = Math.max(getFuzzyScore(a.title, searchLower), getFuzzyScore(a.description || '', searchLower));
+ const scoreB = Math.max(getFuzzyScore(b.title, searchLower), getFuzzyScore(b.description || '', searchLower));
+ return scoreB - scoreA;
+ });
+ }
+ const visibleVideos = n.filtered.slice(0, i.ITEMS_PER_PAGE * (n.page + 1));
+ if (s.clearFilters) s.clearFilters.style.display = n.categories.includes('all') ? 'none' : 'inline-flex';
+ if (s.resultsMeta) s.resultsMeta.textContent = n.filtered.length + ' episode' + (n.filtered.length === 1 ? '' : 's') + ' found';
+ if (s.grid) {
+ if (n.filtered.length === 0) {
+ s.grid.innerHTML = `
No results found
Try different keywords or browse by category to find what you're looking for.
`;
+ } else {
+ s.grid.innerHTML = visibleVideos.map(L).join('');
+ }
+ }
+ if (s.loadMoreContainer) s.loadMoreContainer.style.display = visibleVideos.length < n.filtered.length ? 'block' : 'none';
}
function E() {
(s.statTotal && (s.statTotal.textContent = n.videos.length),
@@ -707,6 +752,10 @@
? 'Escape' === e.key && e.target.blur()
: '/' === (t = e.key.toLowerCase())
? (e.preventDefault(), s.search && s.search.focus())
+ : ' ' === t && n.current
+ ? (e.preventDefault(), s.player && s.player.contentWindow.postMessage('{"event":"command","func":"' + (n.isPlaying ? 'pauseVideo' : 'playVideo') + '","args":""}', '*'), n.isPlaying = !n.isPlaying)
+ : 'm' === t && n.current
+ ? (e.preventDefault(), s.player && s.player.contentWindow.postMessage('{"event":"command","func":"' + (n.isMuted ? 'unMute' : 'mute') + '","args":""}', '*'), n.isMuted = !n.isMuted)
: 'escape' === t
? (h(),
y(),
@@ -734,36 +783,37 @@
});
// Studio Logic
- s.studioToggleBtn && s.studioToggleBtn.addEventListener('click', () => {
- const isStudioOpen = s.studioRoot.style.display === 'block';
- if (isStudioOpen) {
- s.studioRoot.style.display = 'none';
- s.appRoot.style.display = 'block';
- if(s.heroSection) s.heroSection.style.display = 'block';
- if(s.continueBlockSec && n.videos.some(v => d(v.id))) s.continueBlockSec.style.display = 'block';
- s.studioToggleBtn.classList.remove('active');
- s.studioToggleBtn.querySelector('span').textContent = 'Studio';
- } else {
- s.studioRoot.style.display = 'block';
- s.appRoot.style.display = 'none';
- if(s.heroSection) s.heroSection.style.display = 'none';
- if(s.continueBlockSec) s.continueBlockSec.style.display = 'none';
- s.studioToggleBtn.classList.add('active');
- s.studioToggleBtn.querySelector('span').textContent = 'Exit Studio';
- }
+ s.modeBtns && s.modeBtns.forEach(btn => {
+ btn.addEventListener('click', () => {
+ const mode = btn.dataset.mode;
+ s.modeBtns.forEach(b => b.classList.remove('active'));
+ btn.classList.add('active');
+ if (mode === 'creator') {
+ s.studioRoot.style.display = 'block';
+ s.appRoot.style.display = 'none';
+ if(s.heroSection) s.heroSection.style.display = 'none';
+ if(s.continueBlockSec) s.continueBlockSec.style.display = 'none';
+ updateBreadcrumbs('Studio > Projects');
+ } else {
+ s.studioRoot.style.display = 'none';
+ s.appRoot.style.display = 'block';
+ if(s.heroSection) s.heroSection.style.display = 'block';
+ if(s.continueBlockSec && n.videos.some(v => d(v.id))) s.continueBlockSec.style.display = 'block';
+ }
+ });
});
const startScriptBtn = document.getElementById("startScriptBtn");
const openDemoBtn = document.getElementById("openDemoBtn");
if (startScriptBtn) {
startScriptBtn.addEventListener("click", () => {
- if (s.studioToggleBtn) s.studioToggleBtn.click();
+ const creatorBtn = Array.from(s.modeBtns).find(b => b.dataset.mode === 'creator'); if (creatorBtn) creatorBtn.click();
if (s.newProjectBtn) s.newProjectBtn.click();
});
}
if (openDemoBtn) {
openDemoBtn.addEventListener("click", () => {
- if (s.studioToggleBtn) s.studioToggleBtn.click();
+ const creatorBtn = Array.from(s.modeBtns).find(b => b.dataset.mode === 'creator'); if (creatorBtn) creatorBtn.click();
const resumeBtns = document.querySelectorAll(".resume-project-btn");
if (resumeBtns.length > 0) resumeBtns[0].click();
});
@@ -787,12 +837,14 @@
s.studioViews.forEach(v => v.style.display = 'none');
s.activeProjectView.style.display = 'block';
r('current-project-title').textContent = 'New Untitled Video';
+ updateBreadcrumbs('Studio > Projects > New Untitled Video');
s.projectTabBtns[0].click(); // open research tab
});
s.backToProjectsBtn && s.backToProjectsBtn.addEventListener('click', () => {
s.activeProjectView.style.display = 'none';
r('studio-view-projects').style.display = 'block';
+ updateBreadcrumbs('Studio > Projects');
s.studioNavBtns.forEach(b => {
b.classList.remove('active');
if(b.dataset.tab === 'projects') b.classList.add('active');
@@ -819,7 +871,7 @@
.fill(0)
.map(
() => `
-
+
diff --git a/js/script.js b/js/script.js
index 2ace577..ac021da 100644
--- a/js/script.js
+++ b/js/script.js
@@ -1,100 +1,24 @@
// Tamil Script Studio
-
-const SCRIPT_HTML = `
-
-
-
-
-
Script Studio
-
Draft your documentary script with structured sections.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
+const SCRIPT_HTML = `
Script Studio
Draft your documentary script with structured sections.
`;
export function initScriptStudio() {
const container = document.getElementById('ptab-script');
if (!container) return;
-
container.innerHTML = SCRIPT_HTML;
-
const textareas = container.querySelectorAll('.script-textarea');
textareas.forEach(ta => {
ta.addEventListener('input', updateMetrics);
+ ta.addEventListener('mouseup', () => {
+ const selectedText = ta.value.substring(ta.selectionStart, ta.selectionEnd).trim();
+ if (selectedText.length > 5) showMappingPopup(ta, selectedText);
+ else hideMappingPopup();
+ });
});
-
document.getElementById('insertPauseBtn')?.addEventListener('click', () => insertAtCursor(' [PAUSE] '));
document.getElementById('insertEmphasisBtn')?.addEventListener('click', () => insertAtCursor(' ** **'));
-
const focusOverlay = document.getElementById('focusModeOverlay');
const focusTextArea = document.getElementById('focusTextArea');
const focusTitle = document.getElementById('focusTitle');
let activeSourceTA = null;
-
document.getElementById('toggleFocusMode')?.addEventListener('click', () => {
const focused = document.activeElement;
if (focused && focused.classList.contains('script-textarea')) {
@@ -105,11 +29,8 @@ export function initScriptStudio() {
focusOverlay.classList.add('show');
focusTextArea.focus();
updateFocusMetrics();
- } else {
- alert('Please click inside a section to focus.');
- }
+ } else alert('Please click inside a section to focus.');
});
-
document.getElementById('exitFocusMode')?.addEventListener('click', () => {
if (activeSourceTA) {
activeSourceTA.value = focusTextArea.value;
@@ -118,49 +39,56 @@ export function initScriptStudio() {
focusOverlay.setAttribute('aria-hidden', 'true');
focusOverlay.classList.remove('show');
});
-
focusTextArea.addEventListener('input', updateFocusMetrics);
-
updateMetrics();
}
-
+function showMappingPopup(ta, text) {
+ let popup = document.getElementById('mappingPopup');
+ if (!popup) {
+ popup = document.createElement('div');
+ popup.id = 'mappingPopup';
+ popup.className = 'mapping-popup';
+ popup.innerHTML = `
`;
+ document.body.appendChild(popup);
+ }
+ const rect = ta.getBoundingClientRect();
+ popup.style.display = 'block';
+ popup.style.top = `${window.scrollY + rect.top - 40}px`;
+ popup.style.left = `${window.scrollX + rect.left + 20}px`;
+ document.getElementById('linkRefBtn').onclick = () => {
+ const refTab = document.querySelector('.studio-nav-btn[data-tab="islamic"]');
+ if (refTab) refTab.click();
+ hideMappingPopup();
+ };
+}
+function hideMappingPopup() {
+ const popup = document.getElementById('mappingPopup');
+ if (popup) popup.style.display = 'none';
+}
function updateMetrics() {
const textareas = document.querySelectorAll('.script-textarea');
let totalText = '';
textareas.forEach(ta => totalText += ta.value + ' ');
-
const words = totalText.trim().split(/\s+/).filter(w => w.length > 0).length;
const countEl = document.getElementById('scriptWordCount');
if(countEl) countEl.textContent = words;
-
- // Rough estimate: 130 words per minute for Tamil/English narration
const minutes = Math.floor(words / 130);
const seconds = Math.floor((words % 130) / (130 / 60));
-
const durEl = document.getElementById('scriptDuration');
if(durEl) durEl.textContent = `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
-
function updateFocusMetrics() {
- const focusTextArea = document.getElementById("focusTextArea");
- const words = (window.activeFocusTextArea || document.getElementById("focusTextArea")).value.trim().split(/\s+/).filter(w => w.length > 0).length;
+ const words = document.getElementById("focusTextArea").value.trim().split(/\s+/).filter(w => w.length > 0).length;
document.getElementById('focusMetrics').textContent = `${words} words`;
}
-
function insertAtCursor(text) {
const activeEl = document.activeElement;
if (activeEl && (activeEl.classList.contains('script-textarea') || activeEl.classList.contains('focus-textarea'))) {
- const start = activeEl.selectionStart;
- const end = activeEl.selectionEnd;
- const val = activeEl.value;
+ const start = activeEl.selectionStart, end = activeEl.selectionEnd, val = activeEl.value;
activeEl.value = val.substring(0, start) + text + val.substring(end);
activeEl.selectionStart = activeEl.selectionEnd = start + text.length;
activeEl.focus();
updateMetrics();
- } else {
- alert('Please focus on a text area first to insert markers.');
- }
+ } else alert('Please focus on a text area first to insert markers.');
}
-
-// Auto-init on load
document.addEventListener('DOMContentLoaded', initScriptStudio);
diff --git a/js/seo.js b/js/seo.js
index 2b59419..5374aeb 100644
--- a/js/seo.js
+++ b/js/seo.js
@@ -1,130 +1,52 @@
// YouTube SEO Toolkit
-
-const SEO_HTML = `
-
-
-
-
SEO & Metadata
-
Optimize your title, description, and tags for YouTube search.
-
-
-
-
-
-
-
-`;
-
+const SEO_HTML = `
SEO & Metadata
Optimize your title, description, and tags for YouTube search.
`;
export function initSEO() {
const container = document.getElementById('ptab-seo');
if (!container) return;
container.innerHTML = SEO_HTML;
-
const titleInput = document.getElementById('seoTitle');
const thumbTitle = document.getElementById('thumbTitle');
const previewTitle = document.getElementById('previewTitle');
const titleCount = document.getElementById('titleCount');
const scoreTitle = document.getElementById('scoreTitle');
const scoreKeywords = document.getElementById('scoreKeywords');
-
+ const updateHeatmap = () => {
+ const title = titleInput.value.toLowerCase(), desc = document.getElementById('seoDesc').value.toLowerCase();
+ const heatmapFill = document.getElementById('seoHeatmapFill'), heatmapStatus = document.getElementById('heatmapStatus');
+ if (!heatmapFill || !heatmapStatus) return;
+ const keywords = ['quran', 'history', 'truth', 'secret', 'mystery', 'islam', 'prophecy', 'documentary'];
+ let count = 0;
+ keywords.forEach(k => { if (title.includes(k)) count += 2; if (desc.includes(k)) count += 1; });
+ const score = Math.min(100, count * 10);
+ heatmapFill.style.width = `${score}%`;
+ if (score < 30) { heatmapFill.className = 'heatmap-fill low'; heatmapStatus.textContent = 'Low Optimization'; }
+ else if (score < 70) { heatmapFill.className = 'heatmap-fill mid'; heatmapStatus.textContent = 'Good Progress'; }
+ else { heatmapFill.className = 'heatmap-fill high'; heatmapStatus.textContent = 'Highly Optimized'; }
+ };
titleInput.addEventListener('input', (e) => {
const val = e.target.value;
previewTitle.textContent = val || 'Your Title Will Appear Here';
thumbTitle.textContent = val || 'Your Title';
titleCount.textContent = `${val.length}/100`;
-
- if (val.length < 20) {
- scoreTitle.textContent = 'Too Short';
- scoreTitle.className = 'score-badge warning';
- } else if (val.length > 70) {
- scoreTitle.textContent = 'Too Long';
- scoreTitle.className = 'score-badge warning';
- } else {
- scoreTitle.textContent = 'Optimal';
- scoreTitle.className = 'score-badge good';
- }
-
- // Mock keyword strength
+ if (val.length < 20) { scoreTitle.textContent = 'Too Short'; scoreTitle.className = 'score-badge warning'; }
+ else if (val.length > 70) { scoreTitle.textContent = 'Too Long'; scoreTitle.className = 'score-badge warning'; }
+ else { scoreTitle.textContent = 'Optimal'; scoreTitle.className = 'score-badge good'; }
const keywords = ['quran', 'history', 'truth', 'secret', 'mystery', 'islam'];
const hasKeyword = keywords.some(k => val.toLowerCase().includes(k));
- if (hasKeyword) {
- scoreKeywords.textContent = 'Strong';
- scoreKeywords.className = 'score-badge excellent';
- } else {
- scoreKeywords.textContent = 'Low';
- scoreKeywords.className = 'score-badge warning';
- }
+ if (hasKeyword) { scoreKeywords.textContent = 'Strong'; scoreKeywords.className = 'score-badge excellent'; }
+ else { scoreKeywords.textContent = 'Low'; scoreKeywords.className = 'score-badge warning'; }
+ updateHeatmap();
});
-
document.getElementById('seoDesc')?.addEventListener('input', (e) => {
document.getElementById('descCount').textContent = `${e.target.value.length}/5000`;
+ updateHeatmap();
});
-
document.getElementById('seoTags')?.addEventListener('input', (e) => {
document.getElementById('tagCount').textContent = `${e.target.value.length}/500`;
});
-
document.getElementById('aiTitleBtn')?.addEventListener('click', () => {
const modal = document.getElementById('aiModal');
- if(modal) {
- document.getElementById('aiActionSelect').value = 'title';
- modal.classList.add('show');
- modal.setAttribute('aria-hidden', 'false');
- }
+ if(modal) { document.getElementById('aiActionSelect').value = 'title'; modal.classList.add('show'); modal.setAttribute('aria-hidden', 'false'); }
});
}
-
document.addEventListener('DOMContentLoaded', initSEO);