diff options
-rw-r--r-- | src/client/apis/gpt/GPT.ts | 2 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 2 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 29 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCardDeckView.tsx | 231 | ||||
-rw-r--r-- | src/client/views/global/globalScripts.ts | 153 | ||||
-rw-r--r-- | src/client/views/pdf/GPTPopup/GPTPopup.scss | 6 | ||||
-rw-r--r-- | src/client/views/pdf/GPTPopup/GPTPopup.tsx | 102 |
7 files changed, 343 insertions, 182 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 9a24c808c..398f8ae39 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -20,7 +20,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { summary: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Summarize this text in simpler terms: ' }, edit: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: 'Reword this: ' }, completion: { model: 'gpt-3.5-turbo-instruct', maxTokens: 256, temp: 0.5, prompt: '' }, - sort:{model:'gpt-4o',maxTokens:2048,temp:0.5,prompt:"I'm going to give you a list of descriptions. Each one is seperated by ====== on either side. They will vary in length, so make sure to only seperate when you see ======. Sort them into lists by shared content. MAKE SURE EACH DESCRIPTOR IS IN ONLY ONE LIST. Generate only the list with each list seperated by ====== with the elements seperated by ~~~~~~"}, + sort:{model:'gpt-4o',maxTokens:2048,temp:0.5,prompt:"I'm going to give you a list of descriptions. Each one is seperated by ====== on either side. They will vary in length, so make sure to only seperate when you see ======. Sort them into lists by shared content. MAKE SURE EACH DESCRIPTOR IS IN ONLY ONE LIST. Generate only the list with each list seperated by ====== with the elements seperated by ~~~~~~. Try to do around 4 groups, but a little more or less is ok."}, describe:{model:'gpt-4-vision-preview',maxTokens:2048,temp:0,prompt:"Describe these images in 3-5 words"}, diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 57f91399a..eded2b485 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -502,6 +502,8 @@ export class DocumentOptions { cardSort?: STRt = new StrInfo('way cards are sorted in deck view'); customSortNumber?: NUMt = new NumInfo('number of custom sorts the user has created'); customHashMap?: List<string> + visibleGroupNumbers?: List<number> + // card_sort_time?: BOOLt = new BoolInfo('whether sorting cards in deck view by time'); // card_sort_type?: BOOLt = new BoolInfo('whether sorting cards in deck view by type'); // card_sort_color?: BOOLt = new BoolInfo('whether sorting cards in deck view by color'); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index e18c22bac..251771e8e 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -729,18 +729,34 @@ pie title Minerals in my tap water { title: "Time", icon:"hourglass-half", toolTip:"Sort by most recent document creation", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"time", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, { title: "Type", icon:"eye", toolTip:"Sort by document type", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, { title: "Color", icon:"palette", toolTip:"Sort by document color", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, - { title: "Links", icon:"link", toolTip:"Sort by its links", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"links", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, - { title: "Create", icon:"heart", toolTip:"Create your first custom grouping!", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"custom1", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, - { title: "Create", icon:"star", toolTip:"Create your second custom grouping!", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"custom2", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, - { title: "Create", icon:"satellite", toolTip:"Create your third custom grouping!", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"custom3", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, - { title: "Create", icon:"robot", toolTip:"Have ChatGPT sort your text-based nodes !", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"chat", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "Smart Sort", icon:"robot", toolTip:"Have ChatGPT sort your text-based nodes !", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"chat", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + ] + } + static customCardTools(): Button[] { + return [ + { title: "Create", icon:"heart", toolTip:"Create your first custom grouping!", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"custom1", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "Create", icon:"star", toolTip:"Create your second custom grouping!", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"custom2", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "Create", icon:"satellite", toolTip:"Create your third custom grouping!", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"custom3", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "Custom 1", icon: "Custom 1", width: 10, toolTip: "Set visibilty!", subMenu: CurrentUserUtils.cardGroupTools("heart"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!isThatCardGroup(0)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Custom 2", icon: "Custom 2", width: 80, toolTip: "Set visibilty!", subMenu: CurrentUserUtils.cardGroupTools("star"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!isThatCardGroup(1)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "Custom 3", icon: "Custom 3", width: 80, toolTip: "Set visibilty!", subMenu: CurrentUserUtils.cardGroupTools("satellite"), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!isThatCardGroup(2)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + ] + } - // ...customs + static cardGroupTools(icon: string): Button[] { + return [ + { title: "", icon:icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"1", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "", icon:icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"2", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "", icon:icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"3", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, + { title: "", icon:icon, toolTip:"Click to toggle visibility", btnType: ButtonType.ToggleButton, expertMode: false, toolType:"4", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, ] } + + + static viewTools(): Button[] { return [ { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform @@ -842,6 +858,7 @@ pie title Minerals in my tap water { title: "View", icon: "View", toolTip: "View tools", subMenu: CurrentUserUtils.viewTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Stack", icon: "View", toolTip: "Stacking tools", subMenu: CurrentUserUtils.stackTools(), expertMode: false, toolType:CollectionViewType.Stacking, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Card", icon: "Sort", toolTip: "Card sort", subMenu: CurrentUserUtils.cardTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available + { title: "CustomCard", icon: "Create", toolTip: "Create custom groupings!", subMenu: CurrentUserUtils.customCardTools(), expertMode: false, toolType:CollectionViewType.Card, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Web", icon: "Web", toolTip: "Web functions", subMenu: CurrentUserUtils.webTools(), expertMode: false, toolType:DocumentType.WEB, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when Web is selected { title: "Video", icon: "Video", toolTip: "Video functions", subMenu: CurrentUserUtils.videoTools(), expertMode: false, toolType:DocumentType.VID, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when video is selected { title: "Image", icon: "Image", toolTip: "Image functions", subMenu: CurrentUserUtils.imageTools(), expertMode: false, toolType:DocumentType.IMG, funcs: {hidden: `!SelectionManager_selectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectionManager_selectedDocType(this.toolType, this.expertMode)`} }, // Only when image is selected diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index e96fbc161..42c82ca74 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -24,6 +24,7 @@ import { ImageField, PdfField, URLField } from '../../../fields/URLField'; import { GPTPopup } from '../pdf/GPTPopup/GPTPopup'; import { GPTPopupMode } from '../pdf/GPTPopup/GPTPopup'; import { reaction } from 'mobx'; +import { NumListCast } from '../../../fields/Doc'; @observer export class CollectionCardView extends CollectionSubView() { @@ -32,8 +33,42 @@ export class CollectionCardView extends CollectionSubView() { // documents themselves @observable hoveredNodeIndex = -1; + //index to group + @observable customGroupDictionary: Map<number, number>[] = [new Map<number, number>(), new Map<number, number>(), new Map<number, number>()]; + @computed get myChildLayoutPairs() { + let activeGroups = NumListCast(this._props.Document.visibleGroupNumbers); + let currCustom = NumCast(this._props.Document.customSortNumber); + + // console.log("Active Groups:", activeGroups); + + for (let i=0; i< activeGroups.length; i++){ + console.log("Active Groups" + activeGroups[i]) + } + // console.log("Current Custom Sort Number:", currCustom); + + if (activeGroups.length <= 0) { + return this.childLayoutPairs.filter(l => l.layout.type != DocumentType.LINK); + } + + if (StrCast(this._props.Document.cardSort).includes("custom")) { + return this.childLayoutPairs.filter((l, index) => { + if (l.layout.type === DocumentType.LINK) { + return false; + } + + // Get the group number for the current index from the customGroupDictionary + const groupNumber = this.customGroupDictionary[currCustom].get(index); + + // console.log(`Index: ${index}, Group Number: ${groupNumber}`); + + // Check if the group number is in the active groups + return groupNumber !== undefined && activeGroups.includes(groupNumber); + }); + } + + // Default return for non-custom cardSort or other cases, filtering out links return this.childLayoutPairs.filter(l => l.layout.type != DocumentType.LINK); } @@ -90,6 +125,9 @@ export class CollectionCardView extends CollectionSubView() { if (this._props.Document.customHashMap != undefined){ this.customGroupDictionary = this.getCustoms(StrListCast(this._props.Document.customHashMap)) } + // this._props.Document.visibleGroupNumbers = new List<number>([1,2,3,4]) + + reaction( () => this._props.Document.cardSort, @@ -101,7 +139,6 @@ export class CollectionCardView extends CollectionSubView() { ); } - @observable customGroupDictionary: Map<number, number>[] = [new Map<number, number>(), new Map<number, number>(), new Map<number, number>()]; @computed get mapToField(): List<string> { const resultList = new List<string>(); @@ -272,7 +309,8 @@ export class CollectionCardView extends CollectionSubView() { case 'custom': return this.sort(sorted, 'custom', desc); case 'chat': - return { docs: this.sortedDocs || this.myChildLayoutPairs}; // Use the sorted docs from the observable + return this.sort(this.myChildLayoutPairs, 'gpt', BoolCast(this.layoutDoc.sortDesc)); + default: docs = this.myChildLayoutPairs; return { docs }; @@ -458,7 +496,8 @@ export class CollectionCardView extends CollectionSubView() { // const childPair = { layout: doc, data: doc }; const isHovered = this.hoveredNodeIndex === index; - const childPairIndex = this.myChildLayoutPairs.indexOf(childPair); + // const childPairIndex = this.myChildLayoutPairs.indexOf(childPair); + const childPairIndex = this.childLayoutPairs.filter(d => d.layout.type != DocumentType.LINK).indexOf(childPair) const realIndex = this.sortedDocsType.docs.filter(d => !SelectionManager.IsSelected(d.layout)).indexOf(childPair); const calcRowIndex = this.overflowIndexCalc(realIndex); @@ -501,6 +540,8 @@ export class CollectionCardView extends CollectionSubView() { {this.displayDoc(childPair, childScreenToLocal)} {this._props.Document.cardSort == 'custom' ? this.renderButtons(childPairIndex) : ''} + {this._props.Document.cardSort == 'chat' ? this.renderButtons(childPairIndex, childPair.layout, true) : ''} + </div> ); }); @@ -512,38 +553,23 @@ export class CollectionCardView extends CollectionSubView() { - @action toggleButton(childPairIndex: number, buttonID: number) { - this.customGroupDictionary[NumCast(this._props.Document.customSortNumber)].set(childPairIndex, buttonID); - this._props.Document.customHashMap = this.mapToField - - // Cast(selected.Document.data, WebField, null)?.url?.href) - - //note richtext - - // StrCast(selected.Document.data, Cast(selected.Document.data, WebField, null)?.url?.href) - - - - // const - const imgurlperchance = Cast(this.childDocs[1].data, ImageField, null)?.url.href; - const perchance = this.imageUrlToBase64(imgurlperchance) - // const imgurlperchance = Cast(this.childDocs[1].data, PdfField, null)?.url.; - - - // console.log('Print Front of cards: ' + RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text); - // console.log('Print Back of cards: ' + RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text); - - // const perchance = StrCast(this.childDocs[0].text); - - - - // const pdf = (StrCast(this.myChildLayoutPairs[0].layout.text)); //pdf - const queryText = this.myChildLayoutPairs[0].layout.type; //everything else - - // const queryText = RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text; - - console.log(queryText ?? "sad") + @action toggleButton(childPairIndex: number, buttonID: number, isChat = false, doc?: Doc) { + if (!isChat) { + this.customGroupDictionary[NumCast(this._props.Document.customSortNumber)].set(childPairIndex, buttonID); + this._props.Document.customHashMap = this.mapToField; + } + + if (isChat && doc) { + this.gptGroups.set(doc, buttonID); + } + + // console.log(`Toggled button for childPairIndex: ${childPairIndex}, buttonID: ${buttonID}, isChat: ${isChat}`); + // console.log(`Updated customGroupDictionary:`, this.customGroupDictionary); + if (isChat && doc) { + console.log(`Updated gptGroups for doc ${doc}:`, this.gptGroups.get(doc)); + } } + async childPairStringList(): Promise<string> { let string = ""; @@ -598,20 +624,25 @@ export class CollectionCardView extends CollectionSubView() { textToDoc = new Map<string, Doc>() gptProccessedImages = new Set<Doc>() - @action async getImageDesc(image: Doc){ - let href = (image['data'] as URLField).url.href; - let hrefParts = href.split('.'); - let hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; - try { - let hrefBase64 = await this.imageUrlToBase64(hrefComplete); - let response = await gptImageLabel(hrefBase64); - this.textToDoc.set(response.trim(), image); - this.gptProccessedImages.add(image); - console.log(response); - return response; // Return the response from gptImageLabel - } catch (error) { - console.log("bad things have happened"); - } + @action async getImageDesc(image: Doc) { + if (this.gptProccessedImages.has(image)) { + // Return the already processed description + return Array.from(this.textToDoc.keys()).find(key => this.textToDoc.get(key) === image) || ''; + } + + let href = (image['data'] as URLField).url.href; + let hrefParts = href.split('.'); + let hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; + try { + let hrefBase64 = await this.imageUrlToBase64(hrefComplete); + let response = await gptImageLabel(hrefBase64); + this.textToDoc.set(response.trim(), image); + this.gptProccessedImages.add(image); + console.log(response); + return response; // Return the response from gptImageLabel + } catch (error) { + console.log("bad things have happened"); + } } @@ -620,41 +651,43 @@ export class CollectionCardView extends CollectionSubView() { //a map from the text to the Doc (for everything) - @action async smartSort() { - this.isLoading = true; - console.log("loading"); + // @action async smartSort() { + // this.isLoading = true; + // console.log("loading"); - // Store the result of childPairStringList in a variable - const childPairStrings = await this.childPairStringList(); + // // Store the result of childPairStringList in a variable + // const childPairStrings = await this.childPairStringList(); - if (childPairStrings === "") { - console.log("no child pairs :("); - } else { - console.log(childPairStrings + " og list"); - let prompt = childPairStrings; + // if (childPairStrings === "") { + // console.log("no child pairs :("); + // } else { + // console.log(childPairStrings + " og list"); + // let prompt = childPairStrings; - let res = await gptAPICall(prompt, GPTCallType.SORT); - this.isLoading = false; - if (res == 'Error connecting with API.') { - // If GPT call failed - console.error('GPT call failed'); - } else if (res != null) { - console.log(res); - this.processGptOutput(res); - // Update the observable with the sorted documents - this.sortedDocs = this.sort(this.myChildLayoutPairs, 'gpt', BoolCast(this.layoutDoc.sortDesc)).docs; - } - this.isLoading = false; - } - } + // let res = await gptAPICall(prompt, GPTCallType.SORT); + // this.isLoading = false; + // if (res == 'Error connecting with API.') { + // // If GPT call failed + // console.error('GPT call failed'); + // } else if (res != null) { + // console.log(res); + // this.processGptOutput(res); + // // Update the observable with the sorted documents + // this.sortedDocs = this.sort(this.myChildLayoutPairs, 'gpt', BoolCast(this.layoutDoc.sortDesc)).docs; + // } + // this.isLoading = false; + // } + // } - gptGroups = new Map<Doc, number> + gptGroups = new ObservableMap<Doc, number> + @observable amGPTGroups = 0 // Method to convert the GPT-produced string into a map processGptOutput(gptOutput: string) { // Split the string into individual list items const listItems = gptOutput.split('======').filter(item => item.trim() !== ''); + this.amGPTGroups = listItems.length listItems.forEach((item, index) => { // Split the item by '~~~~~~' to get all descriptors @@ -678,14 +711,15 @@ export class CollectionCardView extends CollectionSubView() { @observable isChatPopupOpen = false; @action openChatPopup = async () => { - this.isChatPopupOpen = true; - GPTPopup.Instance.setVisible(true); - GPTPopup.Instance.setMode(GPTPopupMode.SORT); - - // Await the promise to get the string result - const sortDesc = await this.childPairStringList(); - GPTPopup.Instance.setSortDesc(sortDesc); - GPTPopup.Instance.onSortComplete = this.handleGptSortResult; + this.isChatPopupOpen = true; + GPTPopup.Instance.setVisible(true); + GPTPopup.Instance.setMode(GPTPopupMode.SORT); + + // Await the promise to get the string result + const sortDesc = await this.childPairStringList(); + GPTPopup.Instance.setCardsDoneLoading(true); // Set dataDoneLoading to true after data is loaded + GPTPopup.Instance.setSortDesc(sortDesc); + GPTPopup.Instance.onSortComplete = this.handleGptSortResult; }; @action handleGptSortResult = (sortResult: string) => { this.processGptOutput(sortResult); @@ -696,19 +730,34 @@ export class CollectionCardView extends CollectionSubView() { - renderButtons(childPairIndex: number) { + renderButtons(childPairIndex: number, doc?: Doc, isChat = false) { const buttons = []; // Array to hold the button elements - - let amButtons = 4; - - let activeButtonIndex = this.customGroupDictionary[NumCast(this._props.Document.customSortNumber)].get(childPairIndex); - + const groupNumber = NumCast(this._props.Document.customSortNumber); + + let amButtons = 4; // Adjusted to your context + let activeButtonIndex = this.customGroupDictionary[groupNumber].get(childPairIndex); + + if (isChat && doc) { + if (this.amGPTGroups > 4){ + amButtons = this.amGPTGroups; + } + activeButtonIndex = this.gptGroups.get(doc); + } + + console.log("childPairIndex:", childPairIndex, "activeButtonIndex:", activeButtonIndex, "groupNumber:", groupNumber); + for (let i = 0; i < amButtons; i++) { - const isActive = activeButtonIndex == i; - - buttons.push(<button key={i} style={{ backgroundColor: `${isActive ? '#4476f7' : '#323232'}` }} onClick={() => this.toggleButton(childPairIndex, i)}></button>); + const isActive = activeButtonIndex === i; + console.log(`Rendering button ${i} for childPairIndex ${childPairIndex} isActive: ${isActive}`); + buttons.push( + <button + key={i} + style={{ backgroundColor: isActive ? '#4476f7' : '#323232' }} + onClick={() => this.toggleButton(childPairIndex, i, isChat, doc)} + ></button> + ); } - + const totalWidth = amButtons * 35 + amButtons * 2 * 5 + 6; return ( <div className="card-button-container" style={{ width: `${totalWidth}px` }}> diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 14f83beb6..496d7482c 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -22,7 +22,8 @@ import { VideoBox } from '../nodes/VideoBox'; import { WebBox } from '../nodes/WebBox'; import { RichTextMenu } from '../nodes/formattedText/RichTextMenu'; import { ImageBox } from '../nodes/ImageBox'; - +import { NumListCast } from '../../../fields/Doc'; +import { List } from '../../../fields/List'; ScriptingGlobals.add(function IsNoneSelected() { return SelectionManager.Views.length <= 0; }, 'are no document selected'); @@ -107,84 +108,146 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) { -ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'links' | 'custom1' | 'custom2' | 'custom3'| 'chat', checkResult?: boolean, persist?: boolean, customNumber?: number) { +ScriptingGlobals.add(function showFreeform( + attr: 'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'links' | 'custom1' | 'custom2' | 'custom3' | 'chat' | '1' | '2' | '3' | '4', + checkResult?: boolean, + persist?: boolean, + isDoubleClick?: boolean +) { const selected = SelectionManager.Docs.lastElement(); // prettier-ignore - const map: Map<'flashcards' | 'center' |'grid' | 'snaplines' | 'clusters' | 'arrange'| 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'links' | 'custom1' | 'custom2' | 'custom3'| 'chat', { waitForRender?: boolean, checkResult: (doc:Doc) => any; setDoc: (doc:Doc, dv:DocumentView) => void;}> = new Map([ + const map: Map<'flashcards' | 'center' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'links' | 'custom1' | 'custom2' | 'custom3' | 'chat' | '1' | '2' | '3' | '4', + { + waitForRender?: boolean; + checkResult: (doc: Doc) => any; + setDoc: (doc: Doc, dv: DocumentView) => void; + }> = new Map([ ['grid', { - checkResult: (doc:Doc) => BoolCast(doc?._freeform_backgroundGrid, false), - setDoc: (doc:Doc,dv:DocumentView) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid, + checkResult: (doc: Doc) => BoolCast(doc?._freeform_backgroundGrid, false), + setDoc: (doc: Doc, dv: DocumentView) => doc._freeform_backgroundGrid = !doc._freeform_backgroundGrid, }], ['snaplines', { - checkResult: (doc:Doc) => BoolCast(doc?._freeform_snapLines, false), - setDoc: (doc:Doc, dv:DocumentView) => doc._freeform_snapLines = !doc._freeform_snapLines, + checkResult: (doc: Doc) => BoolCast(doc?._freeform_snapLines, false), + setDoc: (doc: Doc, dv: DocumentView) => doc._freeform_snapLines = !doc._freeform_snapLines, }], ['viewAll', { - checkResult: (doc:Doc) => BoolCast(doc?._freeform_fitContentsToBox, false), - setDoc: (doc:Doc,dv:DocumentView) => { + checkResult: (doc: Doc) => BoolCast(doc?._freeform_fitContentsToBox, false), + setDoc: (doc: Doc, dv: DocumentView) => { if (persist) doc._freeform_fitContentsToBox = !doc._freeform_fitContentsToBox; else if (doc._freeform_fitContentsToBox) doc._freeform_fitContentsToBox = undefined; else (dv.ComponentView as CollectionFreeFormView)?.fitContentOnce(); }, }], ['center', { - checkResult: (doc:Doc) => BoolCast(doc?._stacking_alignCenter, false), - setDoc: (doc:Doc,dv:DocumentView) => doc._stacking_alignCenter = !doc._stacking_alignCenter, + checkResult: (doc: Doc) => BoolCast(doc?._stacking_alignCenter, false), + setDoc: (doc: Doc, dv: DocumentView) => doc._stacking_alignCenter = !doc._stacking_alignCenter, }], ['clusters', { - waitForRender: true, // flags that undo batch should terminate after a re-render giving the script the chance to fire - checkResult: (doc:Doc) => BoolCast(doc?._freeform_useClusters, false), - setDoc: (doc:Doc,dv:DocumentView) => doc._freeform_useClusters = !doc._freeform_useClusters, + waitForRender: true, + checkResult: (doc: Doc) => BoolCast(doc?._freeform_useClusters, false), + setDoc: (doc: Doc, dv: DocumentView) => doc._freeform_useClusters = !doc._freeform_useClusters, }], ['flashcards', { - checkResult: (doc:Doc) => BoolCast(Doc.UserDoc().defaultToFlashcards, false), - setDoc: (doc:Doc,dv:DocumentView) => Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards, + checkResult: (doc: Doc) => BoolCast(Doc.UserDoc().defaultToFlashcards, false), + setDoc: (doc: Doc, dv: DocumentView) => Doc.UserDoc().defaultToFlashcards = !Doc.UserDoc().defaultToFlashcards, }], ['time', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "time", + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "time", + setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "time", }], ['docType', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "type", + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "type", + setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "type", }], ['color', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "color", + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "color", + setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "color", }], - ['links', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "links", + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "links", + setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "links", }], - ['custom1', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc, dv) => { + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "custom" && NumCast(doc?.customSortNumber) === 0, + setDoc: (doc: Doc, dv: DocumentView) => { doc.cardSort = "custom"; doc.customSortNumber = 0; + doc.visibleGroupNumbers = new List<number>(); } - }], - + }], ['custom2', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc, dv) => { + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "custom" && NumCast(doc?.customSortNumber) === 1, + setDoc: (doc: Doc, dv: DocumentView) => { doc.cardSort = "custom"; doc.customSortNumber = 1; - console.log(doc.customSortNumber + " numberrrrrrrr") - } }], - + doc.visibleGroupNumbers = new List<number>(); + } + }], ['custom3', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc, dv) => { + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "custom" && NumCast(doc?.customSortNumber) === 2, + setDoc: (doc: Doc, dv: DocumentView) => { doc.cardSort = "custom"; doc.customSortNumber = 2; - } }], + doc.visibleGroupNumbers = new List<number>(); + } + }], ['chat', { - checkResult: (doc:Doc) => StrCast(doc?.cardSort), - setDoc: (doc:Doc,dv:DocumentView) => doc.cardSort = "chat", + checkResult: (doc: Doc) => StrCast(doc?.cardSort) === "chat", + setDoc: (doc: Doc, dv: DocumentView) => doc.cardSort = "chat", + }], + ['1', { + checkResult: (doc: Doc) => NumListCast(doc?.visibleGroupNumbers).includes(0), + setDoc: (doc: Doc, dv: DocumentView) => { + let list = NumListCast(doc.visibleGroupNumbers); + if (list.includes(0)) { + let newList = new List<number>(list.filter(d => d !== 0)); + doc.visibleGroupNumbers = newList; + } else { + list.push(0); + doc.visibleGroupNumbers = new List<number>(list); + } + } }], - ]); + ['2', { + checkResult: (doc: Doc) => NumListCast(doc?.visibleGroupNumbers).includes(1), + setDoc: (doc: Doc, dv: DocumentView) => { + let list = NumListCast(doc.visibleGroupNumbers); + if (list.includes(1)) { + let newList = new List<number>(list.filter(d => d !== 1)); + doc.visibleGroupNumbers = newList; + } else { + list.push(1); + doc.visibleGroupNumbers = new List<number>(list); + } + } + }], + ['3', { + checkResult: (doc: Doc) => NumListCast(doc?.visibleGroupNumbers).includes(2), + setDoc: (doc: Doc, dv: DocumentView) => { + let list = NumListCast(doc.visibleGroupNumbers); + if (list.includes(2)) { + let newList = new List<number>(list.filter(d => d !== 2)); + doc.visibleGroupNumbers = newList; + } else { + list.push(2); + doc.visibleGroupNumbers = new List<number>(list); + } + } + }], + ['4', { + checkResult: (doc: Doc) => NumListCast(doc?.visibleGroupNumbers).includes(3), + setDoc: (doc: Doc, dv: DocumentView) => { + let list = NumListCast(doc.visibleGroupNumbers); + if (list.includes(3)) { + let newList = new List<number>(list.filter(d => d !== 3)); + doc.visibleGroupNumbers = newList; + } else { + list.push(3); + doc.visibleGroupNumbers = new List<number>(list); + } + } + }], + ]); if (checkResult) { return map.get(attr)?.checkResult(selected); @@ -194,6 +257,14 @@ ScriptingGlobals.add(function showFreeform(attr: 'flashcards' | 'center' | 'grid setTimeout(() => batch.end(), 100); }); + +ScriptingGlobals.add(function isThatCardGroup(n: number){ + const canvas = SelectionManager.Docs.lastElement(); + return canvas.customSortNumber == n + + +}) + // ScriptingGlobals.add(function setCardSortAttr(attr: 'time' | 'docType' | 'color', value: any, checkResult?: boolean) { // // const editorView = RichTextMenu.Instance?.TextView?.EditorView; // const selected = SelectionManager.Docs.lastElement(); diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss index 4425cf158..551c8e5af 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.scss +++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss @@ -55,10 +55,10 @@ $highlightedText: #82e0ff; overflow-y: auto; } - .btns-wrapper { + .btns-wrapper-gpt { height: 50px; display: flex; - justify-content: space-between; + justify-content: center; align-items: center; transform: translateY(30px); @@ -76,6 +76,8 @@ $highlightedText: #82e0ff; display: flex; align-items: center; } + + } button { diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index faf66af85..d94be1860 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -154,6 +154,13 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { } @observable onSortComplete?: (sortResult: string) => void; + @observable cardsDoneLoading = false; + + @action setCardsDoneLoading(done: boolean) { + console.log(done + "HI HIHI") + this.cardsDoneLoading = done; + } + @@ -169,12 +176,14 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { this.setSortDone(false); try { - const res = await gptAPICall(this.sortPrompt + this.sortDesc, GPTCallType.SORT); + + const res = await gptAPICall(this.sortDesc, GPTCallType.SORT); this.setSortText(res || 'Something went wrong :('); // Trigger the callback with the result if (this.onSortComplete) { this.onSortComplete(res || 'Something went wrong :('); + console.log(res) } } catch (err) { console.error(err); @@ -313,52 +322,63 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> { {this.heading("SORTING")} {this.loading ? ( <div className="content-wrapper"> - <div className="loading-spinner"> - <ReactLoading type="spin" color="#000" height={30} width={30} /> - <span>Loading...</span> - </div> - </div> - ) : !this.sortDone && ( - <div className="btns-wrapper"> - <input - defaultValue="" - autoComplete="off" - onChange={this.setSortPrompt} - onKeyDown={e => { - if (e.key === 'Enter') { - this.generateSort(); - } - e.stopPropagation(); - }} - type="text" - placeholder="Enter sorting instructions..." - id="search-input" - className="searchBox-input" - style={{ width: "100%" }} - /> + <div className="loading-spinner"> + <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} /> + <span>Loading...</span> </div> - )} + </div> + ) : ( + <> + {!this.cardsDoneLoading ? ( + <div className="content-wrapper"> + <div className="loading-spinner"> + <ReactLoading type="spin" color={StrCast(Doc.UserDoc().userVariantColor)} height={30} width={30} /> + <span>Reading Cards...</span> + </div> + </div> + ) : ( + !this.sortDone && ( + <div className="btns-wrapper-gpt"> + <Button + tooltip="Have ChatGPT sort your cards for you!" + text="Sort!" + onClick={this.generateSort} + color={StrCast(Doc.UserDoc().userVariantColor)} + type={Type.TERT} + style={{ + width: '90%', // Almost as wide as the container + textAlign: 'center', + color: '#ffffff', // White text + fontSize: '16px' // Adjust font size as needed + }} + /> + </div> + ) + )} - {this.sortDone && ( - <div> - <div className="content-wrapper"> - - <p>{this.text== "Something went wrong :(" ? "Something went wrong :(" : "Sorting done! Feel free to move things around / regenerate :) !"}</p> - - - <IconButton - tooltip="Generate Again" - onClick={() => this.setSortDone(false)} - icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} - color={StrCast(Doc.UserDoc().userVariantColor)} - /> - - </div> - </div> + {this.sortDone && ( + <div> + <div className="content-wrapper"> + <p> + {this.text === "Something went wrong :(" ? + "Something went wrong :(" : + "Sorting done! Feel free to move things around / regenerate :) !"} + </p> + <IconButton + tooltip="Generate Again" + onClick={() => this.setSortDone(false)} + icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} + color={StrCast(Doc.UserDoc().userVariantColor)} + /> + </div> + </div> + )} + </> )} </div> </> ); + |