1
0
Fork 0

Suffixes (for verb conjugations)

This commit is contained in:
Fabio Iotti 2024-12-09 20:23:18 +01:00
parent 72c56ec015
commit 6a41d56a82
Signed by: bruce965
GPG key ID: 4EC13D9158A96B4C
3 changed files with 108 additions and 17 deletions

View file

@ -69,6 +69,11 @@
Meaning: Meaning:
<input id="word_meaning" class="button"/> <input id="word_meaning" class="button"/>
</label> </label>
<label class="spacing section">
Suffix:
<input id="word_suffix_meaning" class="button" />
<input id="word_suffix_length" type="number" class="button" value="0" min="0" max="99" />
</label>
<textarea id="word_notes" class="button spacing section" placeholder="Notes"></textarea> <textarea id="word_notes" class="button spacing section" placeholder="Notes"></textarea>
</div> </div>

View file

@ -30,6 +30,8 @@ const wordSymbols = /** @type {SVGElement} */(/** @type {unknown} */(document.qu
const wordSymbolTemplate = /** @type {SVGSVGElement} */(wordSymbols.querySelector('svg')); const wordSymbolTemplate = /** @type {SVGSVGElement} */(wordSymbols.querySelector('svg'));
const wordMeaningInput = /** @type {HTMLInputElement} */(document.getElementById('word_meaning')); const wordMeaningInput = /** @type {HTMLInputElement} */(document.getElementById('word_meaning'));
const wordNotesTextarea = /** @type {HTMLTextAreaElement} */(document.getElementById('word_notes')); const wordNotesTextarea = /** @type {HTMLTextAreaElement} */(document.getElementById('word_notes'));
const wordSuffixMeaningInput = /** @type {HTMLInputElement} */(document.getElementById('word_suffix_meaning'));
const wordSuffixLengthInput = /** @type {HTMLInputElement} */(document.getElementById('word_suffix_length'));
const symbolOuterTopLeftPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_left'))); const symbolOuterTopLeftPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_left')));
const symbolOuterTopRightPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_right'))); const symbolOuterTopRightPath = /** @type {SVGPathElement} */(/** @type {unknown} */(document.getElementById('outer_top_right')));
@ -441,7 +443,7 @@ panBy(0, 0);
/** @typedef {string} GUID */ /** @typedef {string} GUID */
/** @typedef {{ x: number, y: number, w: number, h: number }} WordData */ /** @typedef {{ x: number, y: number, w: number, h: number, suf?: number }} WordData */
/** @typedef {{ x: number, y: number, w: number, h: number, v?: number }} SymbolData */ /** @typedef {{ x: number, y: number, w: number, h: number, v?: number }} SymbolData */
@ -489,10 +491,13 @@ const loadPageElements = (pageId) => {
const dictionary = data.dictionary ?? {}; const dictionary = data.dictionary ?? {};
if (dictionary) { if (dictionary) {
const wordSymbols = getWordSymbols(pageId, word); const wordSymbols = getWordSymbols(pageId, word);
const dictionaryId = getDictionaryId(wordSymbols); const suffixLength = Math.max(0, word.suf ?? 0);
const dictionaryWord = dictionary[dictionaryId]; const wordId = getDictionaryId(wordSymbols.slice(0, wordSymbols.length - suffixLength));
const suffixId = getDictionaryId(wordSymbols.slice(-suffixLength), true);
const dictionaryWord = dictionary[wordId];
const dictionarySuffix = dictionary[suffixId];
/** @type {HTMLDivElement} */(el.querySelector('.word-meaning')).textContent = dictionaryWord?.tran ?? ''; /** @type {HTMLDivElement} */(el.querySelector('.word-meaning')).textContent = (dictionaryWord?.tran ?? '') + (dictionarySuffix?.tran ?? '');
} }
currentPageElements[id] = el; currentPageElements[id] = el;
@ -543,6 +548,22 @@ const loadPageElements = (pageId) => {
} }
}; };
const sortRecursive = (obj) => {
if (typeof obj == 'object') {
const sortedKeys = Object.keys(obj).sort();
const copy = { ...obj };
for (const k in obj)
delete obj[k];
for (const k of sortedKeys)
obj[k] = copy[k];
for (const k of sortedKeys)
sortRecursive();
}
};
const saveUpdatedData = () => { const saveUpdatedData = () => {
localStorage.setItem('tunic_manual_translation.data', JSON.stringify(data)); localStorage.setItem('tunic_manual_translation.data', JSON.stringify(data));
console.debug("Updated data:", JSON.stringify(data)); console.debug("Updated data:", JSON.stringify(data));
@ -609,10 +630,11 @@ const hideProps = () => {
// Words // Words
let lastSelectedWord = ''; /** @type {{ word: WordData, symbols: number[] } | null} */
let lastSelectedWord = null;
/** /**
* @param {number} pageId * @param {string} pageId
* @param {SymbolData} word * @param {SymbolData} word
*/ */
const getWordSymbols = (pageId, word) => { const getWordSymbols = (pageId, word) => {
@ -640,8 +662,8 @@ const getWordSymbols = (pageId, word) => {
}; };
/** @param {number[]} wordSymbols */ /** @param {number[]} wordSymbols */
const getDictionaryId = (wordSymbols) => { const getDictionaryId = (wordSymbols, suffix = false) => {
return wordSymbols.map(v => v.toString(36)).join('-'); return (suffix ? '-' : '') + wordSymbols.map(v => v.toString(36)).join('-');
}; };
/** @param {number} symbol */ /** @param {number} symbol */
@ -656,35 +678,56 @@ const getSymbolMaskForCss = (symbol) => {
}; };
/** /**
* @param {number} pageId * @param {string} pageId
* @param {SymbolData} word * @param {SymbolData} word
*/ */
const loadWord = (pageId, word) => { const loadWord = (pageId, word) => {
const selectedWordSymbols = getWordSymbols(pageId, word); lastSelectedWord = { word, symbols: getWordSymbols(pageId, word) };
lastSelectedWord = getDictionaryId(selectedWordSymbols); refreshWord();
};
const refreshWord = () => {
if (!lastSelectedWord)
return;
const suffixLength = Math.max(0, lastSelectedWord.word.suf ?? 0);
const wordId = getDictionaryId(lastSelectedWord.symbols.slice(0, lastSelectedWord.symbols.length - suffixLength));
const suffixId = getDictionaryId(lastSelectedWord.symbols.slice(-suffixLength), true);
while (wordSymbols.firstChild) while (wordSymbols.firstChild)
wordSymbols.firstChild.remove(); wordSymbols.firstChild.remove();
for (const symbol of selectedWordSymbols) { for (let i = 0; i < lastSelectedWord.symbols.length; i++) {
const symbol = lastSelectedWord.symbols[i];
const symbolMask = getSymbolMaskForCss(symbol); const symbolMask = getSymbolMaskForCss(symbol);
const el = /** @type {SVGSVGElement} */(wordSymbolTemplate.cloneNode(true)); const el = /** @type {SVGSVGElement} */(wordSymbolTemplate.cloneNode(true));
el.setAttribute('data-symbol', symbolMask); el.setAttribute('data-symbol', symbolMask);
el.classList.toggle('suffix', lastSelectedWord.symbols.length - i <= suffixLength);
wordSymbols.appendChild(el); wordSymbols.appendChild(el);
} }
const dictionary = data.dictionary ??= {}; const dictionary = data.dictionary ??= {};
const currentWord = dictionary[lastSelectedWord] ??= {}; const currentWord = dictionary[wordId] ??= {};
const currentSuffix = dictionary[suffixId] ??= {};
wordMeaningInput.value = currentWord.tran ?? ''; wordMeaningInput.value = currentWord.tran ?? '';
wordNotesTextarea.value = currentWord.note ?? ''; wordNotesTextarea.value = currentWord.note ?? '';
wordSuffixMeaningInput.value = suffixLength == 0 ? "-" : (currentSuffix.tran ?? '');
wordSuffixMeaningInput.disabled = suffixLength == 0;
wordSuffixLengthInput.value = String(suffixLength);
}; };
wordSymbolTemplate.remove(); wordSymbolTemplate.remove();
wordMeaningInput.addEventListener('keyup', ev => { wordMeaningInput.addEventListener('keyup', ev => {
if (!lastSelectedWord)
return;
const suffixLength = lastSelectedWord.word.suf ?? 0;
const wordId = getDictionaryId(lastSelectedWord.symbols.slice(0, lastSelectedWord.symbols.length - suffixLength));
const dictionary = data.dictionary ??= {}; const dictionary = data.dictionary ??= {};
const currentWord = dictionary[lastSelectedWord] ??= {}; const currentWord = dictionary[wordId] ??= {};
if (currentWord.tran != wordMeaningInput.value) { if (currentWord.tran != wordMeaningInput.value) {
currentWord.tran = wordMeaningInput.value; currentWord.tran = wordMeaningInput.value;
@ -692,9 +735,42 @@ wordMeaningInput.addEventListener('keyup', ev => {
} }
}); });
wordNotesTextarea.addEventListener('keyup', ev => { wordSuffixLengthInput.addEventListener('change', ev => {
if (!lastSelectedWord)
return;
const suffixLength = Number(wordSuffixLengthInput.value) || 0;
lastSelectedWord.word.suf = suffixLength;
saveUpdatedData();
refreshWord();
});
wordSuffixMeaningInput.addEventListener('keyup', ev => {
if (!lastSelectedWord)
return;
const suffixLength = lastSelectedWord.word.suf ?? 0;
const suffixId = getDictionaryId(lastSelectedWord.symbols.slice(-suffixLength), true);
const dictionary = data.dictionary ??= {}; const dictionary = data.dictionary ??= {};
const currentWord = dictionary[lastSelectedWord] ??= {}; const currentSuffix = dictionary[suffixId] ??= {};
if (currentSuffix.tran != wordSuffixMeaningInput.value) {
currentSuffix.tran = wordSuffixMeaningInput.value;
saveUpdatedData();
}
});
wordNotesTextarea.addEventListener('keyup', ev => {
if (!lastSelectedWord)
return;
const suffixLength = lastSelectedWord.word.suf ?? 0;
const wordId = getDictionaryId(lastSelectedWord.symbols.slice(0, lastSelectedWord.symbols.length - suffixLength));
const dictionary = data.dictionary ??= {};
const currentWord = dictionary[wordId] ??= {};
if (currentWord.note != wordNotesTextarea.value) { if (currentWord.note != wordNotesTextarea.value) {
currentWord.note = wordNotesTextarea.value; currentWord.note = wordNotesTextarea.value;

View file

@ -96,6 +96,10 @@ html {
border: 0; border: 0;
border-radius: .2em; border-radius: .2em;
input[type=number]& {
padding-right: 0;
}
textarea& { textarea& {
width: 100%; width: 100%;
height: 3rem; height: 3rem;
@ -123,6 +127,12 @@ html {
width: 3em; width: 3em;
margin: 0 calc(-3em / 8); margin: 0 calc(-3em / 8);
--stroke-color: #fff;
&.suffix g {
--stroke-color: #08f;
}
.word_middle_line, .word_middle_line,
&[data-symbol*='a'] .word_outer_top_left, &[data-symbol*='a'] .word_outer_top_left,
&[data-symbol*='b'] .word_outer_top_right, &[data-symbol*='b'] .word_outer_top_right,
@ -136,7 +146,7 @@ html {
&[data-symbol*='j'] .word_inner_bottom_middle, &[data-symbol*='j'] .word_inner_bottom_middle,
&[data-symbol*='k'] .word_inner_bottom_right, &[data-symbol*='k'] .word_inner_bottom_right,
&[data-symbol*='l'] .word_circle { &[data-symbol*='l'] .word_circle {
stroke: #fff; stroke: var(--stroke-color);
} }
} }
} }