Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Modules/Text/Views/multi_word_modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

?>
<div x-data="multiWordModal" x-cloak>
<div class="modal" :class="{ 'is-active': isOpen }" role="dialog" aria-modal="true" aria-labelledby="multi-word-modal-title">
<div class="modal reading-modal" :class="{ 'is-active': isOpen }"
role="dialog" aria-modal="true" aria-labelledby="multi-word-modal-title">
<div class="modal-background" @click="close"></div>
<div class="modal-card" style="max-width: 500px;">
<header class="modal-card-head py-3">
Expand Down
315 changes: 177 additions & 138 deletions src/Modules/Text/Views/word_modal.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
?>
<div x-data="wordModal" x-cloak>
<div
class="modal"
class="modal reading-modal"
:class="{ 'is-active': isOpen }"
role="dialog"
aria-modal="true"
Expand Down Expand Up @@ -214,160 +214,199 @@ class="button is-outlined is-link"
</div>
</div>

<!-- Translation -->
<div class="field">
<label class="label is-small">
<?= __e('text.modal.translation') ?> <span class="has-text-danger">*</span>
</label>
<div class="control">
<textarea
class="textarea"
:class="{ 'is-danger': hasFieldError('translation') }"
x-model="translation"
@blur="validateField('translation')"
rows="2"
placeholder="<?= __e('text.modal.translation_placeholder') ?>"
></textarea>
</div>
<template x-if="hasFieldError('translation')">
<p class="help is-danger" x-text="getFieldError('translation')"></p>
</template>
<!-- Section tabs — one section visible at a time keeps the sheet
short enough to leave the reading text visible behind it. -->
<div class="tabs is-boxed is-small is-fullwidth mb-3">
<ul>
<li :class="{ 'is-active': activeTab === 'translate' }">
<a @click.prevent="setActiveTab('translate')">
<span><?= __e('text.modal.translation') ?></span>
<template x-if="tabHasError('translate')">
<span class="tag is-danger is-small ml-1"></span>
</template>
</a>
</li>
<li :class="{ 'is-active': activeTab === 'example' }">
<a @click.prevent="setActiveTab('example')">
<span><?= __e('text.modal.example_sentence') ?></span>
<template x-if="tabHasError('example')"><span class="tag is-danger is-small ml-1"></span></template>
</a>
</li>
<li :class="{ 'is-active': activeTab === 'notes' }">
<a @click.prevent="setActiveTab('notes')">
<span><?= __e('text.modal.notes') ?></span>
<template x-if="tabHasError('notes')"><span class="tag is-danger is-small ml-1"></span></template>
</a>
</li>
<li :class="{ 'is-active': activeTab === 'tags' }">
<a @click.prevent="setActiveTab('tags')">
<span><?= __e('text.modal.tags') ?></span>
</a>
</li>
</ul>
</div>

<!-- Romanization (if enabled for language) -->
<template x-if="showRomanization">
<div class="field">
<label class="label is-small"><?= __e('text.modal.romanization') ?></label>
<div class="control">
<input
class="input"
:class="{ 'is-danger': hasFieldError('romanization') }"
type="text"
x-model="romanization"
@blur="validateField('romanization')"
placeholder="<?= __e('text.modal.romanization_placeholder') ?>"
>
<!-- Translation tab: translation, romanization, status, similar terms -->
<template x-if="activeTab === 'translate'">
<div>
<div class="field">
<label class="label is-small">
<?= __e('text.modal.translation') ?> <span class="has-text-danger">*</span>
</label>
<div class="control">
<textarea
class="textarea"
:class="{ 'is-danger': hasFieldError('translation') }"
x-model="translation"
@blur="validateField('translation')"
rows="2"
placeholder="<?= __e('text.modal.translation_placeholder') ?>"
></textarea>
</div>
<template x-if="hasFieldError('translation')">
<p class="help is-danger" x-text="getFieldError('translation')"></p>
</template>
</div>
<template x-if="hasFieldError('romanization')">
<p class="help is-danger" x-text="getFieldError('romanization')"></p>

<template x-if="showRomanization">
<div class="field">
<label class="label is-small"><?= __e('text.modal.romanization') ?></label>
<div class="control">
<input
class="input"
:class="{ 'is-danger': hasFieldError('romanization') }"
type="text"
x-model="romanization"
@blur="validateField('romanization')"
placeholder="<?= __e('text.modal.romanization_placeholder') ?>"
>
</div>
<template x-if="hasFieldError('romanization')">
<p class="help is-danger" x-text="getFieldError('romanization')"></p>
</template>
</div>
</template>
</div>
</template>

<!-- Sentence -->
<div class="field">
<label class="label is-small"><?= __e('text.modal.example_sentence') ?></label>
<div class="control">
<textarea
class="textarea"
:class="{ 'is-danger': hasFieldError('sentence') }"
x-model="sentence"
@blur="validateField('sentence')"
rows="2"
placeholder="<?= __e('text.modal.sentence_placeholder') ?>"
></textarea>
</div>
<template x-if="hasFieldError('sentence')">
<p class="help is-danger" x-text="getFieldError('sentence')"></p>
</template>
<p class="help"><?= __e('text.modal.sentence_help') ?></p>
</div>
<div class="field">
<label class="label is-small"><?= __e('text.modal.status') ?></label>
<div class="buttons are-small">
<template x-for="s in statuses" :key="s.value">
<button
type="button"
class="button"
:class="getStatusButtonClass(s.value)"
@click="setFormStatus(s.value)"
x-text="s.abbr"
></button>
</template>
</div>
</div>

<!-- Notes -->
<div class="field">
<label class="label is-small"><?= __e('text.modal.notes') ?></label>
<div class="control">
<textarea
class="textarea"
:class="{ 'is-danger': hasFieldError('notes') }"
x-model="notes"
@blur="validateField('notes')"
rows="2"
placeholder="<?= __e('text.modal.notes_placeholder') ?>"
></textarea>
<template x-if="hasSimilarTerms">
<div class="field">
<label class="label is-small"><?= __e('text.modal.similar_terms') ?></label>
<div class="is-size-7">
<template x-for="term in formSimilarTerms" :key="term.id">
<div class="is-flex is-justify-content-space-between is-align-items-center py-1"
style="border-bottom: 1px solid #f0f0f0;">
<div>
<span class="has-text-weight-semibold" x-text="term.text"></span>
<span class="has-text-grey" x-text="getSimilarTermDisplay(term)"></span>
</div>
<button
type="button"
class="button is-small is-ghost"
@click="copyFromSimilar(term)"
title="Copy translation"
x-show="term.translation"
>
<?php echo \Lwt\Shared\UI\Helpers\IconHelper::render('copy', ['size' => 12]); ?>
</button>
</div>
</template>
</div>
</div>
</template>
</div>
<template x-if="hasFieldError('notes')">
<p class="help is-danger" x-text="getFieldError('notes')"></p>
</template>
</div>
</template>

<!-- Status -->
<div class="field">
<label class="label is-small"><?= __e('text.modal.status') ?></label>
<div class="buttons are-small">
<template x-for="s in statuses" :key="s.value">
<button
type="button"
class="button"
:class="getStatusButtonClass(s.value)"
@click="setFormStatus(s.value)"
x-text="s.abbr"
></button>
<!-- Example tab -->
<template x-if="activeTab === 'example'">
<div class="field">
<label class="label is-small"><?= __e('text.modal.example_sentence') ?></label>
<div class="control">
<textarea
class="textarea"
:class="{ 'is-danger': hasFieldError('sentence') }"
x-model="sentence"
@blur="validateField('sentence')"
rows="3"
placeholder="<?= __e('text.modal.sentence_placeholder') ?>"
></textarea>
</div>
<template x-if="hasFieldError('sentence')">
<p class="help is-danger" x-text="getFieldError('sentence')"></p>
</template>
<p class="help"><?= __e('text.modal.sentence_help') ?></p>
</div>
</div>
</template>

<!-- Tags -->
<div class="field">
<label class="label is-small"><?= __e('text.modal.tags') ?></label>
<div class="control">
<!-- Current tags -->
<div class="tags mb-2" x-show="hasTags">
<template x-for="tag in formTags" :key="tag">
<span class="tag is-info is-light">
<span x-text="tag"></span>
<button type="button" class="delete is-small" @click="removeTag(tag)"></button>
</span>
</template>
</div>
<!-- Tag input with autocomplete -->
<div class="dropdown" :class="{ 'is-active': showTagSuggestions }">
<div class="dropdown-trigger" style="width: 100%;">
<input
class="input is-small"
type="text"
x-model="tagInput"
@input="filterTags"
@keydown.enter.prevent="addTag(tagInput)"
@blur="hideTagSuggestions"
placeholder="<?= __e('text.modal.add_tag') ?>"
>
</div>
<div class="dropdown-menu" role="menu" style="width: 100%;">
<div class="dropdown-content">
<template x-for="tag in filteredTags" :key="tag">
<a href="#" class="dropdown-item"
@mousedown.prevent="selectTagSuggestion(tag)" x-text="tag"></a>
</template>
</div>
</div>
<!-- Notes tab -->
<template x-if="activeTab === 'notes'">
<div class="field">
<label class="label is-small"><?= __e('text.modal.notes') ?></label>
<div class="control">
<textarea
class="textarea"
:class="{ 'is-danger': hasFieldError('notes') }"
x-model="notes"
@blur="validateField('notes')"
rows="3"
placeholder="<?= __e('text.modal.notes_placeholder') ?>"
></textarea>
</div>
<template x-if="hasFieldError('notes')">
<p class="help is-danger" x-text="getFieldError('notes')"></p>
</template>
</div>
</div>
</template>

<!-- Similar Terms -->
<template x-if="hasSimilarTerms">
<!-- Tags tab -->
<template x-if="activeTab === 'tags'">
<div class="field">
<label class="label is-small"><?= __e('text.modal.similar_terms') ?></label>
<div class="is-size-7">
<template x-for="term in formSimilarTerms" :key="term.id">
<div class="is-flex is-justify-content-space-between is-align-items-center py-1"
style="border-bottom: 1px solid #f0f0f0;">
<div>
<span class="has-text-weight-semibold" x-text="term.text"></span>
<span class="has-text-grey" x-text="getSimilarTermDisplay(term)"></span>
</div>
<button
type="button"
class="button is-small is-ghost"
@click="copyFromSimilar(term)"
title="Copy translation"
x-show="term.translation"
<label class="label is-small"><?= __e('text.modal.tags') ?></label>
<div class="control">
<!-- Current tags -->
<div class="tags mb-2" x-show="hasTags">
<template x-for="tag in formTags" :key="tag">
<span class="tag is-info is-light">
<span x-text="tag"></span>
<button type="button" class="delete is-small" @click="removeTag(tag)"></button>
</span>
</template>
</div>
<!-- Tag input with autocomplete -->
<div class="dropdown" :class="{ 'is-active': showTagSuggestions }">
<div class="dropdown-trigger" style="width: 100%;">
<input
class="input is-small"
type="text"
x-model="tagInput"
@input="filterTags"
@keydown.enter.prevent="addTag(tagInput)"
@blur="hideTagSuggestions"
placeholder="<?= __e('text.modal.add_tag') ?>"
>
<?php echo \Lwt\Shared\UI\Helpers\IconHelper::render('copy', ['size' => 12]); ?>
</button>
</div>
</template>
<div class="dropdown-menu" role="menu" style="width: 100%;">
<div class="dropdown-content">
<template x-for="tag in filteredTags" :key="tag">
<a href="#" class="dropdown-item"
@mousedown.prevent="selectTagSuggestion(tag)" x-text="tag"></a>
</template>
</div>
</div>
</div>
</div>
</div>
</template>
Expand Down
27 changes: 27 additions & 0 deletions src/frontend/css/base/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -3040,6 +3040,33 @@ Settings Page - Collapsible Sections
}
}

/* Word edit / multi-word modal — keep reading visible behind it.
These reuse Bulma's `.modal`/`.modal-card` but, like `.word-popover` above,
must stay non-blocking: the opaque `.modal-background` and near-fullscreen
`.modal-card` otherwise cover the whole viewport and hide the text the
reader was just looking at. Drop the dimming and, on mobile, cap the card
to a bottom sheet so the top of the reading area stays visible. The edit
form itself is tabbed (one section at a time) precisely to fit this cap
without needing to scroll. */
.reading-modal .modal-background {
background-color: transparent;
}

@media screen and (max-width: 768px) {
.reading-modal .modal-card {
position: fixed;
bottom: 0;
left: 0;
right: 0;
top: auto;
max-width: 100%;
min-width: 100%;
max-height: 50vh;
margin: 0;
border-radius: 12px 12px 0 0;
}
}

/* Dark theme overrides for word popover */
@media (prefers-color-scheme: dark) {
.word-popover__translation {
Expand Down
Loading