353 lines
10 KiB
HTML
353 lines
10 KiB
HTML
{{ define "content" }}
|
|
<div class="min-h-screen bg-gray-100">
|
|
<!-- Header -->
|
|
<!-- Top Navigation -->
|
|
<div class="bg-white border-b border-gray-200 px-6 py-3">
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center gap-4">
|
|
<div class="flex items-center gap-2">
|
|
<i
|
|
class="{{if .PageIcon}}{{.PageIcon}}{{else}}fas fa-users{{end}} text-blue-600"
|
|
></i>
|
|
<span class="text-sm font-medium">Volunteer Management</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="max-w-2xl mx-auto">
|
|
<!-- Create Post Form -->
|
|
<div class="bg-white border-b border-gray-200 p-6">
|
|
<form
|
|
action="/posts"
|
|
method="POST"
|
|
enctype="multipart/form-data"
|
|
class="space-y-4"
|
|
>
|
|
<div class="flex items-start space-x-4">
|
|
<div class="flex-shrink-0">
|
|
<div
|
|
class="w-10 h-10 bg-blue-500 flex items-center justify-center text-white font-semibold"
|
|
>
|
|
You
|
|
</div>
|
|
</div>
|
|
<div class="flex-1">
|
|
<textarea
|
|
id="content"
|
|
name="content"
|
|
placeholder="What's on your mind?"
|
|
class="w-full px-0 py-2 text-gray-900 placeholder-gray-500 border-0 resize-none focus:outline-none focus:ring-0"
|
|
rows="3"
|
|
required
|
|
></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="flex items-center justify-between pt-4 border-t border-gray-100"
|
|
>
|
|
<div class="flex items-center">
|
|
<label
|
|
for="image"
|
|
class="cursor-pointer flex items-center space-x-2 text-blue-500 hover:text-blue-600"
|
|
>
|
|
<svg
|
|
class="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
></path>
|
|
</svg>
|
|
<span class="text-sm font-medium">Photo</span>
|
|
</label>
|
|
<input
|
|
id="image"
|
|
type="file"
|
|
name="image"
|
|
accept="image/*"
|
|
class="hidden"
|
|
/>
|
|
</div>
|
|
<button
|
|
type="submit"
|
|
class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 text-sm font-semibold transition-colors disabled:opacity-50"
|
|
>
|
|
Post
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Image preview -->
|
|
<div id="imagePreview" class="hidden">
|
|
<img
|
|
id="previewImg"
|
|
class="w-full h-64 object-cover border"
|
|
alt="Preview"
|
|
/>
|
|
<button
|
|
type="button"
|
|
id="removeImage"
|
|
class="mt-2 text-red-500 text-sm hover:text-red-600"
|
|
>
|
|
Remove image
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Posts Feed -->
|
|
<div class="space-y-0">
|
|
{{range .Posts}}
|
|
<article class="bg-white border-b border-gray-200">
|
|
<!-- Post Header -->
|
|
<div class="flex items-center px-6 py-4">
|
|
<div class="flex-shrink-0">
|
|
<div
|
|
class="w-10 h-10 bg-blue-500 flex items-center justify-center text-white font-semibold"
|
|
>
|
|
{{slice .AuthorName 0 1}}
|
|
</div>
|
|
</div>
|
|
<div class="ml-4">
|
|
<p class="text-sm font-semibold text-gray-900">{{.AuthorName}}</p>
|
|
<p class="text-xs text-gray-500">
|
|
{{.CreatedAt.Format "Jan 2, 2006"}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Post Image -->
|
|
{{if .ImageURL}}
|
|
<div class="w-full">
|
|
<img
|
|
src="{{.ImageURL}}"
|
|
alt="Post image"
|
|
class="w-full max-h-96 object-cover"
|
|
onerror="this.parentElement.style.display='none'"
|
|
/>
|
|
</div>
|
|
{{end}}
|
|
|
|
<!-- Post Content -->
|
|
{{if .Content}}
|
|
<div class="px-6 pt-2 pb-4">
|
|
<p class="text-gray-900 leading-relaxed">
|
|
<span class="font-semibold">{{.AuthorName}}</span> {{.Content}}
|
|
</p>
|
|
</div>
|
|
{{end}}
|
|
</article>
|
|
{{else}}
|
|
<div class="bg-white p-12 text-center">
|
|
<div class="max-w-sm mx-auto">
|
|
<svg
|
|
class="w-16 h-16 mx-auto text-gray-300 mb-4"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
></path>
|
|
</svg>
|
|
<h3 class="text-lg font-medium text-gray-900 mb-2">No posts yet</h3>
|
|
<p class="text-gray-500">
|
|
Be the first to share something with the community!
|
|
</p>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
/* Custom styles for Instagram-like feel */
|
|
.reaction-btn.active {
|
|
color: #3b82f6 !important;
|
|
}
|
|
|
|
.reaction-btn.active svg {
|
|
fill: currentColor;
|
|
}
|
|
|
|
.reaction-btn.dislike-active {
|
|
color: #ef4444 !important;
|
|
}
|
|
|
|
/* Smooth transitions */
|
|
.reaction-btn {
|
|
transition: all 0.2s ease-in-out;
|
|
}
|
|
|
|
.reaction-btn:hover {
|
|
transform: scale(1.05);
|
|
}
|
|
|
|
/* Focus styles */
|
|
button:focus {
|
|
outline: 2px solid #3b82f6;
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
input:focus,
|
|
textarea:focus {
|
|
outline: 2px solid #3b82f6;
|
|
outline-offset: 2px;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const fileInput = document.getElementById("image");
|
|
const imagePreview = document.getElementById("imagePreview");
|
|
const previewImg = document.getElementById("previewImg");
|
|
const removeImageBtn = document.getElementById("removeImage");
|
|
const form = document.querySelector("form");
|
|
|
|
// Image upload preview
|
|
if (fileInput) {
|
|
fileInput.addEventListener("change", function (e) {
|
|
const file = e.target.files[0];
|
|
if (file) {
|
|
console.log(
|
|
"Selected file:",
|
|
file.name,
|
|
"Size:",
|
|
file.size,
|
|
"Type:",
|
|
file.type
|
|
);
|
|
|
|
// Validate file size (10MB max)
|
|
if (file.size > 10 * 1024 * 1024) {
|
|
alert("File is too large. Maximum size is 10MB.");
|
|
this.value = "";
|
|
return;
|
|
}
|
|
|
|
// Validate file type
|
|
const allowedTypes = [
|
|
"image/jpeg",
|
|
"image/jpg",
|
|
"image/png",
|
|
"image/gif",
|
|
"image/webp",
|
|
];
|
|
if (!allowedTypes.includes(file.type)) {
|
|
alert("Invalid file type. Please select a valid image file.");
|
|
this.value = "";
|
|
return;
|
|
}
|
|
|
|
// Show preview
|
|
const reader = new FileReader();
|
|
reader.onload = function (e) {
|
|
previewImg.src = e.target.result;
|
|
imagePreview.classList.remove("hidden");
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Remove image preview
|
|
if (removeImageBtn) {
|
|
removeImageBtn.addEventListener("click", function () {
|
|
fileInput.value = "";
|
|
imagePreview.classList.add("hidden");
|
|
previewImg.src = "";
|
|
});
|
|
}
|
|
|
|
// Reaction buttons
|
|
const reactionBtns = document.querySelectorAll(".reaction-btn");
|
|
reactionBtns.forEach(function (btn) {
|
|
btn.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
const postId = this.dataset.postId;
|
|
const reaction = this.dataset.reaction;
|
|
|
|
// Toggle active state
|
|
if (reaction === "like") {
|
|
this.classList.toggle("active");
|
|
// Remove dislike active state from sibling
|
|
const dislikeBtn = this.parentElement.querySelector(
|
|
'[data-reaction="dislike"]'
|
|
);
|
|
dislikeBtn.classList.remove("dislike-active");
|
|
} else {
|
|
this.classList.toggle("dislike-active");
|
|
// Remove like active state from sibling
|
|
const likeBtn = this.parentElement.querySelector(
|
|
'[data-reaction="like"]'
|
|
);
|
|
likeBtn.classList.remove("active");
|
|
}
|
|
|
|
// Update count (mock implementation)
|
|
const countSpan = this.querySelector("span");
|
|
const currentCount = parseInt(countSpan.textContent);
|
|
const isActive =
|
|
this.classList.contains("active") ||
|
|
this.classList.contains("dislike-active");
|
|
countSpan.textContent = isActive
|
|
? currentCount + 1
|
|
: Math.max(0, currentCount - 1);
|
|
|
|
console.log(`${reaction} clicked for post ${postId}`);
|
|
|
|
// Here you would typically send an AJAX request to update the backend
|
|
// fetch(`/posts/${postId}/react`, {
|
|
// method: 'POST',
|
|
// headers: { 'Content-Type': 'application/json' },
|
|
// body: JSON.stringify({ reaction: reaction })
|
|
// });
|
|
});
|
|
});
|
|
|
|
// Form submission
|
|
if (form) {
|
|
form.addEventListener("submit", function (e) {
|
|
const content = document.getElementById("content").value.trim();
|
|
const hasImage = fileInput.files.length > 0;
|
|
|
|
if (!content && !hasImage) {
|
|
e.preventDefault();
|
|
alert("Please add some content or an image to your post.");
|
|
return;
|
|
}
|
|
|
|
console.log("Form being submitted...");
|
|
});
|
|
}
|
|
|
|
// Auto-resize textarea
|
|
const textarea = document.getElementById("content");
|
|
if (textarea) {
|
|
textarea.addEventListener("input", function () {
|
|
this.style.height = "auto";
|
|
this.style.height = this.scrollHeight + "px";
|
|
});
|
|
}
|
|
|
|
// Smooth scroll to top when clicking header
|
|
const header = document.querySelector("h1");
|
|
if (header) {
|
|
header.addEventListener("click", function () {
|
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
{{ end }}
|