diff --git a/frontend/viewer/src/App.svelte b/frontend/viewer/src/App.svelte index 7735a3c790..b1c57c1f0e 100644 --- a/frontend/viewer/src/App.svelte +++ b/frontend/viewer/src/App.svelte @@ -19,7 +19,6 @@ import DotnetProjectView from './DotnetProjectView.svelte'; import {setupGlobalErrorHandlers} from '$lib/errors/global-errors'; import {ModeWatcher} from 'mode-watcher'; - import {initScottyPortalContext} from '$lib/layout/Scotty.svelte'; let url = ''; @@ -69,7 +68,6 @@ /* eslint-enable @typescript-eslint/naming-convention */ setupGlobalErrorHandlers(); - initScottyPortalContext(); diff --git a/frontend/viewer/src/CrdtProjectView.svelte b/frontend/viewer/src/CrdtProjectView.svelte deleted file mode 100644 index 5cbbeb0e3a..0000000000 --- a/frontend/viewer/src/CrdtProjectView.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/frontend/viewer/src/FwDataProjectView.svelte b/frontend/viewer/src/FwDataProjectView.svelte deleted file mode 100644 index 14f30d5fa7..0000000000 --- a/frontend/viewer/src/FwDataProjectView.svelte +++ /dev/null @@ -1,48 +0,0 @@ - - - - - diff --git a/frontend/viewer/src/FwDataWebComponent.svelte b/frontend/viewer/src/FwDataWebComponent.svelte deleted file mode 100644 index ed615bda4a..0000000000 --- a/frontend/viewer/src/FwDataWebComponent.svelte +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - {css} - - -
- -
diff --git a/frontend/viewer/src/ProjectLoader.svelte b/frontend/viewer/src/ProjectLoader.svelte index fa3863da08..97abb21511 100644 --- a/frontend/viewer/src/ProjectLoader.svelte +++ b/frontend/viewer/src/ProjectLoader.svelte @@ -1,7 +1,7 @@ - - - {projectName} - - - -{#if projectLoaded} -{#if !readonly} - -{/if} -
- -
-

{projectName}

-
-
-
- -
- -
- {#if $features.write} -
- -
- {/if} - -
-
- navigateToEntry(e.detail.entry, e.detail.search)} - {projectName} - createNew={!readonly} - on:createNew={(e) => openNewEntryDialog(e.detail)} /> -
-
-
-
- {#if !readonly} - openNewEntryDialog()} /> - {/if} - {#if $features.feedback && fwLiteConfig.feedbackUrl} - - {/if} -
-
- showOptionsDialog = true} {about} /> -
-
-
-
-
-
- $state.userPickedEntry = true} /> -
-
- {#if $selectedEntry} -
- -
- { - updateEntryInList($selectedEntry = e.detail.entry); - $entries = $entries; - }} - on:delete={onEntryDeleted} /> - {:else} -
- No entry selected - {#if !readonly} - openNewEntryDialog()} /> - {/if} -
- {/if} -
- showOptionsDialog = true} /> -
-
- - -
-{/if} diff --git a/frontend/viewer/src/app.postcss b/frontend/viewer/src/app.postcss index 3815af075f..cd120d94bf 100644 --- a/frontend/viewer/src/app.postcss +++ b/frontend/viewer/src/app.postcss @@ -1,7 +1,4 @@ @import 'theme.postcss'; -@import './lib/entry-editor/field.postcss'; -@import './lib/entry-editor/EntryOrSensePicker.postcss'; -@import 'theme.postcss'; /* this import is removed by vite-plugin-webfont-dl, and the styles are inlined in webfonts.css */ @import 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap'; @tailwind base; diff --git a/frontend/viewer/src/lib/Editor.svelte b/frontend/viewer/src/lib/Editor.svelte deleted file mode 100644 index 1aa0e1ef1b..0000000000 --- a/frontend/viewer/src/lib/Editor.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - -
- {#key entry.id} - - {/key} -
- - diff --git a/frontend/viewer/src/lib/HomeButton.svelte b/frontend/viewer/src/lib/HomeButton.svelte deleted file mode 100644 index 8fad32da5d..0000000000 --- a/frontend/viewer/src/lib/HomeButton.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - {/if} - - - - {$currentView.label} - - diff --git a/frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte b/frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte index 4229eb55d8..58de1bc776 100644 --- a/frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte +++ b/frontend/viewer/src/lib/entry-editor/NewEntryDialog.svelte @@ -1,6 +1,5 @@ - -{#if isMultiString(value)} - -{:else if isSingleString(value)} - -{:else if isSingleOption(state)} - -{:else if isMultiOption(state)} - -{/if} - diff --git a/frontend/viewer/src/lib/entry-editor/field.postcss b/frontend/viewer/src/lib/entry-editor/field.postcss deleted file mode 100644 index f1da2b226f..0000000000 --- a/frontend/viewer/src/lib/entry-editor/field.postcss +++ /dev/null @@ -1,80 +0,0 @@ -.field { - @apply grid grid-cols-subgrid items-center; - - &:not(:last-child) { - @apply mb-4; - } - - &.multi-field { - @apply items-baseline; - } - - .fields { - @apply grid grid-cols-subgrid col-span-2 gap-1; - } - - &.multi-field .fields { - .ws-field, .ws-field-wrapper { - @apply grid grid-cols-subgrid col-span-2; - } - } - - &.single-field .fields { - @apply grid grid-cols-subgrid; - grid-column-start: 3; - } - - .item-list-field { - grid-column-start: 3; - } - - &.TextField, .TextField { - [class~="border"] { - filter: contrast(0.95); - border-radius: 0; - border-style: none; - border-bottom-style: solid; - @apply !shadow-none; - border-color: hsl(var(--color-surface-content) / 30%); - } - } - - &.readonly.TextField, .readonly.TextField, .readonly .TextField { - /* prevent other "disabled-state styles" from impacting readability */ - opacity: 1; - - [class~="border"] { - border-color: hsl(var(--color-surface-content) / 20%); - background: transparent; - } - - input { - /* enable standard text selection */ - pointer-events: auto; - } - - .append, .prepend { - display: none; - } - } - - .field-title, .fields, .ws-field-wrapper, .ws-field, .item-list-field { - @apply sm-form:!col-span-full; - - & :has(> .field-container) { - @apply sm-form:col-span-2; - } - - &.field-title { - @apply sm-form:mb-2; - } - - &.item-list-field { - @apply sm-form:pl-0; - } - - &.ws-field > .label { - @apply xs-form:text-left; - } - } - } diff --git a/frontend/viewer/src/lib/entry-editor/inputs/CrdtField.svelte b/frontend/viewer/src/lib/entry-editor/inputs/CrdtField.svelte deleted file mode 100644 index e204ea999c..0000000000 --- a/frontend/viewer/src/lib/entry-editor/inputs/CrdtField.svelte +++ /dev/null @@ -1,146 +0,0 @@ - - -
- {#if unsavedChanges} - - - - {/if} - {#if unacceptedChanges} - - -
A different user changed this field
-
-
- Their version: - {value} -
-
- Your version: - {editorValue} -
-
-
-
- - -
-
-
-
- {/if} - - {#if unacceptedChanges} - - {/if} -
- - diff --git a/frontend/viewer/src/lib/entry-editor/inputs/CrdtTextField.svelte b/frontend/viewer/src/lib/entry-editor/inputs/CrdtTextField.svelte deleted file mode 100644 index 8d209eb9dc..0000000000 --- a/frontend/viewer/src/lib/entry-editor/inputs/CrdtTextField.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - - onEditorValueChange(e.detail.inputValue)} - on:blur={(e) => {if (e.target) save()}} - actions={(el) => { - addTitleToLabel(el); - // autofocus requires a delay otherwise it won't work in a dialog - // also we can't use the autofocus attribute because of https://github.com/techniq/svelte-ux/issues/532 - return autofocus ? [autoFocusFunc(el, {delay: 5})] : []; - }} - value={editorValue} - disabled={readonly} - class="ws-field gap-0 text-right" - classes={{ root: `${hasHadValue.pushAndGet(editorValue) ? '' : 'unused'} ${readonly ? 'readonly' : ''}`, input: 'field-input', container: 'field-container', label: 'pr-2' }} - {label} - {labelPlacement} - {placeholder}> - - - diff --git a/frontend/viewer/src/lib/entry-editor/object-editors/EntityEditor.svelte b/frontend/viewer/src/lib/entry-editor/object-editors/EntityEditor.svelte deleted file mode 100644 index 15f758f0e4..0000000000 --- a/frontend/viewer/src/lib/entry-editor/object-editors/EntityEditor.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - -{#each customFieldConfigs as fieldConfig} - -{/each} diff --git a/frontend/viewer/src/lib/generated-signalr-client/Lexbox.ClientServer.Hubs.ts b/frontend/viewer/src/lib/generated-signalr-client/Lexbox.ClientServer.Hubs.ts deleted file mode 100644 index 04bf8ba650..0000000000 --- a/frontend/viewer/src/lib/generated-signalr-client/Lexbox.ClientServer.Hubs.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* THIS (.ts) FILE IS GENERATED BY Tapper */ -/* eslint-disable */ -/* tslint:disable */ - -/** Transpiled from Lexbox.ClientServer.Hubs.JsonOperation */ -export type JsonOperation = { - /** Transpiled from string */ - op: string; - /** Transpiled from string */ - path: string; - /** Transpiled from object? */ - value?: any; - /** Transpiled from string? */ - from?: string; -} - diff --git a/frontend/viewer/src/lib/generated-signalr-client/TypedSignalR.Client/Lexbox.ClientServer.Hubs.ts b/frontend/viewer/src/lib/generated-signalr-client/TypedSignalR.Client/Lexbox.ClientServer.Hubs.ts deleted file mode 100644 index 69dac37931..0000000000 --- a/frontend/viewer/src/lib/generated-signalr-client/TypedSignalR.Client/Lexbox.ClientServer.Hubs.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* THIS (.ts) FILE IS GENERATED BY TypedSignalR.Client.TypeScript */ -/* eslint-disable */ -/* tslint:disable */ - - -import type {IEntry, IMiniLcmJsInvokable} from '$lib/dotnet-types'; - -export type ILexboxApiHub = IMiniLcmJsInvokable; - -export type ILexboxClient = { - /** - * @param entry Transpiled from lexboxClientContracts.Entry - * @returns Transpiled from System.Threading.Tasks.Task - */ - OnEntryUpdated(entry: IEntry): Promise; - OnProjectClosed(reason: CloseReason): Promise; -} - -export enum CloseReason { - User = 0, - Locked = 1, -} diff --git a/frontend/viewer/src/lib/generated-signalr-client/TypedSignalR.Client/index.ts b/frontend/viewer/src/lib/generated-signalr-client/TypedSignalR.Client/index.ts deleted file mode 100644 index 9fa37b3866..0000000000 --- a/frontend/viewer/src/lib/generated-signalr-client/TypedSignalR.Client/index.ts +++ /dev/null @@ -1,346 +0,0 @@ -/* THIS (.ts) FILE IS GENERATED BY TypedSignalR.Client.TypeScript */ -/* eslint-disable */ -/* tslint:disable */ - -import type { - IComplexFormComponent, - IComplexFormType, - IEntry, - IExampleSentence, - IMiniLcmFeatures, - IMiniLcmJsInvokable, - IPartOfSpeech, - IQueryOptions, - ISemanticDomain, - ISense, - IWritingSystem, - IWritingSystems, - WritingSystemType -} from '$lib/dotnet-types'; - -import {HubConnection} from '@microsoft/signalr'; -import type {IFilterQueryOptions} from '$lib/dotnet-types/generated-types/MiniLcm/IFilterQueryOptions'; -import type {ILexboxClient} from './Lexbox.ClientServer.Hubs'; -import type {IPublication} from '$lib/dotnet-types/generated-types/MiniLcm/Models/IPublication'; - -// components - -export type Disposable = { - dispose(): void; -} - -export type HubProxyFactory = { - createHubProxy(connection: HubConnection): T; -} - -export type ReceiverRegister = { - register(connection: HubConnection, receiver: T): Disposable; -} - -type ReceiverMethod = { - methodName: string, - method: (...args: any[]) => void -} - -class ReceiverMethodSubscription implements Disposable { - - public constructor( - private connection: HubConnection, - private receiverMethod: ReceiverMethod[]) { - } - - public readonly dispose = () => { - for (const it of this.receiverMethod) { - this.connection.off(it.methodName, it.method); - } - }; -} - -// API - -export type HubProxyFactoryProvider = { - (hubType: 'ILexboxApiHub'): HubProxyFactory; -} - -export const getHubProxyFactory = ((hubType: string) => { - if (hubType === 'ILexboxApiHub') { - return IMiniLcmJsInvokable_HubProxyFactory.Instance; - } -}) as HubProxyFactoryProvider; - -export type ReceiverRegisterProvider = { - (receiverType: 'ILexboxClient'): ReceiverRegister; -} - -export const getReceiverRegister = ((receiverType: string) => { - if (receiverType === 'ILexboxClient') { - return ILexboxClient_Binder.Instance; - } -}) as ReceiverRegisterProvider; - -// HubProxy - -class IMiniLcmJsInvokable_HubProxyFactory implements HubProxyFactory { - public static Instance = new IMiniLcmJsInvokable_HubProxyFactory(); - - private constructor() { - } - - public readonly createHubProxy = (connection: HubConnection): IMiniLcmJsInvokable => { - return new IMiniLcmJsInvokable_HubProxy(connection); - }; -} - -class IMiniLcmJsInvokable_HubProxy implements IMiniLcmJsInvokable { - - public constructor(private connection: HubConnection) { - } - - public readonly getWritingSystems = async (): Promise => { - return await this.connection.invoke("GetWritingSystems"); - } - - public readonly createWritingSystem = async (type: WritingSystemType, writingSystem: IWritingSystem): Promise => { - return await this.connection.invoke("CreateWritingSystem", type, writingSystem); - } - - public readonly getPartsOfSpeech = async (): Promise => { - return new Promise((resolve, reject) => { - let partsOfSpeech: IPartOfSpeech[] = []; - this.connection.stream('GetPartsOfSpeech').subscribe({ - next(value: IPartOfSpeech) { - partsOfSpeech.push(value); - }, - error(err: any) { - reject(err); - }, - complete() { - resolve(partsOfSpeech); - } - }); - }); - } - - public readonly getSemanticDomains = async (): Promise => { - return new Promise((resolve, reject) => { - let semanticDomains: ISemanticDomain[] = []; - this.connection.stream('GetSemanticDomains').subscribe({ - next(value: ISemanticDomain) { - semanticDomains.push(value); - }, - error(err: any) { - reject(err); - }, - complete() { - resolve(semanticDomains); - } - }); - }); - } - - public readonly getComplexFormTypes = async (): Promise => { - return new Promise((resolve, reject) => { - let complexFormTypes: IComplexFormType[] = []; - this.connection.stream('GetComplexFormTypes').subscribe({ - next(value: IComplexFormType) { - complexFormTypes.push(value); - }, - error(err: any) { - reject(err); - }, - complete() { - resolve(complexFormTypes); - } - }); - }); - } - - public readonly countEntries = async (query?: string, options?: IFilterQueryOptions): Promise => { - return await this.connection.invoke("CountEntries", options); - } - - public readonly getEntries = async (options: IQueryOptions): Promise => { - return await this.connection.invoke("GetEntries", options); - } - - public readonly searchEntries = (query: string, options: IQueryOptions): Promise => { - return new Promise((resolve, reject) => { - let entries: IEntry[] = []; - this.connection.stream('SearchEntries', query, options).subscribe({ - next(value: IEntry) { - entries.push(value); - }, - error(err: any) { - reject(err); - }, - complete() { - resolve(entries); - } - }); - }); - }; - - public readonly getEntry = async (id: string): Promise => { - return await this.connection.invoke("GetEntry", id); - } - - public readonly createEntry = async (entry: IEntry): Promise => { - return await this.connection.invoke("CreateEntry", entry); - } - - public readonly updateEntry = async (before: IEntry, after: IEntry): Promise => { - return await this.connection.invoke("UpdateEntry", before, after); - } - - public readonly deleteEntry = async (id: string): Promise => { - return await this.connection.invoke("DeleteEntry", id); - } - - public readonly createSense = async (entryId: string, sense: ISense): Promise => { - return await this.connection.invoke("CreateSense", entryId, sense); - } - - public readonly deleteSense = async (entryId: string, senseId: string): Promise => { - return await this.connection.invoke("DeleteSense", entryId, senseId); - } - - public readonly createExampleSentence = async (entryId: string, senseId: string, exampleSentence: IExampleSentence): Promise => { - return await this.connection.invoke("CreateExampleSentence", entryId, senseId, exampleSentence); - } - - public readonly deleteExampleSentence = async (entryId: string, senseId: string, exampleSentenceId: string): Promise => { - return await this.connection.invoke("DeleteExampleSentence", entryId, senseId, exampleSentenceId); - } - - supportedFeatures(): Promise { - throw new Error('Method not implemented.'); - } - - getComplexFormType(id: string): Promise { - throw new Error('Method not implemented.'); - } - - getSense(entryId: string, id: string): Promise { - throw new Error('Method not implemented.'); - } - - getPartOfSpeech(id: string): Promise { - throw new Error('Method not implemented.'); - } - - getSemanticDomain(id: string): Promise { - throw new Error('Method not implemented.'); - } - - getExampleSentence(entryId: string, senseId: string, id: string): Promise { - throw new Error('Method not implemented.'); - } - - updateWritingSystem(before: IWritingSystem, after: IWritingSystem): Promise { - throw new Error('Method not implemented.'); - } - - createPartOfSpeech(partOfSpeech: IPartOfSpeech): Promise { - throw new Error('Method not implemented.'); - } - - updatePartOfSpeech(before: IPartOfSpeech, after: IPartOfSpeech): Promise { - throw new Error('Method not implemented.'); - } - - deletePartOfSpeech(id: string): Promise { - throw new Error('Method not implemented.'); - } - - createSemanticDomain(semanticDomain: ISemanticDomain): Promise { - throw new Error('Method not implemented.'); - } - - updateSemanticDomain(before: ISemanticDomain, after: ISemanticDomain): Promise { - throw new Error('Method not implemented.'); - } - - deleteSemanticDomain(id: string): Promise { - throw new Error('Method not implemented.'); - } - - createComplexFormType(complexFormType: IComplexFormType): Promise { - throw new Error('Method not implemented.'); - } - - updateComplexFormType(before: IComplexFormType, after: IComplexFormType): Promise { - throw new Error('Method not implemented.'); - } - - deleteComplexFormType(id: string): Promise { - throw new Error('Method not implemented.'); - } - - createComplexFormComponent(complexFormComponent: IComplexFormComponent): Promise { - throw new Error('Method not implemented.'); - } - - deleteComplexFormComponent(complexFormComponent: IComplexFormComponent): Promise { - throw new Error('Method not implemented.'); - } - - addComplexFormType(entryId: string, complexFormTypeId: string): Promise { - throw new Error('Method not implemented.'); - } - - removeComplexFormType(entryId: string, complexFormTypeId: string): Promise { - throw new Error('Method not implemented.'); - } - - updateSense(entryId: string, before: ISense, after: ISense): Promise { - throw new Error('Method not implemented.'); - } - - addSemanticDomainToSense(senseId: string, semanticDomain: ISemanticDomain): Promise { - throw new Error('Method not implemented.'); - } - - removeSemanticDomainFromSense(senseId: string, semanticDomainId: string): Promise { - throw new Error('Method not implemented.'); - } - - updateExampleSentence(entryId: string, senseId: string, before: IExampleSentence, after: IExampleSentence): Promise { - throw new Error('Method not implemented.'); - } - - getPublications(): Promise { - throw new Error('Method not implemented.'); - } - - dispose(): Promise { - throw new Error('Method not implemented.'); - } -} - - -// Receiver - -class ILexboxClient_Binder implements ReceiverRegister { - - public static Instance = new ILexboxClient_Binder(); - - private constructor() { - } - - public readonly register = (connection: HubConnection, receiver: ILexboxClient): Disposable => { - - const __onEntryUpdated = (...args: Parameters) => receiver.OnEntryUpdated(...args); - const __onProjectClosed = (...args: Parameters) => receiver.OnProjectClosed(...args); - - connection.on("OnEntryUpdated", __onEntryUpdated); - connection.on("OnProjectClosed", __onProjectClosed); - - const methodList: ReceiverMethod[] = [ - { methodName: "OnEntryUpdated", method: __onEntryUpdated }, - { methodName: "OnProjectClosed", method: __onProjectClosed }, - ] - - return new ReceiverMethodSubscription(connection, methodList); - } -} - diff --git a/frontend/viewer/src/lib/history/HistoryView.svelte b/frontend/viewer/src/lib/history/HistoryView.svelte index 3b18d889eb..f876b607b0 100644 --- a/frontend/viewer/src/lib/history/HistoryView.svelte +++ b/frontend/viewer/src/lib/history/HistoryView.svelte @@ -1,5 +1,4 @@  - - -{#key $projectViewState.userPickedEntry} - - - - - -{/key} - -{#if about} - -{/if} - - - diff --git a/frontend/viewer/src/lib/layout/DictionaryEntryViewer.svelte b/frontend/viewer/src/lib/layout/DictionaryEntryViewer.svelte deleted file mode 100644 index 6245242d66..0000000000 --- a/frontend/viewer/src/lib/layout/DictionaryEntryViewer.svelte +++ /dev/null @@ -1,35 +0,0 @@ - - -
-
-
- -
-
- {#if dictionaryEntryLines > 2} -
- - diff --git a/frontend/viewer/src/lib/layout/EntryList.svelte b/frontend/viewer/src/lib/layout/EntryList.svelte deleted file mode 100644 index 5d1691382c..0000000000 --- a/frontend/viewer/src/lib/layout/EntryList.svelte +++ /dev/null @@ -1,149 +0,0 @@ - - -
-
- -
- -
- {#if loading} - - {/if} -
-
-
- - -
-
-
- {#if !entries || entries.length == 0} -
- No entries found - {#if $selectedCharacter} - in - - {/if} -
- {:else} - - {#each visibleItems as entry (entry.id)} -
- {#if dictionaryMode} - - {:else} - selectEntry(entry)} - noShadow - class="!rounded-none" - /> - {/if} -
- {/each} -
- {/if} -
-
-
- - diff --git a/frontend/viewer/src/lib/layout/FieldListDialog.svelte b/frontend/viewer/src/lib/layout/FieldListDialog.svelte deleted file mode 100644 index e96b4f0fbd..0000000000 --- a/frontend/viewer/src/lib/layout/FieldListDialog.svelte +++ /dev/null @@ -1,55 +0,0 @@ - - - -
- -
-
- {#each filteredFields as field} - - {:else} -
- No matching fields -
- {/each} -
-
-
actions
-
- - diff --git a/frontend/viewer/src/lib/layout/IndexCharacters.svelte b/frontend/viewer/src/lib/layout/IndexCharacters.svelte deleted file mode 100644 index 5df70de0cb..0000000000 --- a/frontend/viewer/src/lib/layout/IndexCharacters.svelte +++ /dev/null @@ -1,66 +0,0 @@ - - -{#if characters?.length} - - -
- {#if $selectedCharacter} - - - - {/if} - {#each characters ?? [] as character} - - - - {/each} -
-
- -
-{/if} - - diff --git a/frontend/viewer/src/lib/layout/Scotty.svelte b/frontend/viewer/src/lib/layout/Scotty.svelte deleted file mode 100644 index b20478dbc9..0000000000 --- a/frontend/viewer/src/lib/layout/Scotty.svelte +++ /dev/null @@ -1,52 +0,0 @@ - - - - - diff --git a/frontend/viewer/src/lib/layout/ShowEmptyFieldsSwitch.svelte b/frontend/viewer/src/lib/layout/ShowEmptyFieldsSwitch.svelte deleted file mode 100644 index e467b8ad69..0000000000 --- a/frontend/viewer/src/lib/layout/ShowEmptyFieldsSwitch.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/frontend/viewer/src/lib/layout/Toc.svelte b/frontend/viewer/src/lib/layout/Toc.svelte deleted file mode 100644 index dfb49b536f..0000000000 --- a/frontend/viewer/src/lib/layout/Toc.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - -{#key entry?.id} - {#if entry} - {@const _headword = writingSystemService.headword(entry) ?? ''} - {@const locationWithoutHash = window.location.href.split('#')[0]} -
- {fieldName({id: 'entry'}, $currentView.i18nKey)}:{_headword || '—'} - {#each entry.senses as sense, i (sense.id)} - {@const _sense = writingSystemService.firstDefOrGlossVal(sense) ?? ''} - {fieldName({id: 'sense'}, $currentView.i18nKey)}:{_sense || '—'} - {#each sense.exampleSentences as example, j (example.id)} - {@const _example = writingSystemService.firstSentenceOrTranslationVal(example) ?? ''} - Example:{_example || '—'} - {/each} - {/each} -
- {/if} -{/key} - - diff --git a/frontend/viewer/src/lib/layout/ViewOptionsDrawer.svelte b/frontend/viewer/src/lib/layout/ViewOptionsDrawer.svelte deleted file mode 100644 index d2103ea907..0000000000 --- a/frontend/viewer/src/lib/layout/ViewOptionsDrawer.svelte +++ /dev/null @@ -1,76 +0,0 @@ - - - -
-
-
- ({ value: view.label, label: view.label, group: view.label }))} - value={activeView.label} - on:change={({detail}) => { - // We can't use the view itself as the value, because it gets stringified - // and contains circular references - const view = views.find((view) => view.label === detail.value); - if (view) activeView = view; - }} - classes={{root: 'view-select w-auto', options: 'view-select-options', field: { container: 'border-surface-content/20' }}} - clearable={false} - labelPlacement="top" - clearSearchOnOpen={false} - fieldActions={(elem) => /* a hack to disable typing/filtering */ {elem.readOnly = true; return [];}} - search={() => /* a hack to always show all options */ Promise.resolve()}> - -
- -
- -
- -
- Debug - - - -
-
-
-
- - diff --git a/frontend/viewer/src/lib/sandbox/Sandbox.svelte b/frontend/viewer/src/lib/sandbox/Sandbox.svelte index aa929d83c7..e41f9c1087 100644 --- a/frontend/viewer/src/lib/sandbox/Sandbox.svelte +++ b/frontend/viewer/src/lib/sandbox/Sandbox.svelte @@ -3,7 +3,7 @@ import {Button, buttonVariants} from '$lib/components/ui/button'; import {Checkbox} from '$lib/components/ui/checkbox'; import {DotnetService, type IEntry, type ISense} from '$lib/dotnet-types'; - import type {FieldIds} from '$lib/entry-editor/field-data'; + import type {FieldId} from '$lib/entry-editor/field-data'; import SenseEditorPrimitive from '$lib/entry-editor/object-editors/SenseEditorPrimitive.svelte'; import {InMemoryApiService} from '$lib/in-memory-api-service'; import {AppNotification} from '$lib/notifications/notifications'; @@ -55,9 +55,9 @@ return s; } - let senseFields: ({ id: FieldIds })[] = $state([{id: 'gloss'}, {id: 'definition'}]); + let senseFields: ({ id: FieldId })[] = $state([{id: 'gloss'}, {id: 'definition'}]); - function updateFields(e: CustomEvent<{ items: ({ id: FieldIds })[] }>) { + function updateFields(e: CustomEvent<{ items: ({ id: FieldId })[] }>) { senseFields = e.detail.items; } let count = $state(0); diff --git a/frontend/viewer/src/lib/search-bar/SearchBar.svelte b/frontend/viewer/src/lib/search-bar/SearchBar.svelte deleted file mode 100644 index 5e5f1a4107..0000000000 --- a/frontend/viewer/src/lib/search-bar/SearchBar.svelte +++ /dev/null @@ -1,190 +0,0 @@ - - - - - $search = ''} - classes={{root: 'items-start', title: 'px-2 py-0 max-md:pl-0', dialog: 'md:h-auto md:max-h-[min(50rem, 100%)]'}}> -
- - { - if (e.key === 'Enter' && $displayedEntries.length > 0) { - e.preventDefault(); - selectEntry($displayedEntries[0]); - } - }} - placeholder={`Find ${fieldName({id: 'entry'}, $currentView.i18nKey).toLowerCase()}...`} - class="flex-grow-[2] cursor-pointer opacity-80 hover:opacity-100" - classes={{ prepend: 'text-sm', append: 'flex-row-reverse', container: 'border-surface-content/20' }} - icon={mdiBookSearchOutline}> -
- {#if $loading} - - {/if} -
-
-
-
-
- {#each $displayedEntries as entry} - selectEntry(entry)} - /> - {/each} -
- {#if $displayedEntries.length === 0} -
- {#if $result.search} - No entries found - {:else} - {#if $loading} - - {:else} - Search for an entry - {/if} - {/if} -
- {/if} - {#if $result.search && createNew} - { - dispatch('createNew', $result.search ?? ''); - $showSearchDialog = false; - }} - /> - {/if} - {#if $result.entries.length > $displayedEntries.length} -
- {$result.entries.length - $displayedEntries.length} - {#if $result.entries.length === fetchCount}+{/if} -
- more matching entries... - -
-
- {/if} -
-
diff --git a/frontend/viewer/src/lib/services/event-bus.ts b/frontend/viewer/src/lib/services/event-bus.ts index 85a8e2441d..5c8b460c83 100644 --- a/frontend/viewer/src/lib/services/event-bus.ts +++ b/frontend/viewer/src/lib/services/event-bus.ts @@ -1,5 +1,4 @@ -import {type CloseReason} from '../generated-signalr-client/TypedSignalR.Client/Lexbox.ClientServer.Hubs'; -import {DotnetService, type IEntry} from '$lib/dotnet-types'; +import {DotnetService, type IEntry} from '$lib/dotnet-types'; import {useService} from '$lib/services/service-provider'; import type {IJsEventListener} from '$lib/dotnet-types/generated-types/FwLiteShared/Events/IJsEventListener'; import type {IFwEvent} from '$lib/dotnet-types/generated-types/FwLiteShared/Events/IFwEvent'; @@ -11,6 +10,11 @@ import {ProjectDataFormat} from '$lib/dotnet-types/generated-types/MiniLcm/Model import {type ProjectContext, useProjectContext} from '$lib/project-context.svelte'; import {onDestroy} from 'svelte'; +export enum CloseReason { + User = 0, + Locked = 1, +} + export class EventBus { private _onEvent = new Set<(event: IFwEvent) => void>(); private _onProjectClosed = new Set<(reason: CloseReason) => void>(); diff --git a/frontend/viewer/src/lib/services/lexbox-api.ts b/frontend/viewer/src/lib/services/lexbox-api.ts deleted file mode 100644 index 096cb19d49..0000000000 --- a/frontend/viewer/src/lib/services/lexbox-api.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { - IComplexFormType, - IEntry, - IExampleSentence, - ISense, - IPartOfSpeech, - IQueryOptions, - ISemanticDomain, - IWritingSystem, - IWritingSystems, - IMiniLcmJsInvokable, - WritingSystemType -} from '$lib/dotnet-types'; - - -export type { - IComplexFormType, - IEntry, - IExampleSentence, - ISense, - IPartOfSpeech, - IQueryOptions, - ISemanticDomain, - IWritingSystem, - IWritingSystems, - WritingSystemType -}; - -export type LexboxApiClient = IMiniLcmJsInvokable; diff --git a/frontend/viewer/src/lib/services/selected-entry-service.ts b/frontend/viewer/src/lib/services/selected-entry-service.ts deleted file mode 100644 index 8472ab6642..0000000000 --- a/frontend/viewer/src/lib/services/selected-entry-service.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type {IEntry} from '$lib/dotnet-types'; -import {derived, get, type Readable} from 'svelte/store'; - -/** - * Returns a store like selectedEntry, but only emits when a completely different entry is selected (or no entry is selected), - * rather than when the currently selected entry experiences a change (which may result in selectedEntry emitting). - */ -export function getSelectedEntryChangedStore(selectedEntry: Readable): Readable { - let previousSelectedEntry = get(selectedEntry); - return derived(selectedEntry, ($selectedEntry, set) => { - if (previousSelectedEntry?.id !== $selectedEntry?.id) { - previousSelectedEntry = $selectedEntry; - set($selectedEntry); - } - }); -} diff --git a/frontend/viewer/src/lib/services/service-provider-signalr.ts b/frontend/viewer/src/lib/services/service-provider-signalr.ts deleted file mode 100644 index 6c6cfe156d..0000000000 --- a/frontend/viewer/src/lib/services/service-provider-signalr.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import {getHubProxyFactory, getReceiverRegister} from '../generated-signalr-client/TypedSignalR.Client'; - -import { - type HubConnection, - HubConnectionBuilder, - HubConnectionState, - type IHttpConnectionOptions -} from '@microsoft/signalr'; -import type {LexboxApiClient} from './lexbox-api'; -import {onDestroy} from 'svelte'; -import {type Readable, type Writable, writable} from 'svelte/store'; -import {AppNotification} from '../notifications/notifications'; -import type { - CloseReason, -} from '../generated-signalr-client/TypedSignalR.Client/Lexbox.ClientServer.Hubs'; -import {useEventBus} from './event-bus'; -import {type IMiniLcmFeatures, type IEntry, type IMiniLcmJsInvokable} from '$lib/dotnet-types'; -import {initProjectContext} from '$lib/project-context.svelte'; - -// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -type ErrorContext = {error: Error|unknown, methodName?: string, origin: 'method'|'connection'}; -type ErrorHandler = (errorContext: ErrorContext) => {handled: boolean}; -export function SetupSignalR( - url: string, - features: IMiniLcmFeatures, - onError?: ErrorHandler, - options: IHttpConnectionOptions = {}) : { connected: Readable, lexboxApi: LexboxApiClient } { - const {connection, connected} = setupConnection(url, options, errorContext => { - if (onError && onError(errorContext).handled) { - return {handled: true}; - } - if (errorContext.error instanceof Error) { - const message = errorContext.error.message; - AppNotification.display('Connection error: ' + message, 'error', 'long'); - } else { - AppNotification.display('Unknown Connection error', 'error', 'long'); - } - return {handled: true}; - }); - const hubFactory = getHubProxyFactory('ILexboxApiHub'); - const hubProxy = hubFactory.createHubProxy(connection); - - const lexboxApiHubProxy = Object.assign(hubProxy, { - supportedFeatures(): Promise { - return Promise.resolve(features); - } - } satisfies Partial); - const changeEventBus = useEventBus(); - getReceiverRegister('ILexboxClient').register(connection, { - OnProjectClosed(reason: CloseReason): Promise { - changeEventBus.notifyProjectClosed(reason); - return Promise.resolve(); - }, - OnEntryUpdated(entry: IEntry): Promise { - changeEventBus.notifyEntryUpdated(entry); - return Promise.resolve(); - } - }); - initProjectContext({api: lexboxApiHubProxy, projectName: 'todo-change-me', projectCode: 'todo-change-me'}); - return {connected, lexboxApi: lexboxApiHubProxy}; -} - -function setupConnection(url: string, options: IHttpConnectionOptions, onError: ErrorHandler): {connection: HubConnection, connected: Writable} { - const connected = writable(false) - let connection = new HubConnectionBuilder() - .withUrl(url, options) - .withAutomaticReconnect() - .build(); - - if (import.meta.env.DEV) connection.serverTimeoutInMilliseconds = 60_000 * 10; - console.debug('SignalR connection timeout', connection.serverTimeoutInMilliseconds); - - onDestroy(() => connection.stop()); - connection.onclose((error) => { - connected.set(false); - if (!error) return; - console.error('Connection closed', error); - onError({error, origin: 'connection'}); - }); - void connection.start() - .then(() => connected.set(connection.state == HubConnectionState.Connected)) - .catch(err => { - onError({error: err, origin: 'connection'}); - console.error('error connecting to signalr', err); - }); - connection = new Proxy(connection, { - get(target, prop: keyof HubConnection, receiver) { - if (prop === 'invoke') { - /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument */ - return async (methodName: string, ...args: any[]) => { - try { - return await target.invoke(methodName, ...args); - } catch (e) { - onError({error: e, methodName, origin: 'method'}); - throw e; - } - } - /* eslint-enable */ - } else { - return Reflect.get(target, prop, receiver); - } - } - }); - return {connection, connected}; -} diff --git a/frontend/viewer/src/lib/status/SaveStatus.svelte b/frontend/viewer/src/lib/status/SaveStatus.svelte deleted file mode 100644 index 98806163bb..0000000000 --- a/frontend/viewer/src/lib/status/SaveStatus.svelte +++ /dev/null @@ -1,119 +0,0 @@ - - - -
-
- -
- {#if lastSaved} - {@const savedAgo = Date.now() - lastSaved.getTime()} - Last saved - {#if savedAgo < 30_000} - a few seconds - {:else if savedAgo < 90_000} - a minute - {:else} - {humanizeDuration({ duration: { milliseconds: savedAgo }, minUnits: DurationUnits.Minute })} - {/if} - ago - - {:else if lastStatus === 'saved-to-disk'} - - Saved to disk - - - {:else if lastStatus === 'failed-to-save'} - Save failed - {/if} -
-
- -
-
-
diff --git a/frontend/viewer/src/lib/utils/MapBind.svelte b/frontend/viewer/src/lib/utils/MapBind.svelte deleted file mode 100644 index 06e7ca4265..0000000000 --- a/frontend/viewer/src/lib/utils/MapBind.svelte +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/frontend/viewer/src/lib/utils/MapBind.test.svelte b/frontend/viewer/src/lib/utils/MapBind.test.svelte deleted file mode 100644 index b382a5af37..0000000000 --- a/frontend/viewer/src/lib/utils/MapBind.test.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - - (_a ? { id: _a } : undefined)} - unmap={(_b) => (_b ? _b.id : undefined)} -/> diff --git a/frontend/viewer/src/lib/utils/MapBind.test.ts b/frontend/viewer/src/lib/utils/MapBind.test.ts deleted file mode 100644 index 8365519701..0000000000 --- a/frontend/viewer/src/lib/utils/MapBind.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {expect, test, beforeEach} from 'vitest' -import { get, writable, type Writable } from 'svelte/store' - -import MapBindTest from './MapBind.test.svelte' -import {render} from '@testing-library/svelte' -import { tick } from 'svelte' - -let inStore: Writable; -let outStore: Writable<{ id: string } | undefined>; - -beforeEach(() => { - inStore = writable('World'); - outStore = writable<{ id: string } | undefined>(undefined); - render(MapBindTest, { - a: inStore, - b: outStore, - }); -}); - -test('syncs initial value from in->out', () => { - expect(get(inStore)).toBe('World'); - expect(get(outStore)).toStrictEqual({ id: 'World' }); -}); - - -test('syncs future values from in->out and out->in', async () => { - inStore.set('Hello'); - expect(get(inStore)).toBe('Hello'); - await tick(); - expect(get(outStore)).toStrictEqual({ id: 'Hello' }); - - outStore.set({ id: 'Goodbye' }); - expect(get(outStore)).toStrictEqual({ id: 'Goodbye' }); - await tick(); - expect(get(inStore)).toBe('Goodbye'); - - outStore.set(undefined); - await tick(); - expect(get(outStore)).toBe(undefined); - expect(get(inStore)).toBe(undefined); -}); - -test('in wins conflicts', async () => { - inStore.set('Nope'); - outStore.set({ id: 'Yes' }); - await tick(); - expect(get(outStore)).toStrictEqual({ id: 'Nope' }); - expect(get(inStore)).toBe('Nope'); -}); diff --git a/frontend/viewer/src/lib/utils/size.ts b/frontend/viewer/src/lib/utils/size.ts deleted file mode 100644 index db43645ae2..0000000000 --- a/frontend/viewer/src/lib/utils/size.ts +++ /dev/null @@ -1,6 +0,0 @@ -export function getAvailableHeightForElement(elem: HTMLElement): number { - const elementIsBiggerThanScreenSpace = (elem.scrollHeight + elem.offsetTop) > window.innerHeight; - // Only grow if we need to, otherwise it looks weird when a footer gets pushed down - const growWithScroll = elementIsBiggerThanScreenSpace ? window.scrollY : 0; - return window.innerHeight - Math.max(0, elem.offsetTop - growWithScroll); -} diff --git a/frontend/viewer/src/lib/utils/test-utils.ts b/frontend/viewer/src/lib/utils/test-utils.ts deleted file mode 100644 index 4ca56e6773..0000000000 --- a/frontend/viewer/src/lib/utils/test-utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type {ComponentProps, SvelteComponent} from 'svelte'; - -export function getState(component: T): ComponentProps { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - return (component.$capture_state() as unknown as ComponentProps); -} diff --git a/frontend/viewer/src/lib/views/project-view-state-service.ts b/frontend/viewer/src/lib/views/project-view-state-service.ts deleted file mode 100644 index 17ea291548..0000000000 --- a/frontend/viewer/src/lib/views/project-view-state-service.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {getContext, setContext} from 'svelte'; -import {type Readable, type Writable, writable} from 'svelte/store'; - -const projectViewStateContextName = 'project-view-state'; - -export type ProjectViewState = { - /** - * Tracks whether the user has explicitly collapsed the right toolbar. - * Used to inform the toolbar contents, so it can behave accordingly. - * 🤔 I suppose this could largely be handled by css container queries. - */ - rightToolbarCollapsed: boolean, - /** - * Tracks whether the user has explicitly picked an entry to view. - * (whether via the entry list, an entry-ID in the URL, creating a new entry etc.) - * Used on smaller screen e.g. mobile to determine whether to show the entry list or the entry editor. - */ - userPickedEntry: boolean, -}; - -export function initProjectViewState(defaultFeatures: ProjectViewState): Writable { - const projectViewStateStore = writable(defaultFeatures); - setContext>(projectViewStateContextName, projectViewStateStore); - return projectViewStateStore; -} - -export function useProjectViewState(): Readable { - return getContext>(projectViewStateContextName); -} diff --git a/frontend/viewer/src/lib/views/view-data.ts b/frontend/viewer/src/lib/views/view-data.ts index 21ce400157..adf578d2a6 100644 --- a/frontend/viewer/src/lib/views/view-data.ts +++ b/frontend/viewer/src/lib/views/view-data.ts @@ -1,14 +1,13 @@ -import type {FieldIds} from '$lib/entry-editor/field-data'; -import type {I18nType} from '../i18n'; +import type {FieldId} from '$lib/entry-editor/field-data'; -interface FieldView { +export interface FieldView { show: boolean; order: number; } const defaultDef = Symbol('default spread values'); -export const allFields: Record = { +export const allFields: Record = { //entry lexemeForm: {show: true, order: 1}, citationForm: {show: true, order: 2}, @@ -33,7 +32,6 @@ export const allFields: Record = { export const FW_LITE_VIEW: RootView = { id: 'fwlite', type: 'fw-lite', - i18nKey: '', label: 'FieldWorks Lite', fields: allFields, get alternateView() { return FW_CLASSIC_VIEW; } @@ -42,7 +40,6 @@ export const FW_LITE_VIEW: RootView = { export const FW_CLASSIC_VIEW: RootView = { id: 'fieldworks', type: 'fw-classic', - i18nKey: 'fieldworks', label: 'FieldWorks', fields: recursiveSpread(allFields, {[defaultDef]: {show: true}}), alternateView: FW_LITE_VIEW, @@ -56,7 +53,7 @@ export const views: [RootView, RootView, ...CustomView[]] = [ FW_LITE_VIEW, FW_CLASSIC_VIEW, ...viewDefinitions.map(view => { - const fields: Record = recursiveSpread(allFields, view.fieldOverrides); + const fields: Record = recursiveSpread(allFields, view.fieldOverrides); return { ...FW_LITE_VIEW, ...view, @@ -65,7 +62,7 @@ export const views: [RootView, RootView, ...CustomView[]] = [ }) ]; -function recursiveSpread>(obj1: T, obj2: { [P in keyof T]?: Partial }): T { +function recursiveSpread>(obj1: T, obj2: { [P in keyof T]?: Partial } & { [defaultDef]?: Partial }): T { const result: Record = {...obj1}; const defaultValues = obj2[defaultDef]; if (defaultValues) { @@ -93,17 +90,16 @@ export type ViewType = 'fw-lite' | 'fw-classic'; interface ViewDefinition { id: string; type: ViewType; - i18nKey: I18nType; label: string; } interface CustomViewDefinition extends ViewDefinition { - fieldOverrides: Partial>>; + fieldOverrides: Partial>>; parentView: RootView; } interface ViewBase extends ViewDefinition { - fields: Record; + fields: Record; } interface RootView extends ViewBase { diff --git a/frontend/viewer/src/lib/writing-system-service.svelte.ts b/frontend/viewer/src/lib/writing-system-service.svelte.ts index 159137a780..88bba1babf 100644 --- a/frontend/viewer/src/lib/writing-system-service.svelte.ts +++ b/frontend/viewer/src/lib/writing-system-service.svelte.ts @@ -7,12 +7,17 @@ IWritingSystem, IWritingSystems } from '$lib/dotnet-types'; -import type {WritingSystemSelection} from './config-types'; import {firstTruthy} from './utils'; import {type ProjectContext, useProjectContext} from '$lib/project-context.svelte'; import {type ResourceReturn} from 'runed'; import type {IRichString} from '$lib/dotnet-types/generated-types/MiniLcm/Models/IRichString'; +export type WritingSystemType = 'vernacular' | 'analysis'; +export type WritingSystemSelection = + WritingSystemType + | `first-${WritingSystemType}` + | 'vernacular-analysis' + | 'analysis-vernacular'; const symbol = Symbol.for('fw-lite-ws-service'); export function useWritingSystemService(): WritingSystemService { const projectContext = useProjectContext(); diff --git a/frontend/viewer/src/lib/writing-system/WritingSystemDialog.svelte b/frontend/viewer/src/lib/writing-system/WritingSystemDialog.svelte index f2e4f848a2..490ada22cb 100644 --- a/frontend/viewer/src/lib/writing-system/WritingSystemDialog.svelte +++ b/frontend/viewer/src/lib/writing-system/WritingSystemDialog.svelte @@ -1,24 +1,30 @@  - -
Edit Writing Systems
- - onCreate(e.detail.writingSystem)} - on:change={(e) => onChange(e.detail.writingSystem)}/> -
- -
-
+ + + + Edit Writing Systems + + + + + + + + {#if newWs} + + {:else} + Changes are saved automatically + {/if} diff --git a/frontend/viewer/src/project/browse/EntryView.svelte b/frontend/viewer/src/project/browse/EntryView.svelte index 42bc0c65b1..dfeb6db0b5 100644 --- a/frontend/viewer/src/project/browse/EntryView.svelte +++ b/frontend/viewer/src/project/browse/EntryView.svelte @@ -1,7 +1,6 @@