Make episode info, general notes, and final script per-chunk fields
Each chunk is unique, so these fields no longer share a single project-level value.
This commit is contained in:
Binary file not shown.
+33
-32
@@ -114,6 +114,10 @@ export function migrateChunk(chunk) {
|
|||||||
return {
|
return {
|
||||||
...chunk,
|
...chunk,
|
||||||
spilloverEndVerse: Number.isInteger(chunk.spilloverEndVerse) ? chunk.spilloverEndVerse : null,
|
spilloverEndVerse: Number.isInteger(chunk.spilloverEndVerse) ? chunk.spilloverEndVerse : null,
|
||||||
|
generalNotes: chunk.generalNotes ?? '',
|
||||||
|
episodeNumber: chunk.episodeNumber ?? '',
|
||||||
|
episodeTitle: chunk.episodeTitle ?? '',
|
||||||
|
finalScript: chunk.finalScript ?? '',
|
||||||
}; // already new format
|
}; // already new format
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -123,6 +127,10 @@ export function migrateChunk(chunk) {
|
|||||||
application: '',
|
application: '',
|
||||||
crossReferences: [],
|
crossReferences: [],
|
||||||
spilloverEndVerse: null,
|
spilloverEndVerse: null,
|
||||||
|
generalNotes: '',
|
||||||
|
episodeNumber: '',
|
||||||
|
episodeTitle: '',
|
||||||
|
finalScript: '',
|
||||||
notes: undefined,
|
notes: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -187,10 +195,6 @@ export function migrateProject(raw) {
|
|||||||
if (Array.isArray(raw.chapters)) {
|
if (Array.isArray(raw.chapters)) {
|
||||||
return {
|
return {
|
||||||
...raw,
|
...raw,
|
||||||
generalNotes: raw.generalNotes ?? '',
|
|
||||||
episodeNumber: raw.episodeNumber ?? '',
|
|
||||||
episodeTitle: raw.episodeTitle ?? '',
|
|
||||||
finalScript: raw.finalScript ?? '',
|
|
||||||
chapters: raw.chapters.map((ch) => ({
|
chapters: raw.chapters.map((ch) => ({
|
||||||
...ch,
|
...ch,
|
||||||
chunks: ch.chunks.map(migrateChunk),
|
chunks: ch.chunks.map(migrateChunk),
|
||||||
@@ -205,10 +209,6 @@ export function migrateProject(raw) {
|
|||||||
translation: raw.translation ?? 'BSB',
|
translation: raw.translation ?? 'BSB',
|
||||||
lastEdited: raw.lastEdited ?? Date.now(),
|
lastEdited: raw.lastEdited ?? Date.now(),
|
||||||
selectedChunkId: raw.selectedChunkId ?? null,
|
selectedChunkId: raw.selectedChunkId ?? null,
|
||||||
generalNotes: raw.generalNotes ?? '',
|
|
||||||
episodeNumber: raw.episodeNumber ?? '',
|
|
||||||
episodeTitle: raw.episodeTitle ?? '',
|
|
||||||
finalScript: raw.finalScript ?? '',
|
|
||||||
chapters: [
|
chapters: [
|
||||||
{
|
{
|
||||||
book: raw.book ?? '',
|
book: raw.book ?? '',
|
||||||
@@ -524,6 +524,11 @@ function buildChunkBodies(project) {
|
|||||||
? chunk.crossReferences.join(', ')
|
? chunk.crossReferences.join(', ')
|
||||||
: 'None.';
|
: 'None.';
|
||||||
|
|
||||||
|
const generalNotes = (chunk.generalNotes ?? '').trim();
|
||||||
|
const episodeLabelLine = (chunk.episodeNumber ?? '').trim() || (chunk.episodeTitle ?? '').trim()
|
||||||
|
? `Episode: ${[chunk.episodeNumber?.trim(), chunk.episodeTitle?.trim()].filter(Boolean).join(' — ')}\n`
|
||||||
|
: '';
|
||||||
|
|
||||||
const greekWords = chunk.greekWords.length === 0
|
const greekWords = chunk.greekWords.length === 0
|
||||||
? 'None.'
|
? 'None.'
|
||||||
: chunk.greekWords.map((word) => {
|
: chunk.greekWords.map((word) => {
|
||||||
@@ -543,10 +548,10 @@ function buildChunkBodies(project) {
|
|||||||
return `===
|
return `===
|
||||||
|
|
||||||
CHUNK ${chunkIndex} — ${ref}
|
CHUNK ${chunkIndex} — ${ref}
|
||||||
|
${episodeLabelLine}
|
||||||
Scripture:
|
Scripture:
|
||||||
${verses}
|
${verses}
|
||||||
|
${generalNotes ? `\nBackground / General Notes:\n${generalNotes}\n` : ''}
|
||||||
Observation:
|
Observation:
|
||||||
${observation}
|
${observation}
|
||||||
|
|
||||||
@@ -582,7 +587,6 @@ Below is my work organised by passage chunk, including my OIA notes and Greek wo
|
|||||||
PROJECT: ${project.title}
|
PROJECT: ${project.title}
|
||||||
TRANSLATION: ${project.translation}
|
TRANSLATION: ${project.translation}
|
||||||
PASSAGE: ${chapterLabel}
|
PASSAGE: ${chapterLabel}
|
||||||
${(project.generalNotes ?? '').trim() ? `\nBACKGROUND / GENERAL NOTES:\n${project.generalNotes.trim()}\n` : ''}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return header + buildChunkBodies(project);
|
return header + buildChunkBodies(project);
|
||||||
@@ -610,9 +614,7 @@ export function buildPronunciationGuide(project) {
|
|||||||
export function buildPodcastPrompt(project) {
|
export function buildPodcastPrompt(project) {
|
||||||
const chapters = Array.isArray(project.chapters) ? project.chapters : [];
|
const chapters = Array.isArray(project.chapters) ? project.chapters : [];
|
||||||
const chapterLabel = chapters.map((ch) => `${ch.book} ${ch.chapter}`).join(', ');
|
const chapterLabel = chapters.map((ch) => `${ch.book} ${ch.chapter}`).join(', ');
|
||||||
const episodeLabel = (project.episodeNumber ?? '').trim()
|
const episodeLabel = 'EPISODE';
|
||||||
? `EPISODE ${project.episodeNumber.trim()}${(project.episodeTitle ?? '').trim() ? ` — ${project.episodeTitle.trim()}` : ''}`
|
|
||||||
: (project.episodeTitle ?? '').trim() || 'EPISODE';
|
|
||||||
|
|
||||||
const header = `I'm recording an episode of my Bible study podcast "Verse by Verse with Nate: A Journey Through Scripture" and need a full script written from my study notes below.
|
const header = `I'm recording an episode of my Bible study podcast "Verse by Verse with Nate: A Journey Through Scripture" and need a full script written from my study notes below.
|
||||||
|
|
||||||
@@ -674,7 +676,6 @@ Here are my study notes, organised by passage chunk, including my OIA notes, cro
|
|||||||
PROJECT: ${project.title}
|
PROJECT: ${project.title}
|
||||||
TRANSLATION: ${project.translation}
|
TRANSLATION: ${project.translation}
|
||||||
PASSAGE: ${chapterLabel}
|
PASSAGE: ${chapterLabel}
|
||||||
${(project.generalNotes ?? '').trim() ? `\nBACKGROUND / GENERAL NOTES:\n${project.generalNotes.trim()}\n` : ''}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return header + buildChunkBodies(project);
|
return header + buildChunkBodies(project);
|
||||||
@@ -930,10 +931,6 @@ const App = () => {
|
|||||||
translation: setup.translation,
|
translation: setup.translation,
|
||||||
lastEdited: Date.now(),
|
lastEdited: Date.now(),
|
||||||
selectedChunkId: null,
|
selectedChunkId: null,
|
||||||
generalNotes: '',
|
|
||||||
episodeNumber: '',
|
|
||||||
episodeTitle: '',
|
|
||||||
finalScript: '',
|
|
||||||
chapters: [
|
chapters: [
|
||||||
{
|
{
|
||||||
book: setup.book,
|
book: setup.book,
|
||||||
@@ -1012,6 +1009,10 @@ const App = () => {
|
|||||||
application: '',
|
application: '',
|
||||||
crossReferences: [],
|
crossReferences: [],
|
||||||
greekWords: [],
|
greekWords: [],
|
||||||
|
generalNotes: '',
|
||||||
|
episodeNumber: '',
|
||||||
|
episodeTitle: '',
|
||||||
|
finalScript: '',
|
||||||
};
|
};
|
||||||
return { ...ch, chunks: [...ch.chunks, newChunk] };
|
return { ...ch, chunks: [...ch.chunks, newChunk] };
|
||||||
});
|
});
|
||||||
@@ -2814,29 +2815,29 @@ const restoreRemoteProject = async (id) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Episode metadata for podcast prep */}
|
{/* Episode metadata for podcast prep — unique per chunk */}
|
||||||
<div className="rounded-3xl border border-slate-200 bg-slate-50 p-5">
|
<div className="rounded-3xl border border-slate-200 bg-slate-50 p-5">
|
||||||
<h3 className="text-sm font-semibold text-slate-900">Episode Info</h3>
|
<h3 className="text-sm font-semibold text-slate-900">Episode Info</h3>
|
||||||
<p className="text-xs text-slate-500">Used to label the script when preparing podcast content.</p>
|
<p className="text-xs text-slate-500">Used to label the script when preparing podcast content for this chunk.</p>
|
||||||
<div className="mt-3 flex flex-col gap-3 sm:flex-row">
|
<div className="mt-3 flex flex-col gap-3 sm:flex-row">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={project.episodeNumber ?? ''}
|
value={selectedChunk?.episodeNumber ?? ''}
|
||||||
onChange={(e) => updateProject((current) => ({ ...current, episodeNumber: e.target.value }))}
|
onChange={(e) => updateChunk(selectedChunk.id, { episodeNumber: e.target.value })}
|
||||||
placeholder="Episode #"
|
placeholder="Episode #"
|
||||||
className="w-full rounded-2xl border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200 sm:w-32"
|
className="w-full rounded-2xl border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200 sm:w-32"
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={project.episodeTitle ?? ''}
|
value={selectedChunk?.episodeTitle ?? ''}
|
||||||
onChange={(e) => updateProject((current) => ({ ...current, episodeTitle: e.target.value }))}
|
onChange={(e) => updateChunk(selectedChunk.id, { episodeTitle: e.target.value })}
|
||||||
placeholder="Episode title"
|
placeholder="Episode title"
|
||||||
className="w-full rounded-2xl border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200"
|
className="w-full rounded-2xl border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Background / general notes for the project */}
|
{/* Background / general notes — unique per chunk */}
|
||||||
<div className="rounded-3xl border border-slate-200 bg-slate-50 p-5">
|
<div className="rounded-3xl border border-slate-200 bg-slate-50 p-5">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -2845,14 +2846,14 @@ const restoreRemoteProject = async (id) => {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-slate-900">Background / General Notes</h3>
|
<h3 className="text-sm font-semibold text-slate-900">Background / General Notes</h3>
|
||||||
<p className="text-xs text-slate-500">Context, history, authorship, themes — applies to the whole study, not just this chunk.</p>
|
<p className="text-xs text-slate-500">Context, history, authorship, themes for this chunk.</p>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-slate-400">{collapsedSections.generalNotes ? '▸' : '▾'}</span>
|
<span className="text-slate-400">{collapsedSections.generalNotes ? '▸' : '▾'}</span>
|
||||||
</button>
|
</button>
|
||||||
{!collapsedSections.generalNotes && (
|
{!collapsedSections.generalNotes && (
|
||||||
<textarea
|
<textarea
|
||||||
value={project.generalNotes ?? ''}
|
value={selectedChunk?.generalNotes ?? ''}
|
||||||
onChange={(e) => updateProject((current) => ({ ...current, generalNotes: e.target.value }))}
|
onChange={(e) => updateChunk(selectedChunk.id, { generalNotes: e.target.value })}
|
||||||
rows={4}
|
rows={4}
|
||||||
placeholder="e.g. author, date, audience, historical context, key themes…"
|
placeholder="e.g. author, date, audience, historical context, key themes…"
|
||||||
className="mt-4 w-full resize-y rounded-2xl border border-slate-300 bg-white px-4 py-3 text-sm leading-6 text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200"
|
className="mt-4 w-full resize-y rounded-2xl border border-slate-300 bg-white px-4 py-3 text-sm leading-6 text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200"
|
||||||
@@ -3140,14 +3141,14 @@ const restoreRemoteProject = async (id) => {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold text-slate-900">Final Script</h3>
|
<h3 className="text-sm font-semibold text-slate-900">Final Script</h3>
|
||||||
<p className="text-xs text-slate-500">Paste the finished episode script here once Claude has helped you write it — keeps the project as a complete archive.</p>
|
<p className="text-xs text-slate-500">Paste the finished script for this chunk once Claude has helped you write it — keeps the project as a complete archive.</p>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-slate-400">{collapsedSections.finalScript ? '▸' : '▾'}</span>
|
<span className="text-slate-400">{collapsedSections.finalScript ? '▸' : '▾'}</span>
|
||||||
</button>
|
</button>
|
||||||
{!collapsedSections.finalScript && (
|
{!collapsedSections.finalScript && (
|
||||||
<textarea
|
<textarea
|
||||||
value={project.finalScript ?? ''}
|
value={selectedChunk?.finalScript ?? ''}
|
||||||
onChange={(e) => updateProject((current) => ({ ...current, finalScript: e.target.value }))}
|
onChange={(e) => updateChunk(selectedChunk.id, { finalScript: e.target.value })}
|
||||||
rows={8}
|
rows={8}
|
||||||
placeholder="Paste the final recorded/recordable episode script here…"
|
placeholder="Paste the final recorded/recordable episode script here…"
|
||||||
className="mt-4 w-full resize-y rounded-2xl border border-slate-300 bg-white px-4 py-3 text-sm leading-6 text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200"
|
className="mt-4 w-full resize-y rounded-2xl border border-slate-300 bg-white px-4 py-3 text-sm leading-6 text-slate-900 shadow-sm focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-200"
|
||||||
|
|||||||
Reference in New Issue
Block a user