637 lines
18 KiB
HTML
637 lines
18 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>Dictionary Cards</title>
|
||
<link rel="stylesheet" href="styles.css" />
|
||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/marked@18.0.6/lib/marked.umd.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.4.12/dist/purify.min.js"></script>
|
||
<script src="https://unpkg.com/alpinejs" defer></script>
|
||
<script src="script.js"></script>
|
||
</head>
|
||
<body>
|
||
<div
|
||
class="app-container"
|
||
@alpine:init="$store.dictionary.load_preferences()"
|
||
x-data="{
|
||
search_term: '',
|
||
showPrefs: false,
|
||
lects: [],
|
||
current_result_page: 0,
|
||
results_per_page: 30,
|
||
new_lemma_form_open: false,
|
||
md(text){
|
||
return $store.dictionary.md(text);
|
||
},
|
||
async put_word_form_text(word_form_id, word_form_text){
|
||
$store.dictionary.put_word_form_text(word_form_id, word_form_text).then(()=>{
|
||
this.load_detail();
|
||
});
|
||
},
|
||
async post_new_word_form(lemma_name, lect_name, word_form_text){
|
||
$store.dictionary.post_new_word_form(lemma_name, lect_name, word_form_text).then(()=>{
|
||
this.load_detail();
|
||
});
|
||
},
|
||
async delete_word_form(word_form_id, word_form_text){
|
||
$store.dictionary.delete_word_form(word_form_id, word_form_text).then(()=>{
|
||
this.load_detail();
|
||
});
|
||
},
|
||
async put_definition(definition_id, definition_text){
|
||
$store.dictionary.put_definition(definition_id, definition_text, this.lemma_detail?.lemma_name).then(()=>{
|
||
this.load_detail();
|
||
});
|
||
},
|
||
async delete_definition(definition_id, definition_text){
|
||
$store.dictionary.delete_definition(definition_id, definition_text).then(()=>{
|
||
this.load_detail();
|
||
});
|
||
},
|
||
async put_example(example_id, example_text){
|
||
$store.dictionary.put_example(example_id, example_text, this.lemma_detail?.lemma_name).then(()=>{
|
||
this.load_detail();
|
||
});
|
||
},
|
||
async post_lemma(lect_name, word_form_text){
|
||
$store.dictionary.post_lemma(lect_name, word_form_text).then(lemma=>console.info(JSON.stringify(lemma)));
|
||
},
|
||
async delete_example(example_id, example_text){
|
||
$store.dictionary.delete_example(example_id, example_text).then(()=>{
|
||
this.load_detail();
|
||
});
|
||
},
|
||
}"
|
||
x-init="$store.dictionary.fetch_all_lects().then((lects_response)=>{
|
||
if(!!lects_response.lects) {
|
||
lects = lects_response.lects;
|
||
}
|
||
});">
|
||
<aside class="sidebar">
|
||
<div class="preferences-pane">
|
||
<button
|
||
@click="showPrefs = !showPrefs"
|
||
class="prefs-toggle is-fullwidth">
|
||
Sejenazma
|
||
</button>
|
||
|
||
<div class="prefs-content" x-show="showPrefs">
|
||
<div class="prefs-section">
|
||
<h3>Sejenazma</h3>
|
||
<label>
|
||
Hinafarge fu ljevatel:
|
||
<input
|
||
type="color"
|
||
x-model="$store.dictionary.prefs.colorSidebarBg"
|
||
@input="$store.dictionary.save_preferences()" />
|
||
</label>
|
||
<label>
|
||
Hinafarge fu glavna lehtia:
|
||
<input
|
||
type="color"
|
||
x-model="$store.dictionary.prefs.colorMainBg"
|
||
@input="$store.dictionary.save_preferences()" />
|
||
</label>
|
||
<label>
|
||
Hinafarge fu kofuga:
|
||
<input
|
||
type="color"
|
||
x-model="$store.dictionary.prefs.colorCardBg"
|
||
@input="$store.dictionary.save_preferences()" />
|
||
</label>
|
||
<label>
|
||
Viktifarge:
|
||
<input
|
||
type="color"
|
||
x-model="$store.dictionary.prefs.colorPrimary"
|
||
@input="$store.dictionary.save_preferences()" />
|
||
</label>
|
||
<label>
|
||
Nisvikti farge:
|
||
<input
|
||
type="color"
|
||
x-model="$store.dictionary.prefs.colorSecondary"
|
||
@input="$store.dictionary.save_preferences()" />
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<main class="main-content">
|
||
<div class="top-bar sticky top">
|
||
<div class="search-bar">
|
||
<button
|
||
@click="$store.dictionary.fetch_all_terms(search_term)">
|
||
Zuha
|
||
</button>
|
||
<input
|
||
type="text"
|
||
x-model="search_term"
|
||
@keydown.enter="$store.dictionary.fetch_all_terms(search_term)"
|
||
placeholder="Tasta ko(tel) her..." />
|
||
<button
|
||
class="hollow primary"
|
||
@click="new_lemma_form_open = true">
|
||
+
|
||
</button>
|
||
</div>
|
||
<div
|
||
class="flex-row"
|
||
x-data="{
|
||
page_count: 1,
|
||
item_count: 0
|
||
}"
|
||
x-effect="current_result_page = Math.min(current_result_page, page_count-1); page_count = Math.ceil($store.dictionary.search_results.terms/results_per_page); item_count = $store.dictionary.search_results.terms;">
|
||
<button
|
||
class="hollow primary"
|
||
:disabled="!(item_count > results_per_page && current_result_page > 0)"
|
||
@click="current_result_page-=1">
|
||
<strong>←</strong>
|
||
</button>
|
||
<div
|
||
x-text="`${current_result_page + 1} / ${page_count}`"></div>
|
||
<button
|
||
class="hollow primary"
|
||
:disabled="!(item_count > results_per_page && current_result_page+1 < page_count)"
|
||
@click="current_result_page+=1">
|
||
<strong>→</strong>
|
||
</button>
|
||
<select x-model="results_per_page">
|
||
<option value="15">15</option>
|
||
<option value="30">30</option>
|
||
<option value="60">60</option>
|
||
<option value="120">120</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="cards-container">
|
||
<template
|
||
x-for="item in $store.dictionary.filter_results(search_term).slice(current_result_page*results_per_page, Math.min((current_result_page+1)*results_per_page, $store.dictionary.search_results.terms))"
|
||
:key="item.lemma_name">
|
||
<div
|
||
class="card"
|
||
:class="expanded?'is-expanded':''"
|
||
@click.self="toggle_expand()"
|
||
x-data="{
|
||
expanded: false,
|
||
adding_definition: false,
|
||
adding_example: false,
|
||
adding_media: false,
|
||
example_text: '',
|
||
definition_text: '',
|
||
lemma_detail: null,
|
||
|
||
async toggle_expand() {
|
||
if(!this.lemma_detail){
|
||
/* If there isn't a lemma detail loaded yet, get it then expand. */
|
||
await this.load_detail();
|
||
|
||
if(this.lemma_detail) {
|
||
this.expanded = true;
|
||
} else {
|
||
alert(`Failed to load lemma ${item.lemma_name}`);
|
||
}
|
||
return;
|
||
}
|
||
|
||
/* If there is content, simply toggle the state of the card */
|
||
this.expanded = !this.expanded;
|
||
},
|
||
async load_detail(){
|
||
this.lemma_detail = await $store.dictionary.fetch_one_lemma_detail(item.lemma_name);
|
||
}
|
||
}">
|
||
<h3 x-text="item.lemma_name"></h3>
|
||
<p class="columned">
|
||
<template x-for="wf in item.word_forms">
|
||
<span
|
||
x-text="wf.word_form + ' '"
|
||
:title="wf.lect.name">
|
||
</span>
|
||
</template>
|
||
</p>
|
||
|
||
<button
|
||
class="is-fullwidth dropdown"
|
||
@click.self="toggle_expand()">
|
||
<span x-show="!expanded">v</span>
|
||
<span x-show="expanded">^</span>
|
||
</button>
|
||
|
||
<div x-show="expanded && lemma_detail">
|
||
<!-- wfs -->
|
||
<h4>Trofal</h4>
|
||
<table class="is-fullwidth">
|
||
<tbody>
|
||
<template
|
||
x-for="wf2 in (lemma_detail?.word_forms ?? [])">
|
||
<tr
|
||
x-data="{
|
||
editing:false,
|
||
edited_text: wf2.word_form
|
||
}">
|
||
<td
|
||
style="width: 8em"
|
||
x-text="wf2 ? wf2.lect.name : '(empty)'"></td>
|
||
<td>
|
||
<span
|
||
x-text="wf2 ? wf2.word_form : '(empty)'"
|
||
@click="editing = true"
|
||
x-show="!editing"></span>
|
||
|
||
<input
|
||
type="text"
|
||
class="is-fullwidth"
|
||
@click.outside="editing = false"
|
||
x-show="editing"
|
||
x-model="edited_text" />
|
||
</td>
|
||
<td style="width: 5em">
|
||
<div class="float-right">
|
||
<button
|
||
class="tiny hollow primary"
|
||
x-show="!editing"
|
||
title="kawari"
|
||
@click="editing = true">
|
||
~
|
||
</button>
|
||
<button
|
||
class="tiny hollow delete"
|
||
x-show="!editing"
|
||
title="keshite"
|
||
@click="await delete_word_form(wf2.word_form_id, wf2.word_form)">
|
||
×
|
||
</button>
|
||
<button
|
||
class="tiny edit"
|
||
x-show="editing"
|
||
title="jame"
|
||
@click="editing = false">
|
||
/
|
||
</button>
|
||
<button
|
||
class="tiny"
|
||
x-show="editing"
|
||
title="antaa"
|
||
@click="await put_word_form_text(wf2.word_form_id, edited_text); editing = false">
|
||
>
|
||
</button>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</template>
|
||
</tbody>
|
||
|
||
<!-- Add new wf -->
|
||
<tfoot>
|
||
<tr
|
||
x-data="{
|
||
adding_word_form:false,
|
||
new_word_form_text:'',
|
||
selected_lect:'',
|
||
adding_lect:false,
|
||
new_lect_name:''
|
||
}">
|
||
<td
|
||
colspan="3"
|
||
x-show="!adding_word_form">
|
||
<button
|
||
class="is-fullwidth hollow primary"
|
||
@click="adding_word_form = !adding_word_form">
|
||
+
|
||
</button>
|
||
</td>
|
||
|
||
<td
|
||
colspan="3"
|
||
x-show="adding_word_form"
|
||
style="width: 12em">
|
||
<div
|
||
style="
|
||
display: flex;
|
||
flex-direction: row;
|
||
gap: 2em;
|
||
justify-content: space-between;
|
||
">
|
||
<div>
|
||
<select
|
||
name="vilgovor"
|
||
x-model="selected_lect"
|
||
x-show="!adding_lect">
|
||
<option
|
||
value=""
|
||
selected
|
||
disabled
|
||
hidden>
|
||
Sentaku...
|
||
</option>
|
||
<template
|
||
x-for="lect in lects">
|
||
<option
|
||
:value="lect.name"
|
||
x-text="lect.name"></option>
|
||
</template>
|
||
</select>
|
||
<input
|
||
type="text"
|
||
x-show="adding_lect"
|
||
x-model="new_lect_name" />
|
||
<button
|
||
class="float-right tiny primary"
|
||
x-show="!adding_lect"
|
||
@click="adding_lect = true"
|
||
title="neo govor">
|
||
+
|
||
</button>
|
||
<button
|
||
class="float-right tiny edit"
|
||
x-show="adding_lect"
|
||
title="jame"
|
||
@click="adding_lect = false">
|
||
/
|
||
</button>
|
||
</div>
|
||
<div>
|
||
<input
|
||
type="text"
|
||
x-model="new_word_form_text" />
|
||
</div>
|
||
<div class="float-right">
|
||
<button
|
||
class="tiny edit"
|
||
x-show="adding_word_form"
|
||
title="jame"
|
||
@click="adding_word_form = false">
|
||
/
|
||
</button>
|
||
<button
|
||
class="tiny"
|
||
x-show="adding_word_form"
|
||
title="antaa"
|
||
:disabled="!(selected_lect || new_lect_name)"
|
||
@click="await post_new_word_form(item.lemma_name, adding_lect ? new_lect_name : selected_lect, new_word_form_text); adding_word_form = false">
|
||
>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</tfoot>
|
||
</table>
|
||
|
||
<h4>Imi</h4>
|
||
<ul>
|
||
<template
|
||
x-for="def in (lemma_detail?.definitions ?? [])">
|
||
<li
|
||
x-data="{
|
||
editing: false,
|
||
edited_text: def.definition_text.toString()
|
||
}"
|
||
@click.outside="editing = false">
|
||
<span
|
||
x-show="!editing"
|
||
x-html="md(def.definition_text)"
|
||
@click="editing = true"></span>
|
||
<input
|
||
type="text"
|
||
x-show="editing"
|
||
x-model="edited_text" />
|
||
<div class="float-right">
|
||
<button
|
||
class="tiny hollow primary"
|
||
title="kawari"
|
||
x-show="!editing"
|
||
@click="editing = true">
|
||
~
|
||
</button>
|
||
<button
|
||
class="tiny edit"
|
||
title="jame"
|
||
x-show="editing"
|
||
@click="editing = false">
|
||
/
|
||
</button>
|
||
<button
|
||
class="tiny primary"
|
||
title="antaa"
|
||
x-show="editing"
|
||
@click="await put_definition(def.definition_id, edited_text); editing = false">
|
||
>
|
||
</button>
|
||
<button
|
||
class="tiny hollow delete"
|
||
x-show="!editing"
|
||
title="keshite"
|
||
@click="await delete_definition(def.definition_id, def.definition_text)">
|
||
×
|
||
</button>
|
||
</div>
|
||
</li>
|
||
</template>
|
||
</ul>
|
||
<textarea
|
||
class="is-fullwidth"
|
||
x-show="adding_definition"
|
||
placeholder="Tasta imi..."
|
||
x-model="definition_text"></textarea>
|
||
<div class="flex-row">
|
||
<button
|
||
class="edit"
|
||
x-show="adding_definition"
|
||
@click="adding_definition = false">
|
||
/
|
||
</button>
|
||
<button
|
||
x-show="adding_definition"
|
||
type="button"
|
||
@click="put_definition(null, definition_text)
|
||
.then(()=>{
|
||
adding_definition = false;
|
||
definition_text = '';
|
||
})">
|
||
Popoczta
|
||
</button>
|
||
</div>
|
||
|
||
<button
|
||
class="is-fullwidth hollow primary"
|
||
x-show="!adding_definition"
|
||
@click="adding_definition = !adding_definition">
|
||
+
|
||
</button>
|
||
|
||
<h4>Tatoeba</h4>
|
||
<ul>
|
||
<template
|
||
x-for="ex in (lemma_detail?.examples ?? [])">
|
||
<li
|
||
x-data="{
|
||
editing:false,
|
||
edited_text: ex.example_text.toString()
|
||
}"
|
||
@click.outside="editing = false">
|
||
<span
|
||
x-show="!editing"
|
||
x-html="md(ex.example_text)"
|
||
@click="editing = true"></span>
|
||
<input
|
||
type="text"
|
||
x-show="editing"
|
||
x-model="edited_text" />
|
||
<div class="float-right">
|
||
<button
|
||
class="tiny hollow primary"
|
||
x-show="!editing"
|
||
@click="editing = true"
|
||
title="kawari">
|
||
~
|
||
</button>
|
||
<button
|
||
class="tiny edit"
|
||
x-show="editing"
|
||
@click="editing = false"
|
||
title="jame">
|
||
/
|
||
</button>
|
||
<button
|
||
class="tiny"
|
||
x-show="editing"
|
||
type="button"
|
||
@click="await put_example(ex.example_id, edited_text); editing = false"
|
||
title="antaa">
|
||
>
|
||
</button>
|
||
<button
|
||
class="tiny hollow delete"
|
||
x-show="!editing"
|
||
title="keshite"
|
||
@click="await delete_example(ex.example_id, ex.example_text)">
|
||
×
|
||
</button>
|
||
</div>
|
||
</li>
|
||
</template>
|
||
</ul>
|
||
<textarea
|
||
class="is-fullwidth"
|
||
x-show="adding_example"
|
||
placeholder="Tasta tatoeba..."
|
||
x-model="example_text"></textarea>
|
||
<button
|
||
class="edit"
|
||
x-show="adding_example"
|
||
@click="adding_example = false">
|
||
/
|
||
</button>
|
||
<button
|
||
x-show="adding_example"
|
||
type="button"
|
||
@click="put_example(null, example_text)
|
||
.then(()=>{
|
||
adding_example = false;
|
||
example_text = '';
|
||
})">
|
||
Popoczta
|
||
</button>
|
||
<button
|
||
class="is-fullwidth hollow primary"
|
||
x-show="!adding_example"
|
||
@click="adding_example = !adding_example">
|
||
+
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</main>
|
||
|
||
<div
|
||
x-show="new_lemma_form_open"
|
||
class="modal"
|
||
x-data="{
|
||
adding_word_form:false,
|
||
adding_lect:false,
|
||
new_word_form_text:'',
|
||
selected_lect:'',
|
||
new_lect_name:''
|
||
}"
|
||
@click.self="new_lemma_form_open = false;">
|
||
<div class="card">
|
||
<h3>Neo kotoba...</h3>
|
||
<div class="flex-row">
|
||
<div>
|
||
<label>
|
||
<div>Viljena govor</div>
|
||
<div>
|
||
<select
|
||
name="vilgovor"
|
||
x-model="selected_lect"
|
||
x-show="!adding_lect">
|
||
<option
|
||
value=""
|
||
selected
|
||
disabled
|
||
hidden>
|
||
Sentaku...
|
||
</option>
|
||
<template x-for="lect in lects">
|
||
<option
|
||
:value="lect.name"
|
||
x-text="lect.name"></option>
|
||
</template>
|
||
</select>
|
||
<input
|
||
type="text"
|
||
x-show="adding_lect"
|
||
x-model="new_lect_name" />
|
||
<button
|
||
class="float-right tiny primary"
|
||
x-show="!adding_lect"
|
||
@click="adding_lect = true"
|
||
title="neo govor">
|
||
+
|
||
</button>
|
||
<button
|
||
class="float-right tiny edit"
|
||
x-show="adding_lect"
|
||
title="jame"
|
||
@click="adding_lect = false">
|
||
/
|
||
</button>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
<label>
|
||
<div>Kakufal</div>
|
||
<div>
|
||
<input
|
||
type="text"
|
||
x-model="new_word_form_text" />
|
||
</div>
|
||
</label>
|
||
</div>
|
||
<div style="margin-top: var(--space-sm)">
|
||
<button
|
||
class="edit"
|
||
@click="new_lemma_form_open = false">
|
||
/
|
||
</button>
|
||
<button
|
||
type="button"
|
||
@click="post_lemma(new_lect_name?new_lect_name:selected_lect, new_word_form_text)
|
||
.then(()=>{
|
||
new_lemma_form_open = false;
|
||
})">
|
||
Popoczta
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|