feat: add donate link and modal with supporting information for Ukraine

This commit is contained in:
2025-10-16 20:31:50 +03:00
parent a8267918ca
commit 8b056b66e7
3 changed files with 136 additions and 0 deletions

View File

@@ -23,6 +23,7 @@
<span class="header-link" id="export-link" title="Export all snippets to JSON file">Export</span> <span class="header-link" id="export-link" title="Export all snippets to JSON file">Export</span>
<span class="header-link" id="datasets-link" title="Open dataset manager (Cmd/Ctrl+K)">Datasets</span> <span class="header-link" id="datasets-link" title="Open dataset manager (Cmd/Ctrl+K)">Datasets</span>
<span class="header-link" id="help-link" title="View keyboard shortcuts and help">Help</span> <span class="header-link" id="help-link" title="View keyboard shortcuts and help">Help</span>
<span class="header-link" id="donate-link" title="Support Astrolabe creators">Donate 🇺🇦</span>
<input type="file" id="import-file-input" accept=".json" style="display: none;" /> <input type="file" id="import-file-input" accept=".json" style="display: none;" />
</div> </div>
</div> </div>
@@ -437,6 +438,93 @@
</div> </div>
</div> </div>
<!-- Donate Modal -->
<div id="donate-modal" class="modal" style="display: none;">
<div class="modal-content" style="height: auto;">
<div class="modal-header">
<span class="modal-title"></span>
<button class="btn btn-icon" id="donate-modal-close" title="Close (Escape)">×</button>
</div>
<div class="modal-body">
<div class="help-content">
<section class="help-section">
<h3 class="help-heading">Why Donate?</h3>
<p class="help-text">
Astrolabe is a free open-source project built by a Ukrainian in Kyiv, Ukraine.
If you're thinking of donating, I should be transparent about where that money actually goes - it doesn't go to me or the project.
It goes to something I care about much more. Right now, while I've been building this passion project, there are people I know - my relatives, friends, colleagues - who took arms and joined Ukraine's Armed Forces. They're defending their country against Russian invasion.
Most of them were civilians before this. They're still civilians, really, just doing something they had to do.
I feel deep gratitude to them. So my goal is to support these brave people however I can.
</p>
<p class="help-text">
You might wonder if the military really needs donations.
The honest answer: yes. The government and Ministry of Defense cover basics, but when you're on the frontlines, every small thing matters.
Better equipment, better protection, better conditions - these things can make a difference between life and death.
</p>
<p class="help-text">
If you have concerns about donating to the military: I get it. Not everyone is comfortable with that for various reasons, and I respect that.
The good news is that many of the organizations below also run humanitarian projects for civilians affected by the war. So you have options.
</p>
</section>
<div class="donate-two-column">
<section class="help-section">
<h3 class="help-heading">Where to Donate</h3>
<p class="help-text">
<ul class="help-list">
<li>
<strong><a href="https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi">
National Bank of Ukraine's special account for Ukraine's Armed Forces
</a> - Direct government channel</strong>
</li>
<li>
<strong><a href="https://savelife.in.ua/en/donate-en/#donate-army-card-once">
Come Back Alive Foundation</a></strong> - One of the biggest and most trusted. They've been around since 2014 and share <a href="https://savelife.in.ua/en/reporting-en/">detailed reports</a> of where money goes.
</li>
<li>
<strong><a href="https://macpaw.foundation/">
MacPaw Foundation</a></strong> - Founded by MacPaw (where I work). Started in 2016, shifted focus in 2022 to support the Defence Forces.
</li>
<li>
<strong><a href="https://foundation.kse.ua/en/humanitarian-projects/">
KSE Foundation</a></strong>. Kyiv School of Economics (where I teach). Focuses on both education and humanitarian support for people and defenders
</li>
<li>
<strong><a href="https://standforukraine.com/">
Stand for Ukraine</a></strong> - Not a foundation, but an aggregator of reliable organizations.
The list of fundraisers goes beyond military and covers recovery of veterans & victims of war, shelter for the refugees and many more.
</li>
</ul>
</p>
</section>
<section class="help-section">
<h3 class="help-heading">Other Ways to Support</h3>
<p class="help-text">
Not able to donate? You can still help by:
</p>
<ul class="help-list">
<li>Sharing Astrolabe with colleagues and friends</li>
<li>Reporting bugs and suggesting improvements</li>
<li>Contributing code or documentation</li>
<li>Writing about your experience using Astrolabe</li>
</ul>
</section>
</div>
<section class="help-section">
<p class="help-text" style="text-align: center; font-style: italic; color: var(--win-gray-darker);">
Thank you for considering this.
</p>
<p class="help-text" style="text-align: center; font-style: italic; color: var(--win-gray-darker);">
Oleh Omelchenko
</p>
</section>
</div>
</div>
</div>
</div>
<!-- Toast Notification Container --> <!-- Toast Notification Container -->
<div id="toast-container"></div> <div id="toast-container"></div>

View File

@@ -128,6 +128,13 @@ document.addEventListener('DOMContentLoaded', function () {
}); });
} }
const donateLink = document.getElementById('donate-link');
if (donateLink) {
donateLink.addEventListener('click', function () {
openDonateModal();
});
}
// Dataset Manager // Dataset Manager
const datasetsLink = document.getElementById('datasets-link'); const datasetsLink = document.getElementById('datasets-link');
const toggleDatasetsBtn = document.getElementById('toggle-datasets'); const toggleDatasetsBtn = document.getElementById('toggle-datasets');
@@ -252,6 +259,23 @@ document.addEventListener('DOMContentLoaded', function () {
}); });
} }
// Donate Modal
const donateModal = document.getElementById('donate-modal');
const donateModalClose = document.getElementById('donate-modal-close');
if (donateModalClose) {
donateModalClose.addEventListener('click', closeDonateModal);
}
// Close on overlay click
if (donateModal) {
donateModal.addEventListener('click', function (e) {
if (e.target === donateModal) {
closeDonateModal();
}
});
}
// View mode toggle buttons // View mode toggle buttons
document.getElementById('view-draft').addEventListener('click', () => { document.getElementById('view-draft').addEventListener('click', () => {
switchViewMode('draft'); switchViewMode('draft');
@@ -364,6 +388,7 @@ const KeyboardActions = {
const helpModal = document.getElementById('help-modal'); const helpModal = document.getElementById('help-modal');
const datasetModal = document.getElementById('dataset-modal'); const datasetModal = document.getElementById('dataset-modal');
const extractModal = document.getElementById('extract-modal'); const extractModal = document.getElementById('extract-modal');
const donateModal = document.getElementById('donate-modal');
if (helpModal && helpModal.style.display === 'flex') { if (helpModal && helpModal.style.display === 'flex') {
closeHelpModal(); closeHelpModal();
@@ -377,6 +402,10 @@ const KeyboardActions = {
hideExtractModal(); hideExtractModal();
return true; return true;
} }
if (donateModal && donateModal.style.display === 'flex') {
closeDonateModal();
return true;
}
return false; return false;
} }
}; };
@@ -448,3 +477,18 @@ function closeHelpModal() {
modal.style.display = 'none'; modal.style.display = 'none';
} }
} }
// Donate modal functions
function openDonateModal() {
const modal = document.getElementById('donate-modal');
if (modal) {
modal.style.display = 'flex';
}
}
function closeDonateModal() {
const modal = document.getElementById('donate-modal');
if (modal) {
modal.style.display = 'none';
}
}

View File

@@ -323,6 +323,10 @@ body { font-family: var(--font-main); height: 100vh; overflow: hidden; backgroun
.shortcut-key { font-family: var(--font-mono); font-weight: bold; background: var(--bg-light); border: 1px solid var(--win-gray-dark); padding: 6px 10px; border-radius: 2px; white-space: nowrap; width: 180px; } .shortcut-key { font-family: var(--font-mono); font-weight: bold; background: var(--bg-light); border: 1px solid var(--win-gray-dark); padding: 6px 10px; border-radius: 2px; white-space: nowrap; width: 180px; }
.shortcut-desc { color: var(--win-gray-darker); } .shortcut-desc { color: var(--win-gray-darker); }
/* Two-column layout for donate sections */
.donate-two-column { display: flex; gap: 20px; margin-bottom: 24px; }
.donate-two-column .help-section { flex: 1; margin-bottom: 0; }
/* Toast Notifications */ /* Toast Notifications */
#toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 2000; display: flex; flex-direction: column-reverse; gap: 10px; max-width: 400px; } #toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 2000; display: flex; flex-direction: column-reverse; gap: 10px; max-width: 400px; }
.toast { display: flex; align-items: center; gap: 10px; padding: 12px 16px; background: var(--win-gray); border: 2px outset var(--win-gray); box-shadow: 4px 4px 8px rgba(0,0,0,0.3); font-size: 12px; min-width: 300px; opacity: 0; transform: translateX(400px); transition: all 0.3s ease; } .toast { display: flex; align-items: center; gap: 10px; padding: 12px 16px; background: var(--win-gray); border: 2px outset var(--win-gray); box-shadow: 4px 4px 8px rgba(0,0,0,0.3); font-size: 12px; min-width: 300px; opacity: 0; transform: translateX(400px); transition: all 0.3s ease; }