diff --git a/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj b/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj index 271a269d8..e412078aa 100644 --- a/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj +++ b/backend/FwLite/FwDataMiniLcmBridge/FwDataMiniLcmBridge.csproj @@ -4,6 +4,8 @@ net8.0 enable enable + $(ApplicationDisplayVersion) + $(ApplicationDisplayVersion) diff --git a/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj b/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj index f62ab2c9c..d6f9976d3 100644 --- a/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj +++ b/backend/FwLite/FwLiteProjectSync/FwLiteProjectSync.csproj @@ -6,6 +6,8 @@ enable enable true + $(ApplicationDisplayVersion) + $(ApplicationDisplayVersion) diff --git a/backend/FwLite/LcmCrdt/LcmCrdt.csproj b/backend/FwLite/LcmCrdt/LcmCrdt.csproj index 68176ba8f..c61cc2535 100644 --- a/backend/FwLite/LcmCrdt/LcmCrdt.csproj +++ b/backend/FwLite/LcmCrdt/LcmCrdt.csproj @@ -4,6 +4,8 @@ net8.0 enable enable + $(ApplicationDisplayVersion) + $(ApplicationDisplayVersion) diff --git a/backend/FwLite/LocalWebApp/LocalWebApp.csproj b/backend/FwLite/LocalWebApp/LocalWebApp.csproj index 6b9a7e5fe..6edb2dfdc 100644 --- a/backend/FwLite/LocalWebApp/LocalWebApp.csproj +++ b/backend/FwLite/LocalWebApp/LocalWebApp.csproj @@ -8,6 +8,8 @@ true false true + $(ApplicationDisplayVersion) + $(ApplicationDisplayVersion) diff --git a/backend/FwLite/LocalWebApp/Routes/FeedbackRoute.cs b/backend/FwLite/LocalWebApp/Routes/FeedbackRoute.cs index 336b855d2..29dda9fdc 100644 --- a/backend/FwLite/LocalWebApp/Routes/FeedbackRoute.cs +++ b/backend/FwLite/LocalWebApp/Routes/FeedbackRoute.cs @@ -1,12 +1,15 @@ -namespace LocalWebApp.Routes; +using System.Reflection; + +namespace LocalWebApp.Routes; public static class FeedbackRoute { public static void MapFeedbackRoutes(this IEndpointRouteBuilder endpoints) { - endpoints.MapGet("/api/feedback", () => + endpoints.MapGet("/api/feedback/fw-lite", () => { - var version = "alpha"; + var version = typeof(FeedbackRoute).Assembly + .GetCustomAttribute()?.InformationalVersion ?? "dev"; var os = Environment.OSVersion.Platform switch { PlatformID.Win32NT => "Windows", diff --git a/backend/FwLite/MiniLcm/MiniLcm.csproj b/backend/FwLite/MiniLcm/MiniLcm.csproj index 5e87a4198..dbdbf9ad8 100644 --- a/backend/FwLite/MiniLcm/MiniLcm.csproj +++ b/backend/FwLite/MiniLcm/MiniLcm.csproj @@ -4,6 +4,8 @@ net8.0 enable enable + $(ApplicationDisplayVersion) + $(ApplicationDisplayVersion) diff --git a/backend/LexBoxApi/Controllers/FeedbackController.cs b/backend/LexBoxApi/Controllers/FeedbackController.cs new file mode 100644 index 000000000..d89308218 --- /dev/null +++ b/backend/LexBoxApi/Controllers/FeedbackController.cs @@ -0,0 +1,18 @@ +using LexBoxApi.Services; +using Microsoft.AspNetCore.Mvc; + +namespace LexBoxApi.Controllers; + +[ApiController] +[Route("/api/feedback")] +public class FeedbackController() : ControllerBase +{ + [HttpGet("fw-lite")] + public IResult RedirectToFieldWorksLiteFeedbackForm() + { + var version = AppVersionService.Version; + var os = "Web"; + var url = $"https://docs.google.com/forms/d/e/1FAIpQLSdUdNufT3sdoBscY7vixguYnvtgpaw-hjX-z54BKi9KlYv4vw/viewform?usp=pp_url&entry.2102942583={version}&entry.1772086822={os}"; + return Results.Redirect(url, preserveMethod: true); + } +} diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 1b8763c6f..fa37047bf 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -282,6 +282,9 @@ importers: postcss: specifier: 'catalog:' version: 8.4.47 + svelte-exmarkdown: + specifier: ^3.0.5 + version: 3.0.5(svelte@4.2.19) svelte-preprocess: specifier: 'catalog:' version: 5.1.4(@babel/core@7.24.7)(postcss-load-config@4.0.2(postcss@8.4.47))(postcss@8.4.47)(svelte@4.2.19)(typescript@5.3.3) @@ -307,6 +310,9 @@ importers: '@sveltejs/vite-plugin-svelte': specifier: ^3.1.1 version: 3.1.1(svelte@4.2.19)(vite@5.4.9(@types/node@20.12.12)) + '@tailwindcss/typography': + specifier: ^0.5.13 + version: 0.5.13(tailwindcss@3.4.3) '@tsconfig/svelte': specifier: ^5.0.4 version: 5.0.4 diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 9299bdabc..61ab2bc92 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -720,5 +720,39 @@ If you don't see a dialog or already closed it, click the button below:", "any": "Any", "yes_no": "{value, select, true {Yes} false {No} other {Unknown}}", "did_you_know": "Did you know?", + }, + "viewer": { + "about": "## What is this?\n\ +\ +This is a beta version of a new dictionary building tool that is currently under development.\n\ +\ +The data you see here reflects the current data in the corresponding [Language Forge](https://languageforge.org/) project.\n\ +\ +This read-only version of the new dictionary tool is primarily for gathering early feedback on its look and feel. So, please use the [Feedback](/api/feedback) button in the top right corner of the page.\n\ +\ +## It can edit FieldWorks projects!\n\ +\ +It's true! There's already another version of the tool that you can use today to open and edit your data in FieldWorks.\n\ +It's also loaded with additional features! We're calling it [FieldWorks Lite](https://lexbox.org/fw-lite).\n\ +So, please download and try out the alpha version of [FieldWorks Lite](https://lexbox.org/fw-lite) as well.\n\ +\ +## Should I be excited?\n\ +\ +Yes! FieldWorks Lite will be revolutionary in multiple ways. It will be:\n\ +\ +- Cross-platform: it will work on Windows, Linux, Mac and eventually mobile\n\ +- Usable offline: you won't need an internet connection\n\ +- Collaborative: you will see any changes other users make as they work\n\ +- Faster than you're used to - we're quite confident about that 😀\n\ +\ +Eventually, FieldWorks Lite will replace both [WeSay](https://software.sil.org/wesay/) and [Language Forge](https://languageforge.org/).\n\ +\ +So, please send us your [feedback](/api/feedback). We want this tool to serve you as well as possible.\n\ +\ +## FieldWorks Lite is not\n\ +\ +- A replacement for [FieldWorks](https://software.sil.org/fieldworks/)\n\ +- A replacement for [Dictionary App Builder](https://software.sil.org/dictionaryappbuilder/)\n\ +- A replacement for [Webonary](https://www.webonary.org/)" } } diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/viewer/+page.svelte b/frontend/src/routes/(authenticated)/project/[project_code]/viewer/+page.svelte index da5c6175b..5433b0f72 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/viewer/+page.svelte +++ b/frontend/src/routes/(authenticated)/project/[project_code]/viewer/+page.svelte @@ -3,15 +3,18 @@ import {LexboxService} from 'viewer/service-provider'; import {LfClassicLexboxApi} from './lfClassicLexboxApi'; import type {PageData} from './$types'; + import t from '$lib/i18n'; + import { derived } from 'svelte/store'; export let data: PageData; $: project = data.project; + const about = derived(t, ($t) => $t('viewer.about')); const serviceProvider = window.lexbox.ServiceProvider; let service: LfClassicLexboxApi; $: { if (serviceProvider) { - let localService = new LfClassicLexboxApi($project.code); + let localService = new LfClassicLexboxApi($project.code, about); serviceProvider.setService(LexboxService.LexboxApi, localService); service = localService; } diff --git a/frontend/src/routes/(authenticated)/project/[project_code]/viewer/lfClassicLexboxApi.ts b/frontend/src/routes/(authenticated)/project/[project_code]/viewer/lfClassicLexboxApi.ts index 2cc8a04a1..5cb381db1 100644 --- a/frontend/src/routes/(authenticated)/project/[project_code]/viewer/lfClassicLexboxApi.ts +++ b/frontend/src/routes/(authenticated)/project/[project_code]/viewer/lfClassicLexboxApi.ts @@ -11,6 +11,7 @@ import { type SemanticDomain } from 'viewer/lexbox-api'; import { SEMANTIC_DOMAINS_EN } from './semantic-domains.en.generated-data'; +import { type Readable } from 'svelte/store'; function prepareEntriesForUi(entries: IEntry[]): void { entries.forEach(entry => { @@ -31,11 +32,14 @@ function preparePartsOfSpeedForUi(partsOfSpeech: PartOfSpeech[]): void { } export class LfClassicLexboxApi implements LexboxApiClient { - constructor(private projectCode: string) { + constructor(private projectCode: string, private aboutMarkdown: Readable) { } SupportedFeatures(): LexboxApiFeatures { - return {}; + return { + feedback: true, + about: this.aboutMarkdown, + }; } async GetWritingSystems(): Promise { diff --git a/frontend/viewer/package.json b/frontend/viewer/package.json index da3e3687a..0b19bfda6 100644 --- a/frontend/viewer/package.json +++ b/frontend/viewer/package.json @@ -11,7 +11,6 @@ "main": "dist-web-component/viewer.js", "exports": { "./component": "./dist-web-component/viewer.js", - "./style": "./dist-web-component/style.css", "./lexbox-api": "./src/lib/services/lexbox-api.ts", "./service-provider": "./src/lib/services/service-provider.ts" }, @@ -29,6 +28,7 @@ "@iconify-json/mdi": "^1.1.66", "@mdi/js": "^7.4.47", "@sveltejs/vite-plugin-svelte": "^3.1.1", + "@tailwindcss/typography": "^0.5.13", "@tsconfig/svelte": "^5.0.4", "svelte": "catalog:", "svelte-check": "catalog:", @@ -44,6 +44,7 @@ "autoprefixer": "^10.4.19", "fast-json-patch": "^3.1.1", "postcss": "catalog:", + "svelte-exmarkdown": "^3.0.5", "svelte-preprocess": "catalog:", "svelte-routing": "^2.12.0", "svelte-ux": "^0.66.8", diff --git a/frontend/viewer/src/ProjectView.svelte b/frontend/viewer/src/ProjectView.svelte index 3fe23bf66..7a83aa146 100644 --- a/frontend/viewer/src/ProjectView.svelte +++ b/frontend/viewer/src/ProjectView.svelte @@ -36,6 +36,7 @@ import {views} from './lib/entry-editor/view-data'; import {initWritingSystems} from './lib/writing-systems'; import {useEventBus} from './lib/services/event-bus'; + import AboutDialog from './lib/about/AboutDialog.svelte'; export let loading = false; @@ -286,9 +287,12 @@ {#if $features.history} {/if} + {#if $features.about} + + {/if} {#if $features.feedback} + +
+ +
+
+
+ +
+
+ diff --git a/frontend/viewer/src/lib/about/NewTabLinkRenderer.svelte b/frontend/viewer/src/lib/about/NewTabLinkRenderer.svelte new file mode 100644 index 000000000..e1b72a91d --- /dev/null +++ b/frontend/viewer/src/lib/about/NewTabLinkRenderer.svelte @@ -0,0 +1,16 @@ + + + + +   + + + diff --git a/frontend/viewer/src/lib/services/lexbox-api.ts b/frontend/viewer/src/lib/services/lexbox-api.ts index c003fb7ec..e9795fe5c 100644 --- a/frontend/viewer/src/lib/services/lexbox-api.ts +++ b/frontend/viewer/src/lib/services/lexbox-api.ts @@ -1,6 +1,7 @@ import type {IEntry, IExampleSentence, ISense, PartOfSpeech, QueryOptions, SemanticDomain, WritingSystem, WritingSystems} from '../mini-lcm'; import type { Operation } from 'fast-json-patch'; +import type { Readable } from 'svelte/store'; export type {IEntry, IExampleSentence, ISense, QueryOptions, WritingSystem, WritingSystems, PartOfSpeech, SemanticDomain} from '../mini-lcm'; @@ -17,6 +18,7 @@ export interface LexboxApiFeatures { openWithFlex?: boolean; feedback?: boolean; sync?: boolean; + about?: Readable; } export interface LexboxApi { diff --git a/frontend/viewer/src/lib/utils/style-fix.ts b/frontend/viewer/src/lib/utils/style-fix.ts deleted file mode 100644 index 15872b6a1..000000000 --- a/frontend/viewer/src/lib/utils/style-fix.ts +++ /dev/null @@ -1,13 +0,0 @@ -function regexEscape(s: string): string { - return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string -} - -export function fixBrokenNestedGlobalStyles(shadowRoot: ShadowRoot) { - // for some reason some occurences of :global() stick around - // presumably this is a bug in the svelte css transformer: https://github.com/sveltejs/svelte/blob/272ffc5520dfff0cc4605ecf45147ee660c87bb0/packages/svelte/src/compiler/phases/3-transform/css/index.js - // but I don't think this sort of super-edge-case bug is not going to get a lot of attention - shadowRoot?.querySelectorAll('style').forEach((style) => { - const regex = new RegExp(regexEscape(':is(.dark) :global(*)'), 'g'); - style.innerHTML = style.innerHTML.replace(regex, ':is(.dark *)'); - }); -} diff --git a/frontend/viewer/tailwind.config.cjs b/frontend/viewer/tailwind.config.cjs index a9ae479d5..4304eb406 100644 --- a/frontend/viewer/tailwind.config.cjs +++ b/frontend/viewer/tailwind.config.cjs @@ -14,6 +14,7 @@ module.exports = { collections: getIconCollections(['mdi']), }), svelteUx({ colorSpace: 'oklch' }), + require('@tailwindcss/typography'), ], ux: { themeRoot: ':root, :host',