memes
This commit is contained in:
parent
c9db062d0f
commit
adea5f4a36
1 changed files with 419 additions and 55 deletions
474
index.html
474
index.html
|
|
@ -1,13 +1,15 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RADICAL - Australia's Democratic Revolution</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RADICAL - Australia's Democratic Revolution</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300;400;500;600;700&display=swap"
|
||||
rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--primary: #ff0099;
|
||||
--primary-light: #ff66c4;
|
||||
|
|
@ -648,55 +650,169 @@
|
|||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Meme Upload Styles */
|
||||
.meme-upload {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.meme-upload-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
background-color: var(--darker);
|
||||
padding: 10px 15px;
|
||||
border: 1px dashed var(--border);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.meme-upload-label:hover {
|
||||
border-color: var(--primary);
|
||||
background-color: rgba(255, 0, 153, 0.1);
|
||||
}
|
||||
|
||||
.meme-upload-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.meme-upload-icon {
|
||||
color: var(--primary);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.meme-upload-text {
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.meme-preview {
|
||||
width: 100%;
|
||||
max-height: 300px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border: 1px solid var(--border);
|
||||
background-color: var(--darker);
|
||||
}
|
||||
|
||||
.meme-preview img {
|
||||
max-width: 100%;
|
||||
max-height: 300px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.meme-remove {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: var(--light);
|
||||
border: none;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.meme-remove:hover {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
.meme-upload-progress {
|
||||
height: 4px;
|
||||
width: 100%;
|
||||
background-color: var(--darker);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.meme-upload-progress-bar {
|
||||
height: 100%;
|
||||
background-color: var(--primary);
|
||||
width: 0;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.proposal-meme {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: 1px solid var(--border);
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.proposal-meme img {
|
||||
width: 100%;
|
||||
max-height: 300px;
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>RADICAL</h1>
|
||||
<div class="tagline">Vibe, Vote, Veto</div>
|
||||
<p>Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control.</p>
|
||||
</header>
|
||||
|
||||
<section class="new-proposal">
|
||||
<textarea id="proposal-input" class="proposal-input" placeholder="Your idea to revolutionize Australia? (280 character limit)" maxlength="280"></textarea>
|
||||
<div id="char-counter" class="char-counter">280 characters remaining</div>
|
||||
<button id="post-button" class="post-button" disabled>Post Proposal</button>
|
||||
<div style="clear: both;"></div>
|
||||
</section>
|
||||
|
||||
<section class="proposals">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-title">Democracy Goes Brrr</div>
|
||||
<select id="sort-select" class="sort-select">
|
||||
<option value="newest">Latest Ideas</option>
|
||||
<option value="popular">Most Supported</option>
|
||||
<option value="controversial">Most Debated</option>
|
||||
<option value="petitions">Petition Progress</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="proposals-container">
|
||||
<div class="loading-indicator">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>Loading democracy...</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>RADICAL - Direct Democracy Movement 🇦🇺 © 2025</p>
|
||||
<div class="footer-links">
|
||||
<a href="#about">About Us</a>
|
||||
<a href="#join">Join The Movement</a>
|
||||
<a href="#events">Events</a>
|
||||
<a href="#contact">Contact</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>RADICAL</h1>
|
||||
<div class="tagline">Vibe, Vote, Veto</div>
|
||||
<p>Australia's direct democracy movement. Share policy ideas,
|
||||
vote on proposals, take back control.</p>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
<section class="new-proposal">
|
||||
<textarea id="proposal-input" class="proposal-input"
|
||||
placeholder="Your idea to revolutionize Australia? (280 character limit)"
|
||||
maxlength="280"></textarea>
|
||||
<div id="char-counter" class="char-counter">280 characters
|
||||
remaining</div>
|
||||
<button id="post-button" class="post-button" disabled>Post
|
||||
Proposal</button>
|
||||
<div style="clear: both;"></div>
|
||||
</section>
|
||||
|
||||
<section class="proposals">
|
||||
<div class="filter-bar">
|
||||
<div class="filter-title">Democracy Goes Brrr</div>
|
||||
<select id="sort-select" class="sort-select">
|
||||
<option value="newest">Latest Ideas</option>
|
||||
<option value="popular">Most Supported</option>
|
||||
<option value="controversial">Most Debated</option>
|
||||
<option value="petitions">Petition Progress</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="proposals-container">
|
||||
<div class="loading-indicator">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>Loading democracy...</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>RADICAL - Direct Democracy Movement 🇦🇺 © 2025</p>
|
||||
<div class="footer-links">
|
||||
<a href="#about">About Us</a>
|
||||
<a href="#join">Join The Movement</a>
|
||||
<a href="#events">Events</a>
|
||||
<a href="#contact">Contact</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Configuration
|
||||
const API_BASE_URL = 'https://radical.omar-c29.workers.dev/api'; // Replace with your actual worker URL
|
||||
|
||||
|
|
@ -722,6 +838,8 @@
|
|||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Initialize variables for DOM elements
|
||||
initializeApp();
|
||||
// Initialize meme upload
|
||||
initMemeUpload();
|
||||
});
|
||||
|
||||
// Initialize application
|
||||
|
|
@ -1159,6 +1277,11 @@
|
|||
<span class="petition-count">${proposal.petition_signatures || proposal.upvotes}</span>
|
||||
<span>verified signatures</span>
|
||||
</div>` : '';
|
||||
|
||||
const memeHtml = proposal.meme_url ?
|
||||
`<div class="proposal-meme">
|
||||
<img src="${proposal.meme_url}" alt="Meme for petition" />
|
||||
</div>` : '';
|
||||
|
||||
proposalCard.innerHTML = `
|
||||
${badgeHtml}
|
||||
|
|
@ -1200,6 +1323,247 @@
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createMemeUpload() {
|
||||
const uploadContainer = document.createElement('div');
|
||||
uploadContainer.className = 'meme-upload';
|
||||
|
||||
const uploadLabel = document.createElement('label');
|
||||
uploadLabel.className = 'meme-upload-label';
|
||||
uploadLabel.setAttribute('for', 'meme-upload-input');
|
||||
|
||||
const uploadIcon = document.createElement('span');
|
||||
uploadIcon.className = 'meme-upload-icon';
|
||||
uploadIcon.textContent = '🖼️';
|
||||
|
||||
const uploadText = document.createElement('span');
|
||||
uploadText.className = 'meme-upload-text';
|
||||
uploadText.textContent = 'Add a meme to your petition (optional)';
|
||||
|
||||
const uploadInput = document.createElement('input');
|
||||
uploadInput.className = 'meme-upload-input';
|
||||
uploadInput.id = 'meme-upload-input';
|
||||
uploadInput.type = 'file';
|
||||
uploadInput.accept = 'image/jpeg, image/png, image/gif, image/webp';
|
||||
|
||||
uploadLabel.appendChild(uploadIcon);
|
||||
uploadLabel.appendChild(uploadText);
|
||||
uploadLabel.appendChild(uploadInput);
|
||||
|
||||
uploadContainer.appendChild(uploadLabel);
|
||||
|
||||
const previewContainer = document.createElement('div');
|
||||
previewContainer.className = 'meme-preview';
|
||||
previewContainer.style.display = 'none';
|
||||
|
||||
const previewImage = document.createElement('img');
|
||||
previewImage.id = 'meme-preview-image';
|
||||
|
||||
const removeButton = document.createElement('button');
|
||||
removeButton.className = 'meme-remove';
|
||||
removeButton.innerHTML = '×';
|
||||
removeButton.setAttribute('aria-label', 'Remove meme');
|
||||
|
||||
const progressContainer = document.createElement('div');
|
||||
progressContainer.className = 'meme-upload-progress';
|
||||
progressContainer.style.display = 'none';
|
||||
|
||||
const progressBar = document.createElement('div');
|
||||
progressBar.className = 'meme-upload-progress-bar';
|
||||
|
||||
progressContainer.appendChild(progressBar);
|
||||
previewContainer.appendChild(previewImage);
|
||||
previewContainer.appendChild(removeButton);
|
||||
|
||||
uploadContainer.appendChild(previewContainer);
|
||||
uploadContainer.appendChild(progressContainer);
|
||||
|
||||
return {
|
||||
container: uploadContainer,
|
||||
input: uploadInput,
|
||||
preview: previewContainer,
|
||||
image: previewImage,
|
||||
removeBtn: removeButton,
|
||||
progress: progressContainer,
|
||||
progressBar: progressBar
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize meme upload
|
||||
function initMemeUpload() {
|
||||
const newProposalSection = document.querySelector('.new-proposal');
|
||||
if (!newProposalSection) return;
|
||||
|
||||
const charCounter = document.getElementById('char-counter');
|
||||
if (!charCounter) return;
|
||||
|
||||
// Create meme upload elements
|
||||
const memeUpload = createMemeUpload();
|
||||
|
||||
// Insert after character counter, before post button
|
||||
charCounter.after(memeUpload.container);
|
||||
|
||||
// Variable to store the selected file
|
||||
let selectedMeme = null;
|
||||
|
||||
// Handle file selection
|
||||
memeUpload.input.addEventListener('change', (e) => {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// Validate file type
|
||||
const validTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (!validTypes.includes(file.type)) {
|
||||
showToastMessage('⚠️ Invalid file type. Only JPEG, PNG, GIF, and WebP images are allowed.', '#ff0099');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate file size (limit to 2MB)
|
||||
const MAX_SIZE = 2 * 1024 * 1024; // 2MB
|
||||
if (file.size > MAX_SIZE) {
|
||||
showToastMessage('⚠️ File too large. Maximum size is 2MB.', '#ff0099');
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the file
|
||||
selectedMeme = file;
|
||||
|
||||
// Show preview
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
memeUpload.image.src = event.target.result;
|
||||
memeUpload.preview.style.display = 'flex';
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
// Handle remove button
|
||||
memeUpload.removeBtn.addEventListener('click', () => {
|
||||
selectedMeme = null;
|
||||
memeUpload.input.value = '';
|
||||
memeUpload.preview.style.display = 'none';
|
||||
memeUpload.image.src = '';
|
||||
});
|
||||
|
||||
// Modify post button click handler to include meme upload
|
||||
const postButton = document.getElementById('post-button');
|
||||
if (postButton) {
|
||||
// Store the original click event handler
|
||||
const originalClickHandler = postButton.onclick;
|
||||
|
||||
// Remove the original handler
|
||||
postButton.onclick = null;
|
||||
|
||||
// Add new handler
|
||||
postButton.addEventListener('click', async () => {
|
||||
const proposalInput = document.getElementById('proposal-input');
|
||||
const text = proposalInput?.value.trim();
|
||||
|
||||
if (text) {
|
||||
try {
|
||||
const trending = Math.random() > 0.8; // Randomly mark some as trending
|
||||
|
||||
// Create the proposal first
|
||||
const createResponse = await fetch(`${API_BASE_URL}/proposals`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
authorId: currentUser.id,
|
||||
text: text,
|
||||
trending: trending
|
||||
})
|
||||
});
|
||||
|
||||
if (!createResponse.ok) {
|
||||
throw new Error('Failed to create proposal');
|
||||
}
|
||||
|
||||
const proposalData = await createResponse.json();
|
||||
const proposalId = proposalData.id;
|
||||
|
||||
// If there's a meme, upload it
|
||||
if (selectedMeme) {
|
||||
// Show progress bar
|
||||
memeUpload.progress.style.display = 'block';
|
||||
memeUpload.progressBar.style.width = '0%';
|
||||
|
||||
// Create form data for file upload
|
||||
const formData = new FormData();
|
||||
formData.append('proposalId', proposalId);
|
||||
formData.append('meme', selectedMeme);
|
||||
|
||||
// Track upload progress
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', `${API_BASE_URL}/memes`);
|
||||
|
||||
xhr.upload.addEventListener('progress', (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const percent = (event.loaded / event.total) * 100;
|
||||
memeUpload.progressBar.style.width = percent + '%';
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('load', () => {
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
// Upload successful
|
||||
memeUpload.progress.style.display = 'none';
|
||||
|
||||
// Clear the meme upload
|
||||
selectedMeme = null;
|
||||
memeUpload.input.value = '';
|
||||
memeUpload.preview.style.display = 'none';
|
||||
memeUpload.image.src = '';
|
||||
|
||||
// Show success message
|
||||
animatePostSuccess();
|
||||
|
||||
// Clear input
|
||||
proposalInput.value = '';
|
||||
charCounter.textContent = `${CHAR_LIMIT} characters remaining`;
|
||||
postButton.disabled = true;
|
||||
|
||||
// Refresh proposals
|
||||
fetchProposals();
|
||||
} else {
|
||||
// Upload failed
|
||||
memeUpload.progress.style.display = 'none';
|
||||
console.error('Meme upload failed:', xhr.responseText);
|
||||
showErrorMessage('Failed to upload meme. Please try again.');
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener('error', () => {
|
||||
memeUpload.progress.style.display = 'none';
|
||||
console.error('Meme upload network error');
|
||||
showErrorMessage('Failed to upload meme. Please check your connection.');
|
||||
});
|
||||
|
||||
// Send the upload
|
||||
xhr.send(formData);
|
||||
} else {
|
||||
// No meme to upload, just show success and refresh
|
||||
// Clear input
|
||||
proposalInput.value = '';
|
||||
charCounter.textContent = `${CHAR_LIMIT} characters remaining`;
|
||||
postButton.disabled = true;
|
||||
|
||||
// Show success animation
|
||||
animatePostSuccess();
|
||||
|
||||
// Refresh proposals
|
||||
fetchProposals();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating proposal:', error);
|
||||
showErrorMessage('Failed to post your petition. Parliament might be onto us!');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Display the modal for petition verification
|
||||
function showVerificationModal(proposalId) {
|
||||
|
|
@ -1436,5 +1800,5 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Reference in a new issue