Allow optional title, description, link
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
asonix 2022-06-20 20:49:42 -05:00
parent f823369f30
commit 03d31b9365
5 changed files with 97 additions and 11 deletions

View file

@ -28,11 +28,12 @@ const DAYS: u32 = 24 * HOURS;
mod connection;
mod middleware;
mod optional;
mod pict;
mod store;
mod ui;
use self::{connection::Connection, middleware::ValidToken, store::Store};
use self::{connection::Connection, middleware::ValidToken, optional::Optional, store::Store};
#[derive(Clone, Debug, Parser)]
pub struct Config {
@ -483,8 +484,9 @@ pub enum EntryKind {
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct Entry {
title: String,
description: String,
title: Optional<String>,
description: Optional<String>,
link: Optional<Url>,
#[serde(flatten)]
file_info: EntryKind,
@ -634,8 +636,9 @@ async fn upload(
.stateful(&state)?;
let entry = Entry {
title: String::new(),
description: String::new(),
title: None.into(),
description: None.into(),
link: None.into(),
file_info: EntryKind::Pending {
upload_id: upload.id().to_owned(),
},

72
src/optional.rs Normal file
View file

@ -0,0 +1,72 @@
use serde::{de::Error, Deserialize};
use std::{
fmt::Display,
ops::{Deref, DerefMut},
str::FromStr,
};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
#[serde(transparent)]
pub(crate) struct Optional<T> {
#[serde(skip_serializing_if = "Option::is_none")]
inner: Option<T>,
}
impl<T> Deref for Optional<T> {
type Target = Option<T>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for Optional<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T> From<Option<T>> for Optional<T> {
fn from(inner: Option<T>) -> Self {
Optional { inner }
}
}
impl<T> From<Optional<T>> for Option<T> {
fn from(e: Optional<T>) -> Self {
e.inner
}
}
impl<T> Optional<T> {
pub fn as_ref(&self) -> Option<&T> {
self.inner.as_ref()
}
pub fn as_deref(&self) -> Option<&T::Target>
where
T: Deref,
{
self.inner.as_deref()
}
}
impl<'de, T> Deserialize<'de> for Optional<T>
where
T: FromStr,
T::Err: Display,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: Option<String> = Deserialize::<'de>::deserialize(deserializer)?;
match s.as_deref() {
None | Some("") => Ok(Optional { inner: None }),
Some(s) => T::from_str(&s)
.map_err(D::Error::custom)
.map(Some)
.map(|inner| Optional { inner }),
}
}
}

View file

@ -52,15 +52,15 @@ statics::file_upload_js};
</div>
<div class="edit-item">
<form method="POST" action="@state.update_entry_path(collection_id, *id, token)">
@:text_input("title", Some("Image Title"), Some(&entry.title))
@:text_area("description", Some("Image Description"), Some(&entry.description))
@if let Some(upload_id) = entry.upload_id() {
<input type="hidden" name="upload_id" value="@upload_id" />
}
@if let Some((filename, delete_token)) = entry.file_parts() {
@:text_input("title", Some("Image Title"), entry.title.as_deref())
@:text_area("description", Some("Image Description"), entry.description.as_deref())
@:text_input("link", Some("https://..."), entry.link.as_ref().map(|l| l.as_str()))
<input type="hidden" name="filename" value="@filename" />
<input type="hidden" name="delete_token" value="@delete_token" />
}
<div class="button-group button-space">
@:button("Update Image", ButtonKind::Submit)
@:button_link("Delete Image", &state.delete_entry_path(collection_id, *id, token, false),
@ -78,6 +78,7 @@ statics::file_upload_js};
ButtonKind::Outline)
}
</div>
}
</form>
</div>
</div>

View file

@ -5,6 +5,15 @@
@:image_preview(entry, state)
<div class="image-meta">
<div class="image-title">@entry.title</div>
<div class="image-description">@entry.description</div>
@if let Some(title) = entry.title.as_ref() {
<div class="image-title">@title</div>
}
@if let Some(description) = entry.description.as_ref() {
<div class="image-description">@description</div>
}
@if let Some(link) = entry.link.as_ref() {
<div class="image-href">
<a href="@link" target="_blank" rel="noopener noreferer">@link</a>
</div>
}
</div>

View file

@ -7,7 +7,8 @@
<picture>
<source type="image/webp" srcset="@state.srcset(filename, Extension::Webp)" />
<source type="image/jpeg" srcset="@state.srcset(filename, Extension::Jpg)" />
<img src="@state.image_path(filename)" title="@entry.title" alt="@entry.description" />
<img src="@state.image_path(filename)" @if let Some(title)=entry.title.as_ref() { title="@title" } @if let
Some(description)=entry.description.as_ref() { alt="@description" } />
</picture>
</div>
} else {