Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 34 additions & 24 deletions platform.bible-extension/contributions/localizedStrings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,47 @@
"metadata": {},
"localizedStrings": {
"en": {
"%fwLiteExtension_addWord_title%": "Add to FieldWorks",
"%fwLiteExtension_browseDictionary_title%": "FieldWorks Lite",
"%fwLiteExtension_selectDictionary_title%": "Select FieldWorks dictionary",
"%fwLiteExtension_findRelatedWords_title%": "Find related words in FieldWorks",
"%fwLiteExtension_findWord_title%": "Search in FieldWorks",
"%fwLiteExtension_find_in_dictionary%": "Find in FieldWorks Lite",
"%fwLiteExtension_list_projects_label%": "List all local FieldWorks projects",
"%fwLiteExtension_addWord_buttonAdd%": "Add new entry",
"%fwLiteExtension_addWord_buttonSubmit%": "Submit new entry",
"%fwLiteExtension_addWord_title%": "Add entry to FieldWorks",
"%fwLiteExtension_button_cancel%": "Cancel",
"%fwLiteExtension_dictionary_backToList%": "Back to list",
"%fwLiteExtension_dictionary_loading%": "Loading...",
"%fwLiteExtension_dictionary_noResults%": "No results",
"%fwLiteExtension_dictionarySelect_clear%": "Clear selection",
"%fwLiteExtension_dictionarySelect_confirm%": "Confirm selection",
"%fwLiteExtension_dictionarySelect_loading%": "Loading dictionaries ...",
"%fwLiteExtension_dictionarySelect_noneFound%": "No dictionaries found",
"%fwLiteExtension_dictionarySelect_saved%": "Dictionary selection saved. You can close this window.",
"%fwLiteExtension_dictionarySelect_saveError%": "Error saving dictionary selection:",
"%fwLiteExtension_dictionarySelect_saving%": "Saving dictionary selection",
"%fwLiteExtension_dictionarySelect_select%": "Select a dictionary",
"%fwLiteExtension_dictionarySelect_selected%": "Selected:",
"%fwLiteExtension_entryDisplay_definition%": "Definition",
"%fwLiteExtension_entryDisplay_gloss%": "Gloss",
"%fwLiteExtension_entryDisplay_headword%": "Headword",
"%fwLiteExtension_entryDisplay_partOfSpeech%": "Part of speech",
"%fwLiteExtension_entryDisplay_senses%": "Senses",
"%fwLiteExtension_error_failedToAddEntry%": "Failed to add entry!",
"%fwLiteExtension_error_gettingNetworkObject%": "Error getting network object:",
"%fwLiteExtension_error_missingParam%": "Missing required parameter: ",
"%fwLiteExtension_findRelatedWord_noResultsInDomain%": "No entries in this semantic domain.",
"%fwLiteExtension_findRelatedWord_selectInstruction%": "Select a semantic domain for related words in that domain",
"%fwLiteExtension_findRelatedWord_textField%": "Find related words in dictionary...",
"%fwLiteExtension_findWord_textField%": "Find in dictionary...",
"%fwLiteExtension_menu_addEntry%": "Add to FieldWorks...",
"%fwLiteExtension_menu_browseDictionary%": "Browse FieldWorks dictionary",
"%fwLiteExtension_menu_findEntry%": "Search in FieldWorks...",
"%fwLiteExtension_menu_findRelatedEntries%": "Search for related words...",
"%fwLiteExtension_open_label%": "Open FieldWorks Lite",
"%fwLiteExtension_projectSettings_title%": "FieldWorks Lite settings",
"%fwLiteExtension_projectSettings_analysisLanguage%": "Analysis language",
"%fwLiteExtension_projectSettings_dictionary%": "FieldWorks dictionary",
"%fwLiteExtension_projectSettings_dictionaryDescription%": "The FieldWorks dictionary to use with this project",
"%fwlite_choose_new_entry_button%": "Choose New Entry",
"%fwlite_clear_entry_button%": "Clear Entry",
"%fwlite_clear_selection_button%": "Clear Selection",
"%fwlite_clear_word_selection_button%": "Clear Word Selection",
"%fwlite_definition_label%": "Definition: ",
"%fwlite_form_label%": "Form: ",
"%fwlite_lexical_entries_for_word%": "Lexical Entries for ",
"%fwlite_lexical_information_header%": "Lexical Information for ",
"%fwlite_loading%": "Loading...",
"%fwlite_more_details_placeholder%": "(More details about this lexical entry would go here.)",
"%fwlite_no_entries_found_header%": "No Lexical Entries Found for ",
"%fwlite_no_entries_found_prompt%": "Consider manually adding a link or searching for synonyms.",
"%fwlite_select_entry_button%": "Select Entry",
"%fwlite_select_word_prompt%": "Select a word from the left to view its lexical information or search for entries.",
"%fwlite_words_in_verse_header%": "Words in "
"%fwLiteExtension_projectSettings_title%": "FieldWorks Lite settings",
"%fwLiteExtension_webViewTitle_addWord%": "Add to FieldWorks",
"%fwLiteExtension_webViewTitle_findRelatedWords%": "Find related words in FieldWorks",
"%fwLiteExtension_webViewTitle_findWord%": "Search in FieldWorks",
"%fwLiteExtension_webViewTitle_browseDictionary%": "FieldWorks Lite",
"%fwLiteExtension_webViewTitle_selectDictionary%": "Select FieldWorks dictionary"
}
}
}
6 changes: 0 additions & 6 deletions platform.bible-extension/contributions/menus.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@
"group": "fw-lite-extension.editor",
"order": 4,
"command": "fwLiteExtension.findRelatedEntries"
},
{
"label": "%fwLiteExtension_open_label%",
"group": "fw-lite-extension.editor",
"order": 1007,
"command": "fwLiteExtension.openFWLite"
}
]
}
Expand Down
40 changes: 40 additions & 0 deletions platform.bible-extension/src/components/add-new-entry-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useLocalizedStrings } from '@papi/frontend/react';
import type { DictionaryLanguages, PartialEntry } from 'fw-lite-extension';
import { Button } from 'platform-bible-react';
import { type ReactElement, useState } from 'react';
import AddNewEntry from './add-new-entry';
import { LOCALIZED_STRING_KEYS } from '../types/localized-string-keys';

/** Props for the AddNewEntryButton component */
interface AddNewEntryButtonProps extends DictionaryLanguages {
addEntry: (entry: PartialEntry) => Promise<void>;
headword?: string;
}

/** A button that, when clicked, expands to the AddNewEntry component. */
export default function AddNewEntryButton({
addEntry,
analysisLanguage,
headword,
vernacularLanguage,
}: AddNewEntryButtonProps): ReactElement {
const [localizedStrings] = useLocalizedStrings(LOCALIZED_STRING_KEYS);

const [adding, setAdding] = useState(false);

return adding ? (
<div className="tw-border tw-rounded-lg tw-shadow-sm tw-p-4">
<AddNewEntry
addEntry={addEntry}
analysisLanguage={analysisLanguage}
headword={headword}
onCancel={() => setAdding(false)}
vernacularLanguage={vernacularLanguage}
/>
</div>
) : (
<Button onClick={() => setAdding(true)}>
{localizedStrings['%fwLiteExtension_addWord_buttonAdd%']}
</Button>
);
}
77 changes: 45 additions & 32 deletions platform.bible-extension/src/components/add-new-entry.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,50 @@
import { logger } from '@papi/frontend';
import type { PartialEntry } from 'fw-lite-extension';
import { Button, Card, CardContent, CardHeader, Input, Label } from 'platform-bible-react';
import { useLocalizedStrings } from '@papi/frontend/react';
import type { DictionaryLanguages, PartialEntry } from 'fw-lite-extension';
import { Button, Input, Label } from 'platform-bible-react';
import { type ReactElement, useCallback, useEffect, useState } from 'react';
import { LOCALIZED_STRING_KEYS } from '../types/localized-string-keys';

interface AddNewEntryProps {
/** Props for the AddNewEntry component */
interface AddNewEntryProps extends DictionaryLanguages {
addEntry: (entry: PartialEntry) => Promise<void>;
analysisLang: string;
headword?: string;
isAdding?: boolean;
vernacularLang: string;
onCancel?: () => void;
}

/** A panel for creating a simple entry: headword with gloss and/or definition. */
export default function AddNewEntry({
addEntry,
analysisLang,
analysisLanguage,
headword,
isAdding,
vernacularLang,
onCancel,
vernacularLanguage,
}: AddNewEntryProps): ReactElement {
const [adding, setAdding] = useState(isAdding);
const [localizedStrings] = useLocalizedStrings(LOCALIZED_STRING_KEYS);

const [definition, setDefinition] = useState('');
const [gloss, setGloss] = useState('');
const [ready, setReady] = useState(false);
const [tempHeadword, setTempHeadword] = useState('');

useEffect(() => setAdding(isAdding), [isAdding]);

useEffect(() => setTempHeadword(headword || ''), [headword]);

useEffect(() => {
setReady(!!(vernacularLang && tempHeadword.trim() && (gloss.trim() || definition.trim())));
}, [definition, gloss, tempHeadword, vernacularLang]);
setReady(!!(vernacularLanguage && tempHeadword.trim() && (gloss.trim() || definition.trim())));
}, [definition, gloss, tempHeadword, vernacularLanguage]);

const clearEntry = useCallback((): void => {
setAdding(isAdding);
setDefinition('');
setGloss('');
setTempHeadword(headword || '');
}, [headword, isAdding]);
onCancel?.();
}, [headword, onCancel]);

async function onSubmit(): Promise<void> {
const entry = createEntry(
vernacularLang,
vernacularLanguage,
tempHeadword.trim(),
analysisLang || 'en',
analysisLanguage || 'en',
gloss.trim(),
definition.trim(),
);
Expand All @@ -52,40 +53,52 @@ export default function AddNewEntry({
.catch((e) => logger.error('Error adding entry:', JSON.stringify(e)));
}

return adding ? (
<Card>
<CardHeader>Adding new entry</CardHeader>
<CardContent>
return (
<div className="tw-flex tw-flex-col tw-items-start">
<h3 className="tw-font-semibold tw-mb-2">
{localizedStrings['%fwLiteExtension_addWord_title%']}
</h3>

<div className="tw-flex tw-flex-col tw-gap-1">
<div>
<Label htmlFor="newEntryHeadword">Headword ({vernacularLang}):</Label>
<Label htmlFor="newEntryHeadword">
{localizedStrings['%fwLiteExtension_entryDisplay_headword%']} ({vernacularLanguage}):
</Label>
<Input
id="newEntryHeadword"
onChange={(e) => setTempHeadword(e.target.value)}
value={tempHeadword}
/>
</div>

<div>
<Label htmlFor="newEntryGloss">Gloss ({analysisLang}):</Label>
<Label htmlFor="newEntryGloss">
{localizedStrings['%fwLiteExtension_entryDisplay_gloss%']} ({analysisLanguage}):
</Label>
<Input id="newEntryGloss" onChange={(e) => setGloss(e.target.value)} value={gloss} />
</div>

<div>
<Label htmlFor="newEntryDefinition">Definition ({analysisLang}):</Label>
<Label htmlFor="newEntryDefinition">
{localizedStrings['%fwLiteExtension_entryDisplay_definition%']} ({analysisLanguage}):
</Label>
<Input
id="newEntryDefinition"
onChange={(e) => setDefinition(e.target.value)}
value={definition}
/>
</div>
<div>

<div className="tw-flex tw-gap-1 tw-mt-2">
<Button disabled={!ready} onClick={() => onSubmit()}>
Submit new entry
{localizedStrings['%fwLiteExtension_addWord_buttonSubmit%']}
</Button>
<Button onClick={clearEntry}>
{localizedStrings['%fwLiteExtension_button_cancel%']}
</Button>
<Button onClick={clearEntry}>Cancel</Button>
</div>
</CardContent>
</Card>
) : (
<Button onClick={() => setAdding(true)}>Add new entry</Button>
</div>
</div>
);
}

Expand Down
52 changes: 52 additions & 0 deletions platform.bible-extension/src/components/back-to-list-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Modified from paranext-core/extensions/src/components/dictionary/back-to-list-button.component.tsx

import type { IEntry } from 'fw-lite-extension';
import { ArrowLeft } from 'lucide-react';
import { ListboxOption, Button, DrawerClose } from 'platform-bible-react';
import { LanguageStrings } from 'platform-bible-utils';

/** Props for the BackToListButton component */
type BackToListButtonProps = {
/** Callback function to handle back button click, returning to the list view */
handleBackToListButton?: (option: ListboxOption) => void;
/** Dictionary entry to display in the button */
dictionaryEntry: IEntry;
/** Whether the display is in a drawer or just next to the list */
isDrawer: boolean;
/** Localized strings for the button */
localizedStrings: LanguageStrings;
};

/**
* A button that appears above the detailed view of a dictionary entry.
*
* If the user is viewing the detailed view in a drawer, this button is a drawer close button.
* Otherwise, it is a regular button.
*
* Clicking the button will return the user to the list view of all dictionary entries.
*/
export default function BackToListButton({
handleBackToListButton,
dictionaryEntry,
isDrawer,
localizedStrings,
}: BackToListButtonProps) {
if (!handleBackToListButton) return undefined;

const button = (
<Button
onClick={() => handleBackToListButton({ id: dictionaryEntry.id })}
className="tw-flex tw-items-center"
variant="link"
>
<ArrowLeft className="tw-mr-1 tw-h-4 tw-w-4" />
{localizedStrings['%fwLiteExtension_dictionary_backToList%']}
</Button>
);

return (
<div className="tw-mb-4 tw-flex tw-items-center tw-justify-between">
{isDrawer ? <DrawerClose asChild>{button}</DrawerClose> : button}
</div>
);
}
Loading