vi-ilo/apps/ktb-static/search.html
2026-07-23 01:48:55 -04:00

637 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>