Big Feature and Beautifying Package

This commit is contained in:
Tim Zöller 2026-01-13 12:53:18 +01:00
parent 87da2a3861
commit 1f2ff67f38
171 changed files with 1286 additions and 663 deletions

View file

@ -34,6 +34,9 @@
<h2 id="activityTitle">Activity Title</h2>
<p class="text-muted mb-2">
<span id="activityType" class="activity-type-badge"></span>
<span id="raceBadge" class="badge race-badge ms-2" style="display: none;">
<i class="bi bi-flag-checkered"></i> Race
</span>
<span id="indoorBadge" class="badge bg-warning text-dark ms-2" style="display: none;">
<i class="bi bi-house-door"></i> Indoor
</span>
@ -510,6 +513,28 @@
document.querySelector('#visibilityBadge i').className = `bi bi-${visIcon}`;
document.getElementById('visibilityBadge').className = `ms-2 visibility-${activity.visibility.toLowerCase()}`;
// Race badge and styling
const raceBadge = document.getElementById('raceBadge');
const activityTypeSpan = document.getElementById('activityType');
const activityContent = document.getElementById('activityContent');
const metricsCard = document.querySelector('#activityContent .card.border');
if (activity.race === true) {
raceBadge.style.display = 'inline-block';
activityTypeSpan.classList.add('race-activity');
activityContent.classList.add('race-detail');
if (metricsCard) {
metricsCard.classList.add('race-metrics');
}
} else {
raceBadge.style.display = 'none';
activityTypeSpan.classList.remove('race-activity');
activityContent.classList.remove('race-detail');
if (metricsCard) {
metricsCard.classList.remove('race-metrics');
}
}
// Indoor badge
const indoorBadge = document.getElementById('indoorBadge');
if (activity.indoor === true) {

View file

@ -105,6 +105,19 @@
</div>
</div>
<!-- Race Flag -->
<div class="mb-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="race" name="race">
<label class="form-check-label" for="race">
<i class="bi bi-flag-fill"></i> This is a race/competition
</label>
</div>
<div class="form-text">
Race activities use total time for pace calculation instead of moving time
</div>
</div>
<!-- Activity Summary (Read-only) -->
<div class="alert alert-info">
<h6><i class="bi bi-info-circle"></i> Activity Summary</h6>
@ -202,6 +215,7 @@
document.getElementById('activityType').value = activity.activityType || 'OTHER';
document.getElementById('description').value = activity.description || '';
document.getElementById('visibility').value = activity.visibility || 'PUBLIC';
document.getElementById('race').checked = activity.race || false;
// Update character count
descCharCount.textContent = (activity.description || '').length;
@ -259,7 +273,8 @@
title: document.getElementById('title').value,
activityType: document.getElementById('activityType').value,
description: document.getElementById('description').value,
visibility: document.getElementById('visibility').value
visibility: document.getElementById('visibility').value,
race: document.getElementById('race').checked
};
try {

View file

@ -147,7 +147,7 @@
function renderActivities(activities) {
activitiesList.innerHTML = activities.map(activity => `
<div class="card activity-card mb-3">
<div class="card activity-card mb-3${activity.race ? ' race-list-card' : ''}">
<div class="card-body">
<div class="row">
<div class="col-md-8">
@ -157,9 +157,15 @@
</a>
</h5>
<p class="text-muted mb-2">
<span class="activity-type-badge activity-type-${activity.activityType.toLowerCase()}">
<span class="activity-type-badge activity-type-${activity.activityType.toLowerCase()}${activity.race ? ' race-activity' : ''}">
${activity.activityType}
</span>
${activity.race
? `<span class="badge race-badge ms-2" title="Race/Competition">
<i class="bi bi-flag-checkered"></i> Race
</span>`
: ''
}
${activity.indoor
? `<span class="badge bg-warning text-dark ms-2" title="${activity.indoorDetectionMethod ? 'Detected via: ' + activity.indoorDetectionMethod : 'Indoor Activity'}">
<i class="bi bi-house-door"></i> Indoor

View file

@ -131,6 +131,19 @@
</div>
</div>
<!-- Race Flag -->
<div class="mb-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="race" name="race">
<label class="form-check-label" for="race">
<i class="bi bi-flag-fill"></i> This is a race/competition
</label>
</div>
<div class="form-text">
Race activities use total time for pace calculation instead of moving time
</div>
</div>
<!-- Activity Summary (from uploaded file) -->
<div id="activitySummary" class="alert alert-info">
<h6><i class="bi bi-info-circle"></i> Activity Summary</h6>
@ -418,7 +431,8 @@
const updateData = {
title: document.getElementById('title').value,
description: document.getElementById('description').value,
visibility: document.getElementById('visibility').value
visibility: document.getElementById('visibility').value,
race: document.getElementById('race').checked
};
const response = await FitPubAuth.authenticatedFetch(

View file

@ -224,25 +224,19 @@
Share your fitness activities on the Fediverse
</p>
</div>
<div class="col-md-3">
<div class="col-md-6">
<h6>Links</h6>
<ul class="list-unstyled">
<li><a href="#" class="text-decoration-none">About</a></li>
<li><a href="#" class="text-decoration-none">Privacy</a></li>
<li><a href="#" class="text-decoration-none">Terms</a></li>
</ul>
</div>
<div class="col-md-3">
<h6>Federation</h6>
<ul class="list-unstyled">
<li><a href="#" class="text-decoration-none">ActivityPub</a></li>
<li><a href="#" class="text-decoration-none">API Docs</a></li>
<li><a th:href="@{/terms}" class="text-decoration-none">Terms &amp; Privacy</a></li>
<li><a href="https://github.com/javahippie/fitpub" target="_blank" rel="noopener noreferrer" class="text-decoration-none">
<i class="bi bi-github"></i> GitHub Repository
</a></li>
</ul>
</div>
</div>
<hr>
<div class="text-center text-muted text-small">
<p>&copy; 2024 FitPub. Open Source Software.</p>
<p>&copy; 2026 FitPub. Open Source Software.</p>
</div>
</div>
</footer>

View file

@ -110,7 +110,7 @@
<div>
<h6 class="mb-0">
${follower.local ?
`<a href="/profile/${escapeHtml(follower.username)}" class="text-decoration-none">${escapeHtml(follower.displayName || follower.username)}</a>` :
`<a href="/users/${escapeHtml(follower.username)}" class="text-decoration-none">${escapeHtml(follower.displayName || follower.username)}</a>` :
`<span>${escapeHtml(follower.displayName || follower.username)}</span>`
}
${!follower.local ? '<i class="bi bi-globe text-muted small" title="Remote user"></i>' : ''}

View file

@ -66,8 +66,8 @@
document.getElementById('usernameDisplay').textContent = targetUsername;
// Check if viewing own following list
const currentUser = FitPubAuth.getCurrentUser();
const isOwnProfile = currentUser && currentUser.username === targetUsername;
const currentUsername = FitPubAuth.getUsername();
const isOwnProfile = currentUsername && currentUsername === targetUsername;
loadFollowing(isOwnProfile);
@ -152,7 +152,7 @@
<div class="flex-grow-1">
<h6 class="mb-0">
${user.local ?
`<a href="/profile/${escapeHtml(user.username)}" class="text-decoration-none">${escapeHtml(user.displayName || user.username)}</a>` :
`<a href="/users/${escapeHtml(user.username)}" class="text-decoration-none">${escapeHtml(user.displayName || user.username)}</a>` :
`<span>${escapeHtml(user.displayName || user.username)}</span>`
}
${!user.local ? '<i class="bi bi-globe text-muted small" title="Remote user"></i>' : ''}

View file

@ -0,0 +1,131 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout}">
<head>
<title>Terms &amp; Privacy</title>
</head>
<body>
<div layout:fragment="content">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="card shadow-sm">
<div class="card-body p-4">
<div class="text-center mb-4">
<i class="bi bi-file-text text-primary" style="font-size: 3rem;"></i>
<h1 class="mt-3">Terms &amp; Privacy</h1>
<p class="text-muted">Last updated: January 2026</p>
</div>
<div class="mt-4">
<h2 class="h4 mb-3">The Honest Truth</h2>
<p>
I built FitPub primarily for myself to track my fitness activities and share them on the Fediverse.
I'm making it available for others to use, but please understand what you're getting into.
</p>
<h2 class="h4 mb-3 mt-4">No Guarantees</h2>
<p>
<strong>This is a hobby project.</strong> I make no guarantees that:
</p>
<ul>
<li>All features will work as expected (or at all)</li>
<li>Your data won't be lost due to bugs, hardware failures, or cosmic rays</li>
<li>This instance will still be running in a year, a month, or even next week</li>
<li>The service will be available 24/7 without interruptions</li>
<li>New features will be added, or that existing bugs will be fixed</li>
</ul>
<h2 class="h4 mb-3 mt-4">Use at Your Own Risk</h2>
<p>
By using FitPub, you acknowledge and accept that:
</p>
<ul>
<li>You use this service entirely at your own risk</li>
<li>I am not liable for any data loss, privacy breaches, or other issues that may occur</li>
<li>You should keep backups of your important fitness data elsewhere</li>
<li>The service may be shut down at any time without notice (though I'll try to give a heads up)</li>
<li>I may modify, suspend, or discontinue any part of the service at any time</li>
</ul>
<h2 class="h4 mb-3 mt-4">Privacy & Data</h2>
<p>
I respect your privacy, but remember:
</p>
<ul>
<li>Activities marked as "Public" are federated across the Fediverse and may be seen by anyone</li>
<li>GPS tracks include exact location data - be careful what you share publicly</li>
<li>I don't sell your data because, honestly, who would want to buy it?</li>
<li>The server logs may contain your IP address and activity data for debugging purposes</li>
<li>If you want your data deleted, just ask - I'll do my best to help</li>
</ul>
<h2 class="h4 mb-3 mt-4">User Conduct</h2>
<p>
Please be a decent human being:
</p>
<ul>
<li>Don't abuse the service or try to break it on purpose</li>
<li>Don't upload illegal content or content that violates others' rights</li>
<li>Don't spam, harass, or otherwise annoy other users</li>
<li>Don't try to access other users' private data</li>
<li>If you find a security issue, please let me know instead of exploiting it</li>
</ul>
<h2 class="h4 mb-3 mt-4">Federation & ActivityPub</h2>
<p>
FitPub federates with other ActivityPub-compatible services:
</p>
<ul>
<li>When you post a public activity, it gets sent to your followers' servers</li>
<li>I have no control over what other servers do with your data once it's federated</li>
<li>I may block or limit federation with specific servers for any reason</li>
<li>Once data is federated, deleting it here doesn't guarantee deletion elsewhere</li>
</ul>
<h2 class="h4 mb-3 mt-4">Open Source</h2>
<p>
FitPub is open source software. You can:
</p>
<ul>
<li>Review the code to see what it does</li>
<li>Run your own instance if you want more control</li>
<li>Contribute improvements if you're feeling generous</li>
<li>Fork it and make something better</li>
</ul>
<h2 class="h4 mb-3 mt-4">Changes to These Terms</h2>
<p>
I may update these terms occasionally. I'll try to notify users of significant changes,
but let's be honest - you probably won't read them anyway.
</p>
<h2 class="h4 mb-3 mt-4">The Bottom Line</h2>
<p>
FitPub is a passion project that I'm sharing with the community. It's free to use,
but comes with no warranties or guarantees. If you need enterprise-grade reliability
and support, this probably isn't the right service for you. But if you're okay with
a scrappy, independent fitness tracking platform that federates with the open web,
then welcome aboard!
</p>
<div class="alert alert-info mt-4">
<i class="bi bi-info-circle"></i>
<strong>Questions or concerns?</strong>
Feel free to reach out, but remember - I'm just one person doing this in my spare time.
I'll help if I can, but I can't promise anything.
</div>
<div class="text-center mt-4">
<a th:href="@{/}" class="btn btn-primary">
<i class="bi bi-check-circle"></i> I Understand, Take Me Back
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>