pictures in the blog
This commit is contained in:
@@ -11,14 +11,12 @@ admin-title = Admin
|
||||
admin-dashboard = Dashboard
|
||||
admin-blog = Blog
|
||||
admin-audio = Audio
|
||||
admin-images = Images
|
||||
admin-about = About
|
||||
admin-exit = Exit
|
||||
view-site = View site
|
||||
admin-blog-desc = create and update blog articles.
|
||||
admin-about-desc = edit the public about page content.
|
||||
admin-audio-desc = upload songs, then group them into albums.
|
||||
admin-images-desc = upload images for covers and articles.
|
||||
logout = Log out
|
||||
settings = Settings
|
||||
settings-language = Language
|
||||
@@ -96,6 +94,11 @@ featured-image-id = Featured image id
|
||||
image-file = Image file
|
||||
uploaded-image-id = Uploaded image id
|
||||
url = URL
|
||||
upload-featured-image = Upload image
|
||||
image-upload-help = Upload an image here to use it as the article image.
|
||||
image-uploading = Uploading...
|
||||
image-uploaded = Image uploaded and selected.
|
||||
image-upload-error = Image upload failed.
|
||||
admin-blog-articles = Blog articles
|
||||
admin-blog-index-desc = Create, edit, and remove blog posts.
|
||||
admin-blog-create-desc = Create a blog post for the public site.
|
||||
@@ -103,7 +106,6 @@ admin-no-articles = No articles yet.
|
||||
admin-create-first-post = Create the first blog post.
|
||||
edit-article = Edit article
|
||||
create-article = Create article
|
||||
admin-images-upload-desc = Upload images for blog posts and audio covers.
|
||||
edit-about = Edit About
|
||||
update-about-page = Update the public about page.
|
||||
view-page = View page
|
||||
|
||||
@@ -11,14 +11,12 @@ admin-title = Administrácia
|
||||
admin-dashboard = Prehľad
|
||||
admin-blog = Blog
|
||||
admin-audio = Hudba
|
||||
admin-images = Obrázky
|
||||
admin-about = O mne
|
||||
admin-exit = Späť na web
|
||||
view-site = Zobraziť web
|
||||
admin-blog-desc = vytvoriť a upravovať blogové články.
|
||||
admin-about-desc = upraviť obsah verejnej stránky o mne.
|
||||
admin-audio-desc = nahrať skladby a potom ich zoskupiť do albumov.
|
||||
admin-images-desc = nahrať obrázky pre obaly a články.
|
||||
logout = Odhlásiť sa
|
||||
settings = Nastavenia
|
||||
settings-language = Jazyk
|
||||
@@ -96,6 +94,11 @@ featured-image-id = ID hlavného obrázka
|
||||
image-file = Súbor obrázka
|
||||
uploaded-image-id = ID nahratého obrázka
|
||||
url = URL
|
||||
upload-featured-image = Nahrať obrázok
|
||||
image-upload-help = Tu nahraj obrázok, ktorý sa použije ako obrázok článku.
|
||||
image-uploading = Nahrávam...
|
||||
image-uploaded = Obrázok je nahratý a vybraný.
|
||||
image-upload-error = Nahratie obrázka zlyhalo.
|
||||
admin-blog-articles = Blogové články
|
||||
admin-blog-index-desc = Vytvárať, upravovať a odstraňovať blogové články.
|
||||
admin-blog-create-desc = Vytvoriť blogový článok pre verejný web.
|
||||
@@ -103,7 +106,6 @@ admin-no-articles = Zatiaľ žiadne články.
|
||||
admin-create-first-post = Vytvor prvý blogový článok.
|
||||
edit-article = Upraviť článok
|
||||
create-article = Vytvoriť článok
|
||||
admin-images-upload-desc = Nahrať obrázky pre blogové články a obaly albumov.
|
||||
edit-about = Upraviť O mne
|
||||
update-about-page = Upraviť verejnú stránku O mne.
|
||||
view-page = Zobraziť stránku
|
||||
|
||||
@@ -71,7 +71,6 @@
|
||||
<li><a href="/admin/dashboard" data-nav="/admin/dashboard">{{ t(key="admin-dashboard", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/blog/articles" data-nav="/admin/blog">{{ t(key="admin-blog", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/audio/albums" data-nav="/admin/audio">{{ t(key="admin-audio", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/images" data-nav="/admin/images">{{ t(key="admin-images", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/about" data-nav="/admin/about">{{ t(key="admin-about", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/" class="t-blue">{{ t(key="admin-exit", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li>
|
||||
@@ -93,7 +92,6 @@
|
||||
<li><a href="/admin/dashboard">{{ t(key="admin-dashboard", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/blog/articles">{{ t(key="admin-blog", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/audio/albums">{{ t(key="admin-audio", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/images">{{ t(key="admin-images", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/admin/about">{{ t(key="admin-about", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li><a href="/" class="t-blue">{{ t(key="admin-exit", lang=lang | default(value='sk')) }}</a></li>
|
||||
<li>
|
||||
|
||||
@@ -20,12 +20,56 @@
|
||||
</label>
|
||||
<label>
|
||||
{{ t(key="featured-image-id", lang=lang | default(value='sk')) }}
|
||||
<input type="text" name="featured_image_id" value="{% if article.featured_image_id %}{{ article.featured_image_id }}{% endif %}">
|
||||
<input type="text" name="featured_image_id" data-blog-image-id value="{% if article.featured_image_id %}{{ article.featured_image_id }}{% endif %}">
|
||||
</label>
|
||||
<div>
|
||||
<input type="file" accept="image/jpeg,image/png,image/webp,image/gif" data-blog-image-file class="file-input file-input-bordered">
|
||||
<button type="button" class="btn btn-outline btn-sm" data-blog-image-upload data-uploading="{{ t(key="image-uploading", lang=lang | default(value='sk')) }}" data-ready="{{ t(key="upload-featured-image", lang=lang | default(value='sk')) }}">{{ t(key="upload-featured-image", lang=lang | default(value='sk')) }}</button>
|
||||
<p class="text-sm opacity-70" data-blog-image-status>{{ t(key="image-upload-help", lang=lang | default(value='sk')) }}</p>
|
||||
<img data-blog-image-preview alt="" class="mt-2 max-h-48 rounded border border-base-300 object-cover" {% if article.featured_image_id %}src="/images/{{ article.featured_image_id }}"{% endif %} style="{% if not article.featured_image_id %}display: none;{% endif %}">
|
||||
</div>
|
||||
<label>
|
||||
<input type="checkbox" name="published" {% if article.published %}checked{% endif %}>
|
||||
{{ t(key="published", lang=lang | default(value='sk')) }}
|
||||
</label>
|
||||
<button type="submit">{{ t(key="save", lang=lang | default(value='sk')) }}</button>
|
||||
</form>
|
||||
<script>
|
||||
(function () {
|
||||
const fileInput = document.querySelector('[data-blog-image-file]');
|
||||
const idInput = document.querySelector('[data-blog-image-id]');
|
||||
const uploadButton = document.querySelector('[data-blog-image-upload]');
|
||||
const status = document.querySelector('[data-blog-image-status]');
|
||||
const preview = document.querySelector('[data-blog-image-preview]');
|
||||
if (!fileInput || !idInput || !uploadButton || !status || !preview) return;
|
||||
|
||||
function setPreview(filename) {
|
||||
if (!filename) return;
|
||||
preview.src = '/images/' + filename;
|
||||
preview.style.display = '';
|
||||
}
|
||||
|
||||
uploadButton.addEventListener('click', async function () {
|
||||
const file = fileInput.files && fileInput.files[0];
|
||||
if (!file) return;
|
||||
uploadButton.disabled = true;
|
||||
uploadButton.textContent = uploadButton.dataset.uploading;
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
try {
|
||||
const response = await fetch('/images/upload', { method: 'POST', body: formData });
|
||||
if (!response.ok) throw new Error('upload failed');
|
||||
const result = await response.json();
|
||||
idInput.value = result.filename;
|
||||
setPreview(result.filename);
|
||||
status.textContent = '{{ t(key="image-uploaded", lang=lang | default(value='sk')) }}';
|
||||
} catch (_error) {
|
||||
status.textContent = '{{ t(key="image-upload-error", lang=lang | default(value='sk')) }}';
|
||||
} finally {
|
||||
uploadButton.disabled = false;
|
||||
uploadButton.textContent = uploadButton.dataset.ready;
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -32,7 +32,13 @@
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text">{{ t(key="featured-image-id", lang=lang | default(value='sk')) }}</span></label>
|
||||
<input type="text" name="featured_image_id" class="input input-bordered w-full">
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<input type="text" name="featured_image_id" data-blog-image-id class="input input-bordered min-w-0 flex-1">
|
||||
<input type="file" accept="image/jpeg,image/png,image/webp,image/gif" data-blog-image-file class="file-input file-input-bordered min-w-0 flex-1">
|
||||
<button type="button" class="btn btn-outline btn-sm" data-blog-image-upload data-uploading="{{ t(key="image-uploading", lang=lang | default(value='sk')) }}" data-ready="{{ t(key="upload-featured-image", lang=lang | default(value='sk')) }}">{{ t(key="upload-featured-image", lang=lang | default(value='sk')) }}</button>
|
||||
</div>
|
||||
<p class="text-sm opacity-70" data-blog-image-status>{{ t(key="image-upload-help", lang=lang | default(value='sk')) }}</p>
|
||||
<img data-blog-image-preview alt="" class="mt-2 hidden max-h-48 rounded border border-base-300 object-cover">
|
||||
</div>
|
||||
|
||||
<label class="label cursor-pointer justify-start gap-2">
|
||||
@@ -48,4 +54,42 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const fileInput = document.querySelector('[data-blog-image-file]');
|
||||
const idInput = document.querySelector('[data-blog-image-id]');
|
||||
const uploadButton = document.querySelector('[data-blog-image-upload]');
|
||||
const status = document.querySelector('[data-blog-image-status]');
|
||||
const preview = document.querySelector('[data-blog-image-preview]');
|
||||
if (!fileInput || !idInput || !uploadButton || !status || !preview) return;
|
||||
|
||||
function setPreview(filename) {
|
||||
if (!filename) return;
|
||||
preview.src = '/images/' + filename;
|
||||
preview.classList.remove('hidden');
|
||||
}
|
||||
|
||||
uploadButton.addEventListener('click', async function () {
|
||||
const file = fileInput.files && fileInput.files[0];
|
||||
if (!file) return;
|
||||
uploadButton.disabled = true;
|
||||
uploadButton.textContent = uploadButton.dataset.uploading;
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
try {
|
||||
const response = await fetch('/images/upload', { method: 'POST', body: formData });
|
||||
if (!response.ok) throw new Error('upload failed');
|
||||
const result = await response.json();
|
||||
idInput.value = result.filename;
|
||||
setPreview(result.filename);
|
||||
status.textContent = '{{ t(key="image-uploaded", lang=lang | default(value='sk')) }}';
|
||||
} catch (_error) {
|
||||
status.textContent = '{{ t(key="image-upload-error", lang=lang | default(value='sk')) }}';
|
||||
} finally {
|
||||
uploadButton.disabled = false;
|
||||
uploadButton.textContent = uploadButton.dataset.ready;
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
{% extends "admin/base.html" %}
|
||||
|
||||
{% block title %}{{ t(key="admin-images", lang=lang | default(value='sk')) }}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<div class="space-y-2">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold">{{ t(key="admin-images", lang=lang | default(value='sk')) }}</h1>
|
||||
<p class="text-sm opacity-70">{{ t(key="admin-images-upload-desc", lang=lang | default(value='sk')) }}</p>
|
||||
</div>
|
||||
<a href="/admin/dashboard" class="btn btn-ghost btn-sm">{{ t(key="back-to-dashboard", lang=lang | default(value='sk')) }}</a>
|
||||
</div>
|
||||
|
||||
<div class="card border border-base-300 bg-base-100 shadow-sm">
|
||||
<div class="card-body">
|
||||
{% if uploaded %}
|
||||
<div class="alert mb-4">
|
||||
<div>
|
||||
<p class="font-medium">{{ t(key="uploaded-image-id", lang=lang | default(value='sk')) }}: {{ uploaded }}</p>
|
||||
<p class="text-sm opacity-70">{{ t(key="url", lang=lang | default(value='sk')) }}: {{ uploaded_url }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="/admin/images/upload" enctype="multipart/form-data" class="space-y-2">
|
||||
<div class="form-control">
|
||||
<label class="label"><span class="label-text">{{ t(key="image-file", lang=lang | default(value='sk')) }}</span></label>
|
||||
<input type="file" name="file" accept="image/jpeg,image/png,image/webp,image/gif" required class="file-input file-input-bordered w-full">
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pt-2">
|
||||
<button type="submit" class="btn btn-neutral btn-sm">{{ t(key="upload", lang=lang | default(value='sk')) }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
@@ -56,19 +56,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="card">
|
||||
<div class="term-head">
|
||||
<span class="term-head-name">/admin/images</span>
|
||||
<span class="term-head-meta term-tag is-green">{{ t(key="admin-images", lang=lang | default(value='sk')) }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-base">{{ t(key="admin-images", lang=lang | default(value='sk')) }}</h2>
|
||||
<p class="text-sm opacity-70">{{ t(key="admin-images-desc", lang=lang | default(value='sk')) }}</p>
|
||||
<div class="pt-2">
|
||||
<a href="/admin/images" class="btn btn-primary btn-sm">[ {{ t(key="open", lang=lang | default(value='sk')) }} → ]</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
<span class="term-head-meta term-tag">{{ t(key="post", lang=lang | default(value='sk')) }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if article.featured_image_id %}
|
||||
<img src="/images/{{ article.featured_image_id }}" alt="" class="mb-3 max-h-64 w-full rounded object-cover">
|
||||
{% endif %}
|
||||
<h2 class="card-title text-base">
|
||||
<a href="/blog/{{ article.slug }}">{{ article.title }}</a>
|
||||
</h2>
|
||||
@@ -59,6 +62,9 @@
|
||||
<span class="term-head-meta term-tag">{{ t(key="post", lang=lang | default(value='sk')) }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if article.featured_image_id %}
|
||||
<img src="/images/{{ article.featured_image_id }}" alt="" class="mb-3 max-h-64 w-full rounded object-cover">
|
||||
{% endif %}
|
||||
<h2 class="card-title text-base">
|
||||
<a href="/blog/{{ article.slug }}">{{ article.title }}</a>
|
||||
</h2>
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
<span class="term-head-meta term-tag is-blue">{{ t(key="readonly", lang=lang | default(value='sk')) }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if article.featured_image_id %}
|
||||
<img src="/images/{{ article.featured_image_id }}" alt="" class="mb-4 max-h-[28rem] w-full rounded object-cover">
|
||||
{% endif %}
|
||||
{% if article.excerpt %}
|
||||
<p class="term-prose t-yellow"># {{ article.excerpt }}</p>
|
||||
<div class="border-t border-base-300 pt-4"></div>
|
||||
@@ -45,6 +48,9 @@
|
||||
<span class="term-head-meta term-tag is-blue">{{ t(key="readonly", lang=lang | default(value='sk')) }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if article.featured_image_id %}
|
||||
<img src="/images/{{ article.featured_image_id }}" alt="" class="mb-4 max-h-[28rem] w-full rounded object-cover">
|
||||
{% endif %}
|
||||
{% if article.excerpt %}
|
||||
<p class="term-prose t-yellow"># {{ article.excerpt }}</p>
|
||||
<div class="border-t border-base-300 pt-4"></div>
|
||||
|
||||
Reference in New Issue
Block a user