Initial commit

This commit is contained in:
Bad Manners 2025-04-06 19:14:10 -03:00
commit 2722c7d40a
36 changed files with 6266 additions and 0 deletions

View file

@ -0,0 +1,54 @@
<form hx-put="/post_details/{{ post.id }}" hx-target="this" hx-swap="outerHTML">
<div>
<label>Tags</label>
<input
class="tags"
type="text"
id="search-tags"
name="tags"
hx-post="/search_tags"
hx-trigger="input changed delay:400ms"
hx-target="next .tags-autocomplete"
hx-swap="innerHTML"
hx-on::after-settle="this.focus(); this.setSelectionRange(-1, -1);"
value="{{ tags }}"
autofocus
/>
<ul class="tags-autocomplete" id="search-autocomplete"></ul>
</div>
<div>
<label>Title</label>
<input name="title" type="text" maxlength="100" value="{% if let Some(title) = post.title %}{{ title }}{% endif %}" />
</div>
<div>
<label>Description</label>
<textarea name="description">{% if let Some(description) = post.description %}{{ description }}{% endif %}</textarea>
</div>
<div>
<label>Is public?</label>
<input name="is_public" type="checkbox" {% if post.is_public %}checked{% endif %} value="true" />
</div>
<div>
<label>Rating</label>
<select name="rating">
<option value="u" {% if post.rating == "u" %}selected{% endif %}>Unrated</option>
<option value="s" {% if post.rating == "s" %}selected{% endif %}>Safe</option>
<option value="q" {% if post.rating == "q" %}selected{% endif %}>Questionable</option>
<option value="e" {% if post.rating == "e" %}selected{% endif %}>Explicit</option>
</select>
</div>
<div>
<label>Source(s)</label>
<ul id="sources">
{% for source in sources %}
{% include "post_source.html" %}
{% endfor %}
</ul>
<button hx-post="/post_source" hx-target="#sources" hx-swap="beforeend">+</button>
</div>
<div>
<button>Submit</button>
<button hx-get="/post_details/{{ post.id }}">Cancel</button>
<button hx-confirm="Are you sure that you want to delete this post? This can't be undone!" hx-delete="/post/{{ post.id }}" hx-target="body" hx-replace-url="/posts/1">Delete post</button>
</div>
</div>

View file

@ -0,0 +1,7 @@
<img
hx-get="/media/{{ post.id }}"
hx-swap="outerHTML"
id="media"
src="/files/{{ post.media }}"
style="width: {{ post.width }}px; height: {{ post.height }}px; aspect-ratio: {{ post.width }} / {{ post.height }}; cursor: zoom-out"
/>

7
templates/get_media.html Normal file
View file

@ -0,0 +1,7 @@
<img
hx-get="/media/{{ post.id }}/full"
hx-swap="outerHTML"
id="media"
src="/files/{{ post.media }}"
style="width: 100%; height: 100%; max-width: {{ post.width }}px; max-height: {{ post.height }}px; aspect-ratio: {{ post.width }} / {{ post.height }}; cursor: zoom-in"
/>

56
templates/index.html Normal file
View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<title>Samey</title>
</head>
<body>
<main>
<article>
<h2>Search</h2>
<form method="get" action="/posts/1">
<input
class="tags"
type="text"
id="search-tags"
name="tags"
hx-post="/search_tags"
hx-trigger="input changed delay:400ms"
hx-target="next .tags-autocomplete"
hx-on::after-settle="this.focus(); this.setSelectionRange(-1, -1);"
value=""
autofocus
/>
<ul class="tags-autocomplete" id="search-autocomplete"></ul>
<button type="submit">Search</button>
</form>
</article>
<article>
<h2>Upload media</h2>
<form method="post" action="/upload" enctype="multipart/form-data">
<input
class="tags"
type="text"
id="upload-tags"
name="tags"
hx-post="/search_tags"
hx-trigger="input changed delay:400ms"
hx-target="next .tags-autocomplete"
hx-on::after-settle="this.focus(); this.setSelectionRange(-1, -1);"
value=""
/>
<ul class="tags-autocomplete" id="upload-autocomplete"></ul>
<input
type="file"
id="media-file"
name="media-file"
accept=".jpg, .jpeg, .png, .webp, .gif"
/>
<button type="submit">Submit</button>
</form>
</article>
</main>
</body>
</html>

View file

@ -0,0 +1,48 @@
<div id="post-details" hx-target="this" hx-swap="outerHTML">
<div>
<label>Title</label>
{% if let Some(title) = post.title %}{{ title }}{% else %}<em>None</em>{%
endif %}
</div>
<div>
<label>Description</label>
{% if let Some(description) = post.description %}{{ description }}{% else
%}<em>None</em>{% endif %}
</div>
<div>
<label>Is public?</label>
{% if post.is_public %}Yes{% else %}No{% endif %}
</div>
<div>
<label>Rating</label>
{% match post.rating.as_ref() %} {% when "u" %} Unrated {% when "s" %} Safe
{% when "q" %} Questionable {% when "e" %} Explicit {% else %} Unknown {%
endmatch %}
</div>
<div>
<label>Source(s)</label>
{% if sources.is_empty() %}
<em>None</em>{% else %}
<ul>
{% for source in sources %}
<li id="source-{{ source.id }}">
<a href="{{ source.url }}">{{ source.url }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div>
<label>Width</label>
{{ post.width }}px
</div>
<div>
<label>Height</label>
{{ post.height }}px
</div>
<div>
<label>Upload date</label>
{{ post.uploaded_at }}
</div>
<button hx-get="/post_details/{{ post.id }}/edit">Edit</button>
</div>

View file

@ -0,0 +1,11 @@
<li>
<input
name="source"
type="url"
maxlength="200"
value="{% if let Some(url) = source.url %}{{ url }}{% endif %}"
/>
<button hx-delete="/remove" hx-target="closest li" hx-swap="outerHTML">
-
</button>
</li>

53
templates/posts.html Normal file
View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<title>Posts - Samey</title>
</head>
<body>
<article>
<h2>Search</h2>
<form method="get" action="/posts/1">
<input
class="tags"
type="text"
id="search-tags"
name="tags"
hx-post="/search_tags"
hx-trigger="input changed delay:400ms"
hx-target="next .tags-autocomplete"
hx-on::after-settle="this.focus(); this.setSelectionRange(-1, -1);"
value="{% if let Some(tags_text) = tags_text %}{{ tags_text }}{% endif %}"
/>
<ul class="tags-autocomplete" id="search-autocomplete"></ul>
<button type="submit">Search</button>
</form>
</article>
<article>
<h2>Tags</h2>
<ul>
{% if let Some(tags) = tags %} {% for tag in tags %}
<li><a href="/posts/1?tags={{ tag }}">{{ tag }}</a></li>
{% endfor %} {% endif %}
</ul>
</article>
<main>
<h1>Viewing posts</h1>
<ul>
{% for post in posts %}
<li>
<a
href="{% if let Some(tags_text) = tags_text %}/view/{{ post.id }}?tags={{ tags_text.replace(' ', "+") }}{% else %}/view/{{ post.id }}{% endif %}"
title="{{ post.tags }}"
>
<img src="/files/{{ post.thumbnail }}" />
</a>
</li>
{% endfor %}
</ul>
<div>Page {{ page }} of {{ page_count }}</div>
</main>
</body>
</html>

View file

@ -0,0 +1,11 @@
{% for tag in tags %}
<li>
<button
hx-post="/select_tag/{{ tag.name }}"
hx-target="previous .tags"
hx-swap="outerHTML"
>
{{ tag.name }}
</button>
</li>
{% endfor %}

12
templates/select_tag.html Normal file
View file

@ -0,0 +1,12 @@
<input
class="tags"
type="text"
name="tags"
hx-post="/search_tags"
hx-trigger="input changed delay:400ms"
hx-target="next .tags-autocomplete"
hx-swap="innerHTML"
hx-on::after-settle="this.focus(); this.setSelectionRange(-1, -1);"
value="{{ tags }}"
/>
<ul class="tags-autocomplete" hx-swap-oob="outerHTML:.tags-autocomplete"></ul>

View file

@ -0,0 +1,8 @@
{% include "post_details.html" %}
<ul id="tags-list" hx-swap-oob="outerHTML">
{% for tag in tags %}
<li>
<a href="/posts?tags={{ tag.name }}">{{ tag.name }}</a>
</li>
{% endfor %}
</ul>

48
templates/view_post.html Normal file
View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
<title>Post #{{ post.id }} - Samey</title>
<meta
property="og:title"
content="{% if let Some(title) = post.title %}{{ title }}{% endif %}"
/>
<meta property="og:url" content="/view/{{ post.id }}" />
<meta property="og:image" content="/files/{{ post.media }}" />
<meta property="og:image:width" content="{{ post.width }}" />
<meta property="og:image:height" content="{{ post.height }}" />
<!-- <meta property="og:image:alt" content="TO-DO" /> -->
<meta
property="og:description"
content="{% if let Some(description) = post.description %}{{ description }}{% endif %}"
/>
<meta
property="twitter:title"
content="{% if let Some(title) = post.title %}{{ title }}{% endif %}"
/>
<meta property="twitter:image:src" content="/files/{{ post.media }}" />
<meta property="twitter:card" content="summary_large_image" />
</head>
<body>
<main>
<h1>View post #{{ post.id }}</h1>
<div>{% include "get_media.html" %}</div>
</main>
<article>
<h2>Details</h2>
{% include "post_details.html" %}
</article>
<article>
<h2>Tags</h2>
<ul id="tags-list">
{% for tag in tags %}
<li>
<a href="/posts?tags={{ tag.name }}">{{ tag.name }}</a>
</li>
{% endfor %}
</ul>
</article>
</body>
</html>