website/web/templates/photo/upload.html
Noah 60dd396b30 Photo Upload & Profile Pictures
Basic photo upload support. Square cropped images still buggy.
2022-08-11 23:04:08 -07:00

342 lines
16 KiB
HTML

{{define "title"}}Upload a Photo{{end}}
{{define "content"}}
<div class="container">
<section class="hero is-info is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title">
{{if eq .Intent "profile_pic"}}
Upload a Profile Picture
{{else}}
Upload a Photo
{{end}}
</h1>
</div>
</div>
</section>
{{ $User := .CurrentUser }}
<form action="/photo/upload" method="POST" enctype="multipart/form-data">
{{InputCSRF}}
<input type="hidden" name="intent" value="{{.Intent}}">
<div class="block p-4">
<div class="content block">
<p>
You can use this page to upload a new photo to your profile. Please remember
the rules below:
</p>
<ul>
<li>
🤳 <strong>Self pictures only:</strong> you may only upload pictures which depict
<em>you</em> in them. If the picture also contains other people, be sure you
have their consent to post it here!
</li>
<li>
🔞 <strong>Mark whether your picture is explicit:</strong> not all nudists want to
see sexual content or close-up shots of genitalia. If your picture is not a
"normal nude" please check the Explicit box to help the rest of us out!
</li>
<li>
🧑 <strong>Your main profile picture must show your face:</strong> it doesn't have
to be a nude pic but your face needs to be in it. Additional photos uploaded to
your page do not need to require your face in them.
</li>
</ul>
</div>
<div class="columns">
<div class="column">
<div class="card">
<header class="card-header has-background-link">
<p class="card-header-title has-text-light">
<i class="fa fa-camera pr-2"></i>
Select a Photo
</p>
</header>
<div class="card-content">
<p class="block">
Browse or drag a photo onto this page:
</p>
<div class="field block">
<div class="file has-name is-fullwidth">
<label class="file-label">
<input class="file-input" type="file"
name="file"
id="file"
accept=".jpg,.jpeg,.jpe,.png"
required>
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
Choose a file…
</span>
</span>
<span class="file-name" id="fileName">
Select a file
</span>
</label>
</div>
</div>
<div class="box" id="imagePreview" style="display: none">
<h3 class="subtitle">
{{if .NeedsCrop}}Crop image:{{else}}Selected image:{{end}}
</h3>
{{if .NeedsCrop}}
<p class="block">
Select a square crop of this image for your profile picture. The full
image will go among the rest of your photos, and the square version
will be used as your profile pic and avatar.
</p>
{{end}}
<!-- Container of img tags for the selected photo preview. -->
<div id="previewBox" class="block"></div>
<button type="button" class="button block is-info" onclick="resetCrop()">Reset</button>
</div>
<!-- Holder of image crop coordinates in x,y,w,h format. -->
<input type="text" name="crop" id="cropCoords">
</div>
</div>
</div>
<div class="column">
<div class="card">
<header class="card-header has-background-link">
<p class="card-header-title has-text-light">
<i class="fa fa-pencil pr-2"></i>
Photo Settings
</p>
</header>
<div class="card-content">
<div class="field">
<label class="label" for="caption">Caption</label>
<input type="text" class="input"
name="caption"
id="caption"
placeholder="Caption">
</div>
<div class="field">
<label class="label">Explicit Content</label>
{{if eq .Intent "profile_pic"}}
<span class="has-text-danger">
Your default profile picture should
<strong class="has-text-danger">NOT</strong>
contain explicit content.
</span>
<p class="help">
Your default profile picture is about your face. You can have nudity
in it, too, but not a close-up shot of your genitals or sporting an
erection or engaging in sexual conduct. You can upload pictures like
that to your page, just not as your default profile picture!
</p>
{{else}}
<label class="checkbox">
<input type="checkbox"
name="explicit"
value="true">
This photo contains explicit content
</label>
<p class="help">
Mark this box if this photo contains any explicit content, including an
erect penis, close-up of genitalia, or any depiction of sexual activity.
Use your best judgment. "Normal nudes" such as full body nudes in a
non-sexual context do not need to check this box.
</p>
{{end}}
</div>
<div class="field">
<label class="label">Photo Visibility</label>
<div>
<label class="radio">
<input type="radio"
name="visibility"
value="public"
checked>
<strong>Public:</strong> this photo will appear on your profile page
and can be seen by any logged-in user account. It may also appear
on the site-wide Photo Gallery if that option is enabled, below.
</label>
</div>
<div>
<label class="radio">
<input type="radio"
name="visibility"
value="friends">
<strong>Friends only:</strong> only users you have added as a friend
can see this photo on your profile page.
</label>
</div>
<div>
<label class="radio">
<input type="radio"
name="visibility"
value="private">
<strong>Private:</strong> this photo is not visible to anybody except
for people whom you allow to see your private pictures (not implemented yet!)
</label>
</div>
</div>
<div class="field">
<label class="label">Site Photo Gallery</label>
<label class="checkbox">
<input type="checkbox"
name="gallery"
value="true"
checked>
Show this photo in the site-wide Photo Gallery (public photos only)
</label>
<p class="help">
Leave this box checked and your (public only) photo can appear in the site's
Photo Gallery page. If you uncheck this box, your (public) photo will still
appear on your profile page but not on the site photo gallery. Friends-only
or private photos never appear in the gallery even if this box is checked.
</p>
</div>
<div class="field">
<label class="label">Confirm Upload</label>
<label class="checkbox">
<input type="checkbox"
name="confirm1"
value="true"
required>
I assert that this is a photo <strong>of myself</strong> and that I have
permission to upload this picture.
</label>
{{if eq .Intent "profile_pic"}}
<label class="checkbox">
<input type="checkbox"
name="confirm2"
value="true"
required>
I assert that this picture shows my face and is not explicit
</label>
{{else}}
<input type="hidden" name="confirm2" value="true">
{{end}}
</div>
<div class="field">
<button type="submit" class="button is-primary">Upload Photo</button>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<!-- image cropper -->
<!-- <script src="/static/js/jquery-3.6.0.min.js"></script> -->
<link rel="stylesheet" href="/static/js/croppr/croppr.min.css">
<script src="/static/js/croppr/croppr.js"></script>
<script type="text/javascript">
var croppr = null;
const usingCroppr = true;
function resetCrop() {
if (croppr !== null) {
croppr.reset();
}
}
window.addEventListener("DOMContentLoaded", (event) => {
let $file = document.querySelector("#file"),
$fileName = document.querySelector("#fileName"),
$hiddenPreview = document.querySelector("#imagePreview"),
$previewBox = document.querySelector("#previewBox"),
$cropField = document.querySelector("#cropCoords");
// Clear the answer in case of page reload.
$cropField.value = "";
$file.addEventListener("change", function() {
let file = this.files[0];
$fileName.innerHTML = file.name;
// Read the image to show the preview on-page.
const reader = new FileReader();
reader.addEventListener("load", () => {
const uploadedImg = reader.result;
$hiddenPreview.style.display = "block";
// Create a new <img> tag the first time.
if (croppr !== null) {
croppr.setImage(uploadedImg);
croppr.reset();
return;
}
// If not using croppr, flush the old img preview out.
if (!usingCroppr) {
$previewBox.innerHTML = "";
}
let img = document.createElement("img");
img.src = uploadedImg;
img.style.display = "block";
img.style.maxWidth = "100%";
img.style.height = "auto";
// Add it to the wrapper div.
$previewBox.appendChild(img);
if (usingCroppr) {
croppr = new Croppr(img, {
aspectRatio: 1,
minSize: [ 32, 32, 'px' ],
returnMode: 'real',
onCropStart: (data) => {
// console.log(data);
},
onCropMove: (data) => {
// console.log(data);
},
onCropEnd: (data) => {
// console.log(data);
$cropField.value = [
data.x, data.y, data.width, data.height
].join(",");
},
onInitialize: (inst) => {
// Populate the default crop value into the form field.
let data = inst.getValue();
$cropField.value = [
data.x, data.y, data.width, data.height
].join(",");
}
});
}
});
reader.readAsDataURL(file);
});
})
</script>
</div>
{{end}}