Hello, world

This commit is contained in:
Vishnu Mohandas 2024-10-16 11:21:07 +05:30 committed by GitHub
commit 2c86135000
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

448
index.html Normal file
View file

@ -0,0 +1,448 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>funding.json generator</title>
<style>
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 20px;
background-color: #f4f4f9;
}
.container {
display: flex;
justify-content: space-between;
max-width: 1200px;
margin: 0 auto;
flex-wrap: wrap;
}
form, pre, .json-output {
width: 48%;
}
.output {
width: 96%;
min-height: 420px;
}
label {
font-weight: bold;
display: block;
margin: 10px 0 5px;
}
label.required:after {
content: " *";
color: red;
}
input, textarea, select {
width: 100%;
padding: 8px;
margin-bottom: 10px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
button {
padding: 10px 0;
font-size: 16px;
border: none;
cursor: pointer;
background-color: #1DB954;
color: white;
border-radius: 4px;
width: 100%;
margin-top: 10px;
}
button.secondary {
background-color: #696969;
margin-top: 0px;
}
pre {
padding: 10px;
background-color: #eee;
border: 1px solid #ccc;
border-radius: 4px;
height: auto;
max-height: 600px;
overflow-y: auto;
margin-bottom: 10px;
}
.dynamic-section {
margin-bottom: 2px;
}
h2, h3 {
margin-bottom: 20px;
}
.section {
margin-bottom: 30px;
}
.entity-section, .project-section, .channel-section, .plan-section, .history-section {
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 20px;
border-radius: 4px;
background-color: #fff;
position: relative;
}
.project-section::before,
.channel-section::before,
.plan-section::before,
.history-section::before {
position: absolute;
top: 5px;
left: 10px;
font-weight: bold;
color: #555;
}
.error {
color: red;
font-size: 0.9em;
margin-top: -5px;
margin-bottom: 10px;
}
@media (max-width: 768px) {
.container {
flex-direction: column;
}
form, pre, .json-output {
width: 100%;
}
.output {
width: 94%;
}
}
</style>
</head>
<body>
<div class="container">
<form id="fundingForm">
<h1>FLOSS Fund Application Form</h1>
<!-- Entity Section -->
<div class="section">
<h2>Entity</h2>
<div class="entity-section">
<label for="entityType" class="required">Type</label>
<select id="entityType" required>
<option value="">Select Type</option>
<option value="individual">Individual</option>
<option value="group">Group</option>
<option value="organisation">Organisation</option>
<option value="other">Other</option>
</select>
<label for="entityRole" class="required">Role</label>
<select id="entityRole" required>
<option value="">Select Role</option>
<option value="owner">Owner</option>
<option value="steward">Steward</option>
<option value="maintainer">Maintainer</option>
<option value="contributor">Contributor</option>
<option value="other">Other</option>
</select>
<label for="entityName" class="required">Name</label>
<input type="text" id="entityName" placeholder="Name of the entity" maxlength="250" required>
<label for="entityEmail" class="required">Email</label>
<input type="email" id="entityEmail" maxlength="250"
required>
<label for="entityPhone">Phone</label>
<input type="tel" id="entityPhone" maxlength="32">
<label for="entityDescription"
class="required">Description</label>
<textarea id="entityDescription" placeholder="Information about the entity" maxlength="2000" required></textarea>
<label for="entityWebpageUrl" class="required">Webpage
URL</label>
<input type="url" id="entityWebpageUrl" maxlength="250"
required placeholder="Webpage with information about the entity">
<label for="entityWebpageWellKnown">Well known URL</label>
<input type="url" id="entityWebpageWellKnown"
maxlength="250" placeholder="If the above URL and the URL of the funding.json do not have the same hostname">
</div>
</div>
<!-- Projects Section -->
<div class="section">
<h2>Projects</h2>
<div id="projectsContainer"></div>
<button type="button" class="secondary"
onclick="addProject()">Add Project</button>
</div>
<!-- Funding Section -->
<div class="section">
<h2>Funding</h2>
<!-- Funding Channels (Dynamic) -->
<div id="fundingChannelsContainer"></div>
<button type="button" class="secondary"
onclick="addFundingChannel()">Add Funding Channel</button>
<!-- Funding Plans (Dynamic) -->
<div id="fundingPlansContainer" style="margin-top: 42px;"></div>
<button type="button" class="secondary"
onclick="addFundingPlan()">Add Funding Plan</button>
<!-- Funding History (Dynamic) -->
<div id="fundingHistoryContainer" style="margin-top:
42px;"></div>
<button type="button" class="secondary"
onclick="addFundingHistory()">Add Funding History</button>
</div>
<!-- Generate JSON Button -->
<button type="submit">Generate JSON</button>
</form>
<!-- JSON Output Section -->
<div class="json-output">
<h2>funding.json</h2>
<pre id="output" class="output"></pre>
<button id="copyButton" class="primary" style="width: 100%;">Copy funding.json</button>
</div>
</div>
<script>
// Function to add more projects dynamically
function addProject() {
const container = document.getElementById('projectsContainer');
const newProject = document.createElement('div');
newProject.classList.add('project-section');
newProject.innerHTML = `
<h3>Project</h3>
<label for="projectGuid" class="required">GUID</label>
<input type="text" class="projectGuid" maxlength="32" pattern="^[a-z0-9-]+$" required placeholder="my-cool-project">
<label for="projectName" class="required">Name</label>
<input type="text" class="projectName" maxlength="250" placeholder="Name of the project" required>
<label for="projectDescription" class="required">Description</label>
<textarea class="projectDescription" maxlength="2000" placeholder="Description of the project" required></textarea>
<label for="projectWebpageUrl" class="required">Webpage URL</label>
<input type="url" class="projectWebpageUrl" maxlength="250" required placeholder="Webpage with information about the project">
<label for="projectWebpageWellKnown">Well known URL</label>
<input type="url" class="projectWebpageWellKnown" maxlength="250" placeholder="If the above URL and the URL of the funding.json do not have the same hostname">
<label for="projectRepositoryUrl" class="required">Repository URL</label>
<input type="url" class="projectRepositoryUrl" maxlength="250" required placeholder="Repository where the project's source code and assets are">
<label for="projectRepositoryWellKnown">Repository Well Known URL (optional)</label>
<input type="url" class="projectRepositoryWellKnown" maxlength="250" placeholder="If the above URL and the URL of the funding.json do not have the same hostname">
<label for="projectLicenses" class="required">Licenses (comma separated, up to 5)</label>
<input type="text" class="projectLicenses" required placeholder="spdx:GPL-3.0, spdx:CC-BY-SA-4.0">
<label for="projectTags" class="required">Tags (comma separated, up to 10)</label>
<input type="text" class="projectTags" required placeholder="programming, developer-tools">
`;
container.appendChild(newProject);
}
// Function to add more funding channels dynamically
function addFundingChannel() {
const container = document.getElementById('fundingChannelsContainer');
const newChannel = document.createElement('div');
newChannel.classList.add('channel-section');
newChannel.innerHTML = `
<h3>Channel</h3>
<label for="fundingChannelGuid" class="required">GUID</label>
<input type="text" class="fundingChannelGuid" maxlength="32" pattern="^[a-z0-9-]+$" required placeholder="mybank, my-paypal">
<label for="fundingChannelType" class="required">Type</label>
<select class="fundingChannelType" required>
<option value="">Select Type</option>
<option value="bank">Bank</option>
<option value="gateway">Gateway</option>
<option value="cheque">Cheque</option>
<option value="cash">Cash</option>
<option value="other">Other</option>
</select>
<label for="fundingChannelAddress">Address</label>
<input type="text" class="fundingChannelAddress" maxlength="250" placeholder="Account: 12345 (branch: ABCX)">
<label for="fundingChannelDescription">Description</label>
<textarea class="fundingChannelDescription" maxlength="500" placeholder="Additional description or instructions for the payment channel"></textarea>
`;
container.appendChild(newChannel);
}
// Function to add more funding plans dynamically
function addFundingPlan() {
const container = document.getElementById('fundingPlansContainer');
const newPlan = document.createElement('div');
newPlan.classList.add('plan-section');
newPlan.innerHTML = `
<h3>Plan</h3>
<label for="planGuid" class="required">GUID</label>
<input type="text" class="planGuid" maxlength="32" pattern="^[a-z0-9-]+$" required placeholder="mybank, paypal">
<label for="planStatus" class="required">Status</label>
<select class="planStatus" required>
<option value="">Select Status</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</select>
<label for="planName" class="required">Name</label>
<input type="text" class="planName" required placeholder="Starter support plan, Infra hosting, Monthly funding plan">
<label for="planDescription">Description</label>
<textarea class="planDescription" placeholder="Additional description or instructions for the funding plan"></textarea>
<label for="planAmount" class="required">Amount</label>
<input type="number" class="planAmount" min="0" step="0.01" required placeholder="0">
<label for="planCurrency" class="required">Currency</label>
<input type="text" class="planCurrency" pattern="^[A-Z]{3}$" maxlength="3" required placeholder="USD">
<label for="planFrequency" class="required">Frequency</label>
<select class="planFrequency" required>
<option value="">Select Frequency</option>
<option value="one-time">One-time</option>
<option value="weekly">Weekly</option>
<option value="fortnightly">Fortnightly</option>
<option value="monthly">Monthly</option>
<option value="yearly">Yearly</option>
<option value="other">Other</option>
</select>
<label for="planChannels" class="required">Channel GUIDs (comma-separated)</label>
<input type="text" class="planChannels" required>
`;
container.appendChild(newPlan);
}
// Function to add more funding history dynamically
function addFundingHistory() {
const container = document.getElementById('fundingHistoryContainer');
const newHistory = document.createElement('div');
newHistory.classList.add('history-section');
newHistory.innerHTML = `
<h3>History</h3>
<label for="historyYear" class="required">Year</label>
<input type="number" class="historyYear" min="1900" max="2100" required placeholder="2024">
<label for="historyIncome">Income (optional)</label>
<input type="number" class="historyIncome" min="0" step="0.01" placeholder="0">
<label for="historyExpenses">Expenses (optional)</label>
<input type="number" class="historyExpenses" min="0" step="0.01" placeholder="0">
<label for="historyTaxes">Taxes (optional)</label>
<input type="number" class="historyTaxes" min="0" step="0.01" placeholder="0">
<label for="historyCurrency" class="required">Currency</label>
<input type="text" class="historyCurrency" pattern="^[A-Z]{3}$" maxlength="3" required placeholder="USD">
<label for="historyDescription">Description (optional)</label>
<textarea class="historyDescription" maxlength="500"></textarea>
`;
container.appendChild(newHistory);
}
// Function to generate the JSON when the form is submitted
document.getElementById('fundingForm').addEventListener('submit', function(event) {
event.preventDefault();
const channelGUIDs = [...document.querySelectorAll('.channel-section')].map(channel => channel.querySelector('.fundingChannelGuid').value);
// Validate plan channels
const planSections = [...document.querySelectorAll('.plan-section')];
for (const plan of planSections) {
const planChannels = plan.querySelector('.planChannels').value.split(',').map(guid => guid.trim());
for (const guid of planChannels) {
if (!channelGUIDs.includes(guid)) {
alert(`Error: Channel GUID "${guid}" in plan "${plan.querySelector('.planGuid').value}" does not match any defined channel GUIDs.`);
return;
}
}
}
const output = {
version: "v1.0.0",
entity: {
type: document.getElementById('entityType').value,
role: document.getElementById('entityRole').value,
name: document.getElementById('entityName').value,
email: document.getElementById('entityEmail').value,
phone: document.getElementById('entityPhone').value || undefined,
description: document.getElementById('entityDescription').value,
webpageUrl: {
url: document.getElementById('entityWebpageUrl').value,
wellKnown: document.getElementById('entityWebpageWellKnown').value || undefined
}
},
projects: [...document.querySelectorAll('.project-section')].length > 0 ? [...document.querySelectorAll('.project-section')].map(project => ({
guid: project.querySelector('.projectGuid').value,
name: project.querySelector('.projectName').value,
description: project.querySelector('.projectDescription').value,
webpageUrl: {
url: project.querySelector('.projectWebpageUrl').value,
wellKnown: project.querySelector('.projectWebpageWellKnown').value || undefined
},
repositoryUrl: {
url: project.querySelector('.projectRepositoryUrl').value,
wellKnown: project.querySelector('.projectRepositoryWellKnown').value || undefined
},
licenses: project.querySelector('.projectLicenses').value.split(',').map(license => license.trim()),
tags: project.querySelector('.projectTags').value.split(',').map(tag => tag.trim()),
})) : [],
funding: {
channels: [...document.querySelectorAll('.channel-section')].map(channel => ({
guid: channel.querySelector('.fundingChannelGuid').value,
type: channel.querySelector('.fundingChannelType').value,
address: channel.querySelector('.fundingChannelAddress').value || undefined,
description: channel.querySelector('.fundingChannelDescription').value || undefined,
})),
plans: [...document.querySelectorAll('.plan-section')].map(plan => ({
guid: plan.querySelector('.planGuid').value,
status: plan.querySelector('.planStatus').value,
name: plan.querySelector('.planName').value,
description: plan.querySelector('.planDescription').value || undefined,
amount: parseFloat(plan.querySelector('.planAmount').value),
currency: plan.querySelector('.planCurrency').value,
frequency: plan.querySelector('.planFrequency').value,
channels: plan.querySelector('.planChannels').value.split(',').map(guid => guid.trim()),
})),
history: [...document.querySelectorAll('.history-section')].length > 0 ? [...document.querySelectorAll('.history-section')].map(history => ({
year: parseInt(history.querySelector('.historyYear').value),
income: parseFloat(history.querySelector('.historyIncome').value) || undefined,
expenses: parseFloat(history.querySelector('.historyExpenses').value) || undefined,
taxes: parseFloat(history.querySelector('.historyTaxes').value) || undefined,
currency: history.querySelector('.historyCurrency').value,
description: history.querySelector('.historyDescription').value || undefined,
})): [],
}
};
document.getElementById('output').textContent = JSON.stringify(output, null, 2);
window.scrollTo(0, 0);
});
// Function to copy JSON output to clipboard
document.getElementById('copyButton').addEventListener('click', function() {
const outputText = document.getElementById('output').textContent;
navigator.clipboard.writeText(outputText)
.then(() => {
alert('funding.json copied to clipboard');
})
.catch(err => {
alert('Error copying to clipboard: ', err);
});
});
window.addEventListener('load', function() {
console.log("hello");
addFundingChannel();
addFundingPlan();
});
</script>
</body>
</html>