Skip to content

Commit

Permalink
update formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
lalalune committed Aug 6, 2024
1 parent e3a8b55 commit a3a8b8e
Showing 1 changed file with 123 additions and 89 deletions.
212 changes: 123 additions & 89 deletions src/services/editors/script-editor/useScriptEditor.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,78 @@
"use client"

import { create } from "zustand"
import { Monaco } from "@monaco-editor/react"
import MonacoEditor from "monaco-editor"
import { ClapProject, ClapSegmentCategory } from "@aitube/clap"
import { TimelineStore, useTimeline, leftBarTrackScaleWidth } from "@aitube/timeline"
import { ScriptEditorStore, EditorView, ScrollData } from "@aitube/clapper-services"

import { getDefaultScriptEditorState } from "./getDefaultScriptEditorState"
"use client";

import { create } from "zustand";
import { Monaco } from "@monaco-editor/react";
import MonacoEditor from "monaco-editor";
import { ClapProject, ClapSegmentCategory } from "@aitube/clap";
import {
TimelineStore,
useTimeline,
leftBarTrackScaleWidth,
} from "@aitube/timeline";
import {
ScriptEditorStore,
EditorView,
ScrollData,
} from "@aitube/clapper-services";

import { getDefaultScriptEditorState } from "./getDefaultScriptEditorState";

export const useScriptEditor = create<ScriptEditorStore>((set, get) => ({
...getDefaultScriptEditorState(),
setMonaco: (monaco?: Monaco) => { set({ monaco }) },
setTextModel: (textModel?: MonacoEditor.editor.ITextModel) => { set({ textModel }) },
setStandaloneCodeEditor: (standaloneCodeEditor?: MonacoEditor.editor.IStandaloneCodeEditor) => { set({ standaloneCodeEditor }) },
setMouseIsInside: (mouseIsInside: boolean) => { set({ mouseIsInside }) },
setMonaco: (monaco?: Monaco) => {
set({ monaco });
},
setTextModel: (textModel?: MonacoEditor.editor.ITextModel) => {
set({ textModel });
},
setStandaloneCodeEditor: (
standaloneCodeEditor?: MonacoEditor.editor.IStandaloneCodeEditor,
) => {
set({ standaloneCodeEditor });
},
setMouseIsInside: (mouseIsInside: boolean) => {
set({ mouseIsInside });
},
loadDraftFromClap: (clap: ClapProject) => {
const { setDraft } = get()
const { setDraft } = get();

setDraft(clap.meta.screenplay)
setDraft(clap.meta.screenplay);
},
setDraft: (draft: string) => {
const { draft: previousDraft, highlightElements, textModel } = get()
if (draft === previousDraft) { return }
set({ draft })
const { draft: previousDraft, highlightElements, textModel } = get();
if (draft === previousDraft) {
return;
}
set({ draft });


if (!textModel) { return }
if (!textModel) {
return;
}
// we need to update the model
textModel?.setValue(draft)
textModel?.setValue(draft);

// and highlight the text again
highlightElements()
highlightElements();
},
publishDraftToTimeline: async (): Promise<void> => {
const { draft } = get()
console.log(`user asked to update the whole scene! this is expensive..`)
const { draft } = get();
console.log(`user asked to update the whole scene! this is expensive..`);
// we can do something smart, which is to only reconstruct the impacted segments
// and shift the rest along the time axis, without modifying it
},
onDidScrollChange: ({
scrollHeight,
scrollLeft,
scrollTop,
scrollWidth
scrollWidth,
}: ScrollData) => {
const {
const {
scrollHeight: previousScrollHeight,
scrollLeft: previousScrollLeft,
scrollTop: previousScrollTop,
scrollWidth: previousScrollWidth,
mouseIsInside
} = get()
mouseIsInside,
} = get();

// skip if nothing changed
if (
Expand All @@ -60,28 +81,31 @@ export const useScriptEditor = create<ScriptEditorStore>((set, get) => ({
scrollTop === previousScrollTop &&
scrollWidth === previousScrollWidth
) {
return
return;
}

set({
scrollHeight,
scrollLeft,
scrollTop,
scrollWidth,
})
});

// if the scroll event happened while we where inside the editor,
// then we need to dispatch the it
if (mouseIsInside) {
const timeline: TimelineStore = useTimeline.getState();
if (!timeline.timelineCamera || !timeline.timelineControls) {
return;
}

const timeline: TimelineStore = useTimeline.getState()
if (!timeline.timelineCamera || !timeline.timelineControls) { return }
const { standaloneCodeEditor } = get();

const scrollRatio = scrollTop / scrollHeight;
const scrollX = Math.round(
leftBarTrackScaleWidth + scrollRatio * timeline.contentWidth,
);

const { standaloneCodeEditor } = get()

const scrollRatio = scrollTop / scrollHeight
const scrollX = Math.round(leftBarTrackScaleWidth + scrollRatio * timeline.contentWidth)

/*console.log({
scrollHeight,
scrollLeft,
Expand All @@ -93,87 +117,96 @@ export const useScriptEditor = create<ScriptEditorStore>((set, get) => ({
*/

if (useTimeline.getState().scrolX !== scrollX) {
useTimeline.setState({ scrollX })
timeline.timelineCamera.position.setX(scrollX)
timeline.timelineControls.target.setX(scrollX)
useTimeline.setState({ scrollX });
timeline.timelineCamera.position.setX(scrollX);
timeline.timelineControls.target.setX(scrollX);
}
}
},
jumpCursorOnLineClick: (line?: number) => {
if (typeof line !== "number") { return }
const timeline: TimelineStore = useTimeline.getState()

const { lineNumberToMentionedSegments } = timeline
if (typeof line !== "number") {
return;
}
const timeline: TimelineStore = useTimeline.getState();

const mentionedSegments = lineNumberToMentionedSegments[line] || []
const { lineNumberToMentionedSegments } = timeline;

const firstMentionedSegment = mentionedSegments.at(0)
const mentionedSegments = lineNumberToMentionedSegments[line] || [];

const firstMentionedSegment = mentionedSegments.at(0);

if (typeof firstMentionedSegment?.startTimeInMs !== "number") { return }
if (typeof firstMentionedSegment?.startTimeInMs !== "number") {
return;
}

const { startTimeInMs } = firstMentionedSegment
const { startTimeInMs } = firstMentionedSegment;

timeline.setCursorTimestampAtInMs(startTimeInMs)
timeline.setCursorTimestampAtInMs(startTimeInMs);
},

highlightElements: () => {
const timeline: TimelineStore = useTimeline.getState()
const { clap } = timeline

const { textModel, standaloneCodeEditor, applyClassNameToKeywords } = get()
if (!textModel || !standaloneCodeEditor || !clap) { return }
const timeline: TimelineStore = useTimeline.getState();
const { clap } = timeline;

const { textModel, standaloneCodeEditor, applyClassNameToKeywords } = get();
if (!textModel || !standaloneCodeEditor || !clap) {
return;
}

const characters = clap.entities.filter(entity => entity.category === ClapSegmentCategory.CHARACTER).map(entity => entity.triggerName)
const characters = clap.entities
.filter((entity) => entity.category === ClapSegmentCategory.CHARACTER)
.map((entity) => entity.triggerName);

// any character
applyClassNameToKeywords(
"entity entity-character",
characters
)
applyClassNameToKeywords("entity entity-character", characters);

// UPPERCASE CHARACTER
applyClassNameToKeywords(
"entity entity-character entity-highlight",
characters,
true
)
true,
);

const locations = clap.entities.filter(entity => entity.category === ClapSegmentCategory.LOCATION).map(entity => entity.triggerName)
// any location
applyClassNameToKeywords(
"entity entity-location",
locations
)
const locations = clap.entities
.filter((entity) => entity.category === ClapSegmentCategory.LOCATION)
.map((entity) => entity.triggerName);
// any location
applyClassNameToKeywords("entity entity-location", locations);

// UPPERCASE LOCATION
applyClassNameToKeywords(
"entity entity-location entity-highlight",
locations,
true
)
true,
);
},
applyClassNameToKeywords: (className: string = "", keywords: string[] = [], caseSensitive = false) => {
const timeline: TimelineStore = useTimeline.getState()
const { clap } = timeline

const { textModel, standaloneCodeEditor } = get()
if (!textModel || !standaloneCodeEditor || !clap) { return }
applyClassNameToKeywords: (
className: string = "",
keywords: string[] = [],
caseSensitive = false,
) => {
const timeline: TimelineStore = useTimeline.getState();
const { clap } = timeline;

const { textModel, standaloneCodeEditor } = get();
if (!textModel || !standaloneCodeEditor || !clap) {
return;
}

keywords.forEach((entityTriggerName: string): void => {
const matches: MonacoEditor.editor.FindMatch[] = textModel.findMatches(
// searchString — The string used to search. If it is a regular expression, set isRegex to true.
// searchString: string,
entityTriggerName,

// @param searchOnlyEditableRange — Limit the searching to only search inside the editable range of the model.
// searchOnlyEditableRange: boolean,
false,

// / @param isRegex — Used to indicate that searchString is a regular expression.
// isRegex: boolean,
false,

// @param matchCase — Force the matching to match lower/upper case exactly.
// matchCase: boolean,
caseSensitive,
Expand All @@ -188,27 +221,28 @@ export const useScriptEditor = create<ScriptEditorStore>((set, get) => ({

// limitResultCount — Limit the number of results
// limitResultCount?: number
)
);

matches.forEach((match: MonacoEditor.editor.FindMatch): void => {
standaloneCodeEditor.createDecorationsCollection([
{
range: match.range,
options: {
isWholeLine: false,
inlineClassName: className
}
inlineClassName: className,
},
},
])
})
})
]);
});
});
},
setCurrent: (current?: string) => {
set({ current });
},
setCurrent: (current?: string) => { set({ current }) },
undo: () => {},
redo: () => {},
}))

}));

if (typeof window !== "undefined") {
(window as any).useScriptEditor = useScriptEditor
}
(window as any).useScriptEditor = useScriptEditor;
}

0 comments on commit a3a8b8e

Please sign in to comment.