Skip to content

Commit 8856ded

Browse files
committed
updated ui
1 parent fa16b41 commit 8856ded

26 files changed

Lines changed: 834 additions & 170 deletions

TODO.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,28 @@
1717
Includes bugs and feature requests from the public.
1818

1919
Feature requests - high priority:
20-
- [ ] Add ability to add more than 2 lines
20+
- [x] Add ability to add more than 2 lines
2121
- [ ] Improve support for longer sentences - currently non-svg export is low resolution when font is small
22-
- [ ] add special separator to combine words into a single token - it will be connected with 1 line in the visualization but still be written with a space or spaces
23-
- [ ] add ability to optionally tokenize punctuation as separate tokens
24-
- [ ] add transcription line support (probably can be solved by adding more than 2 lines)
22+
- [x] add special separator to combine words into a single token - it will be connected with 1 line in the visualization but still be written with a space or spaces
23+
- [x] add ability to optionally tokenize punctuation as separate tokens
24+
- [x] add transcription line support (probably can be solved by adding more than 2 lines)
2525

2626
Usability improvements - high priority:
2727
- [ ] Parameter card or other view should move to be next to the editor - currently on small screens you have to scroll back and forth between the editor and the parameters
2828

2929
Bug fixes - high priority:
3030
- [ ] Reportedly ligatures in custom fonts are not working in the export (but fine in preview) - investigate and fix
31-
- [ ] When color palette is depleted, it should cycle through the colors - currently uses the last color
31+
- [x] When color palette is depleted, it should cycle through the colors - currently uses the last color
3232

3333
Advanced features - medium priority:
3434
- [ ] Ability to create custom color palettes
35-
- [ ] Maybe parameter-line connection should be reworked to be more flexible - each line should have all the parameters configured separately.
35+
- [x] Maybe parameter-line connection should be reworked to be more flexible - each line should have all the parameters configured separately.
36+
- [x] Add ability to hide preview controls so that the user can see the entire visualization and screenshot it if needed. In this mode - add the credit to the bottom of the visualization, like in exports.
3637

3738
General interface improvements - medium priority:
3839
- [ ] Interface languages - add pages for some major languages
3940
- [ ] Make interface more compact to accomodate more features
40-
- [ ] Probably add full screen mode for the preview - so that the user would be able to see it all and screenshot if needed - this will partially help if we won't be able to solve ligature problems
41+
- [x] Probably add full screen mode for the preview - so that the user would be able to see it all and screenshot if needed - this will partially help if we won't be able to solve ligature problems
4142

4243
Considerations:
4344
- If we support multiple lines with independent parameters, we can deprecate separate gloss row and configuration - it will be just a single new line with the glosses. Then, the user would be able to add transcription and other annotations in the same manner.

bitext/src/app.css

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,39 @@ html {
123123
align-items: stretch;
124124
}
125125

126+
.preview-frame__attribution {
127+
position: relative;
128+
z-index: 3;
129+
margin-top: 1rem;
130+
text-align: center;
131+
font-family: var(--font-body, system-ui, sans-serif);
132+
font-size: 0.75rem;
133+
line-height: 1.4;
134+
opacity: 0.72;
135+
}
136+
137+
.preview-frame--light .preview-frame__attribution {
138+
color: #64748b;
139+
}
140+
141+
.preview-frame--dark .preview-frame__attribution {
142+
color: #94a3b8;
143+
}
144+
145+
.preview-frame__attribution-link {
146+
text-decoration: underline;
147+
text-underline-offset: 2px;
148+
cursor: pointer;
149+
}
150+
151+
.preview-frame--light .preview-frame__attribution-link {
152+
color: #475569;
153+
}
154+
155+
.preview-frame--dark .preview-frame__attribution-link {
156+
color: #cbd5e1;
157+
}
158+
126159
.preview-gloss-wrap {
127160
width: 100%;
128161
display: flex;

bitext/src/lib/brand.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ export const ALIGNER_SITE_URL = 'https://aligner.tinygods.dev';
44
/** Host label for attribution text in raster/SVG exports. */
55
export const ALIGNER_SITE_HOST = 'aligner.tinygods.dev';
66

7+
/** Plain attribution line (matches standalone SVG export footer text). */
8+
export const EXPORT_ATTRIBUTION_PLAIN = `Created with ${ALIGNER_SITE_HOST}`;
9+
710
/** Google Analytics 4 measurement ID (gtag). */
811
export const GA_MEASUREMENT_ID = 'G-6Z5775NY39';
912

bitext/src/lib/components/editor/Editor.svelte

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
<script lang="ts">
2+
import { LanguageOutline } from 'flowbite-svelte-icons';
23
import LineCard from './LineCard.svelte';
3-
import { DEFAULT_TOKEN_SPLIT_CHARS, MAX_LINES } from '$lib/serialization/schema.js';
4+
import { editorTokenizationChipValues } from '$lib/domain/tokenization-summary.js';
5+
import { MAX_LINES } from '$lib/serialization/schema.js';
46
import { projectStore } from '$lib/state/project.svelte.js';
7+
import { settingsNavStore } from '$lib/state/settingsNav.svelte.js';
58
import { settingsStore } from '$lib/state/settings.svelte.js';
69
710
let editorExpanded = $state(true);
11+
12+
const tok = $derived(editorTokenizationChipValues(settingsStore.settings));
13+
const chipClass =
14+
'rounded-none bg-gray-200 px-1.5 py-0.5 font-mono text-[0.8125rem] leading-none text-gray-900 dark:bg-gray-700 dark:text-gray-100';
815
</script>
916

10-
<section class="mb-8" aria-labelledby="editor-heading">
17+
<section class="mb-8" aria-labelledby="line-editor-heading">
1118
<div class="mb-2 flex flex-wrap items-center justify-between gap-2">
1219
<button
1320
type="button"
@@ -30,18 +37,34 @@
3037
clip-rule="evenodd"
3138
/>
3239
</svg>
33-
<span id="editor-heading" class="font-heading text-lg font-semibold">Editor</span>
40+
<span id="line-editor-heading" class="font-heading text-lg font-semibold">Line editor</span>
3441
</button>
3542
</div>
3643

3744
{#if editorExpanded}
3845
<div id="editor-collapsible">
39-
<p class="mb-3 w-full text-sm leading-snug text-gray-600 dark:text-gray-400">
40-
Whitespace splits words. Extra split characters (from Linguistics in settings) also split
41-
within the line (currently
42-
<code class="rounded-none bg-gray-200 px-1 dark:bg-gray-700"
43-
>{settingsStore.settings.tokenSplitChars || DEFAULT_TOKEN_SPLIT_CHARS}</code
44-
>). Use the preview to link words, change fonts, and add or remove lines.
46+
<p
47+
class="mb-3 flex w-full flex-wrap items-start gap-x-2 gap-y-1 text-sm leading-snug text-gray-600 dark:text-gray-400"
48+
>
49+
<span class="min-w-0 flex-1 [&>span]:mr-1 [&>span]:inline [&>span]:last:mr-0">
50+
<span>Whitespace splits words.</span>
51+
<span>Extra split characters: <code class={chipClass}>{tok.extraSplitChars}</code>.</span>
52+
<span>Join characters: <code class={chipClass}>{tok.joinChars}</code>.</span>
53+
<span
54+
>Tokenize punctuation: <code class="{chipClass} max-w-[min(100%,24rem)] break-all"
55+
>{tok.punctuationChip}</code
56+
>.</span
57+
>
58+
</span>
59+
<button
60+
type="button"
61+
class="shrink-0 rounded-none border border-gray-300 bg-gray-50 p-1.5 text-gray-500 hover:bg-gray-100 hover:text-gray-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 dark:focus-visible:outline-gray-400"
62+
title="Edit tokenization (Settings → Tokens)"
63+
aria-label="Edit tokenization rules"
64+
onclick={() => settingsNavStore.focusTokensTab()}
65+
>
66+
<LanguageOutline class="h-5 w-5" aria-hidden="true" />
67+
</button>
4568
</p>
4669
{#each projectStore.lines as line, i (line.id)}
4770
<LineCard {line} index={i} />

bitext/src/lib/components/editor/LineEditModal.svelte

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<script lang="ts">
2+
import { LanguageOutline } from 'flowbite-svelte-icons';
23
import { Modal, Button } from 'flowbite-svelte';
3-
import { DEFAULT_TOKEN_SPLIT_CHARS } from '$lib/serialization/schema.js';
4+
import { editorTokenizationChipValues } from '$lib/domain/tokenization-summary.js';
45
import { projectStore } from '$lib/state/project.svelte.js';
6+
import { settingsNavStore } from '$lib/state/settingsNav.svelte.js';
57
import { settingsStore } from '$lib/state/settings.svelte.js';
68
import { selectionStore } from '$lib/state/selection.svelte.js';
79
import { layoutExportStore } from '$lib/state/layoutExport.svelte.js';
@@ -33,6 +35,9 @@
3335
3436
const tokens = $derived(currentLine ? projectStore.tokensOnLine(currentLine.id) : []);
3537
const connections = $derived(projectStore.connections);
38+
const tok = $derived(editorTokenizationChipValues(settingsStore.settings));
39+
const chipClass =
40+
'rounded-none bg-gray-200 px-1.5 py-0.5 font-mono text-[0.8125rem] leading-none text-gray-900 dark:bg-gray-700 dark:text-gray-100';
3641
3742
const areaClass =
3843
'block w-full rounded-none border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 placeholder-gray-500 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500';
@@ -88,12 +93,29 @@
8893
size="lg"
8994
>
9095
{#if currentLine}
91-
<p class="text-base text-gray-600 dark:text-gray-400">
92-
Whitespace splits words. Extra split characters (from Linguistics in settings) also split
93-
within the line (currently
94-
<code class="rounded-none bg-gray-200 px-1 dark:bg-gray-700"
95-
>{settingsStore.settings.tokenSplitChars || DEFAULT_TOKEN_SPLIT_CHARS}</code
96-
>). Below is a live preview of tokens.
96+
<p
97+
class="flex flex-wrap items-start gap-x-2 gap-y-1 text-sm leading-snug text-gray-600 dark:text-gray-400"
98+
>
99+
<span class="min-w-0 flex-1 [&>span]:mr-1 [&>span]:inline [&>span]:last:mr-0">
100+
<span>Whitespace splits words.</span>
101+
<span>Extra split characters: <code class={chipClass}>{tok.extraSplitChars}</code>.</span>
102+
<span>Join characters: <code class={chipClass}>{tok.joinChars}</code>.</span>
103+
<span
104+
>Tokenize punctuation: <code class="{chipClass} max-w-[min(100%,24rem)] break-all"
105+
>{tok.punctuationChip}</code
106+
>.</span
107+
>
108+
<span>Preview below.</span>
109+
</span>
110+
<button
111+
type="button"
112+
class="shrink-0 rounded-none border border-gray-300 bg-gray-50 p-1.5 text-gray-500 hover:bg-gray-100 hover:text-gray-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-500 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 dark:focus-visible:outline-gray-400"
113+
title="Edit tokenization (Settings → Tokens)"
114+
aria-label="Edit tokenization rules"
115+
onclick={() => settingsNavStore.focusTokensTab()}
116+
>
117+
<LanguageOutline class="h-5 w-5" aria-hidden="true" />
118+
</button>
97119
</p>
98120
<label
99121
class="my-3 block text-sm font-medium text-gray-900 dark:text-white"

bitext/src/lib/components/preview/AlignmentPreview.svelte

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import { selectionStore } from '$lib/state/selection.svelte.js';
1111
import { lineIsLinkTargetWhilePending } from '$lib/domain/lines-helpers.js';
1212
import { resolveLineFontCss } from '$lib/fonts/visualization-font.js';
13+
import { ALIGNER_SITE_HOST, ALIGNER_SITE_URL } from '$lib/brand.js';
1314
import { MAX_LINES } from '$lib/serialization/schema.js';
1415
1516
let {
@@ -25,6 +26,8 @@
2526
let rootEl = $state<HTMLElement | null>(null);
2627
2728
const bg = $derived(settingsStore.settings.background);
29+
const hideChrome = $derived(settingsStore.settings.previewHideChrome);
30+
const chromeHiddenLayer = 'invisible pointer-events-none select-none';
2831
const connections = $derived(projectStore.connections);
2932
const lineIds = $derived(projectStore.lines.map((l) => l.id));
3033
</script>
@@ -46,7 +49,10 @@
4649
<div class="preview-frame__image-overlay"></div>
4750
{/if}
4851
<div class="preview-stack">
49-
<div class="mb-1 flex justify-center">
52+
<div
53+
class="mb-1 flex justify-center {hideChrome ? chromeHiddenLayer : ''}"
54+
aria-hidden={hideChrome ? true : undefined}
55+
>
5056
<button
5157
type="button"
5258
class="rounded-none border border-dashed border-gray-400 px-2 py-0.5 text-xs font-medium text-gray-600 hover:border-primary-500 hover:text-primary-700 disabled:opacity-40 dark:border-gray-600 dark:text-gray-400 dark:hover:border-primary-400 dark:hover:text-primary-300"
@@ -67,7 +73,12 @@
6773
class:opacity-[0.34]={rowDimmed}
6874
style:font-family={resolveLineFontCss(line)}
6975
>
70-
<LineReorderButtons {line} index={li} total={projectStore.lines.length} />
76+
<div
77+
class="shrink-0 {hideChrome ? chromeHiddenLayer : ''}"
78+
aria-hidden={hideChrome ? true : undefined}
79+
>
80+
<LineReorderButtons {line} index={li} total={projectStore.lines.length} />
81+
</div>
7182
<div class="preview-gloss-wrap min-w-0 flex-1">
7283
<TokenRow
7384
tokens={projectStore.tokensOnLine(line.id)}
@@ -78,20 +89,33 @@
7889
interactive={true}
7990
/>
8091
</div>
81-
<LineTrailingActions
82-
{line}
83-
index={li}
84-
total={projectStore.lines.length}
85-
{gearDomId}
86-
triggeredBy={`#${gearDomId}`}
87-
/>
92+
<div
93+
class="shrink-0 {hideChrome ? chromeHiddenLayer : ''}"
94+
aria-hidden={hideChrome ? true : undefined}
95+
>
96+
<LineTrailingActions
97+
{line}
98+
index={li}
99+
total={projectStore.lines.length}
100+
{gearDomId}
101+
triggeredBy={`#${gearDomId}`}
102+
/>
103+
</div>
88104
</div>
89105
{#if li < projectStore.lines.length - 1}
90106
{@const lowerLine = projectStore.lines[li + 1]!}
91-
<LinePairGapSlider upperLineId={line.id} lowerLineId={lowerLine.id} />
107+
<div
108+
class={hideChrome ? chromeHiddenLayer : ''}
109+
aria-hidden={hideChrome ? true : undefined}
110+
>
111+
<LinePairGapSlider upperLineId={line.id} lowerLineId={lowerLine.id} />
112+
</div>
92113
{/if}
93114
{/each}
94-
<div class="mt-1 flex justify-center">
115+
<div
116+
class="mt-1 flex justify-center {hideChrome ? chromeHiddenLayer : ''}"
117+
aria-hidden={hideChrome ? true : undefined}
118+
>
95119
<button
96120
type="button"
97121
class="rounded-none border border-dashed border-gray-400 px-2 py-0.5 text-xs font-medium text-gray-600 hover:border-primary-500 hover:text-primary-700 disabled:opacity-40 dark:border-gray-600 dark:text-gray-400 dark:hover:border-primary-400 dark:hover:text-primary-300"
@@ -101,6 +125,18 @@
101125
+ Add line
102126
</button>
103127
</div>
128+
{#if hideChrome}
129+
<p class="preview-frame__attribution">
130+
Created with
131+
<button
132+
type="button"
133+
class="preview-frame__attribution-link inline cursor-pointer border-0 bg-transparent p-0 font-inherit underline"
134+
onclick={() => window.open(ALIGNER_SITE_URL, '_blank', 'noopener,noreferrer')}
135+
>
136+
{ALIGNER_SITE_HOST}
137+
</button>
138+
</p>
139+
{/if}
104140
</div>
105141
<AlignmentSvg {rootEl} {connections} {writesExportLayout} />
106142
</div>

bitext/src/lib/components/preview/AlignmentSvg.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
}
114114
void projectStore.pairControls;
115115
void settingsStore.settings.lineStyle;
116+
void settingsStore.settings.previewHideChrome;
116117
void projectStore.lines;
117118
void writesExportLayout;
118119

0 commit comments

Comments
 (0)